ddraw: Reserve extra space for video memory surfaces in compatibility mode.

Some old apps write surface data past the end of locked space. That
used to work on early ddraw hardware as locked surface provided
direct access to video memory mapped to CPU address space and such
access could often go without issues. Currently ddraw on Windows
allocates bigger buffers for video memory surfaces when 8 or 16 bit
display mode is requested.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48788
Signed-off-by: Paul Gofman <gofmanp@gmail.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Paul Gofman 2020-03-27 23:31:41 +03:00 committed by Alexandre Julliard
parent dfc159d874
commit d0ff5e66a7
2 changed files with 60 additions and 3 deletions

View File

@ -219,6 +219,8 @@ struct ddraw_texture
struct ddraw_surface *root;
struct wined3d_device *wined3d_device;
void *texture_memory;
};
HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_desc,

View File

@ -5832,8 +5832,11 @@ static const struct wined3d_parent_ops ddraw_surface_wined3d_parent_ops =
static void STDMETHODCALLTYPE ddraw_texture_wined3d_object_destroyed(void *parent)
{
TRACE("parent %p.\n", parent);
struct ddraw_texture *texture = parent;
TRACE("texture %p, texture_memory %p.\n", texture, texture->texture_memory);
heap_free(texture->texture_memory);
heap_free(parent);
}
@ -5847,18 +5850,50 @@ static HRESULT CDECL ddraw_reset_enum_callback(struct wined3d_resource *resource
return DD_OK;
}
static HRESULT ddraw_surface_reserve_memory(struct wined3d_texture *wined3d_texture)
{
static const unsigned int extra_size = 0x10000;
struct ddraw_texture *texture = wined3d_texture_get_parent(wined3d_texture);
struct wined3d_resource_desc desc;
unsigned int pitch, slice_pitch;
HRESULT hr;
wined3d_resource_get_desc(wined3d_texture_get_resource(wined3d_texture), &desc);
if (!(texture->texture_memory = heap_alloc_zero(desc.size + extra_size)))
{
ERR("Out of memory.\n");
return E_OUTOFMEMORY;
}
TRACE("texture->texture_memory %p.\n", texture->texture_memory);
wined3d_texture_get_pitch(wined3d_texture, 0, &pitch, &slice_pitch);
if (FAILED(hr = wined3d_texture_update_desc(wined3d_texture,
desc.width, desc.height, desc.format,
WINED3D_MULTISAMPLE_NONE, 0, texture->texture_memory, pitch)))
{
heap_free(texture->texture_memory);
texture->texture_memory = NULL;
}
return hr;
}
HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_desc,
struct ddraw_surface **surface, IUnknown *outer_unknown, unsigned int version)
{
struct wined3d_sub_resource_desc wined3d_mip_desc;
struct ddraw_surface *root, *mip, **attach;
struct wined3d_resource_desc wined3d_desc;
DDPIXELFORMAT wined3d_display_mode_format;
struct wined3d_texture *wined3d_texture;
struct wined3d_display_mode mode;
DDSURFACEDESC2 *desc, *mip_desc;
struct ddraw_texture *texture;
unsigned int layers = 1;
unsigned int pitch = 0;
BOOL reserve_memory;
UINT levels, i, j;
HRESULT hr;
@ -5879,6 +5914,7 @@ HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_
if (!(texture = heap_alloc(sizeof(*texture))))
return E_OUTOFMEMORY;
texture->texture_memory = NULL;
texture->version = version;
texture->surface_desc = *surface_desc;
desc = &texture->surface_desc;
@ -6020,12 +6056,14 @@ HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_
return hr_ddraw_from_wined3d(hr);
}
wined3d_display_mode_format.dwSize = sizeof(wined3d_display_mode_format);
ddrawformat_from_wined3dformat(&wined3d_display_mode_format, mode.format_id);
/* No pixelformat given? Use the current screen format. */
if (!(desc->dwFlags & DDSD_PIXELFORMAT))
{
desc->dwFlags |= DDSD_PIXELFORMAT;
desc->u4.ddpfPixelFormat.dwSize = sizeof(desc->u4.ddpfPixelFormat);
ddrawformat_from_wined3dformat(&desc->u4.ddpfPixelFormat, mode.format_id);
desc->u4.ddpfPixelFormat = wined3d_display_mode_format;
}
wined3d_desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
@ -6434,6 +6472,16 @@ HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_
goto fail;
}
reserve_memory = !(desc->dwFlags & DDSD_LPSURFACE)
&& desc->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY
&& wined3d_display_mode_format.u1.dwRGBBitCount <= 16;
if (reserve_memory && FAILED(hr = ddraw_surface_reserve_memory(wined3d_texture)))
{
ERR("Failed to reserve surface memory, hr %#x.\n", hr);
goto fail;
}
if (desc->dwFlags & DDSD_BACKBUFFERCOUNT)
{
unsigned int count = desc->u5.dwBackBufferCount;
@ -6448,6 +6496,7 @@ HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_
goto fail;
}
texture->texture_memory = NULL;
texture->version = version;
texture->surface_desc = root->surface_desc;
desc = &texture->surface_desc;
@ -6487,6 +6536,12 @@ HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_
wined3d_texture_set_color_key(wined3d_texture, DDCKEY_SRCBLT,
(struct wined3d_color_key *)&desc->ddckCKSrcBlt);
if (reserve_memory && FAILED(hr = ddraw_surface_reserve_memory(wined3d_texture)))
{
hr = hr_ddraw_from_wined3d(hr);
goto fail;
}
*attach = last;
attach = &last->complex_array[0];
}