Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 12 ++++ dlls/d3dx9_36/effect.c | 156 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 155 insertions(+), 13 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 5ac5e63aeb6..2044b2af448 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -24,6 +24,8 @@
#define NONAMELESSUNION #include "wine/debug.h" +#include "wine/heap.h" +#include "wine/rbtree.h"
#define COBJMACROS #include "d3dx9.h" @@ -278,6 +280,13 @@ struct d3dx_param_eval ULONG64 *version_counter; };
+struct param_rb_entry +{ + struct wine_rb_entry entry; + char *full_name; + struct d3dx_parameter *param; +}; + struct d3dx_shared_data; struct d3dx_top_level_parameter;
@@ -300,6 +309,9 @@ struct d3dx_parameter
struct d3dx_parameter *members; char *semantic; + + char *full_name; + struct wine_rb_entry rb_entry; };
struct d3dx_top_level_parameter diff --git a/dlls/d3dx9_36/effect.c b/dlls/d3dx9_36/effect.c index 87eaf8684a9..340f3d3fd00 100644 --- a/dlls/d3dx9_36/effect.c +++ b/dlls/d3dx9_36/effect.c @@ -20,6 +20,8 @@ #include "config.h" #include "wine/port.h"
+#include <stdio.h> + #include "d3dx9_private.h" #include "d3dcompiler.h"
@@ -161,6 +163,10 @@ struct d3dx9_base_effect DWORD flags;
ULONG64 version_counter; + + struct wine_rb_tree param_tree; + char *full_name_tmp; + unsigned int full_name_tmp_size; };
struct ID3DXEffectImpl @@ -205,8 +211,8 @@ struct ID3DXEffectCompilerImpl struct d3dx9_base_effect base_effect; };
-static struct d3dx_parameter *get_annotation_by_name(UINT count, struct d3dx_parameter *parameters, - const char *name); +static struct d3dx_parameter *get_annotation_by_name(struct d3dx9_base_effect *base, + unsigned int count, struct d3dx_parameter *parameters, const char *name); static HRESULT d3dx9_parse_state(struct d3dx9_base_effect *base, struct d3dx_state *state, const char *data, const char **ptr, struct d3dx_object *objects); static void free_parameter(struct d3dx_parameter *param, BOOL element, BOOL child); @@ -682,6 +688,8 @@ static void d3dx9_base_effect_cleanup(struct d3dx9_base_effect *base)
TRACE("base %p.\n", base);
+ heap_free(base->full_name_tmp); + if (base->parameters) { for (i = 0; i < base->parameter_count; ++i) @@ -814,7 +822,8 @@ static void set_matrix_transpose(struct d3dx_parameter *param, const D3DXMATRIX } }
-static struct d3dx_parameter *get_parameter_element_by_name(struct d3dx_parameter *parameter, const char *name) +static struct d3dx_parameter *get_parameter_element_by_name(struct d3dx9_base_effect *base, + struct d3dx_parameter *parameter, const char *name) { UINT element; struct d3dx_parameter *temp_parameter; @@ -835,7 +844,7 @@ static struct d3dx_parameter *get_parameter_element_by_name(struct d3dx_paramete switch (*part++) { case '.': - return get_parameter_by_name(NULL, temp_parameter, part); + return get_parameter_by_name(base, temp_parameter, part);
case '\0': TRACE("Returning parameter %p\n", temp_parameter); @@ -851,8 +860,8 @@ static struct d3dx_parameter *get_parameter_element_by_name(struct d3dx_paramete return NULL; }
-static struct d3dx_parameter *get_annotation_by_name(UINT count, struct d3dx_parameter *annotations, - const char *name) +static struct d3dx_parameter *get_annotation_by_name(struct d3dx9_base_effect *base, + unsigned int count, struct d3dx_parameter *annotations, const char *name) { UINT i, length; struct d3dx_parameter *temp_parameter; @@ -879,10 +888,10 @@ static struct d3dx_parameter *get_annotation_by_name(UINT count, struct d3dx_par switch (*part++) { case '.': - return get_parameter_by_name(NULL, temp_parameter, part); + return get_parameter_by_name(base, temp_parameter, part);
case '[': - return get_parameter_element_by_name(temp_parameter, part); + return get_parameter_element_by_name(base, temp_parameter, part);
default: FIXME("Unhandled case "%c"\n", *--part); @@ -898,15 +907,57 @@ static struct d3dx_parameter *get_annotation_by_name(UINT count, struct d3dx_par struct d3dx_parameter *get_parameter_by_name(struct d3dx9_base_effect *base, struct d3dx_parameter *parameter, const char *name) { - UINT i, count, length; struct d3dx_parameter *temp_parameter; + unsigned int name_len, param_name_len; + unsigned int i, count, length; + struct wine_rb_entry *entry; + unsigned int full_name_size; const char *part; + char *full_name;
TRACE("base %p, parameter %p, name %s\n", base, parameter, debugstr_a(name));
if (!name || !*name) return NULL;
+ if (!parameter) + { + if ((entry = wine_rb_get(&base->param_tree, name))) + return WINE_RB_ENTRY_VALUE(entry, struct d3dx_parameter, rb_entry); + return NULL; + } + + /* Pass / technique annotations are not in the parameters tree. */ + if (parameter->full_name) + { + name_len = strlen(name); + param_name_len = strlen(parameter->full_name); + full_name_size = name_len + param_name_len + 2; + if (base->full_name_tmp_size < full_name_size) + { + if (!(full_name = heap_realloc(base->full_name_tmp, full_name_size))) + { + ERR("Out of memory.\n"); + return NULL; + } + base->full_name_tmp = full_name; + base->full_name_tmp_size = full_name_size; + } + else + { + full_name = base->full_name_tmp; + } + memcpy(full_name, parameter->full_name, param_name_len); + full_name[param_name_len] = '.'; + memcpy(full_name + param_name_len + 1, name, name_len); + full_name[param_name_len + 1 + name_len] = 0; + + if ((entry = wine_rb_get(&base->param_tree, full_name))) + return WINE_RB_ENTRY_VALUE(entry, struct d3dx_parameter, rb_entry); + return NULL; + } + count = parameter ? parameter->member_count : base->parameter_count; + length = strcspn( name, "[.@" ); part = name + length;
@@ -925,18 +976,18 @@ struct d3dx_parameter *get_parameter_by_name(struct d3dx9_base_effect *base, switch (*part++) { case '.': - return get_parameter_by_name(NULL, temp_parameter, part); + return get_parameter_by_name(base, temp_parameter, part);
case '@': { struct d3dx_top_level_parameter *top_param = top_level_parameter_from_parameter(temp_parameter);
- return parameter ? NULL : get_annotation_by_name(top_param->annotation_count, + return parameter ? NULL : get_annotation_by_name(base, top_param->annotation_count, top_param->annotations, part); } case '[': - return get_parameter_element_by_name(temp_parameter, part); + return get_parameter_element_by_name(base, temp_parameter, part);
default: FIXME("Unhandled case "%c"\n", *--part); @@ -1460,7 +1511,7 @@ static D3DXHANDLE d3dx9_base_effect_get_annotation_by_name(struct d3dx9_base_eff
annotation_count = get_annotation_from_object(base, object, &annotations);
- annotation = get_annotation_by_name(annotation_count, annotations, name); + annotation = get_annotation_by_name(base, annotation_count, annotations, name); if (annotation) { TRACE("Returning parameter %p\n", annotation); @@ -5436,6 +5487,83 @@ static void param_set_magic_number(struct d3dx_parameter *param) memcpy(param->magic_string, parameter_magic_string, sizeof(parameter_magic_string)); }
+static int param_rb_compare(const void *key, const struct wine_rb_entry *entry) +{ + const char *name = key; + struct d3dx_parameter *param = WINE_RB_ENTRY_VALUE(entry, struct d3dx_parameter, rb_entry); + + return strcmp(name, param->full_name); +} + +static void add_param_to_tree(struct d3dx9_base_effect *base, struct d3dx_parameter *param, + struct d3dx_parameter *parent, char separator, unsigned int element) +{ + const char *parent_name = parent ? parent->full_name : NULL; + unsigned int i; + + TRACE("Adding parameter %p (%s - parent %p, element %u) to the rbtree.\n", + param, debugstr_a(param->name), parent, element); + + if (parent_name) + { + unsigned int parent_name_len = strlen(parent_name); + unsigned int name_len = strlen(param->name); + unsigned int part_str_len; + unsigned int len; + char part_str[16]; + + if (separator == '[') + { + sprintf(part_str, "[%u]", element); + part_str_len = strlen(part_str); + name_len = 0; + } + else + { + part_str[0] = separator; + part_str[1] = 0; + part_str_len = 1; + } + len = parent_name_len + part_str_len + name_len + 1; + + if (!(param->full_name = heap_alloc(len))) + { + ERR("Out of memory.\n"); + return; + } + + memcpy(param->full_name, parent_name, parent_name_len); + memcpy(param->full_name + parent_name_len, part_str, part_str_len); + memcpy(param->full_name + parent_name_len + part_str_len, param->name, name_len); + param->full_name[len - 1] = 0; + } + else + { + unsigned int len = strlen(param->name) + 1; + + if (!(param->full_name = heap_alloc(len))) + { + ERR("Out of memory.\n"); + return; + } + + memcpy(param->full_name, param->name, len); + } + TRACE("Full name is %s.\n", param->full_name); + wine_rb_put(&base->param_tree, param->full_name, ¶m->rb_entry); + + if (is_top_level_parameter(param)) + for (i = 0; i < param->top_level_param->annotation_count; ++i) + add_param_to_tree(base, ¶m->top_level_param->annotations[i], param, '@', 0); + + if (param->element_count) + for (i = 0; i < param->element_count; ++i) + add_param_to_tree(base, ¶m->members[i], param, '[', i); + else + for (i = 0; i < param->member_count; ++i) + add_param_to_tree(base, ¶m->members[i], param, '.', 0); +} + static HRESULT d3dx9_parse_effect_typedef(struct d3dx9_base_effect *base, struct d3dx_parameter *param, const char *data, const char **ptr, struct d3dx_parameter *parent, UINT flags) { @@ -6281,6 +6409,7 @@ static HRESULT d3dx9_parse_effect(struct d3dx9_base_effect *base, const char *da goto err_out; }
+ wine_rb_init(&base->param_tree, param_rb_compare); if (base->parameter_count) { base->parameters = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, @@ -6303,6 +6432,7 @@ static HRESULT d3dx9_parse_effect(struct d3dx9_base_effect *base, const char *da } walk_parameter_tree(&base->parameters[i].param, param_set_top_level_param, &base->parameters[i]); + add_param_to_tree(base, &base->parameters[i].param, NULL, 0, 0); } }
Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- dlls/d3dx9_36/tests/effect.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/dlls/d3dx9_36/tests/effect.c b/dlls/d3dx9_36/tests/effect.c index ced6c8ea67a..b7e2d723e3f 100644 --- a/dlls/d3dx9_36/tests/effect.c +++ b/dlls/d3dx9_36/tests/effect.c @@ -5374,13 +5374,13 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device) ok(hr == D3D_OK, "Got result %#x, i %u, j %u.\n", hr, i, j); } param = effect->lpVtbl->GetParameterByName(effect, NULL, check_op_parameters[i].param_name); - ok(!!param, "GetParameterByName failed.\n"); + ok(!!param, "Failed to get parameter (test %u).\n", i); hr = effect->lpVtbl->GetValue(effect, param, &fvect, sizeof(fvect)); - ok(hr == D3D_OK, "Got result %#x.\n", hr); + ok(hr == D3D_OK, "Failed to get parameter value, hr %#x (test %u).\n", hr, i); hr = effect->lpVtbl->SetValue(effect, param, &fvect, sizeof(fvect)); - ok(hr == D3D_OK, "Got result %#x.\n", hr); + ok(hr == D3D_OK, "Failed to set parameter value, hr %#x (test %u).\n", hr, i); hr = effect->lpVtbl->CommitChanges(effect); - ok(hr == D3D_OK, "Got result %#x.\n", hr); + ok(hr == D3D_OK, "Failed to commit changes, hr %#x (test %u).\n", hr, i);
test_effect_preshader_op_results(device, check_op_parameters[i].state_updated, check_op_parameters[i].param_name);
Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- dlls/d3dx9_36/preshader.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/d3dx9_36/preshader.c b/dlls/d3dx9_36/preshader.c index 78e48689401..8551d2fe631 100644 --- a/dlls/d3dx9_36/preshader.c +++ b/dlls/d3dx9_36/preshader.c @@ -1209,7 +1209,8 @@ static HRESULT parse_preshader(struct d3dx_preshader *pres, unsigned int *ptr, u } if (reg_idx >= pres->regs.table_sizes[table]) { - FIXME("Out of bounds register index, i %u, j %u, table %u, reg_idx %u.\n", + /* Native accepts these broken preshaders. */ + FIXME("Out of bounds register index, i %u, j %u, table %u, reg_idx %u, preshader parsing failed.\n", i, j, table, reg_idx); return D3DXERR_INVALIDDATA; }
Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- dlls/d3dx9_36/effect.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-)
diff --git a/dlls/d3dx9_36/effect.c b/dlls/d3dx9_36/effect.c index 340f3d3fd00..33e0fc4cdae 100644 --- a/dlls/d3dx9_36/effect.c +++ b/dlls/d3dx9_36/effect.c @@ -4328,13 +4328,65 @@ static HRESULT WINAPI ID3DXEffectImpl_GetDevice(ID3DXEffect *iface, struct IDire return S_OK; }
+static BOOL param_on_lost_device(void *data, struct d3dx_parameter *param) +{ + struct IDirect3DVolumeTexture9 *volume_texture; + struct IDirect3DCubeTexture9 *cube_texture; + struct IDirect3DTexture9 *texture; + D3DSURFACE_DESC surface_desc; + D3DVOLUME_DESC volume_desc; + + if (param->class == D3DXPC_OBJECT && !param->element_count) + { + switch (param->type) + { + case D3DXPT_TEXTURE: + case D3DXPT_TEXTURE1D: + case D3DXPT_TEXTURE2D: + texture = *(IDirect3DTexture9 **)param->data; + if (!texture) + return FALSE; + IDirect3DTexture9_GetLevelDesc(texture, 0, &surface_desc); + if (surface_desc.Pool != D3DPOOL_DEFAULT) + return FALSE; + break; + case D3DXPT_TEXTURE3D: + volume_texture = *(IDirect3DVolumeTexture9 **)param->data; + if (!volume_texture) + return FALSE; + IDirect3DVolumeTexture9_GetLevelDesc(volume_texture, 0, &volume_desc); + if (volume_desc.Pool != D3DPOOL_DEFAULT) + return FALSE; + break; + case D3DXPT_TEXTURECUBE: + cube_texture = *(IDirect3DCubeTexture9 **)param->data; + if (!cube_texture) + return FALSE; + IDirect3DTexture9_GetLevelDesc(cube_texture, 0, &surface_desc); + if (surface_desc.Pool != D3DPOOL_DEFAULT) + return FALSE; + break; + default: + return FALSE; + } + IUnknown_Release(*(IUnknown **)param->data); + *(IUnknown **)param->data = NULL; + } + return FALSE; +} + static HRESULT WINAPI ID3DXEffectImpl_OnLostDevice(ID3DXEffect* iface) { - struct ID3DXEffectImpl *This = impl_from_ID3DXEffect(iface); + struct ID3DXEffectImpl *effect = impl_from_ID3DXEffect(iface); + struct d3dx9_base_effect *base = &effect->base_effect; + unsigned int i;
- FIXME("(%p)->(): stub\n", This); + TRACE("iface %p.\n", iface);
- return E_NOTIMPL; + for (i = 0; i < base->parameter_count; ++i) + walk_parameter_tree(&base->parameters[i].param, param_on_lost_device, NULL); + + return D3D_OK; }
static HRESULT WINAPI ID3DXEffectImpl_OnResetDevice(ID3DXEffect* iface)
Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- dlls/d3dx9_36/tests/effect.c | 118 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+)
diff --git a/dlls/d3dx9_36/tests/effect.c b/dlls/d3dx9_36/tests/effect.c index b7e2d723e3f..bcaf377f9dc 100644 --- a/dlls/d3dx9_36/tests/effect.c +++ b/dlls/d3dx9_36/tests/effect.c @@ -7368,6 +7368,123 @@ if (hr == D3D_OK) DestroyWindow(window); }
+static unsigned int get_texture_refcount(IDirect3DTexture9 *iface) +{ + IDirect3DTexture9_AddRef(iface); + return IDirect3DTexture9_Release(iface); +} + +static void test_refcount(void) +{ + IDirect3DTexture9 *texture, *cur_texture, *managed_texture, *sysmem_texture; + unsigned int passes_count; + IDirect3DDevice9 *device; + ID3DXEffect *effect; + ULONG refcount; + HWND window; + HRESULT hr; + + if (!(device = create_device(&window))) + return; + + hr = IDirect3DDevice9_CreateTexture(device, 16, 16, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &texture, NULL); + ok(hr == D3D_OK, "Failed to create texture, hr %#x.\n", hr); + + hr = D3DXCreateEffect(device, test_effect_preshader_effect_blob, + sizeof(test_effect_preshader_effect_blob), NULL, NULL, + D3DXFX_DONOTSAVESTATE, NULL, &effect, NULL); + ok(hr == D3D_OK, "Failed to create effect, hr %#x.\n", hr); + + hr = effect->lpVtbl->SetTexture(effect, "tex1", (IDirect3DBaseTexture9 *)texture); + ok(hr == D3D_OK, "Failed to set texture parameter, hr %#x.\n", hr); + + hr = effect->lpVtbl->Begin(effect, &passes_count, D3DXFX_DONOTSAVESTATE); + ok(hr == D3D_OK, "Begin() failed, hr %#x.\n", hr); + + hr = effect->lpVtbl->BeginPass(effect, 0); + ok(hr == D3D_OK, "BeginPass() failed, hr %#x.\n", hr); + + IDirect3DDevice9_GetTexture(device, 0, (IDirect3DBaseTexture9 **)&cur_texture); + ok(cur_texture == texture, "Unexpected current texture %p.\n", cur_texture); + IDirect3DTexture9_Release(cur_texture); + + IDirect3DDevice9_SetTexture(device, 0, NULL); + effect->lpVtbl->CommitChanges(effect); + + IDirect3DDevice9_GetTexture(device, 0, (IDirect3DBaseTexture9 **)&cur_texture); + ok(cur_texture == NULL, "Unexpected current texture %p.\n", cur_texture); + + hr = effect->lpVtbl->EndPass(effect); + ok(hr == D3D_OK, "EndPass() failed, hr %#x.\n", hr); + + hr = effect->lpVtbl->BeginPass(effect, 0); + ok(hr == D3D_OK, "BeginPass() failed, hr %#x.\n", hr); + + IDirect3DDevice9_GetTexture(device, 0, (IDirect3DBaseTexture9 **)&cur_texture); + ok(cur_texture == texture, "Unexpected current texture %p.\n", cur_texture); + IDirect3DTexture9_Release(cur_texture); + + hr = effect->lpVtbl->EndPass(effect); + ok(hr == D3D_OK, "EndPass() failed, hr %#x.\n", hr); + hr = effect->lpVtbl->End(effect); + ok(hr == D3D_OK, "End() failed, hr %#x.\n", hr); + + IDirect3DDevice9_GetTexture(device, 0, (IDirect3DBaseTexture9 **)&cur_texture); + ok(cur_texture == texture, "Unexpected current texture %p.\n", cur_texture); + IDirect3DTexture9_Release(cur_texture); + refcount = get_texture_refcount(texture); + ok(refcount == 2, "Unexpected texture refcount %u.\n", refcount); + + hr = effect->lpVtbl->OnLostDevice(effect); + ok(hr == D3D_OK, "OnLostDevice() failed, hr %#x.\n", hr); + refcount = get_texture_refcount(texture); + ok(refcount == 1, "Unexpected texture refcount %u.\n", refcount); + + hr = IDirect3DDevice9_CreateTexture(device, 16, 16, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, + &managed_texture, NULL); + ok(hr == D3D_OK, "Failed to create texture, hr %#x.\n", hr); + effect->lpVtbl->SetTexture(effect, "tex1", (IDirect3DBaseTexture9 *)managed_texture); + + refcount = get_texture_refcount(managed_texture); + ok(refcount == 2, "Unexpected texture refcount %u.\n", refcount); + hr = effect->lpVtbl->OnLostDevice(effect); + ok(hr == D3D_OK, "OnLostDevice() failed, hr %#x.\n", hr); + refcount = get_texture_refcount(managed_texture); + ok(refcount == 2, "Unexpected texture refcount %u.\n", refcount); + + hr = IDirect3DDevice9_CreateTexture(device, 16, 16, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, + &sysmem_texture, NULL); + ok(hr == D3D_OK, "Failed to create texture, hr %#x.\n", hr); + effect->lpVtbl->SetTexture(effect, "tex1", (IDirect3DBaseTexture9 *)sysmem_texture); + + refcount = get_texture_refcount(managed_texture); + ok(refcount == 1, "Unexpected texture refcount %u.\n", refcount); + IDirect3DTexture9_Release(managed_texture); + refcount = get_texture_refcount(sysmem_texture); + ok(refcount == 2, "Unexpected texture refcount %u.\n", refcount); + hr = effect->lpVtbl->OnLostDevice(effect); + ok(hr == D3D_OK, "OnLostDevice() failed, hr %#x.\n", hr); + refcount = get_texture_refcount(sysmem_texture); + ok(refcount == 2, "Unexpected texture refcount %u.\n", refcount); + + effect->lpVtbl->Release(effect); + + refcount = get_texture_refcount(sysmem_texture); + ok(refcount == 1, "Unexpected texture refcount %u.\n", refcount); + IDirect3DTexture9_Release(sysmem_texture); + + IDirect3DDevice9_GetTexture(device, 0, (IDirect3DBaseTexture9 **)&cur_texture); + ok(cur_texture == texture, "Unexpected current texture %p.\n", cur_texture); + IDirect3DTexture9_Release(cur_texture); + refcount = get_texture_refcount(texture); + ok(refcount == 1, "Unexpected texture refcount %u.\n", refcount); + IDirect3DTexture9_Release(texture); + + refcount = IDirect3DDevice9_Release(device); + ok(!refcount, "Device has %u references left.\n", refcount); + DestroyWindow(window); +} + START_TEST(effect) { IDirect3DDevice9 *device; @@ -7404,4 +7521,5 @@ START_TEST(effect) test_effect_unsupported_shader(); test_effect_null_shader(); test_effect_clone(); + test_refcount(); }
Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- Might have an effect on bug 42118.
v2: Accept both E_FAIL and S_FALSE for i > 4.
dlls/d3d8/device.c | 6 ++++-- dlls/d3d8/tests/device.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index 367f5c1c4f5..4fcad71451e 100644 --- a/dlls/d3d8/device.c +++ b/dlls/d3d8/device.c @@ -2187,9 +2187,11 @@ static HRESULT WINAPI d3d8_device_ValidateDevice(IDirect3DDevice8 *iface, DWORD static HRESULT WINAPI d3d8_device_GetInfo(IDirect3DDevice8 *iface, DWORD info_id, void *info, DWORD info_size) { - FIXME("iface %p, info_id %#x, info %p, info_size %u stub!\n", iface, info_id, info, info_size); + TRACE("iface %p, info_id %#x, info %p, info_size %u.\n", iface, info_id, info, info_size);
- return D3D_OK; + if (info_id < 4) + return E_FAIL; + return S_FALSE; }
static HRESULT WINAPI d3d8_device_SetPaletteEntries(IDirect3DDevice8 *iface, diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c index 4d0ef714701..8dbd4646254 100644 --- a/dlls/d3d8/tests/device.c +++ b/dlls/d3d8/tests/device.c @@ -8701,6 +8701,47 @@ static void test_device_caps(void) DestroyWindow(window); }
+static void test_get_info(void) +{ + IDirect3DDevice8 *device; + IDirect3D8 *d3d; + BYTE info[1024]; + ULONG refcount; + unsigned int i; + HWND window; + HRESULT hr; + + window = CreateWindowA("static", "d3d8_test", WS_OVERLAPPEDWINDOW, + 0, 0, 640, 480, NULL, NULL, NULL, NULL); + d3d = Direct3DCreate8(D3D_SDK_VERSION); + ok(!!d3d, "Failed to create a D3D object.\n"); + if (!(device = create_device(d3d, window, NULL))) + { + skip("Failed to create a D3D device.\n"); + IDirect3D8_Release(d3d); + DestroyWindow(window); + return; + } + + /* As called by Chessmaster 9000 (bug 42118). */ + hr = IDirect3DDevice8_GetInfo(device, 4, info, 16); + ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); + + for (i = 0; i < 256; ++i) + { + hr = IDirect3DDevice8_GetInfo(device, i, info, sizeof(info)); + if (i <= 4) + ok(hr == (i < 4 ? E_FAIL : S_FALSE), "info_id %u, unexpected hr %#x.\n", i, hr); + else + ok(hr == E_FAIL || hr == S_FALSE, "info_id %u, unexpected hr %#x.\n", i, hr); + } + + refcount = IDirect3DDevice8_Release(device); + ok(!refcount, "Device has %u references left.\n", refcount); + IDirect3D8_Release(d3d); + DestroyWindow(window); +} + START_TEST(device) { HMODULE d3d8_handle = GetModuleHandleA("d3d8.dll"); @@ -8811,6 +8852,7 @@ START_TEST(device) test_clip_planes_limits(); test_swapchain_multisample_reset(); test_device_caps(); + test_get_info();
UnregisterClassA("d3d8_test_wc", GetModuleHandleA(NULL)); }
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check? Full results can be found at https://testbot.winehq.org/JobDetails.pl?Key=36956
Your paranoid android.
=== w1064 (32 bit device) === device.c:1534: Test failed: Reset failed, hr 0x80070057. device.c:1536: Test failed: TestCooperativeLevel failed, hr 0x88760869. device.c:1548: Test failed: D3DVIEWPORT->Width = 400. device.c:1549: Test failed: D3DVIEWPORT->Height = 300. 0f5c:device: unhandled exception c0000005 at 706EA86E
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- dlls/d3d8/device.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index 4fcad71451e..278024f15f8 100644 --- a/dlls/d3d8/device.c +++ b/dlls/d3d8/device.c @@ -1638,10 +1638,30 @@ static HRESULT WINAPI d3d8_device_MultiplyTransform(IDirect3DDevice8 *iface, static HRESULT WINAPI d3d8_device_SetViewport(IDirect3DDevice8 *iface, const D3DVIEWPORT8 *viewport) { struct d3d8_device *device = impl_from_IDirect3DDevice8(iface); + struct wined3d_sub_resource_desc rt_desc; + struct wined3d_rendertarget_view *rtv; + struct d3d8_surface *surface; struct wined3d_viewport vp;
TRACE("iface %p, viewport %p.\n", iface, viewport);
+ wined3d_mutex_lock(); + if (!(rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0))) + { + wined3d_mutex_unlock(); + return D3DERR_NOTFOUND; + } + surface = wined3d_rendertarget_view_get_sub_resource_parent(rtv); + wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &rt_desc); + + if (viewport->Width > rt_desc.width || viewport->X + viewport->Width > rt_desc.width + || viewport->Height > rt_desc.height || viewport->Y + viewport->Height > rt_desc.height) + { + WARN("Invalid viewport, returning D3DERR_INVALIDCALL.\n"); + wined3d_mutex_unlock(); + return D3DERR_INVALIDCALL; + } + vp.x = viewport->X; vp.y = viewport->Y; vp.width = viewport->Width; @@ -1649,7 +1669,6 @@ static HRESULT WINAPI d3d8_device_SetViewport(IDirect3DDevice8 *iface, const D3D vp.min_z = viewport->MinZ; vp.max_z = viewport->MaxZ;
- wined3d_mutex_lock(); wined3d_device_set_viewport(device->wined3d_device, &vp); wined3d_mutex_unlock();
On 20 March 2018 at 23:37, Matteo Bruni mbruni@codeweavers.com wrote:
- if (viewport->Width > rt_desc.width || viewport->X + viewport->Width > rt_desc.width
|| viewport->Height > rt_desc.height || viewport->Y + viewport->Height > rt_desc.height)
- {
WARN("Invalid viewport, returning D3DERR_INVALIDCALL.\n");
wined3d_mutex_unlock();
return D3DERR_INVALIDCALL;
- }
So suppose you have e.g. a 640x480 render target, and I try to set {~319u, ~239u, 640, 480, 0.0f, 1.0f} as viewport. Do we really want that to succeed?
Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- dlls/d3d8/tests/visual.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+)
diff --git a/dlls/d3d8/tests/visual.c b/dlls/d3d8/tests/visual.c index b64f08c8a15..a476be389fb 100644 --- a/dlls/d3d8/tests/visual.c +++ b/dlls/d3d8/tests/visual.c @@ -196,6 +196,45 @@ static D3DCOLOR get_surface_color(IDirect3DSurface8 *surface, UINT x, UINT y) return color; }
+static void check_rect(struct surface_readback *rb, RECT r, const char *message) +{ + LONG x_coords[2][2] = + { + {r.left - 1, r.left + 1}, + {r.right + 1, r.right - 1}, + }; + LONG y_coords[2][2] = + { + {r.top - 1, r.top + 1}, + {r.bottom + 1, r.bottom - 1} + }; + unsigned int i, j, x_side, y_side; + DWORD color; + LONG x, y; + + for (i = 0; i < 2; ++i) + { + for (j = 0; j < 2; ++j) + { + for (x_side = 0; x_side < 2; ++x_side) + { + for (y_side = 0; y_side < 2; ++y_side) + { + DWORD expected = (x_side == 1 && y_side == 1) ? 0xffffffff : 0xff000000; + + x = x_coords[i][x_side]; + y = y_coords[j][y_side]; + if (x < 0 || x >= 640 || y < 0 || y >= 480) + continue; + color = get_readback_color(rb, x, y); + ok(color == expected, "%s: Pixel (%d, %d) has color %08x, expected %08x.\n", + message, x, y, color, expected); + } + } + } + } +} + static IDirect3DDevice8 *create_device(IDirect3D8 *d3d, HWND device_window, HWND focus_window, BOOL windowed) { D3DPRESENT_PARAMETERS present_parameters = {0}; @@ -10132,6 +10171,121 @@ done: DestroyWindow(window); }
+static void test_viewport(void) +{ + static const struct + { + D3DVIEWPORT8 vp; + RECT expected_rect; + const char *message; + } + tests[] = + { + {{ 0, 0, 640, 480}, { 0, 120, 479, 359}, "Viewport (0, 0) - (640, 480)"}, + {{ 0, 0, 320, 240}, { 0, 60, 239, 179}, "Viewport (0, 0) - (320, 240)"}, + {{ 0, 0, 1280, 960}, { 0, 240, 639, 479}, "Viewport (0, 0) - (1280, 960)"}, + {{ 0, 0, 2000, 1600}, {-10, -10, -10, -10}, "Viewport (0, 0) - (2000, 1600)"}, + {{100, 100, 640, 480}, {100, 220, 579, 459}, "Viewport (100, 100) - (640, 480)"}, + {{ 0, 0, 10000, 10000}, {-10, -10, -10, -10}, "Viewport (0, 0) - (10000, 10000)"}, + }; + static const struct vec3 quad[] = + { + {-1.5f, -0.5f, 0.1f}, + {-1.5f, 0.5f, 0.1f}, + { 0.5f, -0.5f, 0.1f}, + { 0.5f, 0.5f, 0.1f}, + }; + static const struct vec2 rt_sizes[] = + { + {640, 480}, {1280, 960}, + }; + struct surface_readback rb; + IDirect3DDevice8 *device; + IDirect3DSurface8 *rt; + unsigned int i, j; + IDirect3D8 *d3d; + ULONG refcount; + HWND window; + HRESULT hr; + + window = create_window(); + d3d = Direct3DCreate8(D3D_SDK_VERSION); + ok(!!d3d, "Failed to create a D3D object.\n"); + if (!(device = create_device(d3d, window, window, TRUE))) + { + skip("Failed to create a D3D device, skipping tests.\n"); + goto done; + } + + hr = IDirect3DDevice8_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE); + ok(SUCCEEDED(hr), "Failed to enable z test, hr %#x.\n", hr); + hr = IDirect3DDevice8_SetRenderState(device, D3DRS_LIGHTING, FALSE); + ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#x.\n", hr); + + hr = IDirect3DDevice8_SetVertexShader(device, D3DFVF_XYZ); + ok(hr == D3D_OK, "Failed to set FVF, hr %#x.\n", hr); + + /* This crashes on Windows. */ + /* hr = IDirect3DDevice8_SetViewport(device, NULL); */ + + for (i = 0; i < sizeof(rt_sizes) / sizeof(rt_sizes[0]); ++i) + { + if (i) + { + hr = IDirect3DDevice8_CreateRenderTarget(device, 1280, 960, D3DFMT_A8R8G8B8, + D3DMULTISAMPLE_NONE, TRUE, &rt); + ok(hr == D3D_OK, "Failed to create render target, hr %#x.\n", hr); + hr = IDirect3DDevice8_SetRenderTarget(device, rt, NULL); + ok(hr == D3D_OK, "Failed to set render target, hr %#x.\n", hr); + } + else + { + hr = IDirect3DDevice8_GetBackBuffer(device, 0, D3DBACKBUFFER_TYPE_MONO, &rt); + ok(hr == D3D_OK, "Failed to get backbuffer, hr %#x.\n", hr); + } + + for (j = 0; j < sizeof(tests) / sizeof(tests[0]); ++j) + { + hr = IDirect3DDevice8_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff000000, 1.0f, 0); + ok(hr == D3D_OK, "Failed to clear, hr %#x.\n", hr); + + hr = IDirect3DDevice8_SetViewport(device, &tests[j].vp); + if (tests[j].vp.X + tests[j].vp.Width > rt_sizes[i].x + || tests[j].vp.Y + tests[j].vp.Height > rt_sizes[i].y) + { + ok(hr == D3DERR_INVALIDCALL, "Setting the viewport returned unexpected hr %#x.\n", hr); + continue; + } + else + { + ok(hr == D3D_OK, "Failed to set the viewport, hr %#x.\n", hr); + } + + hr = IDirect3DDevice8_BeginScene(device); + ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr); + hr = IDirect3DDevice8_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, sizeof(quad[0])); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + hr = IDirect3DDevice8_EndScene(device); + ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr); + + get_rt_readback(rt, &rb); + check_rect(&rb, tests[j].expected_rect, tests[j].message); + release_surface_readback(&rb); + } + + IDirect3DSurface8_Release(rt); + } + + hr = IDirect3DDevice8_Present(device, NULL, NULL, NULL, NULL); + ok(hr == D3D_OK, "Failed to present, hr %#x.\n", hr); + + refcount = IDirect3DDevice8_Release(device); + ok(!refcount, "Device has %u references left.\n", refcount); +done: + IDirect3D8_Release(d3d); + DestroyWindow(window); +} + START_TEST(visual) { D3DADAPTER_IDENTIFIER8 identifier; @@ -10204,4 +10358,5 @@ START_TEST(visual) test_backbuffer_resize(); test_drawindexedprimitiveup(); test_map_synchronisation(); + test_viewport(); }
Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- dlls/ddraw/device.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c index 75e000aa096..49989112f63 100644 --- a/dlls/ddraw/device.c +++ b/dlls/ddraw/device.c @@ -5315,6 +5315,9 @@ static HRESULT WINAPI d3d_device7_Clear_FPUPreserve(IDirect3DDevice7 *iface, DWO static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport) { struct d3d_device *device = impl_from_IDirect3DDevice7(iface); + struct wined3d_sub_resource_desc rt_desc; + struct wined3d_rendertarget_view *rtv; + struct ddraw_surface *surface; struct wined3d_viewport vp;
TRACE("iface %p, viewport %p.\n", iface, viewport); @@ -5322,6 +5325,23 @@ static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *vi if (!viewport) return DDERR_INVALIDPARAMS;
+ wined3d_mutex_lock(); + if (!(rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0))) + { + wined3d_mutex_unlock(); + return DDERR_INVALIDCAPS; + } + surface = wined3d_rendertarget_view_get_sub_resource_parent(rtv); + wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &rt_desc); + + if (viewport->dwWidth > rt_desc.width || viewport->dwX + viewport->dwWidth > rt_desc.width + || viewport->dwHeight > rt_desc.height || viewport->dwY + viewport->dwHeight > rt_desc.height) + { + WARN("Invalid viewport, returning E_INVALIDARG.\n"); + wined3d_mutex_unlock(); + return E_INVALIDARG; + } + vp.x = viewport->dwX; vp.y = viewport->dwY; vp.width = viewport->dwWidth; @@ -5329,7 +5349,6 @@ static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *vi vp.min_z = viewport->dvMinZ; vp.max_z = viewport->dvMaxZ;
- wined3d_mutex_lock(); wined3d_device_set_viewport(device->wined3d_device, &vp); wined3d_mutex_unlock();
Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- dlls/ddraw/tests/ddraw7.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+)
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c index 3f433a6765b..cfa05e3ec1e 100644 --- a/dlls/ddraw/tests/ddraw7.c +++ b/dlls/ddraw/tests/ddraw7.c @@ -280,6 +280,45 @@ static D3DCOLOR get_surface_color(IDirectDrawSurface7 *surface, UINT x, UINT y) return color; }
+static void check_rect(IDirectDrawSurface7 *surface, RECT r, const char *message) +{ + LONG x_coords[2][2] = + { + {r.left - 1, r.left + 1}, + {r.right + 1, r.right - 1}, + }; + LONG y_coords[2][2] = + { + {r.top - 1, r.top + 1}, + {r.bottom + 1, r.bottom - 1} + }; + unsigned int i, j, x_side, y_side; + DWORD color; + LONG x, y; + + for (i = 0; i < 2; ++i) + { + for (j = 0; j < 2; ++j) + { + for (x_side = 0; x_side < 2; ++x_side) + { + for (y_side = 0; y_side < 2; ++y_side) + { + DWORD expected = (x_side == 1 && y_side == 1) ? 0x00ffffff : 0x00000000; + + x = x_coords[i][x_side]; + y = y_coords[j][y_side]; + if (x < 0 || x >= 640 || y < 0 || y >= 480) + continue; + color = get_surface_color(surface, x, y); + ok(color == expected, "%s: Pixel (%d, %d) has color %08x, expected %08x.\n", + message, x, y, color, expected); + } + } + } + } +} + static HRESULT CALLBACK enum_z_fmt(DDPIXELFORMAT *format, void *ctx) { DDPIXELFORMAT *z_fmt = ctx; @@ -14095,6 +14134,130 @@ static void test_enum_surfaces(void) IDirectDraw7_Release(ddraw); }
+static void test_viewport(void) +{ + static struct + { + D3DVIEWPORT7 vp; + RECT expected_rect; + const char *message; + } + tests[] = + { + {{ 0, 0, 640, 480}, { 0, 120, 479, 359}, "Viewport (0, 0) - (640, 480)"}, + {{ 0, 0, 320, 240}, { 0, 60, 239, 179}, "Viewport (0, 0) - (320, 240)"}, + {{ 0, 0, 1280, 960}, { 0, 240, 639, 479}, "Viewport (0, 0) - (1280, 960)"}, + {{ 0, 0, 2000, 1600}, {-10, -10, -10, -10}, "Viewport (0, 0) - (2000, 1600)"}, + {{100, 100, 640, 480}, {100, 220, 579, 459}, "Viewport (100, 100) - (640, 480)"}, + {{ 0, 0, 10000, 10000}, {-10, -10, -10, -10}, "Viewport (0, 0) - (10000, 10000)"}, + }; + static struct vec3 quad[] = + { + {-1.5f, -0.5f, 0.1f}, + {-1.5f, 0.5f, 0.1f}, + { 0.5f, -0.5f, 0.1f}, + { 0.5f, 0.5f, 0.1f}, + }; + static const struct vec2 rt_sizes[] = + { + {640, 480}, {1280, 960}, + }; + IDirect3DDevice7 *device; + IDirectDrawSurface7 *rt; + IDirectDraw7 *ddraw; + unsigned int i, j; + IDirect3D7 *d3d; + ULONG refcount; + HWND window; + HRESULT hr; + + window = CreateWindowA("static", "d3d7_test", WS_OVERLAPPEDWINDOW, + 0, 0, 640, 480, 0, 0, 0, 0); + if (!(device = create_device(window, DDSCL_NORMAL))) + { + skip("Failed to create a 3D device, skipping test.\n"); + DestroyWindow(window); + return; + } + + hr = IDirect3DDevice7_GetDirect3D(device, &d3d); + ok(SUCCEEDED(hr), "Failed to get Direct3D7 interface, hr %#x.\n", hr); + hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **)&ddraw); + ok(SUCCEEDED(hr), "Failed to get ddraw interface, hr %#x.\n", hr); + IDirect3D7_Release(d3d); + + hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE); + ok(SUCCEEDED(hr), "Failed to enable z test, hr %#x.\n", hr); + hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE); + ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#x.\n", hr); + + hr = IDirect3DDevice7_SetViewport(device, NULL); + ok(hr == E_INVALIDARG, "Setting NULL viewport data returned unexpected hr %#x.\n", hr); + + for (i = 0; i < sizeof(rt_sizes) / sizeof(rt_sizes[0]); ++i) + { + if (i) + { + DDSURFACEDESC2 surface_desc; + + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT; + surface_desc.dwWidth = rt_sizes[i].x; + surface_desc.dwHeight = rt_sizes[i].y; + surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_3DDEVICE; + U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; + U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount = 32; + U2(U4(surface_desc).ddpfPixelFormat).dwRBitMask = 0x00ff0000; + U3(U4(surface_desc).ddpfPixelFormat).dwGBitMask = 0x0000ff00; + U4(U4(surface_desc).ddpfPixelFormat).dwBBitMask = 0x000000ff; + U5(U4(surface_desc).ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000; + hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &rt, NULL); + ok(hr == D3D_OK, "Failed to create render target, hr %#x.\n", hr); + hr = IDirect3DDevice7_SetRenderTarget(device, rt, 0); + ok(hr == D3D_OK, "Failed to set render target, hr %#x.\n", hr); + } + else + { + hr = IDirect3DDevice7_GetRenderTarget(device, &rt); + ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr); + } + + for (j = 0; j < sizeof(tests) / sizeof(tests[0]); ++j) + { + hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff000000, 1.0f, 0); + ok(hr == D3D_OK, "Failed to clear, hr %#x.\n", hr); + + hr = IDirect3DDevice7_SetViewport(device, &tests[j].vp); + if (tests[j].vp.dwX + tests[j].vp.dwWidth > rt_sizes[i].x + || tests[j].vp.dwY + tests[j].vp.dwHeight > rt_sizes[i].y) + { + ok(hr == E_INVALIDARG, "Setting the viewport returned unexpected hr %#x.\n", hr); + continue; + } + else + { + ok(hr == D3D_OK, "Failed to set the viewport, hr %#x.\n", hr); + } + + hr = IDirect3DDevice7_BeginScene(device); + ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr); + hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ, quad, 4, 0); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + hr = IDirect3DDevice7_EndScene(device); + ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr); + + check_rect(rt, tests[j].expected_rect, tests[j].message); + } + + IDirectDrawSurface7_Release(rt); + } + + refcount = IDirect3DDevice7_Release(device); + ok(!refcount, "Device has %u references left.\n", refcount); + DestroyWindow(window); +} + START_TEST(ddraw7) { DDDEVICEIDENTIFIER2 identifier; @@ -14229,4 +14392,5 @@ START_TEST(ddraw7) test_depth_readback(); test_clear(); test_enum_surfaces(); + test_viewport(); }