Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
b27b3aea
Commit
b27b3aea
authored
Jul 12, 2018
by
Józef Kucia
Committed by
Alexandre Julliard
Jul 12, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
winevulkan: Implement VK_KHR_device_group_creation.
Signed-off-by:
Józef Kucia
<
jkucia@codeweavers.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
0f115346
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
95 additions
and
22 deletions
+95
-22
vulkan-1.spec
dlls/vulkan-1/vulkan-1.spec
+1
-1
make_vulkan
dlls/winevulkan/make_vulkan
+5
-0
vulkan.c
dlls/winevulkan/vulkan.c
+72
-19
vulkan_private.h
dlls/winevulkan/vulkan_private.h
+1
-1
vulkan_thunks.c
dlls/winevulkan/vulkan_thunks.c
+3
-0
vulkan_thunks.h
dlls/winevulkan/vulkan_thunks.h
+6
-0
winevulkan.spec
dlls/winevulkan/winevulkan.spec
+1
-1
vulkan.h
include/wine/vulkan.h
+6
-0
No files found.
dlls/vulkan-1/vulkan-1.spec
View file @
b27b3aea
...
...
@@ -149,7 +149,7 @@
@ stdcall vkEnumerateInstanceExtensionProperties(str ptr ptr)
@ stdcall vkEnumerateInstanceLayerProperties(ptr ptr)
@ stub vkEnumerateInstanceVersion
@ st
ub
vkEnumeratePhysicalDeviceGroups
@ st
dcall vkEnumeratePhysicalDeviceGroups(ptr ptr ptr) winevulkan.wine_
vkEnumeratePhysicalDeviceGroups
@ stdcall vkEnumeratePhysicalDevices(ptr ptr ptr) winevulkan.wine_vkEnumeratePhysicalDevices
@ stdcall vkFlushMappedMemoryRanges(ptr long ptr) winevulkan.wine_vkFlushMappedMemoryRanges
@ stdcall vkFreeCommandBuffers(ptr int64 long ptr) winevulkan.wine_vkFreeCommandBuffers
...
...
dlls/winevulkan/make_vulkan
View file @
b27b3aea
...
...
@@ -86,6 +86,7 @@ EXT_BLOCK_SIZE = 1000
# and need custom wrappers due to e.g. win32 / X11 specific code.
# List of supported instance extensions.
SUPPORTED_INSTANCE_EXTENSIONS
=
[
"VK_KHR_device_group_creation"
,
"VK_KHR_get_physical_device_properties2"
,
"VK_KHR_surface"
,
"VK_KHR_win32_surface"
,
...
...
@@ -150,6 +151,7 @@ FUNCTION_OVERRIDES = {
"vkDestroyInstance"
:
{
"dispatch"
:
False
,
"driver"
:
True
,
"thunk"
:
False
},
"vkEnumerateDeviceExtensionProperties"
:
{
"dispatch"
:
True
,
"driver"
:
False
,
"thunk"
:
False
},
"vkEnumeratePhysicalDevices"
:
{
"dispatch"
:
True
,
"driver"
:
False
,
"thunk"
:
False
},
"vkEnumeratePhysicalDeviceGroups"
:
{
"dispatch"
:
True
,
"driver"
:
False
,
"thunk"
:
False
},
# Device functions
"vkAllocateCommandBuffers"
:
{
"dispatch"
:
True
,
"driver"
:
False
,
"thunk"
:
False
},
...
...
@@ -177,6 +179,9 @@ FUNCTION_OVERRIDES = {
"vkDestroySwapchainKHR"
:
{
"dispatch"
:
True
,
"driver"
:
True
,
"thunk"
:
True
},
"vkGetSwapchainImagesKHR"
:
{
"dispatch"
:
True
,
"driver"
:
True
,
"thunk"
:
True
},
"vkQueuePresentKHR"
:
{
"dispatch"
:
True
,
"driver"
:
True
,
"thunk"
:
True
},
# VK_KHR_device_group_creation
"vkEnumeratePhysicalDeviceGroupsKHR"
:
{
"dispatch"
:
True
,
"driver"
:
False
,
"thunk"
:
False
},
}
...
...
dlls/winevulkan/vulkan.c
View file @
b27b3aea
...
...
@@ -390,34 +390,31 @@ static void wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src
/* Helper function which stores wrapped physical devices in the instance object. */
static
VkResult
wine_vk_instance_load_physical_devices
(
struct
VkInstance_T
*
instance
)
{
VkResult
res
;
struct
VkPhysicalDevice_T
**
tmp_phys_devs
;
uint32_t
num_phys_devs
=
0
;
VkPhysicalDevice
*
tmp_phys_devs
;
uint32_t
phys_dev_count
;
unsigned
int
i
;
VkResult
res
;
res
=
instance
->
funcs
.
p_vkEnumeratePhysicalDevices
(
instance
->
instance
,
&
num_phys_devs
,
NULL
);
res
=
instance
->
funcs
.
p_vkEnumeratePhysicalDevices
(
instance
->
instance
,
&
phys_dev_count
,
NULL
);
if
(
res
!=
VK_SUCCESS
)
{
ERR
(
"Failed to enumerate physical devices, res=%d
\n
"
,
res
);
return
res
;
}
if
(
!
phys_dev_count
)
return
res
;
/* Don't bother with any of the rest if the system just lacks devices. */
if
(
num_phys_devs
==
0
)
return
VK_SUCCESS
;
tmp_phys_devs
=
heap_calloc
(
num_phys_devs
,
sizeof
(
*
tmp_phys_devs
));
if
(
!
tmp_phys_devs
)
if
(
!
(
tmp_phys_devs
=
heap_calloc
(
phys_dev_count
,
sizeof
(
*
tmp_phys_devs
))))
return
VK_ERROR_OUT_OF_HOST_MEMORY
;
res
=
instance
->
funcs
.
p_vkEnumeratePhysicalDevices
(
instance
->
instance
,
&
num_phys_devs
,
tmp_phys_devs
);
res
=
instance
->
funcs
.
p_vkEnumeratePhysicalDevices
(
instance
->
instance
,
&
phys_dev_count
,
tmp_phys_devs
);
if
(
res
!=
VK_SUCCESS
)
{
heap_free
(
tmp_phys_devs
);
return
res
;
}
instance
->
phys_devs
=
heap_calloc
(
num_phys_devs
,
sizeof
(
*
instance
->
phys_devs
));
instance
->
phys_devs
=
heap_calloc
(
phys_dev_count
,
sizeof
(
*
instance
->
phys_devs
));
if
(
!
instance
->
phys_devs
)
{
heap_free
(
tmp_phys_devs
);
...
...
@@ -425,7 +422,7 @@ static VkResult wine_vk_instance_load_physical_devices(struct VkInstance_T *inst
}
/* Wrap each native physical device handle into a dispatchable object for the ICD loader. */
for
(
i
=
0
;
i
<
num_phys_devs
;
i
++
)
for
(
i
=
0
;
i
<
phys_dev_count
;
i
++
)
{
struct
VkPhysicalDevice_T
*
phys_dev
=
wine_vk_physical_device_alloc
(
instance
,
tmp_phys_devs
[
i
]);
if
(
!
phys_dev
)
...
...
@@ -436,14 +433,30 @@ static VkResult wine_vk_instance_load_physical_devices(struct VkInstance_T *inst
}
instance
->
phys_devs
[
i
]
=
phys_dev
;
instance
->
num_phys_devs
=
i
+
1
;
instance
->
phys_dev_count
=
i
+
1
;
}
instance
->
num_phys_devs
=
num_phys_devs
;
instance
->
phys_dev_count
=
phys_dev_count
;
heap_free
(
tmp_phys_devs
);
return
VK_SUCCESS
;
}
static
struct
VkPhysicalDevice_T
*
wine_vk_instance_wrap_physical_device
(
struct
VkInstance_T
*
instance
,
VkPhysicalDevice
physical_device
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
instance
->
phys_dev_count
;
++
i
)
{
struct
VkPhysicalDevice_T
*
current
=
instance
->
phys_devs
[
i
];
if
(
current
->
phys_dev
==
physical_device
)
return
current
;
}
ERR
(
"Unrecognized physical device %p.
\n
"
,
physical_device
);
return
NULL
;
}
/* Helper function used for freeing an instance structure. This function supports full
* and partial object cleanups and can thus be used for vkCreateInstance failures.
*/
...
...
@@ -456,7 +469,7 @@ static void wine_vk_instance_free(struct VkInstance_T *instance)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
instance
->
num_phys_devs
;
i
++
)
for
(
i
=
0
;
i
<
instance
->
phys_dev_count
;
i
++
)
{
wine_vk_physical_device_free
(
instance
->
phys_devs
[
i
]);
}
...
...
@@ -826,18 +839,18 @@ VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *c
if
(
!
devices
)
{
*
count
=
instance
->
num_phys_devs
;
*
count
=
instance
->
phys_dev_count
;
return
VK_SUCCESS
;
}
*
count
=
min
(
*
count
,
instance
->
num_phys_devs
);
*
count
=
min
(
*
count
,
instance
->
phys_dev_count
);
for
(
i
=
0
;
i
<
*
count
;
i
++
)
{
devices
[
i
]
=
instance
->
phys_devs
[
i
];
}
TRACE
(
"Returning %u devices.
\n
"
,
*
count
);
return
*
count
<
instance
->
num_phys_devs
?
VK_INCOMPLETE
:
VK_SUCCESS
;
return
*
count
<
instance
->
phys_dev_count
?
VK_INCOMPLETE
:
VK_SUCCESS
;
}
void
WINAPI
wine_vkFreeCommandBuffers
(
VkDevice
device
,
VkCommandPool
pool
,
uint32_t
count
,
...
...
@@ -1016,6 +1029,46 @@ err:
return
res
;
}
static
VkResult
wine_vk_enumerate_physical_device_groups
(
struct
VkInstance_T
*
instance
,
VkResult
(
*
p_vkEnumeratePhysicalDeviceGroups
)(
VkInstance
,
uint32_t
*
,
VkPhysicalDeviceGroupProperties
*
),
uint32_t
*
count
,
VkPhysicalDeviceGroupProperties
*
properties
)
{
unsigned
int
i
,
j
;
VkResult
res
;
res
=
p_vkEnumeratePhysicalDeviceGroups
(
instance
->
instance
,
count
,
properties
);
if
(
res
<
0
||
!
properties
)
return
res
;
for
(
i
=
0
;
i
<
*
count
;
++
i
)
{
VkPhysicalDeviceGroupProperties
*
current
=
&
properties
[
i
];
for
(
j
=
0
;
j
<
current
->
physicalDeviceCount
;
++
j
)
{
VkPhysicalDevice
dev
=
current
->
physicalDevices
[
j
];
if
(
!
(
current
->
physicalDevices
[
j
]
=
wine_vk_instance_wrap_physical_device
(
instance
,
dev
)))
return
VK_ERROR_INITIALIZATION_FAILED
;
}
}
return
res
;
}
VkResult
WINAPI
wine_vkEnumeratePhysicalDeviceGroups
(
VkInstance
instance
,
uint32_t
*
count
,
VkPhysicalDeviceGroupProperties
*
properties
)
{
TRACE
(
"%p, %p, %p
\n
"
,
instance
,
count
,
properties
);
return
wine_vk_enumerate_physical_device_groups
(
instance
,
instance
->
funcs
.
p_vkEnumeratePhysicalDeviceGroups
,
count
,
properties
);
}
VkResult
WINAPI
wine_vkEnumeratePhysicalDeviceGroupsKHR
(
VkInstance
instance
,
uint32_t
*
count
,
VkPhysicalDeviceGroupProperties
*
properties
)
{
TRACE
(
"%p, %p, %p
\n
"
,
instance
,
count
,
properties
);
return
wine_vk_enumerate_physical_device_groups
(
instance
,
instance
->
funcs
.
p_vkEnumeratePhysicalDeviceGroupsKHR
,
count
,
properties
);
}
BOOL
WINAPI
DllMain
(
HINSTANCE
hinst
,
DWORD
reason
,
void
*
reserved
)
{
...
...
dlls/winevulkan/vulkan_private.h
View file @
b27b3aea
...
...
@@ -86,7 +86,7 @@ struct VkInstance_T
* dispatchable objects.
*/
struct
VkPhysicalDevice_T
**
phys_devs
;
uint32_t
num_phys_devs
;
uint32_t
phys_dev_count
;
unsigned
int
quirks
;
};
...
...
dlls/winevulkan/vulkan_thunks.c
View file @
b27b3aea
...
...
@@ -2919,6 +2919,8 @@ static const struct vulkan_func vk_instance_dispatch_table[] =
{
"vkDestroySurfaceKHR"
,
&
wine_vkDestroySurfaceKHR
},
{
"vkEnumerateDeviceExtensionProperties"
,
&
wine_vkEnumerateDeviceExtensionProperties
},
{
"vkEnumerateDeviceLayerProperties"
,
&
wine_vkEnumerateDeviceLayerProperties
},
{
"vkEnumeratePhysicalDeviceGroups"
,
&
wine_vkEnumeratePhysicalDeviceGroups
},
{
"vkEnumeratePhysicalDeviceGroupsKHR"
,
&
wine_vkEnumeratePhysicalDeviceGroupsKHR
},
{
"vkEnumeratePhysicalDevices"
,
&
wine_vkEnumeratePhysicalDevices
},
{
"vkGetPhysicalDeviceFeatures"
,
&
wine_vkGetPhysicalDeviceFeatures
},
{
"vkGetPhysicalDeviceFeatures2"
,
&
wine_vkGetPhysicalDeviceFeatures2
},
...
...
@@ -3048,6 +3050,7 @@ static const char * const vk_device_extensions[] =
static
const
char
*
const
vk_instance_extensions
[]
=
{
"VK_KHR_device_group_creation"
,
"VK_KHR_get_physical_device_properties2"
,
"VK_KHR_surface"
,
"VK_KHR_win32_surface"
,
...
...
dlls/winevulkan/vulkan_thunks.h
View file @
b27b3aea
...
...
@@ -45,6 +45,8 @@ VkResult WINAPI wine_vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDev
void
WINAPI
wine_vkDestroyDevice
(
VkDevice
device
,
const
VkAllocationCallbacks
*
pAllocator
);
void
WINAPI
wine_vkDestroyInstance
(
VkInstance
instance
,
const
VkAllocationCallbacks
*
pAllocator
);
VkResult
WINAPI
wine_vkEnumerateDeviceExtensionProperties
(
VkPhysicalDevice
physicalDevice
,
const
char
*
pLayerName
,
uint32_t
*
pPropertyCount
,
VkExtensionProperties
*
pProperties
);
VkResult
WINAPI
wine_vkEnumeratePhysicalDeviceGroups
(
VkInstance
instance
,
uint32_t
*
pPhysicalDeviceGroupCount
,
VkPhysicalDeviceGroupProperties
*
pPhysicalDeviceGroupProperties
);
VkResult
WINAPI
wine_vkEnumeratePhysicalDeviceGroupsKHR
(
VkInstance
instance
,
uint32_t
*
pPhysicalDeviceGroupCount
,
VkPhysicalDeviceGroupProperties
*
pPhysicalDeviceGroupProperties
)
DECLSPEC_HIDDEN
;
VkResult
WINAPI
wine_vkEnumeratePhysicalDevices
(
VkInstance
instance
,
uint32_t
*
pPhysicalDeviceCount
,
VkPhysicalDevice
*
pPhysicalDevices
);
void
WINAPI
wine_vkFreeCommandBuffers
(
VkDevice
device
,
VkCommandPool
commandPool
,
uint32_t
commandBufferCount
,
const
VkCommandBuffer
*
pCommandBuffers
);
PFN_vkVoidFunction
WINAPI
wine_vkGetDeviceProcAddr
(
VkDevice
device
,
const
char
*
pName
);
...
...
@@ -942,6 +944,8 @@ struct vulkan_instance_funcs
void
(
*
p_vkDestroySurfaceKHR
)(
VkInstance
,
VkSurfaceKHR
,
const
VkAllocationCallbacks
*
);
VkResult
(
*
p_vkEnumerateDeviceExtensionProperties
)(
VkPhysicalDevice
,
const
char
*
,
uint32_t
*
,
VkExtensionProperties
*
);
VkResult
(
*
p_vkEnumerateDeviceLayerProperties
)(
VkPhysicalDevice
,
uint32_t
*
,
VkLayerProperties
*
);
VkResult
(
*
p_vkEnumeratePhysicalDeviceGroups
)(
VkInstance
,
uint32_t
*
,
VkPhysicalDeviceGroupProperties
*
);
VkResult
(
*
p_vkEnumeratePhysicalDeviceGroupsKHR
)(
VkInstance
,
uint32_t
*
,
VkPhysicalDeviceGroupProperties
*
);
VkResult
(
*
p_vkEnumeratePhysicalDevices
)(
VkInstance
,
uint32_t
*
,
VkPhysicalDevice
*
);
void
(
*
p_vkGetPhysicalDeviceFeatures
)(
VkPhysicalDevice
,
VkPhysicalDeviceFeatures
*
);
void
(
*
p_vkGetPhysicalDeviceFeatures2
)(
VkPhysicalDevice
,
VkPhysicalDeviceFeatures2
*
);
...
...
@@ -1180,6 +1184,8 @@ struct vulkan_instance_funcs
USE_VK_FUNC(vkDestroySurfaceKHR) \
USE_VK_FUNC(vkEnumerateDeviceExtensionProperties) \
USE_VK_FUNC(vkEnumerateDeviceLayerProperties) \
USE_VK_FUNC(vkEnumeratePhysicalDeviceGroups) \
USE_VK_FUNC(vkEnumeratePhysicalDeviceGroupsKHR) \
USE_VK_FUNC(vkEnumeratePhysicalDevices) \
USE_VK_FUNC(vkGetPhysicalDeviceFeatures) \
USE_VK_FUNC(vkGetPhysicalDeviceFeatures2) \
...
...
dlls/winevulkan/winevulkan.spec
View file @
b27b3aea
...
...
@@ -150,7 +150,7 @@
@ stdcall wine_vkEnumerateDeviceLayerProperties(ptr ptr ptr)
@ stdcall wine_vkEnumerateInstanceExtensionProperties(str ptr ptr)
@ stub vkEnumerateInstanceVersion
@ st
ub vkEnumeratePhysicalDeviceGroups
@ st
dcall wine_vkEnumeratePhysicalDeviceGroups(ptr ptr ptr)
@ stdcall wine_vkEnumeratePhysicalDevices(ptr ptr ptr)
@ stdcall wine_vkFlushMappedMemoryRanges(ptr long ptr)
@ stdcall wine_vkFreeCommandBuffers(ptr int64 long ptr)
...
...
include/wine/vulkan.h
View file @
b27b3aea
...
...
@@ -137,6 +137,8 @@
#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
#define VK_KHR_MAINTENANCE1_SPEC_VERSION 2
#define VK_KHR_MAINTENANCE1_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_PUSH_DESCRIPTOR_SPEC_VERSION 2
#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor"
#define VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR 1
...
...
@@ -4290,6 +4292,8 @@ typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysica
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_vkEnumeratePhysicalDeviceGroups
)(
VkInstance
,
uint32_t
*
,
VkPhysicalDeviceGroupProperties
*
);
typedef
VkResult
(
VKAPI_PTR
*
PFN_vkEnumeratePhysicalDeviceGroupsKHR
)(
VkInstance
,
uint32_t
*
,
VkPhysicalDeviceGroupProperties
*
);
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
*
);
...
...
@@ -4495,6 +4499,8 @@ VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physic
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
vkEnumeratePhysicalDeviceGroups
(
VkInstance
instance
,
uint32_t
*
pPhysicalDeviceGroupCount
,
VkPhysicalDeviceGroupProperties
*
pPhysicalDeviceGroupProperties
);
VkResult
VKAPI_CALL
vkEnumeratePhysicalDeviceGroupsKHR
(
VkInstance
instance
,
uint32_t
*
pPhysicalDeviceGroupCount
,
VkPhysicalDeviceGroupProperties
*
pPhysicalDeviceGroupProperties
);
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
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment