ddraw: Properly support creating compressed user memory surfaces.

This commit is contained in:
Henri Verbeet 2014-06-12 11:52:31 +02:00 committed by Alexandre Julliard
parent e2d9cb69ba
commit b0f1feb4f0
4 changed files with 277 additions and 49 deletions

View file

@ -575,6 +575,13 @@ void DDSD2_to_DDSD(const DDSURFACEDESC2 *in, DDSURFACEDESC *out) DECLSPEC_HIDDEN
void multiply_matrix(D3DMATRIX *dst, const D3DMATRIX *src1, const D3DMATRIX *src2) DECLSPEC_HIDDEN;
static inline BOOL format_is_compressed(const DDPIXELFORMAT *format)
{
return (format->dwFlags & DDPF_FOURCC) && (format->dwFourCC == WINED3DFMT_DXT1
|| format->dwFourCC == WINED3DFMT_DXT2 || format->dwFourCC == WINED3DFMT_DXT3
|| format->dwFourCC == WINED3DFMT_DXT4 || format->dwFourCC == WINED3DFMT_DXT5);
}
static inline BOOL format_is_paletteindexed(const DDPIXELFORMAT *fmt)
{
DWORD flags = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4

View file

@ -5886,11 +5886,30 @@ HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_
return DDERR_INVALIDPARAMS;
}
if (!(desc->dwFlags & DDSD_PITCH))
if (format_is_compressed(&desc->u4.ddpfPixelFormat))
{
WARN("User memory surfaces should explicitly specify the pitch.\n");
HeapFree(GetProcessHeap(), 0, texture);
return DDERR_INVALIDPARAMS;
if (version != 4 && (desc->dwFlags & DDSD_PITCH))
{
WARN("Pitch specified on a compressed user memory surface.\n");
HeapFree(GetProcessHeap(), 0, texture);
return DDERR_INVALIDPARAMS;
}
if (!(desc->dwFlags & (DDSD_LINEARSIZE | DDSD_PITCH)))
{
WARN("Compressed user memory surfaces should explicitly specify the linear size.\n");
HeapFree(GetProcessHeap(), 0, texture);
return DDERR_INVALIDPARAMS;
}
}
else
{
if (!(desc->dwFlags & DDSD_PITCH))
{
WARN("User memory surfaces should explicitly specify the pitch.\n");
HeapFree(GetProcessHeap(), 0, texture);
return DDERR_INVALIDPARAMS;
}
}
}
@ -6112,41 +6131,63 @@ HRESULT ddraw_surface_init(struct ddraw_surface *surface, struct ddraw *ddraw, s
desc->dwHeight = wined3d_desc.height;
surface->first_attached = surface;
/* Anno 1602 stores the pitch right after surface creation, so make sure
* it's there. TODO: Test other fourcc formats. */
if (wined3d_desc.format == WINED3DFMT_DXT1 || wined3d_desc.format == WINED3DFMT_DXT2
|| wined3d_desc.format == WINED3DFMT_DXT3 || wined3d_desc.format == WINED3DFMT_DXT4
|| wined3d_desc.format == WINED3DFMT_DXT5)
if (format_is_compressed(&desc->u4.ddpfPixelFormat))
{
desc->dwFlags |= DDSD_LINEARSIZE;
desc->dwFlags &= ~DDSD_PITCH;
desc->u1.dwLinearSize = wined3d_surface_get_pitch(wined3d_surface) * ((desc->dwHeight + 3) / 4);
}
else if (!(desc->dwFlags & DDSD_LPSURFACE))
{
desc->dwFlags |= DDSD_PITCH;
desc->dwFlags &= ~DDSD_LINEARSIZE;
desc->u1.lPitch = wined3d_surface_get_pitch(wined3d_surface);
}
if (desc->dwFlags & DDSD_LPSURFACE)
{
if (desc->u1.lPitch < wined3d_calculate_format_pitch(ddraw->wined3d, WINED3DADAPTER_DEFAULT,
wined3d_desc.format, wined3d_desc.width) || desc->u1.lPitch & 3)
if (desc->dwFlags & DDSD_LPSURFACE)
{
WARN("Invalid pitch %u specified.\n", desc->u1.lPitch);
return DDERR_INVALIDPARAMS;
}
if ((desc->dwFlags & DDSD_LINEARSIZE)
&& desc->u1.dwLinearSize < wined3d_surface_get_pitch(wined3d_surface) * ((desc->dwHeight + 3) / 4))
{
WARN("Invalid linear size %u specified.\n", desc->u1.dwLinearSize);
return DDERR_INVALIDPARAMS;
}
if (FAILED(hr = wined3d_surface_update_desc(wined3d_surface, wined3d_desc.width,
wined3d_desc.height, wined3d_desc.format, WINED3D_MULTISAMPLE_NONE, 0,
desc->lpSurface, desc->u1.lPitch)))
if (FAILED(hr = wined3d_surface_update_desc(wined3d_surface, wined3d_desc.width,
wined3d_desc.height, wined3d_desc.format, WINED3D_MULTISAMPLE_NONE, 0,
desc->lpSurface, 0)))
{
ERR("Failed to set surface memory, hr %#x.\n", hr);
return hr;
}
desc->dwFlags |= DDSD_LINEARSIZE;
desc->dwFlags &= ~(DDSD_LPSURFACE | DDSD_PITCH);
desc->u1.dwLinearSize = ~0u;
}
else
{
ERR("Failed to set surface memory, hr %#x.\n", hr);
return hr;
desc->dwFlags |= DDSD_LINEARSIZE;
desc->dwFlags &= ~DDSD_PITCH;
desc->u1.dwLinearSize = wined3d_surface_get_pitch(wined3d_surface) * ((desc->dwHeight + 3) / 4);
}
}
else
{
if (desc->dwFlags & DDSD_LPSURFACE)
{
if (desc->u1.lPitch < wined3d_calculate_format_pitch(ddraw->wined3d, WINED3DADAPTER_DEFAULT,
wined3d_desc.format, wined3d_desc.width) || desc->u1.lPitch & 3)
{
WARN("Invalid pitch %u specified.\n", desc->u1.lPitch);
return DDERR_INVALIDPARAMS;
}
desc->dwFlags &= ~(DDSD_LPSURFACE | DDSD_LINEARSIZE);
if (FAILED(hr = wined3d_surface_update_desc(wined3d_surface, wined3d_desc.width,
wined3d_desc.height, wined3d_desc.format, WINED3D_MULTISAMPLE_NONE, 0,
desc->lpSurface, desc->u1.lPitch)))
{
ERR("Failed to set surface memory, hr %#x.\n", hr);
return hr;
}
desc->dwFlags &= ~(DDSD_LPSURFACE | DDSD_LINEARSIZE);
}
else
{
desc->dwFlags |= DDSD_PITCH;
desc->dwFlags &= ~DDSD_LINEARSIZE;
desc->u1.lPitch = wined3d_surface_get_pitch(wined3d_surface);
}
}
wined3d_surface_incref(wined3d_surface);

View file

@ -4107,6 +4107,7 @@ static void test_block_formats_creation(void)
DWORD num_fourcc_codes = 0, *fourcc_codes;
DDSURFACEDESC2 ddsd;
DDCAPS hal_caps;
void *mem;
static const struct
{
@ -4115,19 +4116,20 @@ static void test_block_formats_creation(void)
DWORD support_flag;
unsigned int block_width;
unsigned int block_height;
unsigned int block_size;
BOOL create_size_checked, overlay;
}
formats[] =
{
{MAKEFOURCC('D','X','T','1'), "D3DFMT_DXT1", SUPPORT_DXT1, 4, 4, TRUE, FALSE},
{MAKEFOURCC('D','X','T','2'), "D3DFMT_DXT2", SUPPORT_DXT2, 4, 4, TRUE, FALSE},
{MAKEFOURCC('D','X','T','3'), "D3DFMT_DXT3", SUPPORT_DXT3, 4, 4, TRUE, FALSE},
{MAKEFOURCC('D','X','T','4'), "D3DFMT_DXT4", SUPPORT_DXT4, 4, 4, TRUE, FALSE},
{MAKEFOURCC('D','X','T','5'), "D3DFMT_DXT5", SUPPORT_DXT5, 4, 4, TRUE, FALSE},
{MAKEFOURCC('Y','U','Y','2'), "D3DFMT_YUY2", SUPPORT_YUY2, 2, 1, FALSE, TRUE },
{MAKEFOURCC('U','Y','V','Y'), "D3DFMT_UYVY", SUPPORT_UYVY, 2, 1, FALSE, TRUE },
{MAKEFOURCC('D','X','T','1'), "D3DFMT_DXT1", SUPPORT_DXT1, 4, 4, 8, TRUE, FALSE},
{MAKEFOURCC('D','X','T','2'), "D3DFMT_DXT2", SUPPORT_DXT2, 4, 4, 16, TRUE, FALSE},
{MAKEFOURCC('D','X','T','3'), "D3DFMT_DXT3", SUPPORT_DXT3, 4, 4, 16, TRUE, FALSE},
{MAKEFOURCC('D','X','T','4'), "D3DFMT_DXT4", SUPPORT_DXT4, 4, 4, 16, TRUE, FALSE},
{MAKEFOURCC('D','X','T','5'), "D3DFMT_DXT5", SUPPORT_DXT5, 4, 4, 16, TRUE, FALSE},
{MAKEFOURCC('Y','U','Y','2'), "D3DFMT_YUY2", SUPPORT_YUY2, 2, 1, 4, FALSE, TRUE },
{MAKEFOURCC('U','Y','V','Y'), "D3DFMT_UYVY", SUPPORT_UYVY, 2, 1, 4, FALSE, TRUE },
};
const struct
static const struct
{
DWORD caps, caps2;
const char *name;
@ -4158,6 +4160,36 @@ static void test_block_formats_creation(void)
"managed texture", FALSE
}
};
enum size_type
{
SIZE_TYPE_ZERO,
SIZE_TYPE_PITCH,
SIZE_TYPE_SIZE,
};
static const struct
{
DWORD flags;
enum size_type size_type;
int rel_size;
HRESULT hr;
}
user_mem_tests[] =
{
{DDSD_LINEARSIZE, SIZE_TYPE_ZERO, 0, DD_OK},
{DDSD_LINEARSIZE, SIZE_TYPE_SIZE, 0, DD_OK},
{DDSD_PITCH, SIZE_TYPE_ZERO, 0, DD_OK},
{DDSD_PITCH, SIZE_TYPE_PITCH, 0, DD_OK},
{DDSD_LPSURFACE, SIZE_TYPE_ZERO, 0, DDERR_INVALIDPARAMS},
{DDSD_LPSURFACE | DDSD_LINEARSIZE, SIZE_TYPE_ZERO, 0, DDERR_INVALIDPARAMS},
{DDSD_LPSURFACE | DDSD_LINEARSIZE, SIZE_TYPE_PITCH, 0, DDERR_INVALIDPARAMS},
{DDSD_LPSURFACE | DDSD_LINEARSIZE, SIZE_TYPE_SIZE, 0, DD_OK},
{DDSD_LPSURFACE | DDSD_LINEARSIZE, SIZE_TYPE_SIZE, 1, DD_OK},
{DDSD_LPSURFACE | DDSD_LINEARSIZE, SIZE_TYPE_SIZE, -1, DDERR_INVALIDPARAMS},
{DDSD_LPSURFACE | DDSD_PITCH, SIZE_TYPE_ZERO, 0, DD_OK},
{DDSD_LPSURFACE | DDSD_PITCH, SIZE_TYPE_PITCH, 0, DD_OK},
{DDSD_LPSURFACE | DDSD_PITCH, SIZE_TYPE_SIZE, 0, DD_OK},
{DDSD_LPSURFACE | DDSD_PITCH | DDSD_LINEARSIZE, SIZE_TYPE_SIZE, 0, DD_OK},
};
window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
0, 0, 640, 480, 0, 0, 0, 0);
@ -4202,6 +4234,8 @@ static void test_block_formats_creation(void)
hr = IDirectDraw4_GetCaps(ddraw, &hal_caps, NULL);
ok(SUCCEEDED(hr), "Failed to get caps, hr %#x.\n", hr);
mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 2 * 2 * 16 + 1);
for (i = 0; i < sizeof(formats) / sizeof(*formats); i++)
{
for (j = 0; j < sizeof(types) / sizeof(*types); j++)
@ -4268,8 +4302,64 @@ static void test_block_formats_creation(void)
}
}
}
if (formats[i].overlay)
continue;
for (j = 0; j < sizeof(user_mem_tests) / sizeof(*user_mem_tests); ++j)
{
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | user_mem_tests[j].flags;
ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE;
switch (user_mem_tests[j].size_type)
{
case SIZE_TYPE_ZERO:
U1(ddsd).dwLinearSize = 0;
break;
case SIZE_TYPE_PITCH:
U1(ddsd).dwLinearSize = 2 * formats[i].block_size;
break;
case SIZE_TYPE_SIZE:
U1(ddsd).dwLinearSize = 2 * 2 * formats[i].block_size;
break;
}
U1(ddsd).dwLinearSize += user_mem_tests[j].rel_size;
ddsd.lpSurface = mem;
U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_FOURCC;
U4(ddsd).ddpfPixelFormat.dwFourCC = formats[i].fourcc;
ddsd.dwWidth = 8;
ddsd.dwHeight = 8;
hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &surface, NULL);
ok(hr == user_mem_tests[j].hr, "Test %u: Got unexpected hr %#x, format %s.\n", j, hr, formats[i].name);
if (FAILED(hr))
continue;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
hr = IDirectDrawSurface4_GetSurfaceDesc(surface, &ddsd);
ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#x.\n", j, hr);
ok(ddsd.dwFlags == (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_LINEARSIZE),
"Test %u: Got unexpected flags %#x.\n", j, ddsd.dwFlags);
if (user_mem_tests[j].flags & DDSD_LPSURFACE)
ok(U1(ddsd).dwLinearSize == ~0u, "Test %u: Got unexpected linear size %#x.\n",
j, U1(ddsd).dwLinearSize);
else
ok(U1(ddsd).dwLinearSize == 2 * 2 * formats[i].block_size,
"Test %u: Got unexpected linear size %#x, expected %#x.\n",
j, U1(ddsd).dwLinearSize, 2 * 2 * formats[i].block_size);
IDirectDrawSurface4_Release(surface);
}
}
HeapFree(GetProcessHeap(), 0, mem);
cleanup:
IDirectDraw4_Release(ddraw);
IDirect3DDevice3_Release(device);

View file

@ -3876,6 +3876,7 @@ static void test_block_formats_creation(void)
DWORD num_fourcc_codes = 0, *fourcc_codes;
DDSURFACEDESC2 ddsd;
DDCAPS hal_caps;
void *mem;
static const struct
{
@ -3884,19 +3885,20 @@ static void test_block_formats_creation(void)
DWORD support_flag;
unsigned int block_width;
unsigned int block_height;
unsigned int block_size;
BOOL create_size_checked, overlay;
}
formats[] =
{
{MAKEFOURCC('D','X','T','1'), "D3DFMT_DXT1", SUPPORT_DXT1, 4, 4, TRUE, FALSE},
{MAKEFOURCC('D','X','T','2'), "D3DFMT_DXT2", SUPPORT_DXT2, 4, 4, TRUE, FALSE},
{MAKEFOURCC('D','X','T','3'), "D3DFMT_DXT3", SUPPORT_DXT3, 4, 4, TRUE, FALSE},
{MAKEFOURCC('D','X','T','4'), "D3DFMT_DXT4", SUPPORT_DXT4, 4, 4, TRUE, FALSE},
{MAKEFOURCC('D','X','T','5'), "D3DFMT_DXT5", SUPPORT_DXT5, 4, 4, TRUE, FALSE},
{MAKEFOURCC('Y','U','Y','2'), "D3DFMT_YUY2", SUPPORT_YUY2, 2, 1, FALSE, TRUE },
{MAKEFOURCC('U','Y','V','Y'), "D3DFMT_UYVY", SUPPORT_UYVY, 2, 1, FALSE, TRUE },
{MAKEFOURCC('D','X','T','1'), "D3DFMT_DXT1", SUPPORT_DXT1, 4, 4, 8, TRUE, FALSE},
{MAKEFOURCC('D','X','T','2'), "D3DFMT_DXT2", SUPPORT_DXT2, 4, 4, 16, TRUE, FALSE},
{MAKEFOURCC('D','X','T','3'), "D3DFMT_DXT3", SUPPORT_DXT3, 4, 4, 16, TRUE, FALSE},
{MAKEFOURCC('D','X','T','4'), "D3DFMT_DXT4", SUPPORT_DXT4, 4, 4, 16, TRUE, FALSE},
{MAKEFOURCC('D','X','T','5'), "D3DFMT_DXT5", SUPPORT_DXT5, 4, 4, 16, TRUE, FALSE},
{MAKEFOURCC('Y','U','Y','2'), "D3DFMT_YUY2", SUPPORT_YUY2, 2, 1, 4, FALSE, TRUE },
{MAKEFOURCC('U','Y','V','Y'), "D3DFMT_UYVY", SUPPORT_UYVY, 2, 1, 4, FALSE, TRUE },
};
const struct
static const struct
{
DWORD caps, caps2;
const char *name;
@ -3927,6 +3929,36 @@ static void test_block_formats_creation(void)
"managed texture", FALSE
}
};
enum size_type
{
SIZE_TYPE_ZERO,
SIZE_TYPE_PITCH,
SIZE_TYPE_SIZE,
};
static const struct
{
DWORD flags;
enum size_type size_type;
int rel_size;
HRESULT hr;
}
user_mem_tests[] =
{
{DDSD_LINEARSIZE, SIZE_TYPE_ZERO, 0, DD_OK},
{DDSD_LINEARSIZE, SIZE_TYPE_SIZE, 0, DD_OK},
{DDSD_PITCH, SIZE_TYPE_ZERO, 0, DD_OK},
{DDSD_PITCH, SIZE_TYPE_PITCH, 0, DD_OK},
{DDSD_LPSURFACE, SIZE_TYPE_ZERO, 0, DDERR_INVALIDPARAMS},
{DDSD_LPSURFACE | DDSD_LINEARSIZE, SIZE_TYPE_ZERO, 0, DDERR_INVALIDPARAMS},
{DDSD_LPSURFACE | DDSD_LINEARSIZE, SIZE_TYPE_PITCH, 0, DDERR_INVALIDPARAMS},
{DDSD_LPSURFACE | DDSD_LINEARSIZE, SIZE_TYPE_SIZE, 0, DD_OK},
{DDSD_LPSURFACE | DDSD_LINEARSIZE, SIZE_TYPE_SIZE, 1, DD_OK},
{DDSD_LPSURFACE | DDSD_LINEARSIZE, SIZE_TYPE_SIZE, -1, DDERR_INVALIDPARAMS},
{DDSD_LPSURFACE | DDSD_PITCH, SIZE_TYPE_ZERO, 0, DDERR_INVALIDPARAMS},
{DDSD_LPSURFACE | DDSD_PITCH, SIZE_TYPE_PITCH, 0, DDERR_INVALIDPARAMS},
{DDSD_LPSURFACE | DDSD_PITCH, SIZE_TYPE_SIZE, 0, DDERR_INVALIDPARAMS},
{DDSD_LPSURFACE | DDSD_PITCH | DDSD_LINEARSIZE, SIZE_TYPE_SIZE, 0, DDERR_INVALIDPARAMS},
};
window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
0, 0, 640, 480, 0, 0, 0, 0);
@ -3971,6 +4003,8 @@ static void test_block_formats_creation(void)
hr = IDirectDraw7_GetCaps(ddraw, &hal_caps, NULL);
ok(SUCCEEDED(hr), "Failed to get caps, hr %#x.\n", hr);
mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 2 * 2 * 16 + 1);
for (i = 0; i < sizeof(formats) / sizeof(*formats); i++)
{
for (j = 0; j < sizeof(types) / sizeof(*types); j++)
@ -4037,8 +4071,64 @@ static void test_block_formats_creation(void)
}
}
}
if (formats[i].overlay)
continue;
for (j = 0; j < sizeof(user_mem_tests) / sizeof(*user_mem_tests); ++j)
{
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | user_mem_tests[j].flags;
ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE;
switch (user_mem_tests[j].size_type)
{
case SIZE_TYPE_ZERO:
U1(ddsd).dwLinearSize = 0;
break;
case SIZE_TYPE_PITCH:
U1(ddsd).dwLinearSize = 2 * formats[i].block_size;
break;
case SIZE_TYPE_SIZE:
U1(ddsd).dwLinearSize = 2 * 2 * formats[i].block_size;
break;
}
U1(ddsd).dwLinearSize += user_mem_tests[j].rel_size;
ddsd.lpSurface = mem;
U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_FOURCC;
U4(ddsd).ddpfPixelFormat.dwFourCC = formats[i].fourcc;
ddsd.dwWidth = 8;
ddsd.dwHeight = 8;
hr = IDirectDraw7_CreateSurface(ddraw, &ddsd, &surface, NULL);
ok(hr == user_mem_tests[j].hr, "Test %u: Got unexpected hr %#x, format %s.\n", j, hr, formats[i].name);
if (FAILED(hr))
continue;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
hr = IDirectDrawSurface7_GetSurfaceDesc(surface, &ddsd);
ok(SUCCEEDED(hr), "Test %u: Failed to get surface desc, hr %#x.\n", j, hr);
ok(ddsd.dwFlags == (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_LINEARSIZE),
"Test %u: Got unexpected flags %#x.\n", j, ddsd.dwFlags);
if (user_mem_tests[j].flags & DDSD_LPSURFACE)
ok(U1(ddsd).dwLinearSize == ~0u, "Test %u: Got unexpected linear size %#x.\n",
j, U1(ddsd).dwLinearSize);
else
ok(U1(ddsd).dwLinearSize == 2 * 2 * formats[i].block_size,
"Test %u: Got unexpected linear size %#x, expected %#x.\n",
j, U1(ddsd).dwLinearSize, 2 * 2 * formats[i].block_size);
IDirectDrawSurface7_Release(surface);
}
}
HeapFree(GetProcessHeap(), 0, mem);
cleanup:
IDirectDraw7_Release(ddraw);
IDirect3DDevice7_Release(device);