From 66ea1296b0b3493271a7611bfa56b0d74b34b16c Mon Sep 17 00:00:00 2001
From: Christian Costa <titan.costa@gmail.com>
Date: Fri, 19 Dec 2014 22:31:46 +0100
Subject: d3dx9_36: Implement ID3DXEffect_FindNextValidTechnique + add tests.

---
 dlls/d3dx9_36/effect.c       | 34 ++++++++++++++++++++++---
 dlls/d3dx9_36/tests/effect.c | 60 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/dlls/d3dx9_36/effect.c b/dlls/d3dx9_36/effect.c
index a210bb3..2fbc1cb 100644
--- a/dlls/d3dx9_36/effect.c
+++ b/dlls/d3dx9_36/effect.c
@@ -3483,13 +3483,41 @@ static HRESULT WINAPI ID3DXEffectImpl_ValidateTechnique(ID3DXEffect* iface, D3DX
     return D3D_OK;
 }
 
-static HRESULT WINAPI ID3DXEffectImpl_FindNextValidTechnique(ID3DXEffect* iface, D3DXHANDLE technique, D3DXHANDLE* next_technique)
+static HRESULT WINAPI ID3DXEffectImpl_FindNextValidTechnique(ID3DXEffect *iface,
+        D3DXHANDLE technique, D3DXHANDLE *next_technique)
 {
     struct ID3DXEffectImpl *This = impl_from_ID3DXEffect(iface);
+    struct d3dx9_base_effect *base_effect = &This->base_effect;
+    UINT i = 0;
 
-    FIXME("(%p)->(%p, %p): stub\n", This, technique, next_technique);
+    TRACE("iface %p, technique %p, next_technique %p\n", iface, technique, next_technique);
 
-    return E_NOTIMPL;
+    if (!next_technique)
+        return D3DERR_INVALIDCALL;
+
+    if (technique)
+    {
+        for (; i < base_effect->technique_count; i++)
+        {
+            if (technique == get_technique_handle(&base_effect->techniques[i]))
+            {
+                i++; /* Go to next technique */
+                break;
+            }
+        }
+    }
+
+    for (; i < base_effect->technique_count; i++)
+    {
+        if (SUCCEEDED(iface->lpVtbl->ValidateTechnique(iface, get_technique_handle(&base_effect->techniques[i]))))
+        {
+            *next_technique = get_technique_handle(&base_effect->techniques[i]);
+            return D3D_OK;
+        }
+    }
+
+    *next_technique = NULL;
+    return S_FALSE;
 }
 
 static BOOL WINAPI ID3DXEffectImpl_IsParameterUsed(ID3DXEffect* iface, D3DXHANDLE parameter, D3DXHANDLE technique)
diff --git a/dlls/d3dx9_36/tests/effect.c b/dlls/d3dx9_36/tests/effect.c
index c388e7d..8653e0e 100644
--- a/dlls/d3dx9_36/tests/effect.c
+++ b/dlls/d3dx9_36/tests/effect.c
@@ -3886,6 +3886,65 @@ static void test_effect_preshader(IDirect3DDevice9 *device)
     effect->lpVtbl->Release(effect);
 }
 
+/*
+ * fxc.exe /Tfx_2_0
+ */
+#if 0
+technique t1 { pass p { ZEnable = TRUE; } }
+technique t2 { pass p { ZEnable = FALSE; } }
+#endif
+static const DWORD test_effect_technique_validation_blob[] =
+{
+0xfeff0901, 0x00000064, 0x00000000, 0x00000001, 0x00000002, 0x00000002, 0x00000000, 0x00000000,
+0x00000000, 0x00000001, 0x00000001, 0x00000002, 0x00000070, 0x00000003, 0x00003174, 0x00000000,
+0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000002,
+0x00000070, 0x00000003, 0x00003274, 0x00000000, 0x00000002, 0x00000002, 0x00000001, 0x0000002c,
+0x00000000, 0x00000001, 0x00000024, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000008,
+0x00000004, 0x0000005c, 0x00000000, 0x00000001, 0x00000054, 0x00000000, 0x00000001, 0x00000000,
+0x00000000, 0x00000038, 0x00000034, 0x00000000, 0x00000000
+};
+
+static void test_effect_technique_validation(IDirect3DDevice9 *device)
+{
+    ID3DXEffect *effect;
+    ULONG count;
+    D3DXHANDLE technique1, technique2, technique;
+    HRESULT hr;
+
+    hr = D3DXCreateEffect(device, test_effect_technique_validation_blob,
+            sizeof(test_effect_technique_validation_blob), NULL, NULL, 0, NULL, &effect, NULL);
+    ok(hr == D3D_OK, "D3DXCreateEffect failed, got %#x, expected %#x\n", hr, D3D_OK);
+
+    technique1 = effect->lpVtbl->GetTechniqueByName(effect, "t1");
+    ok(technique1 != NULL, "Failed to get technique\n");
+    technique2 = effect->lpVtbl->GetTechniqueByName(effect, "t2");
+    ok(technique2 != NULL, "Failed to get technique\n");
+
+#if 0 /* This crashes on Windows */
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, (D3DXHANDLE)0xdeadbeef, &technique);
+#endif
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, NULL, NULL);
+    ok(hr == D3DERR_INVALIDCALL, "FindNextValidTechnique, got %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
+
+    technique = (D3DXHANDLE)0xdeadbeef;
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, NULL, &technique);
+    ok(hr == D3D_OK, "FindNextValidTechnique failed, got %#x, expected %#x\n", hr, D3D_OK);
+    ok(technique == technique1, "Technique returned %p, expected %p\n", technique, technique1);
+
+    technique = (D3DXHANDLE)0xdeadbeef;
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, technique1, &technique);
+    ok(hr == D3D_OK, "FindNextValidTechnique failed, got %#x, expected %#x\n", hr, D3D_OK);
+    ok(technique == technique2, "Technique returned %p, expected %p\n", technique, technique2);
+
+    technique = (D3DXHANDLE)0xdeadbeef;
+    hr = effect->lpVtbl->FindNextValidTechnique(effect, technique2, &technique);
+    ok(hr == S_FALSE, "FindNextValidTechnique, got %#x, expected %#x\n", hr, S_FALSE);
+    ok(technique == NULL, "Technique returned %p, expected %p\n", technique, NULL);
+
+    count = effect->lpVtbl->Release(effect);
+    ok(!count, "Release failed %u\n", count);
+}
+
 START_TEST(effect)
 {
     HWND wnd;
@@ -3927,6 +3986,7 @@ START_TEST(effect)
     test_effect_compilation_errors(device);
     test_effect_states(device);
     test_effect_preshader(device);
+    test_effect_technique_validation(device);
 
     count = IDirect3DDevice9_Release(device);
     ok(count == 0, "The device was not properly freed: refcount %u\n", count);
-- 
2.7.1

