On Wed, May 25, 2011 at 9:53 AM, Michael Mc Donnell
<mich...@mcdonnell.dk> wrote:
> On Tue, May 24, 2011 at 8:32 PM, Stefan Dösinger <stefandoesin...@gmx.at> 
> wrote:
>> On Tuesday 24 May 2011 19:56:06 Michael Mc Donnell wrote:
>>> > *) In your first test you forgot to check the HeapAlloc result.
>>>
>>> Ok, I'll return E_OUTOFMEMORY in that case.
>> I guess the callers will only abort the tests if NewTestContext fails, so I
>> think the NULL / non-NULL return value was better.

I've reverted those changes, so it's back to NULL / non-NULL. I've
also moved it near the top of the file, so that other tests will be
able to re-use the test context creation.

>>> Should I try to make some more invalid
>>> D3DVERTEXELEMENT9 arrays to see if I can provoke an error?
>> I was thinking about something that would make CreateVertexDeclaration fail,
>> e.g. declaring a usage+usage index twice or using an undefined type.
>> dlls/d3d9/vertexdeclaration.c and dlls/wined3d/vertexdeclaration.c check for 
>> a
>> few error conditions in their vertexdeclaration_init functions. Just pick one
>> of them(no need to check all of them)
>> But watch out that you don't open a can of worms here. Our
>> CreateVertexDeclaration probably doesn't catch all error conditions. I
>> recommend that you pick one it does catch, otherwise you'll have to fix
>> d3d9.dll and wined3d.dll too for a small test.
>
> Ok thanks I'll do that.

I've added some more tests to see if I could make it fail. Microsoft's
UpdateSemantics is not very picky. I can't get it to return anything
but D3D_OK except for when I pass a null pointer. My implementation
follows this behavior except for two cases: it returns E_FAIL when
passing an undefined type and when the offset is not 4 byte aligned.
This is because the values are checked inside vertexdeclaration_init.
So Wine is stricter. I don't think that it is necessarily a problem
because applications that pass bogus declarations like those will
likely not work anyway. My own tests with a small interactive demo
show that in those cases the application will crash with an access
violation when it tries to re-draw the scene.
diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index cedef32..0ca4b25 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -2,6 +2,7 @@
  * Copyright 2008 David Adam
  * Copyright 2008 Luis Busquets
  * Copyright 2009 Henri Verbeet for CodeWeavers
+ * Copyright 2011 Michael Mc Donnell
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -61,6 +62,93 @@ static BOOL compare_face(face a, face b)
     return (a[0]==b[0] && a[1] == b[1] && a[2] == b[2]);
 }
 
+struct TestContext
+{
+    HWND hwnd;
+    IDirect3D9 *d3d;
+    IDirect3DDevice9 *device;
+};
+
+/*
+ * Initializes a TestContext. Use this to initialize DirectX.
+ *
+ * Returns NULL if an error occured.
+ */
+static struct TestContext* NewTestContext(void)
+{
+    HRESULT hr;
+    HWND hwnd = NULL;
+    IDirect3D9 *d3d = NULL;
+    IDirect3DDevice9 *device = NULL;
+    D3DPRESENT_PARAMETERS d3dpp = {0};
+    struct TestContext *testContext;
+
+    hwnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+    if (!hwnd)
+    {
+        skip("Couldn't create application window\n");
+        goto error;
+    }
+
+    d3d = Direct3DCreate9(D3D_SDK_VERSION);
+    if (!d3d)
+    {
+        skip("Couldn't create IDirect3D9 object\n");
+        goto error;
+    }
+
+    memset(&d3dpp, 0, sizeof(d3dpp));
+    d3dpp.Windowed = TRUE;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
+    if (FAILED(hr))
+    {
+        skip("Couldn't create IDirect3DDevice9 object %#x\n", hr);
+        goto error;
+    }
+
+    testContext = HeapAlloc(GetProcessHeap(), 0, sizeof(struct TestContext));
+    if (!testContext)
+    {
+        skip("Couldn't allocate memory for TestContext\n");
+        goto error;
+    }
+    testContext->hwnd = hwnd;
+    testContext->d3d = d3d;
+    testContext->device = device;
+
+    return testContext;
+
+error:
+    if (device)
+        IDirect3DDevice9_Release(device);
+
+    if (d3d)
+        IDirect3D9_Release(d3d);
+
+    if (hwnd)
+        DestroyWindow(hwnd);
+
+    return NULL;
+}
+
+static void FreeTestContext(struct TestContext *testContext)
+{
+    if (!testContext)
+        return;
+
+    if (testContext->device)
+        IDirect3DDevice9_Release(testContext->device);
+
+    if (testContext->d3d)
+        IDirect3D9_Release(testContext->d3d);
+
+    if (testContext->hwnd)
+        DestroyWindow(testContext->hwnd);
+
+    HeapFree(GetProcessHeap(), 0, testContext);
+}
+
 struct mesh
 {
     DWORD number_of_vertices;
@@ -3305,6 +3393,200 @@ static void D3DXGenerateAdjacencyTest(void)
     if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh);
 }
 
+struct VertexTwoPositions
+{
+    float x0, y0, z0; /* Position 0 */
+    float x1, y1, z1; /* Position 1 */
+    float nx, ny, nz; /* Normal */
+    DWORD color;
+};
+
+static void UpdateSemanticsTest(void)
+{
+    HRESULT hr;
+    struct TestContext *tc = NULL;
+    LPD3DXMESH mesh;
+    D3DVERTEXELEMENT9 declaration0[] =
+    {
+         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+         D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_double_usage[] =
+    {
+         {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+         D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_wrong_type_color[] =
+    {
+         {0, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+         D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_undefined_type[] =
+    {
+         {0, 0, D3DDECLTYPE_UNUSED+1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+         D3DDECL_END()
+    };
+    D3DVERTEXELEMENT9 declaration_not_4_byte_aligned_offset[] =
+    {
+         {0, 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+         {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
+         {0, 36, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+         D3DDECL_END()
+    };
+    /* x0, y0, z0, x1, y1, z1 ,nx, ny, nz, color */
+    struct VertexTwoPositions vertices[] =
+    {
+        {  0.0f,  1.0f,  0.f,    1.0f,  0.0f,  0.f,    0.0f,  0.0f,  1.0f, 0xffff0000, },
+        {  1.0f, -1.0f,  0.f,   -1.0f, -1.0f,  0.f,    0.0f,  0.0f,  1.0f, 0xff00ff00, },
+        { -1.0f, -1.0f,  0.f,   -1.0f,  1.0f,  0.f,    0.0f,  0.0f,  1.0f, 0xff0000ff, },
+    };
+    unsigned int faces[] = {0, 1, 2};
+    unsigned int attributes[] = {0};
+    unsigned int numFaces = 1;
+    unsigned int numVertices = 3;
+    int offset = 12;
+    DWORD options = D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM;
+    LPVOID pVertices;
+    LPVOID pFaces;
+    LPDWORD pAttributes;
+    D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
+    D3DVERTEXELEMENT9 *pDecl;
+
+    tc = NewTestContext();
+    if (!tc)
+    {
+        skip("Couldn't create a TestContext");
+        goto cleanup;
+    }
+
+    /* Create the test mesh */
+    hr = D3DXCreateMesh(numFaces, numVertices, options, declaration0, tc->device, &mesh);
+    if (FAILED(hr))
+    {
+        skip("Couldn't create test mesh %#x\n", hr);
+        goto cleanup;
+    }
+
+    mesh->lpVtbl->LockVertexBuffer(mesh, 0, &pVertices);
+    memcpy(pVertices, vertices, sizeof(vertices));
+    mesh->lpVtbl->UnlockVertexBuffer(mesh);
+
+    mesh->lpVtbl->LockIndexBuffer(mesh, 0, &pFaces);
+    memcpy(pFaces, faces, sizeof(faces));
+    mesh->lpVtbl->UnlockIndexBuffer(mesh);
+
+    mesh->lpVtbl->LockAttributeBuffer(mesh, 0, &pAttributes);
+    memcpy(pAttributes, attributes, sizeof(attributes));
+    mesh->lpVtbl->UnlockAttributeBuffer(mesh);
+
+    /* Get the declaration and try to change it */
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    if (FAILED(hr))
+    {
+        skip("Couldn't get mesh declaration %#x\n", hr);
+        goto cleanup;
+    }
+
+    for (pDecl = declaration; pDecl->Stream != 0xFF; pDecl++)
+    {
+        if (pDecl->Usage == D3DDECLUSAGE_POSITION)
+        {
+            /* Use second vertex position instead of first */
+            pDecl->Offset = offset;
+        }
+    }
+
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
+    todo_wine ok(hr == D3D_OK, "Test UpdateSematics, got %#x expected %#x\n", hr, D3D_OK);
+
+    /* Check that declaration was written by getting it again */
+    memset(declaration, 0, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    if (FAILED(hr))
+    {
+        skip("Couldn't get mesh declaration %#x\n", hr);
+        goto cleanup;
+    }
+
+    for (pDecl = declaration; pDecl->Stream != 0xFF; pDecl++)
+    {
+        if (pDecl->Usage == D3DDECLUSAGE_POSITION)
+        {
+            todo_wine ok(pDecl->Offset == offset, "Test UpdateSematics, got offset %d expected %d\n",
+                pDecl->Offset, offset);
+        }
+    }
+
+    /* UpdateSemantics does not check for a bigger vertex size */
+    memset(declaration, 0, sizeof(declaration));
+    hr = mesh->lpVtbl->GetDeclaration(mesh, declaration);
+    if (FAILED(hr))
+    {
+        skip("Couldn't get mesh declaration %#x\n", hr);
+        goto cleanup;
+    }
+
+    for (pDecl = declaration; pDecl->Stream != 0xFF; pDecl++)
+    {
+        if (pDecl->Type == D3DDECLTYPE_FLOAT3)
+        {
+            pDecl->Type = D3DDECLTYPE_FLOAT4;
+        }
+    }
+
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
+    todo_wine ok(hr == D3D_OK, "Test UpdateSematics for bigger vertex size, "
+        "got %#x expected D3D_OK\n", hr);
+
+    /* Null pointer declaration */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics null pointer declaration, "
+        "got %#x expected D3DERR_INVALIDCALL\n", hr);
+
+    /*
+     * Two null pointers. Setting only the mesh to null will result in an
+     * exception on Windows.
+     */
+    hr = mesh->lpVtbl->UpdateSemantics(NULL, NULL);
+    todo_wine ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics null pointers, "
+        "got %#x expected D3DERR_INVALIDCALL\n", hr);
+
+    /* Double usage is not checked */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_double_usage);
+    todo_wine ok(hr == D3D_OK, "Test UpdateSematics double usage, "
+        "got %#x expected D3D_OK\n", hr);
+
+    /* Set the position type to color instead of float3 */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_wrong_type_color);
+    todo_wine ok(hr == D3D_OK, "Test UpdateSematics wrong type color, "
+        "got %#x expected D3D_OK\n", hr);
+
+    /* Set the position to an undefined type */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_undefined_type);
+    todo_wine ok(hr == D3D_OK, "Test UpdateSematics undefined type, "
+        "got %#x expected D3D_OK\n", hr);
+
+    /* Use a not 4 byte aligned offset */
+    hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_not_4_byte_aligned_offset);
+    todo_wine ok(hr == D3D_OK, "Test UpdateSematics not 4 byte aligned offset, "
+        "got %#x expected D3D_OK\n", hr);
+
+cleanup:
+    if (mesh)
+        mesh->lpVtbl->Release(mesh);
+
+    FreeTestContext(tc);
+}
+
 START_TEST(mesh)
 {
     D3DXBoundProbeTest();
@@ -3322,4 +3604,5 @@ START_TEST(mesh)
     test_get_decl_vertex_size();
     test_fvf_decl_conversion();
     D3DXGenerateAdjacencyTest();
+    UpdateSemanticsTest();
 }
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index c5954b3..74a929f 100644
--- a/dlls/d3dx9_36/mesh.c
+++ b/dlls/d3dx9_36/mesh.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2009 David Adam
  * Copyright (C) 2010 Tony Wasserka
  * Copyright (C) 2011 Dylan Smith
+ * Copyright (C) 2011 Michael Mc Donnell
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -597,11 +598,30 @@ cleanup:
 
 static HRESULT WINAPI ID3DXMeshImpl_UpdateSemantics(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
 {
+    HRESULT hr;
     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
+    IDirect3DVertexDeclaration9 *new_vertex_declaration;
+    if (declaration == NULL)
+        return D3DERR_INVALIDCALL;
 
-    FIXME("(%p)->(%p): stub\n", This, declaration);
+    TRACE("(%p)->(%p)\n", This, declaration);
 
-    return E_NOTIMPL;
+    /* Create new vertex declaration */
+    hr = IDirect3DDevice9_CreateVertexDeclaration(This->device,
+                                                  declaration,
+                                                  &new_vertex_declaration);
+    if (FAILED(hr))
+    {
+        WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr);
+        return hr;
+    }
+
+    /* Free old vertex declaration */
+    IDirect3DVertexDeclaration9_Release(This->vertex_declaration);
+    /* Use new declaration */
+    This->vertex_declaration = new_vertex_declaration;
+
+    return D3D_OK;
 }
 
 /*** ID3DXMesh ***/
diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c
index 0ca4b25..0f5ca27 100644
--- a/dlls/d3dx9_36/tests/mesh.c
+++ b/dlls/d3dx9_36/tests/mesh.c
@@ -3506,7 +3506,7 @@ static void UpdateSemanticsTest(void)
     }
 
     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
-    todo_wine ok(hr == D3D_OK, "Test UpdateSematics, got %#x expected %#x\n", hr, D3D_OK);
+    ok(hr == D3D_OK, "Test UpdateSematics, got %#x expected %#x\n", hr, D3D_OK);
 
     /* Check that declaration was written by getting it again */
     memset(declaration, 0, sizeof(declaration));
@@ -3521,7 +3521,7 @@ static void UpdateSemanticsTest(void)
     {
         if (pDecl->Usage == D3DDECLUSAGE_POSITION)
         {
-            todo_wine ok(pDecl->Offset == offset, "Test UpdateSematics, got offset %d expected %d\n",
+            ok(pDecl->Offset == offset, "Test UpdateSematics, got offset %d expected %d\n",
                 pDecl->Offset, offset);
         }
     }
@@ -3544,12 +3544,12 @@ static void UpdateSemanticsTest(void)
     }
 
     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration);
-    todo_wine ok(hr == D3D_OK, "Test UpdateSematics for bigger vertex size, "
+    ok(hr == D3D_OK, "Test UpdateSematics for bigger vertex size, "
         "got %#x expected D3D_OK\n", hr);
 
     /* Null pointer declaration */
     hr = mesh->lpVtbl->UpdateSemantics(mesh, NULL);
-    todo_wine ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics null pointer declaration, "
+    ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics null pointer declaration, "
         "got %#x expected D3DERR_INVALIDCALL\n", hr);
 
     /*
@@ -3557,17 +3557,17 @@ static void UpdateSemanticsTest(void)
      * exception on Windows.
      */
     hr = mesh->lpVtbl->UpdateSemantics(NULL, NULL);
-    todo_wine ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics null pointers, "
+    ok(hr == D3DERR_INVALIDCALL, "Test UpdateSematics null pointers, "
         "got %#x expected D3DERR_INVALIDCALL\n", hr);
 
     /* Double usage is not checked */
     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_double_usage);
-    todo_wine ok(hr == D3D_OK, "Test UpdateSematics double usage, "
+    ok(hr == D3D_OK, "Test UpdateSematics double usage, "
         "got %#x expected D3D_OK\n", hr);
 
     /* Set the position type to color instead of float3 */
     hr = mesh->lpVtbl->UpdateSemantics(mesh, declaration_wrong_type_color);
-    todo_wine ok(hr == D3D_OK, "Test UpdateSematics wrong type color, "
+    ok(hr == D3D_OK, "Test UpdateSematics wrong type color, "
         "got %#x expected D3D_OK\n", hr);
 
     /* Set the position to an undefined type */


Reply via email to