d3d9: Use a separate draw texture for managed resources.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52954
This commit is contained in:
Zebediah Figura 2022-07-30 19:10:09 -05:00 committed by Alexandre Julliard
parent 2091bb34c2
commit 5f1cbb1b85
4 changed files with 97 additions and 29 deletions

View file

@ -125,6 +125,7 @@ struct d3d9_device
HRESULT device_init(struct d3d9_device *device, struct d3d9 *parent, struct wined3d *wined3d,
UINT adapter, D3DDEVTYPE device_type, HWND focus_window, DWORD flags,
D3DPRESENT_PARAMETERS *parameters, D3DDISPLAYMODEEX *mode) DECLSPEC_HIDDEN;
void d3d9_device_upload_managed_textures(struct d3d9_device *device);
struct d3d9_resource
{
@ -219,7 +220,7 @@ struct d3d9_texture
{
IDirect3DBaseTexture9 IDirect3DBaseTexture9_iface;
struct d3d9_resource resource;
struct wined3d_texture *wined3d_texture;
struct wined3d_texture *wined3d_texture, *draw_texture;
struct d3d9_device *parent_device;
struct list rtv_list;
DWORD usage;
@ -235,6 +236,11 @@ HRESULT d3d9_texture_3d_init(struct d3d9_texture *texture, struct d3d9_device *d
HRESULT d3d9_texture_cube_init(struct d3d9_texture *texture, struct d3d9_device *device,
unsigned int edge_length, unsigned int level_count, DWORD usage, D3DFORMAT format, D3DPOOL pool);
static inline struct wined3d_texture *d3d9_texture_get_draw_texture(struct d3d9_texture *texture)
{
return texture->draw_texture ? texture->draw_texture : texture->wined3d_texture;
}
struct d3d9_texture *unsafe_impl_from_IDirect3DBaseTexture9(IDirect3DBaseTexture9 *iface) DECLSPEC_HIDDEN;
void d3d9_texture_flag_auto_gen_mipmap(struct d3d9_texture *texture) DECLSPEC_HIDDEN;
void d3d9_texture_gen_auto_mipmap(struct d3d9_texture *texture) DECLSPEC_HIDDEN;

View file

@ -988,7 +988,7 @@ static HRESULT CDECL reset_enum_callback(struct wined3d_resource *resource)
IUnknown *parent;
wined3d_resource_get_desc(resource, &desc);
if (desc.access & WINED3D_RESOURCE_ACCESS_CPU)
if ((desc.access & WINED3D_RESOURCE_ACCESS_CPU) || (desc.usage & WINED3DUSAGE_MANAGED))
return D3D_OK;
if (desc.resource_type != WINED3D_RTYPE_TEXTURE_2D)
@ -1724,6 +1724,12 @@ static HRESULT WINAPI d3d9_device_UpdateTexture(IDirect3DDevice9Ex *iface,
src_impl = unsafe_impl_from_IDirect3DBaseTexture9(src_texture);
dst_impl = unsafe_impl_from_IDirect3DBaseTexture9(dst_texture);
if (src_impl->draw_texture || dst_impl->draw_texture)
{
WARN("Source or destination is managed; returning D3DERR_INVALIDCALL.\n");
return D3DERR_INVALIDCALL;
}
wined3d_mutex_lock();
hr = wined3d_device_update_texture(device->wined3d_device,
src_impl->wined3d_texture, dst_impl->wined3d_texture);
@ -2638,7 +2644,7 @@ static HRESULT WINAPI d3d9_device_SetTexture(IDirect3DDevice9Ex *iface, DWORD st
wined3d_mutex_lock();
wined3d_stateblock_set_texture(device->update_state, stage,
texture_impl ? texture_impl->wined3d_texture : NULL);
texture_impl ? d3d9_texture_get_draw_texture(texture_impl) : NULL);
if (!device->recording)
{
if (stage < D3D9_MAX_TEXTURE_UNITS)
@ -3004,6 +3010,25 @@ static HRESULT d3d9_device_upload_sysmem_index_buffer(struct d3d9_device *device
return S_OK;
}
void d3d9_device_upload_managed_textures(struct d3d9_device *device)
{
const struct wined3d_stateblock_state *state = device->stateblock_state;
unsigned int i;
for (i = 0; i < WINED3D_MAX_COMBINED_SAMPLERS; ++i)
{
struct wined3d_texture *wined3d_texture = state->textures[i];
struct d3d9_texture *d3d9_texture;
if (!wined3d_texture)
continue;
d3d9_texture = wined3d_texture_get_parent(wined3d_texture);
if (d3d9_texture->draw_texture)
wined3d_device_update_texture(device->wined3d_device,
d3d9_texture->wined3d_texture, d3d9_texture->draw_texture);
}
}
static HRESULT WINAPI d3d9_device_DrawPrimitive(IDirect3DDevice9Ex *iface,
D3DPRIMITIVETYPE primitive_type, UINT start_vertex, UINT primitive_count)
{
@ -3022,6 +3047,7 @@ static HRESULT WINAPI d3d9_device_DrawPrimitive(IDirect3DDevice9Ex *iface,
}
wined3d_device_apply_stateblock(device->wined3d_device, device->state);
vertex_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
d3d9_device_upload_managed_textures(device);
d3d9_device_upload_sysmem_vertex_buffers(device, 0, start_vertex, vertex_count);
d3d9_generate_auto_mipmaps(device);
wined3d_device_context_set_primitive_type(device->immediate_context,
@ -3059,6 +3085,7 @@ static HRESULT WINAPI d3d9_device_DrawIndexedPrimitive(IDirect3DDevice9Ex *iface
return D3DERR_INVALIDCALL;
}
index_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
d3d9_device_upload_managed_textures(device);
d3d9_device_upload_sysmem_vertex_buffers(device, base_vertex_idx, min_vertex_idx, vertex_count);
d3d9_generate_auto_mipmaps(device);
wined3d_device_context_set_primitive_type(device->immediate_context,
@ -3113,6 +3140,7 @@ static HRESULT WINAPI d3d9_device_DrawPrimitiveUP(IDirect3DDevice9Ex *iface,
goto done;
d3d9_generate_auto_mipmaps(device);
d3d9_device_upload_managed_textures(device);
wined3d_device_context_set_primitive_type(device->immediate_context,
wined3d_primitive_type_from_d3d(primitive_type), 0);
wined3d_device_apply_stateblock(device->wined3d_device, device->state);
@ -3174,11 +3202,11 @@ static HRESULT WINAPI d3d9_device_DrawIndexedPrimitiveUP(IDirect3DDevice9Ex *ifa
hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer.buffer, 0, vertex_stride);
if (FAILED(hr))
goto done;
d3d9_generate_auto_mipmaps(device);
wined3d_stateblock_set_index_buffer(device->state, device->index_buffer.buffer,
wined3dformat_from_d3dformat(index_format));
d3d9_generate_auto_mipmaps(device);
d3d9_device_upload_managed_textures(device);
wined3d_device_apply_stateblock(device->wined3d_device, device->state);
wined3d_device_context_set_primitive_type(device->immediate_context,
wined3d_primitive_type_from_d3d(primitive_type), 0);

View file

@ -19678,7 +19678,7 @@ static void add_dirty_rect_test(void)
color = getPixelColor(device, 320, 240);
ok(color_match(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
color = getPixelColor(device, 1, 1);
todo_wine ok(color_match(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
ok(color_match(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
ok(SUCCEEDED(hr), "Failed to present, hr %#lx.\n", hr);

View file

@ -38,7 +38,7 @@ static ULONG d3d9_texture_incref(struct d3d9_texture *texture)
{
wined3d_rendertarget_view_incref(surface->wined3d_rtv);
}
wined3d_texture_incref(texture->wined3d_texture);
wined3d_texture_incref(d3d9_texture_get_draw_texture(texture));
wined3d_mutex_unlock();
}
@ -61,7 +61,7 @@ static ULONG d3d9_texture_decref(struct d3d9_texture *texture)
wined3d_shader_resource_view_decref(texture->wined3d_srv);
LIST_FOR_EACH_ENTRY(surface, &texture->rtv_list, struct d3d9_surface, rtv_entry)
wined3d_rendertarget_view_decref(surface->wined3d_rtv);
wined3d_texture_decref(texture->wined3d_texture);
wined3d_texture_decref(d3d9_texture_get_draw_texture(texture));
wined3d_mutex_unlock();
/* Release the device last, as it may cause the device to be destroyed. */
@ -73,7 +73,7 @@ static ULONG d3d9_texture_decref(struct d3d9_texture *texture)
static void d3d9_texture_preload(struct d3d9_texture *texture)
{
wined3d_mutex_lock();
wined3d_resource_preload(wined3d_texture_get_resource(texture->wined3d_texture));
wined3d_resource_preload(wined3d_texture_get_resource(d3d9_texture_get_draw_texture(texture)));
wined3d_mutex_unlock();
}
@ -122,7 +122,7 @@ static struct wined3d_shader_resource_view *d3d9_texture_acquire_shader_resource
desc.u.texture.layer_idx = 0;
desc.u.texture.layer_count = sr_desc.usage & WINED3DUSAGE_LEGACY_CUBEMAP ? 6 : 1;
if (FAILED(hr = wined3d_shader_resource_view_create(&desc,
wined3d_texture_get_resource(texture->wined3d_texture), texture,
wined3d_texture_get_resource(d3d9_texture_get_draw_texture(texture)), texture,
&d3d9_srv_wined3d_parent_ops, &texture->wined3d_srv)))
{
ERR("Failed to create shader resource view, hr %#x.\n", hr);
@ -138,6 +138,7 @@ void d3d9_texture_gen_auto_mipmap(struct d3d9_texture *texture)
if (!(texture->flags & D3D9_TEXTURE_MIPMAP_DIRTY))
return;
d3d9_texture_acquire_shader_resource_view(texture);
d3d9_device_upload_managed_textures(texture->parent_device);
wined3d_device_context_generate_mipmaps(texture->parent_device->immediate_context, texture->wined3d_srv);
texture->flags &= ~D3D9_TEXTURE_MIPMAP_DIRTY;
}
@ -233,7 +234,7 @@ static DWORD WINAPI d3d9_texture_2d_SetPriority(IDirect3DTexture9 *iface, DWORD
TRACE("iface %p, priority %u.\n", iface, priority);
wined3d_mutex_lock();
resource = wined3d_texture_get_resource(texture->wined3d_texture);
resource = wined3d_texture_get_resource(d3d9_texture_get_draw_texture(texture));
ret = wined3d_resource_set_priority(resource, priority);
wined3d_mutex_unlock();
@ -249,7 +250,7 @@ static DWORD WINAPI d3d9_texture_2d_GetPriority(IDirect3DTexture9 *iface)
TRACE("iface %p.\n", iface);
wined3d_mutex_lock();
resource = wined3d_texture_get_resource(texture->wined3d_texture);
resource = wined3d_texture_get_resource(d3d9_texture_get_draw_texture(texture));
ret = wined3d_resource_get_priority(resource);
wined3d_mutex_unlock();
@ -280,7 +281,7 @@ static DWORD WINAPI d3d9_texture_2d_SetLOD(IDirect3DTexture9 *iface, DWORD lod)
TRACE("iface %p, lod %u.\n", iface, lod);
wined3d_mutex_lock();
ret = wined3d_texture_set_lod(texture->wined3d_texture, lod);
ret = wined3d_texture_set_lod(d3d9_texture_get_draw_texture(texture), lod);
wined3d_mutex_unlock();
return ret;
@ -294,7 +295,7 @@ static DWORD WINAPI d3d9_texture_2d_GetLOD(IDirect3DTexture9 *iface)
TRACE("iface %p.\n", iface);
wined3d_mutex_lock();
ret = wined3d_texture_get_lod(texture->wined3d_texture);
ret = wined3d_texture_get_lod(d3d9_texture_get_draw_texture(texture));
wined3d_mutex_unlock();
return ret;
@ -607,7 +608,7 @@ static DWORD WINAPI d3d9_texture_cube_SetPriority(IDirect3DCubeTexture9 *iface,
TRACE("iface %p, priority %u.\n", iface, priority);
wined3d_mutex_lock();
resource = wined3d_texture_get_resource(texture->wined3d_texture);
resource = wined3d_texture_get_resource(d3d9_texture_get_draw_texture(texture));
ret = wined3d_resource_set_priority(resource, priority);
wined3d_mutex_unlock();
@ -623,7 +624,7 @@ static DWORD WINAPI d3d9_texture_cube_GetPriority(IDirect3DCubeTexture9 *iface)
TRACE("iface %p.\n", iface);
wined3d_mutex_lock();
resource = wined3d_texture_get_resource(texture->wined3d_texture);
resource = wined3d_texture_get_resource(d3d9_texture_get_draw_texture(texture));
ret = wined3d_resource_get_priority(resource);
wined3d_mutex_unlock();
@ -654,7 +655,7 @@ static DWORD WINAPI d3d9_texture_cube_SetLOD(IDirect3DCubeTexture9 *iface, DWORD
TRACE("iface %p, lod %u.\n", iface, lod);
wined3d_mutex_lock();
ret = wined3d_texture_set_lod(texture->wined3d_texture, lod);
ret = wined3d_texture_set_lod(d3d9_texture_get_draw_texture(texture), lod);
wined3d_mutex_unlock();
return ret;
@ -668,7 +669,7 @@ static DWORD WINAPI d3d9_texture_cube_GetLOD(IDirect3DCubeTexture9 *iface)
TRACE("iface %p.\n", iface);
wined3d_mutex_lock();
ret = wined3d_texture_get_lod(texture->wined3d_texture);
ret = wined3d_texture_get_lod(d3d9_texture_get_draw_texture(texture));
wined3d_mutex_unlock();
return ret;
@ -1007,7 +1008,7 @@ static DWORD WINAPI d3d9_texture_3d_SetPriority(IDirect3DVolumeTexture9 *iface,
TRACE("iface %p, priority %u.\n", iface, priority);
wined3d_mutex_lock();
resource = wined3d_texture_get_resource(texture->wined3d_texture);
resource = wined3d_texture_get_resource(d3d9_texture_get_draw_texture(texture));
ret = wined3d_resource_set_priority(resource, priority);
wined3d_mutex_unlock();
@ -1023,7 +1024,7 @@ static DWORD WINAPI d3d9_texture_3d_GetPriority(IDirect3DVolumeTexture9 *iface)
TRACE("iface %p.\n", iface);
wined3d_mutex_lock();
resource = wined3d_texture_get_resource(texture->wined3d_texture);
resource = wined3d_texture_get_resource(d3d9_texture_get_draw_texture(texture));
ret = wined3d_resource_get_priority(resource);
wined3d_mutex_unlock();
@ -1054,7 +1055,7 @@ static DWORD WINAPI d3d9_texture_3d_SetLOD(IDirect3DVolumeTexture9 *iface, DWORD
TRACE("iface %p, lod %u.\n", iface, lod);
wined3d_mutex_lock();
ret = wined3d_texture_set_lod(texture->wined3d_texture, lod);
ret = wined3d_texture_set_lod(d3d9_texture_get_draw_texture(texture), lod);
wined3d_mutex_unlock();
return ret;
@ -1068,7 +1069,7 @@ static DWORD WINAPI d3d9_texture_3d_GetLOD(IDirect3DVolumeTexture9 *iface)
TRACE("iface %p.\n", iface);
wined3d_mutex_lock();
ret = wined3d_texture_get_lod(texture->wined3d_texture);
ret = wined3d_texture_get_lod(d3d9_texture_get_draw_texture(texture));
wined3d_mutex_unlock();
return ret;
@ -1256,6 +1257,10 @@ struct d3d9_texture *unsafe_impl_from_IDirect3DBaseTexture9(IDirect3DBaseTexture
static void STDMETHODCALLTYPE d3d9_texture_wined3d_object_destroyed(void *parent)
{
struct d3d9_texture *texture = parent;
/* If the texture was managed, release the sysmem copy now. */
if (texture->draw_texture)
wined3d_texture_decref(texture->wined3d_texture);
d3d9_resource_cleanup(&texture->resource);
heap_free(texture);
}
@ -1286,7 +1291,7 @@ static HRESULT d3d9_texture_init(struct d3d9_texture *texture, struct d3d9_devic
if (desc->resource_type == WINED3D_RTYPE_TEXTURE_2D && is_gdi_compat_wined3dformat(desc->format))
flags |= WINED3D_TEXTURE_CREATE_GET_DC;
if (pool == D3DPOOL_SYSTEMMEM)
if (pool == D3DPOOL_SYSTEMMEM || pool == D3DPOOL_MANAGED)
flags |= WINED3D_TEXTURE_CREATE_RECORD_DIRTY_REGIONS;
if (usage & D3DUSAGE_WRITEONLY)
@ -1341,14 +1346,43 @@ static HRESULT d3d9_texture_init(struct d3d9_texture *texture, struct d3d9_devic
level_count = wined3d_log2i(max(max(desc->width, desc->height), desc->depth)) + 1;
wined3d_mutex_lock();
hr = wined3d_texture_create(device->wined3d_device, desc, layer_count, level_count, flags,
NULL, texture, &d3d9_texture_wined3d_parent_ops, &texture->wined3d_texture);
wined3d_mutex_unlock();
if (FAILED(hr))
if (pool == D3DPOOL_MANAGED)
{
WARN("Failed to create wined3d texture, hr %#x.\n", hr);
return hr;
struct wined3d_resource_desc managed_desc = *desc;
managed_desc.access = WINED3D_RESOURCE_ACCESS_CPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
managed_desc.bind_flags = 0;
if (FAILED(hr = wined3d_texture_create(device->wined3d_device, &managed_desc, layer_count, level_count, flags,
NULL, texture, &d3d9_null_wined3d_parent_ops, &texture->wined3d_texture)))
{
wined3d_mutex_unlock();
WARN("Failed to create sysmem texture, hr %#x.\n", hr);
return hr;
}
managed_desc.access = WINED3D_RESOURCE_ACCESS_GPU;
managed_desc.bind_flags = desc->bind_flags;
flags &= WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS;
if (FAILED(hr = wined3d_texture_create(device->wined3d_device, &managed_desc, layer_count, level_count, flags,
NULL, texture, &d3d9_texture_wined3d_parent_ops, &texture->draw_texture)))
{
wined3d_texture_decref(texture->wined3d_texture);
wined3d_mutex_unlock();
WARN("Failed to create draw texture, hr %#x.\n", hr);
return hr;
}
}
else
{
if (FAILED(hr = wined3d_texture_create(device->wined3d_device, desc, layer_count, level_count, flags,
NULL, texture, &d3d9_texture_wined3d_parent_ops, &texture->wined3d_texture)))
{
wined3d_mutex_unlock();
WARN("Failed to create wined3d texture, hr %#x.\n", hr);
return hr;
}
}
wined3d_mutex_unlock();
texture->parent_device = device;
IDirect3DDevice9Ex_AddRef(&texture->parent_device->IDirect3DDevice9Ex_iface);