Commit 267ee07d authored by Georg Lehmann's avatar Georg Lehmann Committed by Alexandre Julliard

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).
parent fc8570a1
......@@ -258,6 +258,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},
......@@ -782,6 +786,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:
......@@ -796,9 +801,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():
......@@ -811,7 +819,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
......@@ -819,7 +833,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.
......@@ -848,7 +862,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():
......@@ -1112,6 +1129,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":
......@@ -1725,7 +1744,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),
......@@ -1733,7 +1752,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"
......
......@@ -1894,6 +1894,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);
}
#ifdef _WIN64
NTSTATUS vk_is_available_instance_function(void *arg)
......
......@@ -287,6 +287,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
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -21,6 +21,7 @@ VkResult wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateI
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_vkCreateDeferredOperationKHR(VkDevice device, const VkAllocationCallbacks *pAllocator, VkDeferredOperationKHR *pDeferredOperation) 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;
......@@ -28,6 +29,7 @@ VkResult wine_vkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceC
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_vkDestroyDeferredOperationKHR(VkDevice device, VkDeferredOperationKHR operation, 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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment