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
ec87407e
Commit
ec87407e
authored
Aug 20, 2014
by
Henri Verbeet
Committed by
Alexandre Julliard
Aug 20, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
wined3d: Keep a reference to the frontbuffer texture instead of the surface in the swapchain.
parent
415b8037
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
53 additions
and
40 deletions
+53
-40
arb_program_shader.c
dlls/wined3d/arb_program_shader.c
+1
-1
context.c
dlls/wined3d/context.c
+2
-2
device.c
dlls/wined3d/device.c
+7
-4
resource.c
dlls/wined3d/resource.c
+1
-1
surface.c
dlls/wined3d/surface.c
+13
-10
swapchain.c
dlls/wined3d/swapchain.c
+28
-21
wined3d_private.h
dlls/wined3d/wined3d_private.h
+1
-1
No files found.
dlls/wined3d/arb_program_shader.c
View file @
ec87407e
...
...
@@ -7675,7 +7675,7 @@ HRESULT arbfp_blit_surface(struct wined3d_device *device, DWORD filter,
if
(
wined3d_settings
.
strict_draw_ordering
||
(
dst_surface
->
container
->
swapchain
&&
(
dst_surface
->
container
->
swapchain
->
front_buffer
==
dst_surface
)))
&&
(
dst_surface
->
container
->
swapchain
->
front_buffer
==
dst_surface
->
container
)))
context
->
gl_info
->
gl_ops
.
gl
.
p_glFlush
();
/* Flush to ensure ordering across contexts. */
context_release
(
context
);
...
...
dlls/wined3d/context.c
View file @
ec87407e
...
...
@@ -1826,7 +1826,7 @@ static void context_get_rt_size(const struct wined3d_context *context, SIZE *siz
{
const
struct
wined3d_surface
*
rt
=
context
->
current_rt
;
if
(
rt
->
container
->
swapchain
&&
rt
->
container
->
swapchain
->
front_buffer
==
rt
)
if
(
rt
->
container
->
swapchain
&&
rt
->
container
->
swapchain
->
front_buffer
==
rt
->
container
)
{
RECT
window_size
;
...
...
@@ -3104,7 +3104,7 @@ struct wined3d_context *context_acquire(const struct wined3d_device *device, str
if
(
swapchain
->
back_buffers
)
target
=
swapchain
->
back_buffers
[
0
];
else
target
=
s
wapchain
->
front_buffer
;
target
=
s
urface_from_resource
(
wined3d_texture_get_sub_resource
(
swapchain
->
front_buffer
,
0
))
;
}
}
...
...
dlls/wined3d/device.c
View file @
ec87407e
...
...
@@ -462,7 +462,7 @@ void device_clear_render_targets(struct wined3d_device *device, UINT rt_count, c
}
if
(
wined3d_settings
.
strict_draw_ordering
||
(
flags
&
WINED3DCLEAR_TARGET
&&
target
->
container
->
swapchain
&&
target
->
container
->
swapchain
->
front_buffer
==
target
))
&&
target
->
container
->
swapchain
&&
target
->
container
->
swapchain
->
front_buffer
==
target
->
container
))
gl_info
->
gl_ops
.
gl
.
p_glFlush
();
/* Flush to ensure ordering across contexts. */
context_release
(
context
);
...
...
@@ -913,7 +913,8 @@ HRESULT CDECL wined3d_device_init_3d(struct wined3d_device *device,
device
->
swapchains
[
0
]
=
swapchain
;
device_init_swapchain_state
(
device
,
swapchain
);
context
=
context_acquire
(
device
,
swapchain
->
front_buffer
);
context
=
context_acquire
(
device
,
surface_from_resource
(
wined3d_texture_get_sub_resource
(
swapchain
->
front_buffer
,
0
)));
create_dummy_textures
(
device
,
context
);
...
...
@@ -4169,7 +4170,8 @@ static HRESULT create_primary_opengl_context(struct wined3d_device *device, stru
return
E_OUTOFMEMORY
;
}
target
=
swapchain
->
back_buffers
?
swapchain
->
back_buffers
[
0
]
:
swapchain
->
front_buffer
;
target
=
swapchain
->
back_buffers
?
swapchain
->
back_buffers
[
0
]
:
surface_from_resource
(
wined3d_texture_get_sub_resource
(
swapchain
->
front_buffer
,
0
));
if
(
!
(
context
=
context_create
(
swapchain
,
target
,
swapchain
->
ds_format
)))
{
WARN
(
"Failed to create context.
\n
"
);
...
...
@@ -4401,7 +4403,8 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
{
UINT
i
;
if
(
FAILED
(
hr
=
wined3d_surface_update_desc
(
swapchain
->
front_buffer
,
swapchain
->
desc
.
backbuffer_width
,
if
(
FAILED
(
hr
=
wined3d_surface_update_desc
(
surface_from_resource
(
wined3d_texture_get_sub_resource
(
swapchain
->
front_buffer
,
0
)),
swapchain
->
desc
.
backbuffer_width
,
swapchain
->
desc
.
backbuffer_height
,
swapchain
->
desc
.
backbuffer_format
,
swapchain
->
desc
.
multisample_type
,
swapchain
->
desc
.
multisample_quality
,
NULL
,
0
)))
return
hr
;
...
...
dlls/wined3d/resource.c
View file @
ec87407e
...
...
@@ -316,7 +316,7 @@ BOOL wined3d_resource_is_offscreen(struct wined3d_resource *resource)
return
TRUE
;
/* The front buffer is always onscreen */
if
(
resource
==
&
swapchain
->
front_buffer
->
container
->
resource
)
if
(
resource
==
&
swapchain
->
front_buffer
->
resource
)
return
FALSE
;
/* If the swapchain is rendered to an FBO, the backbuffer is
...
...
dlls/wined3d/surface.c
View file @
ec87407e
...
...
@@ -749,7 +749,7 @@ static void surface_unmap(struct wined3d_surface *surface)
return
;
}
if
(
surface
->
container
->
swapchain
&&
surface
->
container
->
swapchain
->
front_buffer
==
surface
)
if
(
surface
->
container
->
swapchain
&&
surface
->
container
->
swapchain
->
front_buffer
==
surface
->
container
)
surface_load_location
(
surface
,
surface
->
container
->
resource
.
draw_binding
);
else
if
(
surface
->
resource
.
format
->
flags
&
(
WINED3DFMT_FLAG_DEPTH
|
WINED3DFMT_FLAG_STENCIL
))
FIXME
(
"Depth / stencil buffer locking is not implemented.
\n
"
);
...
...
@@ -968,7 +968,7 @@ static void surface_blt_fbo(const struct wined3d_device *device, enum wined3d_te
if
(
wined3d_settings
.
strict_draw_ordering
||
(
dst_location
==
WINED3D_LOCATION_DRAWABLE
&&
dst_surface
->
container
->
swapchain
->
front_buffer
==
dst_surface
))
&&
dst_surface
->
container
->
swapchain
->
front_buffer
==
dst_surface
->
container
))
gl_info
->
gl_ops
.
gl
.
p_glFlush
();
context_release
(
context
);
...
...
@@ -1291,7 +1291,7 @@ static void gdi_surface_unmap(struct wined3d_surface *surface)
TRACE
(
"surface %p.
\n
"
,
surface
);
/* Tell the swapchain to update the screen. */
if
(
surface
->
container
->
swapchain
&&
surface
==
surface
->
container
->
swapchain
->
front_buffer
)
if
(
surface
->
container
->
swapchain
&&
surface
->
container
==
surface
->
container
->
swapchain
->
front_buffer
)
x11_copy_to_screen
(
surface
->
container
->
swapchain
,
&
surface
->
lockedRect
);
memset
(
&
surface
->
lockedRect
,
0
,
sizeof
(
RECT
));
...
...
@@ -1607,7 +1607,7 @@ static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_
* conflicts with this.
*/
if
(
!
((
blit_supported
&&
surface
->
container
->
swapchain
&&
surface
==
surface
->
container
->
swapchain
->
front_buffer
))
&&
surface
->
container
==
surface
->
container
->
swapchain
->
front_buffer
))
||
colorkey_active
||
!
use_texturing
)
{
format
->
glFormat
=
GL_RGBA
;
...
...
@@ -1995,7 +1995,7 @@ GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
TRACE
(
"Returning GL_BACK
\n
"
);
return
GL_BACK
;
}
else
if
(
surface
==
swapchain
->
front_buffer
)
else
if
(
surface
->
container
==
swapchain
->
front_buffer
)
{
TRACE
(
"Returning GL_FRONT
\n
"
);
return
GL_FRONT
;
...
...
@@ -3855,7 +3855,7 @@ void surface_translate_drawable_coords(const struct wined3d_surface *surface, HW
{
UINT
drawable_height
;
if
(
surface
->
container
->
swapchain
&&
surface
==
surface
->
container
->
swapchain
->
front_buffer
)
if
(
surface
->
container
->
swapchain
&&
surface
->
container
==
surface
->
container
->
swapchain
->
front_buffer
)
{
POINT
offset
=
{
0
,
0
};
RECT
windowsize
;
...
...
@@ -3936,7 +3936,8 @@ static void surface_blt_to_drawable(const struct wined3d_device *device,
device
->
blitter
->
unset_shader
(
context
->
gl_info
);
if
(
wined3d_settings
.
strict_draw_ordering
||
(
dst_surface
->
container
->
swapchain
&&
dst_surface
->
container
->
swapchain
->
front_buffer
==
dst_surface
))
||
(
dst_surface
->
container
->
swapchain
&&
dst_surface
->
container
->
swapchain
->
front_buffer
==
dst_surface
->
container
))
gl_info
->
gl_ops
.
gl
.
p_glFlush
();
/* Flush to ensure ordering across contexts. */
context_release
(
context
);
...
...
@@ -4309,7 +4310,8 @@ void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_co
/* Note that we use depth_blt here as well, rather than glCopyTexImage2D
* directly on the FBO texture. That's because we need to flip. */
context_apply_fbo_state_blit
(
context
,
GL_FRAMEBUFFER
,
context
->
swapchain
->
front_buffer
,
NULL
,
WINED3D_LOCATION_DRAWABLE
);
surface_from_resource
(
wined3d_texture_get_sub_resource
(
context
->
swapchain
->
front_buffer
,
0
)),
NULL
,
WINED3D_LOCATION_DRAWABLE
);
if
(
surface
->
texture_target
==
GL_TEXTURE_RECTANGLE_ARB
)
{
gl_info
->
gl_ops
.
gl
.
p_glGetIntegerv
(
GL_TEXTURE_BINDING_RECTANGLE_ARB
,
&
old_binding
);
...
...
@@ -4355,7 +4357,8 @@ void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_co
TRACE
(
"Copying depth texture to onscreen depth buffer.
\n
"
);
context_apply_fbo_state_blit
(
context
,
GL_FRAMEBUFFER
,
context
->
swapchain
->
front_buffer
,
NULL
,
WINED3D_LOCATION_DRAWABLE
);
surface_from_resource
(
wined3d_texture_get_sub_resource
(
context
->
swapchain
->
front_buffer
,
0
)),
NULL
,
WINED3D_LOCATION_DRAWABLE
);
surface_depth_blt
(
surface
,
context
,
surface
->
container
->
texture_rgb
.
name
,
0
,
surface
->
pow2Height
-
h
,
w
,
h
,
surface
->
texture_target
);
checkGLcall
(
"depth_blt"
);
...
...
@@ -5828,7 +5831,7 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
* to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
* applications can't blit directly to the frontbuffer. */
if
(
dst_swapchain
&&
dst_swapchain
->
back_buffers
&&
dst_surface
==
dst_swapchain
->
front_buffer
&&
dst_surface
->
container
==
dst_swapchain
->
front_buffer
&&
src_surface
==
dst_swapchain
->
back_buffers
[
0
])
{
enum
wined3d_swap_effect
swap_effect
=
dst_swapchain
->
desc
.
swap_effect
;
...
...
dlls/wined3d/swapchain.c
View file @
ec87407e
...
...
@@ -40,8 +40,8 @@ static void swapchain_cleanup(struct wined3d_swapchain *swapchain)
* is the last buffer to be destroyed, FindContext() depends on that. */
if
(
swapchain
->
front_buffer
)
{
wined3d_texture_set_swapchain
(
swapchain
->
front_buffer
->
container
,
NULL
);
if
(
wined3d_
surfac
e_decref
(
swapchain
->
front_buffer
))
wined3d_texture_set_swapchain
(
swapchain
->
front_buffer
,
NULL
);
if
(
wined3d_
textur
e_decref
(
swapchain
->
front_buffer
))
WARN
(
"Something's still holding the front buffer (%p).
\n
"
,
swapchain
->
front_buffer
);
swapchain
->
front_buffer
=
NULL
;
}
...
...
@@ -163,7 +163,7 @@ HRESULT CDECL wined3d_swapchain_get_front_buffer_data(const struct wined3d_swapc
TRACE
(
"swapchain %p, dst_surface %p.
\n
"
,
swapchain
,
dst_surface
);
src_surface
=
s
wapchain
->
front_buffer
;
src_surface
=
s
urface_from_resource
(
wined3d_texture_get_sub_resource
(
swapchain
->
front_buffer
,
0
))
;
SetRect
(
&
src_rect
,
0
,
0
,
src_surface
->
resource
.
width
,
src_surface
->
resource
.
height
);
dst_rect
=
src_rect
;
...
...
@@ -315,7 +315,8 @@ static void swapchain_blit(const struct wined3d_swapchain *swapchain,
gl_info
->
gl_ops
.
gl
.
p_glReadBuffer
(
GL_COLOR_ATTACHMENT0
);
context_check_fbo_status
(
context
,
GL_READ_FRAMEBUFFER
);
context_apply_fbo_state_blit
(
context
,
GL_DRAW_FRAMEBUFFER
,
swapchain
->
front_buffer
,
context_apply_fbo_state_blit
(
context
,
GL_DRAW_FRAMEBUFFER
,
surface_from_resource
(
wined3d_texture_get_sub_resource
(
swapchain
->
front_buffer
,
0
)),
NULL
,
WINED3D_LOCATION_DRAWABLE
);
context_set_draw_buffer
(
context
,
GL_BACK
);
context_invalidate_state
(
context
,
STATE_FRAMEBUFFER
);
...
...
@@ -358,7 +359,8 @@ static void swapchain_blit(const struct wined3d_swapchain *swapchain,
if
(
is_complex_fixup
(
backbuffer
->
resource
.
format
->
color_fixup
))
gl_filter
=
GL_NEAREST
;
context_apply_fbo_state_blit
(
context2
,
GL_FRAMEBUFFER
,
swapchain
->
front_buffer
,
context_apply_fbo_state_blit
(
context2
,
GL_FRAMEBUFFER
,
surface_from_resource
(
wined3d_texture_get_sub_resource
(
swapchain
->
front_buffer
,
0
)),
NULL
,
WINED3D_LOCATION_DRAWABLE
);
context_bind_texture
(
context2
,
backbuffer
->
texture_target
,
backbuffer
->
container
->
texture_rgb
.
name
);
...
...
@@ -420,6 +422,7 @@ static void swapchain_gl_present(struct wined3d_swapchain *swapchain, const RECT
const
struct
wined3d_fb_state
*
fb
=
&
swapchain
->
device
->
fb
;
const
struct
wined3d_gl_info
*
gl_info
;
struct
wined3d_context
*
context
;
struct
wined3d_surface
*
front
;
RECT
src_rect
,
dst_rect
;
BOOL
render_to_fbo
;
...
...
@@ -549,13 +552,13 @@ static void swapchain_gl_present(struct wined3d_swapchain *swapchain, const RECT
}
}
if
(
!
swapchain
->
render_to_fbo
&&
((
swapchain
->
front_buffer
->
locations
&
WINED3D_LOCATION_SYSMEM
)
front
=
surface_from_resource
(
wined3d_texture_get_sub_resource
(
swapchain
->
front_buffer
,
0
));
if
(
!
swapchain
->
render_to_fbo
&&
((
front
->
locations
&
WINED3D_LOCATION_SYSMEM
)
||
(
back_buffer
->
locations
&
WINED3D_LOCATION_SYSMEM
)))
{
/* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying
* Doesn't work with render_to_fbo because we're not flipping
*/
struct
wined3d_surface
*
front
=
swapchain
->
front_buffer
;
if
(
front
->
resource
.
size
==
back_buffer
->
resource
.
size
)
{
...
...
@@ -576,8 +579,8 @@ static void swapchain_gl_present(struct wined3d_swapchain *swapchain, const RECT
}
else
{
surface_validate_location
(
swapchain
->
front_buffer
,
WINED3D_LOCATION_DRAWABLE
);
surface_invalidate_location
(
swapchain
->
front_buffer
,
~
WINED3D_LOCATION_DRAWABLE
);
surface_validate_location
(
front
,
WINED3D_LOCATION_DRAWABLE
);
surface_invalidate_location
(
front
,
~
WINED3D_LOCATION_DRAWABLE
);
/* If the swapeffect is DISCARD, the back buffer is undefined. That means the SYSMEM
* and INTEXTURE copies can keep their old content if they have any defined content.
* If the swapeffect is COPY, the content remains the same. If it is FLIP however,
...
...
@@ -625,10 +628,10 @@ void x11_copy_to_screen(const struct wined3d_swapchain *swapchain, const RECT *r
TRACE
(
"swapchain %p, rect %s.
\n
"
,
swapchain
,
wine_dbgstr_rect
(
rect
));
front
=
surface_from_resource
(
wined3d_texture_get_sub_resource
(
swapchain
->
front_buffer
,
0
));
if
(
swapchain
->
palette
)
wined3d_palette_apply_to_dc
(
swapchain
->
palette
,
swapchain
->
front_buffer
->
hDC
);
wined3d_palette_apply_to_dc
(
swapchain
->
palette
,
front
->
hDC
);
front
=
swapchain
->
front_buffer
;
if
(
front
->
resource
.
map_count
)
ERR
(
"Trying to blit a mapped surface.
\n
"
);
...
...
@@ -666,7 +669,7 @@ static void swapchain_gdi_present(struct wined3d_swapchain *swapchain, const REC
{
struct
wined3d_surface
*
front
,
*
back
;
front
=
s
wapchain
->
front_buffer
;
front
=
s
urface_from_resource
(
wined3d_texture_get_sub_resource
(
swapchain
->
front_buffer
,
0
))
;
back
=
swapchain
->
back_buffers
[
0
];
/* Flip the DC. */
...
...
@@ -767,6 +770,7 @@ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3
{
const
struct
wined3d_adapter
*
adapter
=
device
->
adapter
;
struct
wined3d_resource_desc
surface_desc
;
struct
wined3d_surface
*
front_buffer
;
BOOL
displaymode_set
=
FALSE
;
RECT
client_rect
;
HWND
window
;
...
...
@@ -848,17 +852,18 @@ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3
surface_desc
.
size
=
0
;
if
(
FAILED
(
hr
=
device
->
device_parent
->
ops
->
create_swapchain_surface
(
device
->
device_parent
,
parent
,
&
surface_desc
,
&
swapchain
->
front_buffer
)))
parent
,
&
surface_desc
,
&
front_buffer
)))
{
WARN
(
"Failed to create front buffer, hr %#x.
\n
"
,
hr
);
goto
err
;
}
wined3d_texture_set_swapchain
(
swapchain
->
front_buffer
->
container
,
swapchain
);
swapchain
->
front_buffer
=
front_buffer
->
container
;
wined3d_texture_set_swapchain
(
swapchain
->
front_buffer
,
swapchain
);
if
(
!
(
device
->
wined3d
->
flags
&
WINED3D_NO3D
))
{
surface_validate_location
(
swapchain
->
front_buffer
,
WINED3D_LOCATION_DRAWABLE
);
surface_invalidate_location
(
swapchain
->
front_buffer
,
~
WINED3D_LOCATION_DRAWABLE
);
surface_validate_location
(
front_buffer
,
WINED3D_LOCATION_DRAWABLE
);
surface_invalidate_location
(
front_buffer
,
~
WINED3D_LOCATION_DRAWABLE
);
}
/* MSDN says we're only allowed a single fullscreen swapchain per device,
...
...
@@ -920,7 +925,7 @@ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3
for
(
i
=
0
;
i
<
(
sizeof
(
formats
)
/
sizeof
(
*
formats
));
i
++
)
{
swapchain
->
ds_format
=
wined3d_get_format
(
gl_info
,
formats
[
i
]);
swapchain
->
context
[
0
]
=
context_create
(
swapchain
,
swapchain
->
front_buffer
,
swapchain
->
ds_format
);
swapchain
->
context
[
0
]
=
context_create
(
swapchain
,
front_buffer
,
swapchain
->
ds_format
);
if
(
swapchain
->
context
[
0
])
break
;
TRACE
(
"Depth stencil format %s is not supported, trying next format
\n
"
,
debug_d3dformat
(
formats
[
i
]));
...
...
@@ -1025,8 +1030,8 @@ err:
if
(
swapchain
->
front_buffer
)
{
wined3d_texture_set_swapchain
(
swapchain
->
front_buffer
->
container
,
NULL
);
wined3d_
surfac
e_decref
(
swapchain
->
front_buffer
);
wined3d_texture_set_swapchain
(
swapchain
->
front_buffer
,
NULL
);
wined3d_
textur
e_decref
(
swapchain
->
front_buffer
);
}
return
hr
;
...
...
@@ -1066,7 +1071,9 @@ static struct wined3d_context *swapchain_create_context(struct wined3d_swapchain
TRACE
(
"Creating a new context for swapchain %p, thread %u.
\n
"
,
swapchain
,
GetCurrentThreadId
());
if
(
!
(
ctx
=
context_create
(
swapchain
,
swapchain
->
front_buffer
,
swapchain
->
ds_format
)))
if
(
!
(
ctx
=
context_create
(
swapchain
,
surface_from_resource
(
wined3d_texture_get_sub_resource
(
swapchain
->
front_buffer
,
0
)),
swapchain
->
ds_format
)))
{
ERR
(
"Failed to create a new context for the swapchain
\n
"
);
return
NULL
;
...
...
@@ -1144,7 +1151,7 @@ void swapchain_update_draw_bindings(struct wined3d_swapchain *swapchain)
{
UINT
i
;
wined3d_resource_update_draw_binding
(
&
swapchain
->
front_buffer
->
container
->
resource
);
wined3d_resource_update_draw_binding
(
&
swapchain
->
front_buffer
->
resource
);
for
(
i
=
0
;
i
<
swapchain
->
desc
.
backbuffer_count
;
++
i
)
{
...
...
dlls/wined3d/wined3d_private.h
View file @
ec87407e
...
...
@@ -2622,7 +2622,7 @@ struct wined3d_swapchain
struct
wined3d_device
*
device
;
struct
wined3d_surface
**
back_buffers
;
struct
wined3d_
surfac
e
*
front_buffer
;
struct
wined3d_
textur
e
*
front_buffer
;
struct
wined3d_swapchain_desc
desc
;
struct
wined3d_display_mode
original_mode
;
struct
wined3d_gamma_ramp
orig_gamma
;
...
...
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