d3dx9: Use temporary surface in D3DXFillTexture() for unmappable textures.

Fixes a regression triggered by commit 949dbbd31f.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46453
Signed-off-by: Paul Gofman <gofmanp@gmail.com>
Signed-off-by: Matteo Bruni <mbruni@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Paul Gofman 2019-01-14 21:45:09 +01:00 committed by Alexandre Julliard
parent 33be8439fc
commit 4e44d74afb
4 changed files with 138 additions and 55 deletions

View File

@ -121,6 +121,10 @@ HRESULT load_volume_from_dds(IDirect3DVolume9 *dst_volume, const PALETTEENTRY *d
const D3DXIMAGE_INFO *src_info) DECLSPEC_HIDDEN; const D3DXIMAGE_INFO *src_info) DECLSPEC_HIDDEN;
HRESULT load_volume_texture_from_dds(IDirect3DVolumeTexture9 *volume_texture, const void *src_data, HRESULT load_volume_texture_from_dds(IDirect3DVolumeTexture9 *volume_texture, const void *src_data,
const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info) DECLSPEC_HIDDEN; const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info) DECLSPEC_HIDDEN;
HRESULT lock_surface(IDirect3DSurface9 *surface, D3DLOCKED_RECT *lock,
IDirect3DSurface9 **temp_surface, BOOL write) DECLSPEC_HIDDEN;
HRESULT unlock_surface(IDirect3DSurface9 *surface, D3DLOCKED_RECT *lock,
IDirect3DSurface9 *temp_surface, BOOL update) DECLSPEC_HIDDEN;
unsigned short float_32_to_16(const float in) DECLSPEC_HIDDEN; unsigned short float_32_to_16(const float in) DECLSPEC_HIDDEN;
float float_16_to_32(const unsigned short in) DECLSPEC_HIDDEN; float float_16_to_32(const unsigned short in) DECLSPEC_HIDDEN;

View File

@ -199,49 +199,70 @@ static const struct {
{ 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000, D3DFMT_X8B8G8R8 }, { 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000, D3DFMT_X8B8G8R8 },
}; };
static HRESULT lock_surface(IDirect3DSurface9 *surface, D3DLOCKED_RECT *lock, HRESULT lock_surface(IDirect3DSurface9 *surface, D3DLOCKED_RECT *lock,
IDirect3DSurface9 **temp_surface) IDirect3DSurface9 **temp_surface, BOOL write)
{ {
IDirect3DDevice9 *device; IDirect3DDevice9 *device;
D3DSURFACE_DESC desc; D3DSURFACE_DESC desc;
DWORD lock_flag;
HRESULT hr; HRESULT hr;
lock_flag = write ? D3DLOCK_DISCARD : D3DLOCK_READONLY;
*temp_surface = NULL; *temp_surface = NULL;
if (FAILED(hr = IDirect3DSurface9_LockRect(surface, lock, NULL, D3DLOCK_READONLY))) if (FAILED(hr = IDirect3DSurface9_LockRect(surface, lock, NULL, lock_flag)))
{ {
IDirect3DSurface9_GetDevice(surface, &device); IDirect3DSurface9_GetDevice(surface, &device);
IDirect3DSurface9_GetDesc(surface, &desc); IDirect3DSurface9_GetDesc(surface, &desc);
if (FAILED(hr = IDirect3DDevice9_CreateRenderTarget(device, desc.Width, desc.Height,
desc.Format, D3DMULTISAMPLE_NONE, 0, TRUE, temp_surface, NULL))) hr = write ? IDirect3DDevice9_CreateOffscreenPlainSurface(device, desc.Width, desc.Height,
desc.Format, D3DPOOL_SYSTEMMEM, temp_surface, NULL)
: IDirect3DDevice9_CreateRenderTarget(device, desc.Width, desc.Height,
desc.Format, D3DMULTISAMPLE_NONE, 0, TRUE, temp_surface, NULL);
if (FAILED(hr))
{ {
WARN("Failed to create temporary surface, surface %p, format %#x,"
" usage %#x, pool %#x, write %#x, width %u, height %u.\n",
surface, desc.Format, desc.Usage, desc.Pool, write, desc.Width, desc.Height);
IDirect3DDevice9_Release(device); IDirect3DDevice9_Release(device);
return hr; return hr;
} }
if (SUCCEEDED(hr = IDirect3DDevice9_StretchRect(device, surface, NULL, *temp_surface, NULL, D3DTEXF_NONE))) if (write || SUCCEEDED(hr = IDirect3DDevice9_StretchRect(device, surface, NULL,
hr = IDirect3DSurface9_LockRect(*temp_surface, lock, NULL, D3DLOCK_READONLY); *temp_surface, NULL, D3DTEXF_NONE)))
hr = IDirect3DSurface9_LockRect(*temp_surface, lock, NULL, lock_flag);
IDirect3DDevice9_Release(device); IDirect3DDevice9_Release(device);
if (FAILED(hr)) if (FAILED(hr))
{ {
WARN("Failed to lock surface %p, usage %#x, pool %#x.\n", WARN("Failed to lock surface %p, write %#x, usage %#x, pool %#x.\n",
surface, desc.Usage, desc.Pool); surface, write, desc.Usage, desc.Pool);
IDirect3DSurface9_Release(*temp_surface); IDirect3DSurface9_Release(*temp_surface);
*temp_surface = NULL; *temp_surface = NULL;
return hr; return hr;
} }
TRACE("Created temporary surface %p.\n", surface);
} }
return hr; return hr;
} }
static HRESULT unlock_surface(IDirect3DSurface9 *surface, D3DLOCKED_RECT *lock, HRESULT unlock_surface(IDirect3DSurface9 *surface, D3DLOCKED_RECT *lock,
IDirect3DSurface9 *temp_surface) IDirect3DSurface9 *temp_surface, BOOL update)
{ {
IDirect3DDevice9 *device;
HRESULT hr; HRESULT hr;
if (!temp_surface) if (!temp_surface)
return IDirect3DSurface9_UnlockRect(surface); return IDirect3DSurface9_UnlockRect(surface);
hr = IDirect3DSurface9_UnlockRect(temp_surface); hr = IDirect3DSurface9_UnlockRect(temp_surface);
if (update)
{
IDirect3DSurface9_GetDevice(surface, &device);
if (FAILED(hr = IDirect3DDevice9_UpdateSurface(device, temp_surface, NULL, surface, NULL)))
WARN("Updating surface failed, hr %#x, surface %p, temp_surface %p.\n",
hr, surface, temp_surface);
IDirect3DDevice9_Release(device);
}
IDirect3DSurface9_Release(temp_surface); IDirect3DSurface9_Release(temp_surface);
return hr; return hr;
} }
@ -2026,13 +2047,13 @@ HRESULT WINAPI D3DXLoadSurfaceFromSurface(IDirect3DSurface9 *dst_surface,
src_rect = &s; src_rect = &s;
} }
if (FAILED(lock_surface(src_surface, &lock, &temp_surface))) if (FAILED(lock_surface(src_surface, &lock, &temp_surface, FALSE)))
return D3DXERR_INVALIDDATA; return D3DXERR_INVALIDDATA;
hr = D3DXLoadSurfaceFromMemory(dst_surface, dst_palette, dst_rect, lock.pBits, hr = D3DXLoadSurfaceFromMemory(dst_surface, dst_palette, dst_rect, lock.pBits,
src_desc.Format, lock.Pitch, src_palette, src_rect, filter, color_key); src_desc.Format, lock.Pitch, src_palette, src_rect, filter, color_key);
if (FAILED(unlock_surface(src_surface, &lock, temp_surface))) if (FAILED(unlock_surface(src_surface, &lock, temp_surface, FALSE)))
return D3DXERR_INVALIDDATA; return D3DXERR_INVALIDDATA;
return hr; return hr;

View File

@ -1007,59 +1007,103 @@ static void WINAPI fillfunc(D3DXVECTOR4 *value, const D3DXVECTOR2 *texcoord,
static void test_D3DXFillTexture(IDirect3DDevice9 *device) static void test_D3DXFillTexture(IDirect3DDevice9 *device)
{ {
static const struct
{
DWORD usage;
D3DPOOL pool;
}
test_access_types[] =
{
{0, D3DPOOL_MANAGED},
{0, D3DPOOL_DEFAULT},
{D3DUSAGE_RENDERTARGET, D3DPOOL_DEFAULT},
};
IDirect3DTexture9 *tex; IDirect3DTexture9 *tex;
HRESULT hr; HRESULT hr;
D3DLOCKED_RECT lock_rect; D3DLOCKED_RECT lock_rect;
DWORD x, y, m; DWORD x, y, m;
DWORD v[4], e[4]; DWORD v[4], e[4];
DWORD value, expected, size, pitch; DWORD value, expected, size, pitch;
unsigned int i;
size = 4; for (i = 0; i < ARRAY_SIZE(test_access_types); ++i)
hr = IDirect3DDevice9_CreateTexture(device, size, size, 0, 0, D3DFMT_A8R8G8B8,
D3DPOOL_MANAGED, &tex, NULL);
if (SUCCEEDED(hr))
{ {
size = 4;
hr = IDirect3DDevice9_CreateTexture(device, size, size, 0, test_access_types[i].usage,
D3DFMT_A8R8G8B8, test_access_types[i].pool, &tex, NULL);
ok(hr == D3D_OK, "Unexpected hr %#x, i %u.\n", hr, i);
hr = D3DXFillTexture(tex, fillfunc, NULL); hr = D3DXFillTexture(tex, fillfunc, NULL);
ok(hr == D3D_OK, "D3DXFillTexture returned %#x, expected %#x\n", hr, D3D_OK); ok(hr == D3D_OK, "Unexpected hr %#x, i %u.\n", hr, i);
for (m = 0; m < 3; m++) for (m = 0; m < 3; m++)
{ {
hr = IDirect3DTexture9_LockRect(tex, m, &lock_rect, NULL, D3DLOCK_READONLY); IDirect3DSurface9 *src_surface, *temp_surface;
ok(hr == D3D_OK, "Couldn't lock the texture, error %#x\n", hr);
if (SUCCEEDED(hr)) hr = IDirect3DTexture9_GetSurfaceLevel(tex, m, &src_surface);
ok(hr == D3D_OK, "Unexpected hr %#x, i %u, m %u.\n", hr, i, m);
temp_surface = src_surface;
if (FAILED(hr = IDirect3DSurface9_LockRect(src_surface, &lock_rect, NULL, D3DLOCK_READONLY)))
{ {
pitch = lock_rect.Pitch / sizeof(DWORD); hr = IDirect3DDevice9_CreateRenderTarget(device, size, size,
for (y = 0; y < size; y++) D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &temp_surface, NULL);
{ ok(hr == D3D_OK, "Unexpected hr %#x, i %u, m %u.\n", hr, i, m);
for (x = 0; x < size; x++) hr = IDirect3DDevice9_StretchRect(device, src_surface, NULL, temp_surface, NULL, D3DTEXF_NONE);
{ ok(hr == D3D_OK, "Unexpected hr %#x, i %u, m %u.\n", hr, i, m);
value = ((DWORD *)lock_rect.pBits)[y * pitch + x]; hr = IDirect3DSurface9_LockRect(temp_surface, &lock_rect, NULL, D3DLOCK_READONLY);
v[0] = (value >> 24) & 0xff; ok(hr == D3D_OK, "Unexpected hr %#x, i %u, m %u.\n", hr, i, m);
v[1] = (value >> 16) & 0xff;
v[2] = (value >> 8) & 0xff;
v[3] = value & 0xff;
e[0] = 0xff;
e[1] = (x + 0.5f) / size * 255.0f + 0.5f;
e[2] = (y + 0.5f) / size * 255.0f + 0.5f;
e[3] = 255.0f / size + 0.5f;
expected = e[0] << 24 | e[1] << 16 | e[2] << 8 | e[3];
ok(color_match(v, e),
"Texel at (%u, %u) doesn't match: %#x, expected %#x\n",
x, y, value, expected);
}
}
IDirect3DTexture9_UnlockRect(tex, m);
} }
pitch = lock_rect.Pitch / sizeof(DWORD);
for (y = 0; y < size; y++)
{
for (x = 0; x < size; x++)
{
value = ((DWORD *)lock_rect.pBits)[y * pitch + x];
v[0] = (value >> 24) & 0xff;
v[1] = (value >> 16) & 0xff;
v[2] = (value >> 8) & 0xff;
v[3] = value & 0xff;
e[0] = 0xff;
e[1] = (x + 0.5f) / size * 255.0f + 0.5f;
e[2] = (y + 0.5f) / size * 255.0f + 0.5f;
e[3] = 255.0f / size + 0.5f;
expected = e[0] << 24 | e[1] << 16 | e[2] << 8 | e[3];
ok(color_match(v, e),
"Texel at (%u, %u) doesn't match: %#x, expected %#x, i %u, m %u.\n",
x, y, value, expected, i, m);
}
}
IDirect3DSurface9_UnlockRect(temp_surface);
if (temp_surface != src_surface)
IDirect3DSurface9_Release(temp_surface);
IDirect3DSurface9_Release(src_surface);
size >>= 1; size >>= 1;
} }
IDirect3DTexture9_Release(tex); IDirect3DTexture9_Release(tex);
} }
else
skip("Failed to create texture\n"); hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 1, D3DUSAGE_DEPTHSTENCIL,
D3DFMT_D16_LOCKABLE, D3DPOOL_DEFAULT, &tex, NULL);
if (hr == D3D_OK)
{
hr = D3DXFillTexture(tex, fillfunc, NULL);
todo_wine ok(hr == D3D_OK, "Unexpected hr %#x.\n", hr);
IDirect3DTexture9_Release(tex);
}
hr = IDirect3DDevice9_CreateTexture(device, 256, 256, 1, D3DUSAGE_DEPTHSTENCIL,
D3DFMT_D16, D3DPOOL_DEFAULT, &tex, NULL);
if (hr == D3D_OK)
{
hr = D3DXFillTexture(tex, fillfunc, NULL);
ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#x.\n", hr);
IDirect3DTexture9_Release(tex);
}
hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_A1R5G5B5, hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_A1R5G5B5,
D3DPOOL_MANAGED, &tex, NULL); D3DPOOL_MANAGED, &tex, NULL);

View File

@ -1323,6 +1323,7 @@ static inline void fill_texture(const struct pixel_format_desc *format, BYTE *po
HRESULT WINAPI D3DXFillTexture(struct IDirect3DTexture9 *texture, LPD3DXFILL2D function, void *funcdata) HRESULT WINAPI D3DXFillTexture(struct IDirect3DTexture9 *texture, LPD3DXFILL2D function, void *funcdata)
{ {
IDirect3DSurface9 *surface, *temp_surface;
DWORD miplevels; DWORD miplevels;
DWORD m, x, y; DWORD m, x, y;
D3DSURFACE_DESC desc; D3DSURFACE_DESC desc;
@ -1331,26 +1332,34 @@ HRESULT WINAPI D3DXFillTexture(struct IDirect3DTexture9 *texture, LPD3DXFILL2D f
D3DXVECTOR2 coord, size; D3DXVECTOR2 coord, size;
const struct pixel_format_desc *format; const struct pixel_format_desc *format;
BYTE *data; BYTE *data;
HRESULT hr;
if (texture == NULL || function == NULL) TRACE("texture %p, function %p, funcdata %p.\n", texture, function, funcdata);
if (!texture || !function)
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
miplevels = IDirect3DBaseTexture9_GetLevelCount(texture); miplevels = IDirect3DBaseTexture9_GetLevelCount(texture);
for (m = 0; m < miplevels; m++) for (m = 0; m < miplevels; m++)
{ {
if (FAILED(IDirect3DTexture9_GetLevelDesc(texture, m, &desc))) if (FAILED(hr = IDirect3DTexture9_GetLevelDesc(texture, m, &desc)))
return D3DERR_INVALIDCALL; return hr;
format = get_format_info(desc.Format); format = get_format_info(desc.Format);
if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF) if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF)
{ {
FIXME("Unsupported texture format %#x\n", desc.Format); FIXME("Unsupported texture format %#x.\n", desc.Format);
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
} }
if (FAILED(IDirect3DTexture9_LockRect(texture, m, &lock_rect, NULL, D3DLOCK_DISCARD))) if (FAILED(hr = IDirect3DTexture9_GetSurfaceLevel(texture, m, &surface)))
return D3DERR_INVALIDCALL; return hr;
if (FAILED(hr = lock_surface(surface, &lock_rect, &temp_surface, TRUE)))
{
IDirect3DSurface9_Release(surface);
return hr;
}
size.x = 1.0f / desc.Width; size.x = 1.0f / desc.Width;
size.y = 1.0f / desc.Height; size.y = 1.0f / desc.Height;
@ -1372,7 +1381,12 @@ HRESULT WINAPI D3DXFillTexture(struct IDirect3DTexture9 *texture, LPD3DXFILL2D f
fill_texture(format, data + y * lock_rect.Pitch + x * format->bytes_per_pixel, &value); fill_texture(format, data + y * lock_rect.Pitch + x * format->bytes_per_pixel, &value);
} }
} }
IDirect3DTexture9_UnlockRect(texture, m); if (FAILED(hr = unlock_surface(surface, &lock_rect, temp_surface, TRUE)))
{
IDirect3DSurface9_Release(surface);
return hr;
}
IDirect3DSurface9_Release(surface);
} }
return D3D_OK; return D3D_OK;