widl: Use the output buffer functions to write typelibs.
[wine] / dlls / ddraw / tests / d3d.c
1 /*
2  * Some unit tests for d3d functions
3  *
4  * Copyright (C) 2005 Antoine Chavasse
5  * Copyright (C) 2006 Stefan Dösinger for CodeWeavers
6  * Copyright (C) 2008 Alexander Dorofeyev
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #define COBJMACROS
24
25 #include <assert.h>
26 #include "wine/test.h"
27 #include "initguid.h"
28 #include "ddraw.h"
29 #include "d3d.h"
30 #include "unknwn.h"
31
32 static LPDIRECTDRAW7           lpDD = NULL;
33 static LPDIRECT3D7             lpD3D = NULL;
34 static LPDIRECTDRAWSURFACE7    lpDDS = NULL;
35 static LPDIRECTDRAWSURFACE7    lpDDSdepth = NULL;
36 static LPDIRECT3DDEVICE7       lpD3DDevice = NULL;
37 static LPDIRECT3DVERTEXBUFFER7 lpVBufSrc = NULL;
38 static LPDIRECT3DVERTEXBUFFER7 lpVBufDest1 = NULL;
39 static LPDIRECT3DVERTEXBUFFER7 lpVBufDest2 = NULL;
40
41 static IDirectDraw *DirectDraw1 = NULL;
42 static IDirectDrawSurface *Surface1 = NULL;
43 static IDirect3D *Direct3D1 = NULL;
44 static IDirect3DDevice *Direct3DDevice1 = NULL;
45 static IDirect3DExecuteBuffer *ExecuteBuffer = NULL;
46 static IDirect3DViewport *Viewport = NULL;
47 static IDirect3DLight *Light = NULL;
48
49 typedef struct {
50     int total;
51     int rgb;
52     int hal;
53     int tnlhal;
54     int unk;
55 } D3D7ETest;
56
57 /* To compare bad floating point numbers. Not the ideal way to do it,
58  * but it should be enough for here */
59 #define comparefloat(a, b) ( (((a) - (b)) < 0.0001) && (((a) - (b)) > -0.0001) )
60
61 static HRESULT (WINAPI *pDirectDrawCreateEx)(LPGUID,LPVOID*,REFIID,LPUNKNOWN);
62
63 typedef struct _VERTEX
64 {
65     float x, y, z;  /* position */
66 } VERTEX, *LPVERTEX;
67
68 typedef struct _TVERTEX
69 {
70     float x, y, z;  /* position */
71     float rhw;
72 } TVERTEX, *LPTVERTEX;
73
74
75 static void init_function_pointers(void)
76 {
77     HMODULE hmod = GetModuleHandleA("ddraw.dll");
78     pDirectDrawCreateEx = (void*)GetProcAddress(hmod, "DirectDrawCreateEx");
79 }
80
81
82 static ULONG getRefcount(IUnknown *iface)
83 {
84     IUnknown_AddRef(iface);
85     return IUnknown_Release(iface);
86 }
87
88
89 static BOOL CreateDirect3D(void)
90 {
91     HRESULT rc;
92     DDSURFACEDESC2 ddsd;
93
94     rc = pDirectDrawCreateEx(NULL, (void**)&lpDD,
95         &IID_IDirectDraw7, NULL);
96     ok(rc==DD_OK || rc==DDERR_NODIRECTDRAWSUPPORT, "DirectDrawCreateEx returned: %x\n", rc);
97     if (!lpDD) {
98         trace("DirectDrawCreateEx() failed with an error %x\n", rc);
99         return FALSE;
100     }
101
102     rc = IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_NORMAL);
103     ok(rc==DD_OK, "SetCooperativeLevel returned: %x\n", rc);
104
105     rc = IDirectDraw7_QueryInterface(lpDD, &IID_IDirect3D7, (void**) &lpD3D);
106     if (rc == E_NOINTERFACE) return FALSE;
107     ok(rc==DD_OK, "QueryInterface returned: %x\n", rc);
108
109     memset(&ddsd, 0, sizeof(ddsd));
110     ddsd.dwSize = sizeof(ddsd);
111     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
112     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
113     ddsd.dwWidth = 256;
114     ddsd.dwHeight = 256;
115     rc = IDirectDraw7_CreateSurface(lpDD, &ddsd, &lpDDS, NULL);
116     if (FAILED(rc))
117         return FALSE;
118
119     memset(&ddsd, 0, sizeof(ddsd));
120     ddsd.dwSize = sizeof(ddsd);
121     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
122     ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
123     U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
124     U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
125     U1(U4(ddsd).ddpfPixelFormat).dwZBufferBitDepth = 16;
126     U3(U4(ddsd).ddpfPixelFormat).dwZBitMask = 0x0000FFFF;
127     ddsd.dwWidth = 256;
128     ddsd.dwHeight = 256;
129     rc = IDirectDraw7_CreateSurface(lpDD, &ddsd, &lpDDSdepth, NULL);
130     ok(rc==DD_OK, "CreateSurface returned: %x\n", rc);
131     if (FAILED(rc)) {
132         lpDDSdepth = NULL;
133     } else {
134         rc = IDirectDrawSurface_AddAttachedSurface(lpDDS, lpDDSdepth);
135         ok(rc == DD_OK, "IDirectDrawSurface_AddAttachedSurface returned %x\n", rc);
136         if (FAILED(rc))
137             return FALSE;
138     }
139
140     rc = IDirect3D7_CreateDevice(lpD3D, &IID_IDirect3DTnLHalDevice, lpDDS,
141         &lpD3DDevice);
142     ok(rc==D3D_OK || rc==DDERR_NOPALETTEATTACHED || rc==E_OUTOFMEMORY, "CreateDevice returned: %x\n", rc);
143     if (!lpD3DDevice) {
144         trace("IDirect3D7::CreateDevice() for a TnL Hal device failed with an error %x, trying HAL\n", rc);
145         rc = IDirect3D7_CreateDevice(lpD3D, &IID_IDirect3DHALDevice, lpDDS,
146             &lpD3DDevice);
147         if (!lpD3DDevice) {
148             trace("IDirect3D7::CreateDevice() for a HAL device failed with an error %x, trying RGB\n", rc);
149             rc = IDirect3D7_CreateDevice(lpD3D, &IID_IDirect3DRGBDevice, lpDDS,
150                 &lpD3DDevice);
151             if (!lpD3DDevice) {
152                 trace("IDirect3D7::CreateDevice() for a RGB device failed with an error %x, giving up\n", rc);
153                 return FALSE;
154             }
155         }
156     }
157
158     return TRUE;
159 }
160
161 static void ReleaseDirect3D(void)
162 {
163     if (lpD3DDevice != NULL)
164     {
165         IDirect3DDevice7_Release(lpD3DDevice);
166         lpD3DDevice = NULL;
167     }
168
169     if (lpDDSdepth != NULL)
170     {
171         IDirectDrawSurface_Release(lpDDSdepth);
172         lpDDSdepth = NULL;
173     }
174
175     if (lpDDS != NULL)
176     {
177         IDirectDrawSurface_Release(lpDDS);
178         lpDDS = NULL;
179     }
180
181     if (lpD3D != NULL)
182     {
183         IDirect3D7_Release(lpD3D);
184         lpD3D = NULL;
185     }
186
187     if (lpDD != NULL)
188     {
189         IDirectDraw_Release(lpDD);
190         lpDD = NULL;
191     }
192 }
193
194 static void LightTest(void)
195 {
196     HRESULT rc;
197     D3DLIGHT7 light;
198     D3DLIGHT7 defaultlight;
199     BOOL bEnabled = FALSE;
200     float one = 1.0f;
201     float zero= 0.0f;
202     D3DMATERIAL7 mat;
203     BOOL enabled;
204     unsigned int i;
205     D3DDEVICEDESC7 caps;
206
207     /* Set a few lights with funky indices. */
208     memset(&light, 0, sizeof(light));
209     light.dltType = D3DLIGHT_DIRECTIONAL;
210     U1(light.dcvDiffuse).r = 0.5f;
211     U2(light.dcvDiffuse).g = 0.6f;
212     U3(light.dcvDiffuse).b = 0.7f;
213     U2(light.dvDirection).y = 1.f;
214
215     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 5, &light);
216     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
217     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 10, &light);
218     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
219     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 45, &light);
220     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
221
222
223     /* Try to retrieve a light beyond the indices of the lights that have
224        been set. */
225     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 50, &light);
226     ok(rc==DDERR_INVALIDPARAMS, "GetLight returned: %x\n", rc);
227     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 2, &light);
228     ok(rc==DDERR_INVALIDPARAMS, "GetLight returned: %x\n", rc);
229
230
231     /* Try to retrieve one of the lights that have been set */
232     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 10, &light);
233     ok(rc==D3D_OK, "GetLight returned: %x\n", rc);
234
235
236     /* Enable a light that have been previously set. */
237     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 10, TRUE);
238     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
239
240
241     /* Enable some lights that have not been previously set, and verify that
242        they have been initialized with proper default values. */
243     memset(&defaultlight, 0, sizeof(D3DLIGHT7));
244     defaultlight.dltType = D3DLIGHT_DIRECTIONAL;
245     U1(defaultlight.dcvDiffuse).r = 1.f;
246     U2(defaultlight.dcvDiffuse).g = 1.f;
247     U3(defaultlight.dcvDiffuse).b = 1.f;
248     U3(defaultlight.dvDirection).z = 1.f;
249
250     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 20, TRUE);
251     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
252     memset(&light, 0, sizeof(D3DLIGHT7));
253     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 20, &light);
254     ok(rc==D3D_OK, "GetLight returned: %x\n", rc);
255     ok(!memcmp(&light, &defaultlight, sizeof(D3DLIGHT7)),
256         "light data doesn't match expected default values\n" );
257
258     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 50, TRUE);
259     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
260     memset(&light, 0, sizeof(D3DLIGHT7));
261     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 50, &light);
262     ok(rc==D3D_OK, "GetLight returned: %x\n", rc);
263     ok(!memcmp(&light, &defaultlight, sizeof(D3DLIGHT7)),
264         "light data doesn't match expected default values\n" );
265
266
267     /* Disable one of the light that have been previously enabled. */
268     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 20, FALSE);
269     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
270
271     /* Try to retrieve the enable status of some lights */
272     /* Light 20 is supposed to be disabled */
273     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 20, &bEnabled );
274     ok(rc==D3D_OK, "GetLightEnable returned: %x\n", rc);
275     ok(!bEnabled, "GetLightEnable says the light is enabled\n");
276
277     /* Light 10 is supposed to be enabled */
278     bEnabled = FALSE;
279     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 10, &bEnabled );
280     ok(rc==D3D_OK, "GetLightEnable returned: %x\n", rc);
281     ok(bEnabled, "GetLightEnable says the light is disabled\n");
282
283     /* Light 80 has not been set */
284     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 80, &bEnabled );
285     ok(rc==DDERR_INVALIDPARAMS, "GetLightEnable returned: %x\n", rc);
286
287     /* Light 23 has not been set */
288     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 23, &bEnabled );
289     ok(rc==DDERR_INVALIDPARAMS, "GetLightEnable returned: %x\n", rc);
290
291     /* Set some lights with invalid parameters */
292     memset(&light, 0, sizeof(D3DLIGHT7));
293     light.dltType = 0;
294     U1(light.dcvDiffuse).r = 1.f;
295     U2(light.dcvDiffuse).g = 1.f;
296     U3(light.dcvDiffuse).b = 1.f;
297     U3(light.dvDirection).z = 1.f;
298     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 100, &light);
299     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
300
301     memset(&light, 0, sizeof(D3DLIGHT7));
302     light.dltType = 12345;
303     U1(light.dcvDiffuse).r = 1.f;
304     U2(light.dcvDiffuse).g = 1.f;
305     U3(light.dcvDiffuse).b = 1.f;
306     U3(light.dvDirection).z = 1.f;
307     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 101, &light);
308     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
309
310     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 102, NULL);
311     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
312
313     memset(&light, 0, sizeof(D3DLIGHT7));
314     light.dltType = D3DLIGHT_SPOT;
315     U1(light.dcvDiffuse).r = 1.f;
316     U2(light.dcvDiffuse).g = 1.f;
317     U3(light.dcvDiffuse).b = 1.f;
318     U3(light.dvDirection).z = 1.f;
319
320     light.dvAttenuation0 = -one / zero; /* -INFINITY */
321     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
322     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
323
324     light.dvAttenuation0 = -1.0;
325     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
326     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
327
328     light.dvAttenuation0 = 0.0;
329     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
330     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
331
332     light.dvAttenuation0 = 1.0;
333     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
334     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
335
336     light.dvAttenuation0 = one / zero; /* +INFINITY */
337     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
338     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
339
340     light.dvAttenuation0 = zero / zero; /* NaN */
341     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
342     ok(rc==D3D_OK ||
343        broken(rc==DDERR_INVALIDPARAMS), "SetLight returned: %x\n", rc);
344
345     /* Directional light ignores attenuation */
346     light.dltType = D3DLIGHT_DIRECTIONAL;
347     light.dvAttenuation0 = -1.0;
348     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
349     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
350
351     memset(&mat, 0, sizeof(mat));
352     rc = IDirect3DDevice7_SetMaterial(lpD3DDevice, &mat);
353     ok(rc == D3D_OK, "IDirect3DDevice7_SetMaterial returned: %x\n", rc);
354
355     U4(mat).power = 129.0;
356     rc = IDirect3DDevice7_SetMaterial(lpD3DDevice, &mat);
357     ok(rc == D3D_OK, "IDirect3DDevice7_SetMaterial(power = 129.0) returned: %x\n", rc);
358     memset(&mat, 0, sizeof(mat));
359     rc = IDirect3DDevice7_GetMaterial(lpD3DDevice, &mat);
360     ok(rc == D3D_OK, "IDirect3DDevice7_GetMaterial returned: %x\n", rc);
361     ok(U4(mat).power == 129, "Returned power is %f\n", U4(mat).power);
362
363     U4(mat).power = -1.0;
364     rc = IDirect3DDevice7_SetMaterial(lpD3DDevice, &mat);
365     ok(rc == D3D_OK, "IDirect3DDevice7_SetMaterial(power = -1.0) returned: %x\n", rc);
366     memset(&mat, 0, sizeof(mat));
367     rc = IDirect3DDevice7_GetMaterial(lpD3DDevice, &mat);
368     ok(rc == D3D_OK, "IDirect3DDevice7_GetMaterial returned: %x\n", rc);
369     ok(U4(mat).power == -1, "Returned power is %f\n", U4(mat).power);
370
371     memset(&caps, 0, sizeof(caps));
372     rc = IDirect3DDevice7_GetCaps(lpD3DDevice, &caps);
373     ok(rc == D3D_OK, "IDirect3DDevice7_GetCaps failed with %x\n", rc);
374
375     if ( caps.dwMaxActiveLights == (DWORD) -1) {
376         /* Some cards without T&L Support return -1 (Examples: Voodoo Banshee, RivaTNT / NV4) */
377         skip("T&L not supported\n");
378         return;
379     }
380
381     for(i = 1; i <= caps.dwMaxActiveLights; i++) {
382         rc = IDirect3DDevice7_LightEnable(lpD3DDevice, i, TRUE);
383         ok(rc == D3D_OK, "Enabling light %u failed with %x\n", i, rc);
384         rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, i, &enabled);
385         ok(rc == D3D_OK, "GetLightEnable on light %u failed with %x\n", i, rc);
386         ok(enabled, "Light %d is %s\n", i, enabled ? "enabled" : "disabled");
387     }
388
389     /* TODO: Test the rendering results in this situation */
390     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, i + 1, TRUE);
391     ok(rc == D3D_OK, "Enabling one light more than supported returned %x\n", rc);
392     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, i + 1, &enabled);
393     ok(rc == D3D_OK, "GetLightEnable on light %u failed with %x\n", i + 1,  rc);
394     ok(enabled, "Light %d is %s\n", i + 1, enabled ? "enabled" : "disabled");
395     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, i + 1, FALSE);
396     ok(rc == D3D_OK, "Disabling the additional returned %x\n", rc);
397
398     for(i = 1; i <= caps.dwMaxActiveLights; i++) {
399         rc = IDirect3DDevice7_LightEnable(lpD3DDevice, i, FALSE);
400         ok(rc == D3D_OK, "Disabling light %u failed with %x\n", i, rc);
401     }
402 }
403
404 static void ProcessVerticesTest(void)
405 {
406     D3DVERTEXBUFFERDESC desc;
407     HRESULT rc;
408     VERTEX *in;
409     TVERTEX *out;
410     VERTEX *out2;
411     D3DVIEWPORT7 vp;
412     D3DMATRIX view = {  2.0, 0.0, 0.0, 0.0,
413                         0.0, -1.0, 0.0, 0.0,
414                         0.0, 0.0, 1.0, 0.0,
415                         0.0, 0.0, 0.0, 3.0 };
416
417     D3DMATRIX world = { 0.0, 1.0, 0.0, 0.0,
418                         1.0, 0.0, 0.0, 0.0,
419                         0.0, 0.0, 0.0, 1.0,
420                         0.0, 1.0, 1.0, 1.0 };
421
422     D3DMATRIX proj = {  1.0, 0.0, 0.0, 1.0,
423                         0.0, 1.0, 1.0, 0.0,
424                         0.0, 1.0, 1.0, 0.0,
425                         1.0, 0.0, 0.0, 1.0 };
426     /* Create some vertex buffers */
427
428     memset(&desc, 0, sizeof(desc));
429     desc.dwSize = sizeof(desc);
430     desc.dwCaps = 0;
431     desc.dwFVF = D3DFVF_XYZ;
432     desc.dwNumVertices = 16;
433     rc = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &lpVBufSrc, 0);
434     ok(rc==D3D_OK || rc==E_OUTOFMEMORY, "CreateVertexBuffer returned: %x\n", rc);
435     if (!lpVBufSrc)
436     {
437         trace("IDirect3D7::CreateVertexBuffer() failed with an error %x\n", rc);
438         goto out;
439     }
440
441     memset(&desc, 0, sizeof(desc));
442     desc.dwSize = sizeof(desc);
443     desc.dwCaps = 0;
444     desc.dwFVF = D3DFVF_XYZRHW;
445     desc.dwNumVertices = 16;
446     /* Msdn says that the last parameter must be 0 - check that */
447     rc = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &lpVBufDest1, 4);
448     ok(rc==D3D_OK || rc==E_OUTOFMEMORY, "CreateVertexBuffer returned: %x\n", rc);
449     if (!lpVBufDest1)
450     {
451         trace("IDirect3D7::CreateVertexBuffer() failed with an error %x\n", rc);
452         goto out;
453     }
454
455     memset(&desc, 0, sizeof(desc));
456     desc.dwSize = sizeof(desc);
457     desc.dwCaps = 0;
458     desc.dwFVF = D3DFVF_XYZ;
459     desc.dwNumVertices = 16;
460     /* Msdn says that the last parameter must be 0 - check that */
461     rc = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &lpVBufDest2, 12345678);
462     ok(rc==D3D_OK || rc==E_OUTOFMEMORY, "CreateVertexBuffer returned: %x\n", rc);
463     if (!lpVBufDest2)
464     {
465         trace("IDirect3D7::CreateVertexBuffer() failed with an error %x\n", rc);
466         goto out;
467     }
468
469     rc = IDirect3DVertexBuffer7_Lock(lpVBufSrc, 0, (void **) &in, NULL);
470     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
471     if(!in) goto out;
472
473     /* Check basic transformation */
474
475     in[0].x = 0.0;
476     in[0].y = 0.0;
477     in[0].z = 0.0;
478
479     in[1].x = 1.0;
480     in[1].y = 1.0;
481     in[1].z = 1.0;
482
483     in[2].x = -1.0;
484     in[2].y = -1.0;
485     in[2].z = 0.5;
486
487     in[3].x = 0.5;
488     in[3].y = -0.5;
489     in[3].z = 0.25;
490     rc = IDirect3DVertexBuffer7_Unlock(lpVBufSrc);
491     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
492
493     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest1, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
494     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
495
496     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest2, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
497     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
498
499     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest1, 0, (void **) &out, NULL);
500     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
501     if(!out) goto out;
502
503     /* Check the results */
504     ok( comparefloat(out[0].x, 128.0 ) &&
505         comparefloat(out[0].y, 128.0 ) &&
506         comparefloat(out[0].z, 0.0 ) &&
507         comparefloat(out[0].rhw, 1.0 ),
508         "Output 0 vertex is (%f , %f , %f , %f)\n", out[0].x, out[0].y, out[0].z, out[0].rhw);
509
510     ok( comparefloat(out[1].x, 256.0 ) &&
511         comparefloat(out[1].y, 0.0 ) &&
512         comparefloat(out[1].z, 1.0 ) &&
513         comparefloat(out[1].rhw, 1.0 ),
514         "Output 1 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
515
516     ok( comparefloat(out[2].x, 0.0 ) &&
517         comparefloat(out[2].y, 256.0 ) &&
518         comparefloat(out[2].z, 0.5 ) &&
519         comparefloat(out[2].rhw, 1.0 ),
520         "Output 2 vertex is (%f , %f , %f , %f)\n", out[2].x, out[2].y, out[2].z, out[2].rhw);
521
522     ok( comparefloat(out[3].x, 192.0 ) &&
523         comparefloat(out[3].y, 192.0 ) &&
524         comparefloat(out[3].z, 0.25 ) &&
525         comparefloat(out[3].rhw, 1.0 ),
526         "Output 3 vertex is (%f , %f , %f , %f)\n", out[3].x, out[3].y, out[3].z, out[3].rhw);
527
528     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest1);
529     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
530     out = NULL;
531
532     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest2, 0, (void **) &out2, NULL);
533     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
534     if(!out2) goto out;
535     /* Small thing without much practical meaning, but I stumbled upon it,
536      * so let's check for it: If the output vertex buffer has to RHW value,
537      * The RHW value of the last vertex is written into the next vertex
538      */
539     ok( comparefloat(out2[4].x, 1.0 ) &&
540         comparefloat(out2[4].y, 0.0 ) &&
541         comparefloat(out2[4].z, 0.0 ),
542         "Output 4 vertex is (%f , %f , %f)\n", out2[4].x, out2[4].y, out2[4].z);
543
544     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest2);
545     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
546     out = NULL;
547
548     /* Try a more complicated viewport, same vertices */
549     memset(&vp, 0, sizeof(vp));
550     vp.dwX = 10;
551     vp.dwY = 5;
552     vp.dwWidth = 246;
553     vp.dwHeight = 130;
554     vp.dvMinZ = -2.0;
555     vp.dvMaxZ = 4.0;
556     rc = IDirect3DDevice7_SetViewport(lpD3DDevice, &vp);
557     ok(rc==D3D_OK, "IDirect3DDevice7_SetViewport failed with rc=%x\n", rc);
558
559     /* Process again */
560     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest1, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
561     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
562
563     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest1, 0, (void **) &out, NULL);
564     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
565     if(!out) goto out;
566
567     /* Check the results */
568     ok( comparefloat(out[0].x, 133.0 ) &&
569         comparefloat(out[0].y, 70.0 ) &&
570         comparefloat(out[0].z, -2.0 ) &&
571         comparefloat(out[0].rhw, 1.0 ),
572         "Output 0 vertex is (%f , %f , %f , %f)\n", out[0].x, out[0].y, out[0].z, out[0].rhw);
573
574     ok( comparefloat(out[1].x, 256.0 ) &&
575         comparefloat(out[1].y, 5.0 ) &&
576         comparefloat(out[1].z, 4.0 ) &&
577         comparefloat(out[1].rhw, 1.0 ),
578         "Output 1 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
579
580     ok( comparefloat(out[2].x, 10.0 ) &&
581         comparefloat(out[2].y, 135.0 ) &&
582         comparefloat(out[2].z, 1.0 ) &&
583         comparefloat(out[2].rhw, 1.0 ),
584         "Output 2 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
585
586     ok( comparefloat(out[3].x, 194.5 ) &&
587         comparefloat(out[3].y, 102.5 ) &&
588         comparefloat(out[3].z, -0.5 ) &&
589         comparefloat(out[3].rhw, 1.0 ),
590         "Output 3 vertex is (%f , %f , %f , %f)\n", out[3].x, out[3].y, out[3].z, out[3].rhw);
591
592     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest1);
593     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
594     out = NULL;
595
596     /* Play with some matrices. */
597
598     rc = IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_VIEW, &view);
599     ok(rc==D3D_OK, "IDirect3DDevice7_SetTransform failed\n");
600
601     rc = IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_PROJECTION, &proj);
602     ok(rc==D3D_OK, "IDirect3DDevice7_SetTransform failed\n");
603
604     rc = IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_WORLD, &world);
605     ok(rc==D3D_OK, "IDirect3DDevice7_SetTransform failed\n");
606
607     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest1, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
608     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
609
610     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest1, 0, (void **) &out, NULL);
611     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
612     if(!out) goto out;
613
614     /* Keep the viewport simpler, otherwise we get bad numbers to compare */
615     vp.dwX = 0;
616     vp.dwY = 0;
617     vp.dwWidth = 100;
618     vp.dwHeight = 100;
619     vp.dvMinZ = 1.0;
620     vp.dvMaxZ = 0.0;
621     rc = IDirect3DDevice7_SetViewport(lpD3DDevice, &vp);
622     ok(rc==D3D_OK, "IDirect3DDevice7_SetViewport failed\n");
623
624     /* Check the results */
625     ok( comparefloat(out[0].x, 256.0 ) &&    /* X coordinate is cut at the surface edges */
626         comparefloat(out[0].y, 70.0 ) &&
627         comparefloat(out[0].z, -2.0 ) &&
628         comparefloat(out[0].rhw, (1.0 / 3.0)),
629         "Output 0 vertex is (%f , %f , %f , %f)\n", out[0].x, out[0].y, out[0].z, out[0].rhw);
630
631     ok( comparefloat(out[1].x, 256.0 ) &&
632         comparefloat(out[1].y, 78.125000 ) &&
633         comparefloat(out[1].z, -2.750000 ) &&
634         comparefloat(out[1].rhw, 0.125000 ),
635         "Output 1 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
636
637     ok( comparefloat(out[2].x, 256.0 ) &&
638         comparefloat(out[2].y, 44.000000 ) &&
639         comparefloat(out[2].z, 0.400000 ) &&
640         comparefloat(out[2].rhw, 0.400000 ),
641         "Output 2 vertex is (%f , %f , %f , %f)\n", out[2].x, out[2].y, out[2].z, out[2].rhw);
642
643     ok( comparefloat(out[3].x, 256.0 ) &&
644         comparefloat(out[3].y, 81.818184 ) &&
645         comparefloat(out[3].z, -3.090909 ) &&
646         comparefloat(out[3].rhw, 0.363636 ),
647         "Output 3 vertex is (%f , %f , %f , %f)\n", out[3].x, out[3].y, out[3].z, out[3].rhw);
648
649     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest1);
650     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
651     out = NULL;
652
653 out:
654     IDirect3DVertexBuffer7_Release(lpVBufSrc);
655     IDirect3DVertexBuffer7_Release(lpVBufDest1);
656     IDirect3DVertexBuffer7_Release(lpVBufDest2);
657 }
658
659 static void StateTest( void )
660 {
661     HRESULT rc;
662
663     /* The msdn says its undocumented, does it return an error too? */
664     rc = IDirect3DDevice7_SetRenderState(lpD3DDevice, D3DRENDERSTATE_ZVISIBLE, TRUE);
665     ok(rc == D3D_OK, "IDirect3DDevice7_SetRenderState(D3DRENDERSTATE_ZVISIBLE, TRUE) returned %08x\n", rc);
666     rc = IDirect3DDevice7_SetRenderState(lpD3DDevice, D3DRENDERSTATE_ZVISIBLE, FALSE);
667     ok(rc == D3D_OK, "IDirect3DDevice7_SetRenderState(D3DRENDERSTATE_ZVISIBLE, FALSE) returned %08x\n", rc);
668 }
669
670
671 static void SceneTest(void)
672 {
673     HRESULT                      hr;
674
675     /* Test an EndScene without beginscene. Should return an error */
676     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
677     ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr);
678
679     /* Test a normal BeginScene / EndScene pair, this should work */
680     hr = IDirect3DDevice7_BeginScene(lpD3DDevice);
681     ok(hr == D3D_OK, "IDirect3DDevice7_BeginScene failed with %08x\n", hr);
682     if(SUCCEEDED(hr))
683     {
684         DDBLTFX fx;
685         memset(&fx, 0, sizeof(fx));
686         fx.dwSize = sizeof(fx);
687
688         if(lpDDSdepth) {
689             hr = IDirectDrawSurface7_Blt(lpDDSdepth, NULL, NULL, NULL, DDBLT_DEPTHFILL, &fx);
690             ok(hr == D3D_OK, "Depthfill failed in a BeginScene / EndScene pair\n");
691         } else {
692             skip("Depth stencil creation failed at startup, skipping\n");
693         }
694         hr = IDirect3DDevice7_EndScene(lpD3DDevice);
695         ok(hr == D3D_OK, "IDirect3DDevice7_EndScene failed with %08x\n", hr);
696     }
697
698     /* Test another EndScene without having begun a new scene. Should return an error */
699     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
700     ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr);
701
702     /* Two nested BeginScene and EndScene calls */
703     hr = IDirect3DDevice7_BeginScene(lpD3DDevice);
704     ok(hr == D3D_OK, "IDirect3DDevice7_BeginScene failed with %08x\n", hr);
705     hr = IDirect3DDevice7_BeginScene(lpD3DDevice);
706     ok(hr == D3DERR_SCENE_IN_SCENE, "IDirect3DDevice7_BeginScene returned %08x\n", hr);
707     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
708     ok(hr == D3D_OK, "IDirect3DDevice7_EndScene failed with %08x\n", hr);
709     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
710     ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr);
711
712     /* TODO: Verify that blitting works in the same way as in d3d9 */
713 }
714
715 static void LimitTest(void)
716 {
717     IDirectDrawSurface7 *pTexture = NULL;
718     HRESULT hr;
719     int i;
720     DDSURFACEDESC2 ddsd;
721
722     memset(&ddsd, 0, sizeof(ddsd));
723     ddsd.dwSize = sizeof(ddsd);
724     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
725     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
726     ddsd.dwWidth = 16;
727     ddsd.dwHeight = 16;
728     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &pTexture, NULL);
729     ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
730     if(!pTexture) return;
731
732     for(i = 0; i < 8; i++) {
733         hr = IDirect3DDevice7_SetTexture(lpD3DDevice, i, pTexture);
734         ok(hr == D3D_OK, "IDirect3DDevice8_SetTexture for sampler %d failed with %08x\n", i, hr);
735         hr = IDirect3DDevice7_SetTexture(lpD3DDevice, i, NULL);
736         ok(hr == D3D_OK, "IDirect3DDevice8_SetTexture for sampler %d failed with %08x\n", i, hr);
737         hr = IDirect3DDevice7_SetTextureStageState(lpD3DDevice, i, D3DTSS_COLOROP, D3DTOP_ADD);
738         ok(hr == D3D_OK, "IDirect3DDevice8_SetTextureStageState for texture %d failed with %08x\n", i, hr);
739     }
740
741     IDirectDrawSurface7_Release(pTexture);
742 }
743
744 static HRESULT WINAPI enumDevicesCallback(GUID *Guid,LPSTR DeviceDescription,LPSTR DeviceName, D3DDEVICEDESC *hal, D3DDEVICEDESC *hel, VOID *ctx)
745 {
746     UINT ver = *((UINT *) ctx);
747     if(IsEqualGUID(&IID_IDirect3DRGBDevice, Guid))
748     {
749         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
750            "RGB Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
751         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
752            "RGB Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
753         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
754            "RGB Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
755         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
756            "RGB Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
757
758         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
759            "RGB Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
760         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
761            "RGB Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
762         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
763            "RGB Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
764         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
765            "RGB Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
766     }
767     else if(IsEqualGUID(&IID_IDirect3DHALDevice, Guid))
768     {
769         /* pow2 is hardware dependent */
770
771         ok(hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
772            "HAL Device %d hal line caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
773         ok(hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
774            "HAL Device %d hal tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
775         ok((hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
776            "HAL Device %d hel line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
777         ok((hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
778            "HAL Device %d hel tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
779     }
780     else if(IsEqualGUID(&IID_IDirect3DRefDevice, Guid))
781     {
782         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
783            "REF Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
784         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
785            "REF Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
786         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
787            "REF Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
788         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
789            "REF Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
790
791         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
792            "REF Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
793         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
794            "REF Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
795         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
796            "REF Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
797         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
798            "REF Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
799     }
800     else if(IsEqualGUID(&IID_IDirect3DRampDevice, Guid))
801     {
802         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
803            "Ramp Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
804         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
805            "Ramp Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
806         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
807            "Ramp Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
808         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
809            "Ramp Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
810
811         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
812            "Ramp Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
813         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
814            "Ramp Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
815         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
816            "Ramp Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
817         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
818            "Ramp Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
819     }
820     else if(IsEqualGUID(&IID_IDirect3DMMXDevice, Guid))
821     {
822         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
823            "MMX Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
824         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
825            "MMX Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
826         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
827            "MMX Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
828         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
829            "MMX Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
830
831         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
832            "MMX Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
833         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
834            "MMX Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
835         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
836            "MMX Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
837         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
838            "MMX Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
839     }
840     else
841     {
842         ok(FALSE, "Unexpected device enumerated: \"%s\" \"%s\"\n", DeviceDescription, DeviceName);
843         if(hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hal line has pow2 set\n");
844         else trace("hal line does NOT have pow2 set\n");
845         if(hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hal tri has pow2 set\n");
846         else trace("hal tri does NOT have pow2 set\n");
847         if(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hel line has pow2 set\n");
848         else trace("hel line does NOT have pow2 set\n");
849         if(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hel tri has pow2 set\n");
850         else trace("hel tri does NOT have pow2 set\n");
851     }
852     return DDENUMRET_OK;
853 }
854
855 static HRESULT WINAPI enumDevicesCallbackTest7(LPSTR DeviceDescription, LPSTR DeviceName, LPD3DDEVICEDESC7 lpdd7, LPVOID Context)
856 {
857     D3D7ETest *d3d7et = Context;
858     if(IsEqualGUID(&lpdd7->deviceGUID, &IID_IDirect3DRGBDevice))
859         d3d7et->rgb++;
860     else if(IsEqualGUID(&lpdd7->deviceGUID, &IID_IDirect3DHALDevice))
861         d3d7et->hal++;
862     else if(IsEqualGUID(&lpdd7->deviceGUID, &IID_IDirect3DTnLHalDevice))
863         d3d7et->tnlhal++;
864     else
865         d3d7et->unk++;
866
867     d3d7et->total++;
868
869     return DDENUMRET_OK;
870 }
871
872
873 /*  Check the deviceGUID of devices enumerated by
874     IDirect3D7_EnumDevices. */
875 static void D3D7EnumTest(void)
876 {
877     D3D7ETest d3d7et;
878
879     if (!lpD3D) {
880         skip("No Direct3D7 interface.\n");
881         return;
882     }
883
884     memset(&d3d7et, 0, sizeof(d3d7et));
885     IDirect3D7_EnumDevices(lpD3D, enumDevicesCallbackTest7, &d3d7et);
886
887     /* A couple of games (Delta Force LW and TFD) rely on this behaviour */
888     ok(d3d7et.tnlhal < d3d7et.total, "TnLHal device enumerated as only device.\n");
889
890     /* We make two additional assumptions. */
891     ok(d3d7et.rgb, "No RGB Device enumerated.\n");
892
893     if(d3d7et.tnlhal)
894         ok(d3d7et.hal, "TnLHal device enumerated, but no Hal device found.\n");
895 }
896
897 static void CapsTest(void)
898 {
899     IDirect3D3 *d3d3;
900     IDirect3D3 *d3d2;
901     IDirectDraw *dd1;
902     HRESULT hr;
903     UINT ver;
904
905     hr = DirectDrawCreate(NULL, &dd1, NULL);
906     ok(hr == DD_OK, "Cannot create a DirectDraw 1 interface, hr = %08x\n", hr);
907     hr = IDirectDraw_QueryInterface(dd1, &IID_IDirect3D3, (void **) &d3d3);
908     ok(hr == D3D_OK, "IDirectDraw_QueryInterface returned %08x\n", hr);
909     ver = 3;
910     IDirect3D3_EnumDevices(d3d3, enumDevicesCallback, &ver);
911
912     IDirect3D3_Release(d3d3);
913     IDirectDraw_Release(dd1);
914
915     hr = DirectDrawCreate(NULL, &dd1, NULL);
916     ok(hr == DD_OK, "Cannot create a DirectDraw 1 interface, hr = %08x\n", hr);
917     hr = IDirectDraw_QueryInterface(dd1, &IID_IDirect3D2, (void **) &d3d2);
918     ok(hr == D3D_OK, "IDirectDraw_QueryInterface returned %08x\n", hr);
919     ver = 2;
920     IDirect3D2_EnumDevices(d3d2, enumDevicesCallback, &ver);
921
922     IDirect3D2_Release(d3d2);
923     IDirectDraw_Release(dd1);
924 }
925
926 struct v_in {
927     float x, y, z;
928 };
929 struct v_out {
930     float x, y, z, rhw;
931 };
932
933 static BOOL D3D1_createObjects(void)
934 {
935     HRESULT hr;
936     DDSURFACEDESC ddsd;
937     D3DEXECUTEBUFFERDESC desc;
938     D3DVIEWPORT vp_data;
939
940     /* An IDirect3DDevice cannot be queryInterfaced from an IDirect3DDevice7 on windows */
941     hr = DirectDrawCreate(NULL, &DirectDraw1, NULL);
942     ok(hr==DD_OK || hr==DDERR_NODIRECTDRAWSUPPORT, "DirectDrawCreate returned: %x\n", hr);
943     if (!DirectDraw1) {
944         return FALSE;
945     }
946
947     hr = IDirectDraw_SetCooperativeLevel(DirectDraw1, NULL, DDSCL_NORMAL);
948     ok(hr==DD_OK, "SetCooperativeLevel returned: %x\n", hr);
949
950     hr = IDirectDraw_QueryInterface(DirectDraw1, &IID_IDirect3D, (void**) &Direct3D1);
951     if (hr == E_NOINTERFACE) return FALSE;
952     ok(hr==DD_OK, "QueryInterface returned: %x\n", hr);
953     if (!Direct3D1) {
954         return FALSE;
955     }
956
957     memset(&ddsd, 0, sizeof(ddsd));
958     ddsd.dwSize = sizeof(ddsd);
959     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
960     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
961     ddsd.dwWidth = 256;
962     ddsd.dwHeight = 256;
963     IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &Surface1, NULL);
964     if (!Surface1) {
965         skip("DDSCAPS_3DDEVICE surface not available\n");
966         return FALSE;
967     }
968
969     hr = IDirectDrawSurface_QueryInterface(Surface1, &IID_IDirect3DRGBDevice, (void **) &Direct3DDevice1);
970     ok(hr==D3D_OK || hr==DDERR_NOPALETTEATTACHED || hr==E_OUTOFMEMORY, "CreateDevice returned: %x\n", hr);
971     if(!Direct3DDevice1) {
972         return FALSE;
973     }
974
975     memset(&desc, 0, sizeof(desc));
976     desc.dwSize = sizeof(desc);
977     desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
978     desc.dwCaps = D3DDEBCAPS_VIDEOMEMORY;
979     desc.dwBufferSize = 128;
980     desc.lpData = NULL;
981     hr = IDirect3DDevice_CreateExecuteBuffer(Direct3DDevice1, &desc, &ExecuteBuffer, NULL);
982     ok(hr == D3D_OK, "IDirect3DDevice_CreateExecuteBuffer failed: %08x\n", hr);
983     if(!ExecuteBuffer) {
984         return FALSE;
985     }
986
987     hr = IDirect3D_CreateViewport(Direct3D1, &Viewport, NULL);
988     ok(hr == D3D_OK, "IDirect3D_CreateViewport failed: %08x\n", hr);
989     if(!Viewport) {
990         return FALSE;
991     }
992
993     hr = IDirect3DViewport_Initialize(Viewport, Direct3D1);
994     ok(hr == DDERR_ALREADYINITIALIZED, "IDirect3DViewport_Initialize returned %08x\n", hr);
995
996     hr = IDirect3DDevice_AddViewport(Direct3DDevice1, Viewport);
997     ok(hr == D3D_OK, "IDirect3DDevice_AddViewport returned %08x\n", hr);
998     vp_data.dwSize = sizeof(vp_data);
999     vp_data.dwX = 0;
1000     vp_data.dwY = 0;
1001     vp_data.dwWidth = 256;
1002     vp_data.dwHeight = 256;
1003     vp_data.dvScaleX = 1;
1004     vp_data.dvScaleY = 1;
1005     vp_data.dvMaxX = 256;
1006     vp_data.dvMaxY = 256;
1007     vp_data.dvMinZ = 0;
1008     vp_data.dvMaxZ = 1;
1009     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1010     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1011
1012     hr = IDirect3D_CreateLight(Direct3D1, &Light, NULL);
1013     ok(hr == D3D_OK, "IDirect3D_CreateLight failed: %08x\n", hr);
1014     if (!Light)
1015         return FALSE;
1016
1017     return TRUE;
1018 }
1019
1020 static void D3D1_releaseObjects(void)
1021 {
1022     if (Light) IDirect3DLight_Release(Light);
1023     if (Viewport) IDirect3DViewport_Release(Viewport);
1024     if (ExecuteBuffer) IDirect3DExecuteBuffer_Release(ExecuteBuffer);
1025     if (Direct3DDevice1) IDirect3DDevice_Release(Direct3DDevice1);
1026     if (Surface1) IDirectDrawSurface_Release(Surface1);
1027     if (Direct3D1) IDirect3D_Release(Direct3D1);
1028     if (DirectDraw1) IDirectDraw_Release(DirectDraw1);
1029 }
1030
1031 static void ViewportTest(void)
1032 {
1033     HRESULT hr;
1034     LPDIRECT3DVIEWPORT2 Viewport2;
1035     D3DVIEWPORT vp1_data, ret_vp1_data;
1036     D3DVIEWPORT2 vp2_data, ret_vp2_data;
1037     float infinity;
1038
1039     *(DWORD*)&infinity = 0x7f800000;
1040
1041     hr = IDirect3DDevice_AddViewport(Direct3DDevice1, Viewport);
1042     ok(hr == D3D_OK, "IDirect3DDevice_AddViewport returned %08x\n", hr);
1043
1044     hr = IDirect3DViewport_QueryInterface(Viewport, &IID_IDirect3DViewport2, (void**) &Viewport2);
1045     ok(hr==D3D_OK, "QueryInterface returned: %x\n", hr);
1046
1047     vp1_data.dwSize = sizeof(vp1_data);
1048     vp1_data.dwX = 0;
1049     vp1_data.dwY = 1;
1050     vp1_data.dwWidth = 256;
1051     vp1_data.dwHeight = 257;
1052     vp1_data.dvMaxX = 0;
1053     vp1_data.dvMaxY = 0;
1054     vp1_data.dvScaleX = 0;
1055     vp1_data.dvScaleY = 0;
1056     vp1_data.dvMinZ = 0.25;
1057     vp1_data.dvMaxZ = 0.75;
1058
1059     vp2_data.dwSize = sizeof(vp2_data);
1060     vp2_data.dwX = 2;
1061     vp2_data.dwY = 3;
1062     vp2_data.dwWidth = 258;
1063     vp2_data.dwHeight = 259;
1064     vp2_data.dvClipX = 0;
1065     vp2_data.dvClipY = 0;
1066     vp2_data.dvClipWidth = 0;
1067     vp2_data.dvClipHeight = 0;
1068     vp2_data.dvMinZ = 0.1;
1069     vp2_data.dvMaxZ = 0.9;
1070
1071     hr = IDirect3DViewport2_SetViewport(Viewport2, &vp1_data);
1072     ok(hr == D3D_OK, "IDirect3DViewport2_SetViewport returned %08x\n", hr);
1073
1074     memset(&ret_vp1_data, 0xff, sizeof(ret_vp1_data));
1075     ret_vp1_data.dwSize = sizeof(vp1_data);
1076
1077     hr = IDirect3DViewport2_GetViewport(Viewport2, &ret_vp1_data);
1078     ok(hr == D3D_OK, "IDirect3DViewport2_GetViewport returned %08x\n", hr);
1079
1080     ok(ret_vp1_data.dwX == vp1_data.dwX, "dwX is %u, expected %u\n", ret_vp1_data.dwX, vp1_data.dwX);
1081     ok(ret_vp1_data.dwY == vp1_data.dwY, "dwY is %u, expected %u\n", ret_vp1_data.dwY, vp1_data.dwY);
1082     ok(ret_vp1_data.dwWidth == vp1_data.dwWidth, "dwWidth is %u, expected %u\n", ret_vp1_data.dwWidth, vp1_data.dwWidth);
1083     ok(ret_vp1_data.dwHeight == vp1_data.dwHeight, "dwHeight is %u, expected %u\n", ret_vp1_data.dwHeight, vp1_data.dwHeight);
1084     ok(ret_vp1_data.dvMaxX == vp1_data.dvMaxX, "dvMaxX is %f, expected %f\n", ret_vp1_data.dvMaxX, vp1_data.dvMaxX);
1085     ok(ret_vp1_data.dvMaxY == vp1_data.dvMaxY, "dvMaxY is %f, expected %f\n", ret_vp1_data.dvMaxY, vp1_data.dvMaxY);
1086     todo_wine ok(ret_vp1_data.dvScaleX == infinity, "dvScaleX is %f, expected %f\n", ret_vp1_data.dvScaleX, infinity);
1087     todo_wine ok(ret_vp1_data.dvScaleY == infinity, "dvScaleY is %f, expected %f\n", ret_vp1_data.dvScaleY, infinity);
1088     ok(ret_vp1_data.dvMinZ == 0.0, "dvMinZ is %f, expected 0.0\n", ret_vp1_data.dvMinZ);
1089     ok(ret_vp1_data.dvMaxZ == 1.0, "dvMaxZ is %f, expected 1.0\n", ret_vp1_data.dvMaxZ);
1090
1091     hr = IDirect3DViewport2_SetViewport2(Viewport2, &vp2_data);
1092     ok(hr == D3D_OK, "IDirect3DViewport2_SetViewport2 returned %08x\n", hr);
1093
1094     memset(&ret_vp2_data, 0xff, sizeof(ret_vp2_data));
1095     ret_vp2_data.dwSize = sizeof(vp2_data);
1096
1097     hr = IDirect3DViewport2_GetViewport2(Viewport2, &ret_vp2_data);
1098     ok(hr == D3D_OK, "IDirect3DViewport2_GetViewport2 returned %08x\n", hr);
1099
1100     ok(ret_vp2_data.dwX == vp2_data.dwX, "dwX is %u, expected %u\n", ret_vp2_data.dwX, vp2_data.dwX);
1101     ok(ret_vp2_data.dwY == vp2_data.dwY, "dwY is %u, expected %u\n", ret_vp2_data.dwY, vp2_data.dwY);
1102     ok(ret_vp2_data.dwWidth == vp2_data.dwWidth, "dwWidth is %u, expected %u\n", ret_vp2_data.dwWidth, vp2_data.dwWidth);
1103     ok(ret_vp2_data.dwHeight == vp2_data.dwHeight, "dwHeight is %u, expected %u\n", ret_vp2_data.dwHeight, vp2_data.dwHeight);
1104     ok(ret_vp2_data.dvClipX == vp2_data.dvClipX, "dvClipX is %f, expected %f\n", ret_vp2_data.dvClipX, vp2_data.dvClipX);
1105     ok(ret_vp2_data.dvClipY == vp2_data.dvClipY, "dvClipY is %f, expected %f\n", ret_vp2_data.dvClipY, vp2_data.dvClipY);
1106     ok(ret_vp2_data.dvClipWidth == vp2_data.dvClipWidth, "dvClipWidth is %f, expected %f\n",
1107         ret_vp2_data.dvClipWidth, vp2_data.dvClipWidth);
1108     ok(ret_vp2_data.dvClipHeight == vp2_data.dvClipHeight, "dvClipHeight is %f, expected %f\n",
1109         ret_vp2_data.dvClipHeight, vp2_data.dvClipHeight);
1110     ok(ret_vp2_data.dvMinZ == vp2_data.dvMinZ, "dvMinZ is %f, expected %f\n", ret_vp2_data.dvMinZ, vp2_data.dvMinZ);
1111     ok(ret_vp2_data.dvMaxZ == vp2_data.dvMaxZ, "dvMaxZ is %f, expected %f\n", ret_vp2_data.dvMaxZ, vp2_data.dvMaxZ);
1112
1113     memset(&ret_vp1_data, 0xff, sizeof(ret_vp1_data));
1114     ret_vp1_data.dwSize = sizeof(vp1_data);
1115
1116     hr = IDirect3DViewport2_GetViewport(Viewport2, &ret_vp1_data);
1117     ok(hr == D3D_OK, "IDirect3DViewport2_GetViewport returned %08x\n", hr);
1118
1119     ok(ret_vp1_data.dwX == vp2_data.dwX, "dwX is %u, expected %u\n", ret_vp1_data.dwX, vp2_data.dwX);
1120     ok(ret_vp1_data.dwY == vp2_data.dwY, "dwY is %u, expected %u\n", ret_vp1_data.dwY, vp2_data.dwY);
1121     ok(ret_vp1_data.dwWidth == vp2_data.dwWidth, "dwWidth is %u, expected %u\n", ret_vp1_data.dwWidth, vp2_data.dwWidth);
1122     ok(ret_vp1_data.dwHeight == vp2_data.dwHeight, "dwHeight is %u, expected %u\n", ret_vp1_data.dwHeight, vp2_data.dwHeight);
1123     ok(ret_vp1_data.dvMaxX == vp1_data.dvMaxX, "dvMaxX is %f, expected %f\n", ret_vp1_data.dvMaxX, vp1_data.dvMaxX);
1124     ok(ret_vp1_data.dvMaxY == vp1_data.dvMaxY, "dvMaxY is %f, expected %f\n", ret_vp1_data.dvMaxY, vp1_data.dvMaxY);
1125     todo_wine ok(ret_vp1_data.dvScaleX == infinity, "dvScaleX is %f, expected %f\n", ret_vp1_data.dvScaleX, infinity);
1126     todo_wine ok(ret_vp1_data.dvScaleY == infinity, "dvScaleY is %f, expected %f\n", ret_vp1_data.dvScaleY, infinity);
1127     todo_wine ok(ret_vp1_data.dvMinZ == 0.0, "dvMinZ is %f, expected 0.0\n", ret_vp1_data.dvMinZ);
1128     todo_wine ok(ret_vp1_data.dvMaxZ == 1.0, "dvMaxZ is %f, expected 1.0\n", ret_vp1_data.dvMaxZ);
1129
1130     hr = IDirect3DViewport2_SetViewport2(Viewport2, &vp2_data);
1131     ok(hr == D3D_OK, "IDirect3DViewport2_SetViewport2 returned %08x\n", hr);
1132
1133     memset(&ret_vp2_data, 0xff, sizeof(ret_vp2_data));
1134     ret_vp2_data.dwSize = sizeof(vp2_data);
1135
1136     hr = IDirect3DViewport2_GetViewport2(Viewport2, &ret_vp2_data);
1137     ok(hr == D3D_OK, "IDirect3DViewport2_GetViewport2 returned %08x\n", hr);
1138
1139     ok(ret_vp2_data.dwX == vp2_data.dwX, "dwX is %u, expected %u\n", ret_vp2_data.dwX, vp2_data.dwX);
1140     ok(ret_vp2_data.dwY == vp2_data.dwY, "dwY is %u, expected %u\n", ret_vp2_data.dwY, vp2_data.dwY);
1141     ok(ret_vp2_data.dwWidth == vp2_data.dwWidth, "dwWidth is %u, expected %u\n", ret_vp2_data.dwWidth, vp2_data.dwWidth);
1142     ok(ret_vp2_data.dwHeight == vp2_data.dwHeight, "dwHeight is %u, expected %u\n", ret_vp2_data.dwHeight, vp2_data.dwHeight);
1143     ok(ret_vp2_data.dvClipX == vp2_data.dvClipX, "dvClipX is %f, expected %f\n", ret_vp2_data.dvClipX, vp2_data.dvClipX);
1144     ok(ret_vp2_data.dvClipY == vp2_data.dvClipY, "dvClipY is %f, expected %f\n", ret_vp2_data.dvClipY, vp2_data.dvClipY);
1145     ok(ret_vp2_data.dvClipWidth == vp2_data.dvClipWidth, "dvClipWidth is %f, expected %f\n",
1146         ret_vp2_data.dvClipWidth, vp2_data.dvClipWidth);
1147     ok(ret_vp2_data.dvClipHeight == vp2_data.dvClipHeight, "dvClipHeight is %f, expected %f\n",
1148         ret_vp2_data.dvClipHeight, vp2_data.dvClipHeight);
1149     ok(ret_vp2_data.dvMinZ == vp2_data.dvMinZ, "dvMinZ is %f, expected %f\n", ret_vp2_data.dvMinZ, vp2_data.dvMinZ);
1150     ok(ret_vp2_data.dvMaxZ == vp2_data.dvMaxZ, "dvMaxZ is %f, expected %f\n", ret_vp2_data.dvMaxZ, vp2_data.dvMaxZ);
1151
1152     hr = IDirect3DViewport2_SetViewport(Viewport2, &vp1_data);
1153     ok(hr == D3D_OK, "IDirect3DViewport2_SetViewport returned %08x\n", hr);
1154
1155     memset(&ret_vp1_data, 0xff, sizeof(ret_vp1_data));
1156     ret_vp1_data.dwSize = sizeof(vp1_data);
1157
1158     hr = IDirect3DViewport2_GetViewport(Viewport2, &ret_vp1_data);
1159     ok(hr == D3D_OK, "IDirect3DViewport2_GetViewport returned %08x\n", hr);
1160
1161     ok(ret_vp1_data.dwX == vp1_data.dwX, "dwX is %u, expected %u\n", ret_vp1_data.dwX, vp1_data.dwX);
1162     ok(ret_vp1_data.dwY == vp1_data.dwY, "dwY is %u, expected %u\n", ret_vp1_data.dwY, vp1_data.dwY);
1163     ok(ret_vp1_data.dwWidth == vp1_data.dwWidth, "dwWidth is %u, expected %u\n", ret_vp1_data.dwWidth, vp1_data.dwWidth);
1164     ok(ret_vp1_data.dwHeight == vp1_data.dwHeight, "dwHeight is %u, expected %u\n", ret_vp1_data.dwHeight, vp1_data.dwHeight);
1165     ok(ret_vp1_data.dvMaxX == vp1_data.dvMaxX, "dvMaxX is %f, expected %f\n", ret_vp1_data.dvMaxX, vp1_data.dvMaxX);
1166     ok(ret_vp1_data.dvMaxY == vp1_data.dvMaxY, "dvMaxY is %f, expected %f\n", ret_vp1_data.dvMaxY, vp1_data.dvMaxY);
1167     todo_wine ok(ret_vp1_data.dvScaleX == infinity, "dvScaleX is %f, expected %f\n", ret_vp1_data.dvScaleX, infinity);
1168     todo_wine ok(ret_vp1_data.dvScaleY == infinity, "dvScaleY is %f, expected %f\n", ret_vp1_data.dvScaleY, infinity);
1169     ok(ret_vp1_data.dvMinZ == 0.0, "dvMinZ is %f, expected 0.0\n", ret_vp1_data.dvMinZ);
1170     ok(ret_vp1_data.dvMaxZ == 1.0, "dvMaxZ is %f, expected 1.0\n", ret_vp1_data.dvMaxZ);
1171
1172     memset(&ret_vp2_data, 0xff, sizeof(ret_vp2_data));
1173     ret_vp2_data.dwSize = sizeof(vp2_data);
1174
1175     hr = IDirect3DViewport2_GetViewport2(Viewport2, &ret_vp2_data);
1176     ok(hr == D3D_OK, "IDirect3DViewport2_GetViewport2 returned %08x\n", hr);
1177
1178     ok(ret_vp2_data.dwX == vp1_data.dwX, "dwX is %u, expected %u\n", ret_vp2_data.dwX, vp1_data.dwX);
1179     ok(ret_vp2_data.dwY == vp1_data.dwY, "dwY is %u, expected %u\n", ret_vp2_data.dwY, vp1_data.dwY);
1180     ok(ret_vp2_data.dwWidth == vp1_data.dwWidth, "dwWidth is %u, expected %u\n", ret_vp2_data.dwWidth, vp1_data.dwWidth);
1181     ok(ret_vp2_data.dwHeight == vp1_data.dwHeight, "dwHeight is %u, expected %u\n", ret_vp2_data.dwHeight, vp1_data.dwHeight);
1182     ok(ret_vp2_data.dvClipX == vp2_data.dvClipX, "dvClipX is %f, expected %f\n", ret_vp2_data.dvClipX, vp2_data.dvClipX);
1183     ok(ret_vp2_data.dvClipY == vp2_data.dvClipY, "dvClipY is %f, expected %f\n", ret_vp2_data.dvClipY, vp2_data.dvClipY);
1184     ok(ret_vp2_data.dvClipWidth == vp2_data.dvClipWidth, "dvClipWidth is %f, expected %f\n",
1185         ret_vp2_data.dvClipWidth, vp2_data.dvClipWidth);
1186     ok(ret_vp2_data.dvClipHeight == vp2_data.dvClipHeight, "dvClipHeight is %f, expected %f\n",
1187         ret_vp2_data.dvClipHeight, vp2_data.dvClipHeight);
1188     ok(ret_vp2_data.dvMinZ == 0.0, "dvMinZ is %f, expected 0.0\n", ret_vp2_data.dvMinZ);
1189     ok(ret_vp2_data.dvMaxZ == 1.0, "dvMaxZ is %f, expected 1.0\n", ret_vp2_data.dvMaxZ);
1190
1191     IDirect3DViewport2_Release(Viewport2);
1192
1193     hr = IDirect3DDevice_DeleteViewport(Direct3DDevice1, Viewport);
1194     ok(hr == D3D_OK, "IDirect3DDevice_DeleteViewport returned %08x\n", hr);
1195 }
1196
1197 #define SET_VP_DATA(vp_data) \
1198     vp_data.dwSize = sizeof(vp_data); \
1199     vp_data.dwX = 0; \
1200     vp_data.dwY = 0; \
1201     vp_data.dwWidth = 256; \
1202     vp_data.dwHeight = 256; \
1203     vp_data.dvMaxX = 256; \
1204     vp_data.dvMaxY = 256; \
1205     vp_data.dvScaleX = 5; \
1206     vp_data.dvScaleY = 5; \
1207     vp_data.dvMinZ = -25; \
1208     vp_data.dvMaxZ = 60;
1209
1210 static void Direct3D1Test(void)
1211 {
1212     HRESULT hr;
1213     D3DEXECUTEBUFFERDESC desc;
1214     D3DVIEWPORT vp_data;
1215     D3DINSTRUCTION *instr;
1216     D3DBRANCH *branch;
1217     IDirect3D *Direct3D_alt;
1218     IDirect3DLight *d3dlight;
1219     ULONG refcount;
1220     unsigned int idx = 0;
1221     static struct v_in testverts[] = {
1222         {0.0, 0.0, 0.0},  { 1.0,  1.0,  1.0}, {-1.0, -1.0, -1.0},
1223         {0.5, 0.5, 0.5},  {-0.5, -0.5, -0.5}, {-0.5, -0.5, 0.0},
1224     };
1225     static struct v_in cliptest[] = {
1226         {25.59, 25.59, 1.0},  {-25.59, -25.59,  0.0},
1227         {25.61, 25.61, 1.01}, {-25.61, -25.61, -0.01},
1228     };
1229     static struct v_in offscreentest[] = {
1230         {128.1, 0.0, 0.0},
1231     };
1232     struct v_out out[sizeof(testverts) / sizeof(testverts[0])];
1233     D3DHVERTEX outH[sizeof(testverts) / sizeof(testverts[0])];
1234     D3DTRANSFORMDATA transformdata;
1235     DWORD i = FALSE;
1236
1237     /* Interface consistency check. */
1238     hr = IDirect3DDevice_GetDirect3D(Direct3DDevice1, &Direct3D_alt);
1239     ok(hr == D3D_OK, "IDirect3DDevice_GetDirect3D failed: %08x\n", hr);
1240     if (hr == D3D_OK)
1241         ok(Direct3D_alt == Direct3D1, "Direct3D1 struct pointer missmatch: %p != %p\n", Direct3D_alt, Direct3D1);
1242
1243     memset(&desc, 0, sizeof(desc));
1244     desc.dwSize = sizeof(desc);
1245     hr = IDirect3DExecuteBuffer_Lock(ExecuteBuffer, &desc);
1246     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Lock failed: %08x\n", hr);
1247
1248     memset(desc.lpData, 0, 128);
1249     instr = desc.lpData;
1250     instr[idx].bOpcode = D3DOP_BRANCHFORWARD;
1251     instr[idx].bSize = sizeof(*branch);
1252     instr[idx].wCount = 1;
1253     idx++;
1254     branch = (D3DBRANCH *) &instr[idx];
1255     branch->dwMask = 0x0;
1256     branch->dwValue = 1;
1257     branch->bNegate = TRUE;
1258     branch->dwOffset = 0;
1259     idx += (sizeof(*branch) / sizeof(*instr));
1260     instr[idx].bOpcode = D3DOP_EXIT;
1261     instr[idx].bSize = 0;
1262     instr[idx].wCount = 0;
1263     hr = IDirect3DExecuteBuffer_Unlock(ExecuteBuffer);
1264     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Unlock failed: %08x\n", hr);
1265
1266     hr = IDirect3DDevice_Execute(Direct3DDevice1, ExecuteBuffer, Viewport, D3DEXECUTE_CLIPPED);
1267     ok(hr == D3D_OK, "IDirect3DDevice_Execute returned %08x\n", hr);
1268
1269     memset(&desc, 0, sizeof(desc));
1270     desc.dwSize = sizeof(desc);
1271
1272     hr = IDirect3DExecuteBuffer_Lock(ExecuteBuffer, &desc);
1273     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Lock failed: %08x\n", hr);
1274
1275     memset(desc.lpData, 0, 128);
1276     instr = desc.lpData;
1277     idx = 0;
1278     instr[idx].bOpcode = D3DOP_BRANCHFORWARD;
1279     instr[idx].bSize = sizeof(*branch);
1280     instr[idx].wCount = 1;
1281     idx++;
1282     branch = (D3DBRANCH *) &instr[idx];
1283     branch->dwMask = 0x0;
1284     branch->dwValue = 1;
1285     branch->bNegate = TRUE;
1286     branch->dwOffset = 64;
1287     instr = (D3DINSTRUCTION*)((char*)desc.lpData + 64);
1288     instr[0].bOpcode = D3DOP_EXIT;
1289     instr[0].bSize = 0;
1290     instr[0].wCount = 0;
1291     hr = IDirect3DExecuteBuffer_Unlock(ExecuteBuffer);
1292     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Unlock failed: %08x\n", hr);
1293
1294     hr = IDirect3DDevice_Execute(Direct3DDevice1, ExecuteBuffer, Viewport, D3DEXECUTE_CLIPPED);
1295     ok(hr == D3D_OK, "IDirect3DDevice_Execute returned %08x\n", hr);
1296
1297     /* Test rendering 0 triangles */
1298     memset(&desc, 0, sizeof(desc));
1299     desc.dwSize = sizeof(desc);
1300
1301     hr = IDirect3DExecuteBuffer_Lock(ExecuteBuffer, &desc);
1302     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Lock failed: %08x\n", hr);
1303
1304     memset(desc.lpData, 0, 128);
1305     instr = desc.lpData;
1306     idx = 0;
1307
1308     instr->bOpcode = D3DOP_TRIANGLE;
1309     instr->bSize = sizeof(D3DOP_TRIANGLE);
1310     instr->wCount = 0;
1311     instr++;
1312     instr->bOpcode = D3DOP_EXIT;
1313     instr->bSize = 0;
1314     instr->wCount = 0;
1315     hr = IDirect3DExecuteBuffer_Unlock(ExecuteBuffer);
1316     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Unlock failed: %08x\n", hr);
1317
1318     hr = IDirect3DDevice_Execute(Direct3DDevice1, ExecuteBuffer, Viewport, D3DEXECUTE_CLIPPED);
1319     ok(hr == D3D_OK, "IDirect3DDevice_Execute returned %08x\n", hr);
1320
1321     memset(&transformdata, 0, sizeof(transformdata));
1322     transformdata.dwSize = sizeof(transformdata);
1323     transformdata.lpIn = testverts;
1324     transformdata.dwInSize = sizeof(testverts[0]);
1325     transformdata.lpOut = out;
1326     transformdata.dwOutSize = sizeof(out[0]);
1327
1328     transformdata.lpHOut = NULL;
1329     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1330                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1331                                              &i);
1332     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1333
1334     transformdata.lpHOut = outH;
1335     memset(outH, 0xcc, sizeof(outH));
1336     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1337                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1338                                              &i);
1339     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1340     ok(i == 0, "Offscreen is %d\n", i);
1341
1342     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
1343         static const struct v_out cmp[] = {
1344             {128.0, 128.0, 0.0, 1}, {129.0, 127.0,  1.0, 1}, {127.0, 129.0, -1, 1},
1345             {128.5, 127.5, 0.5, 1}, {127.5, 128.5, -0.5, 1}, {127.5, 128.5,  0, 1}
1346         };
1347
1348         ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
1349            cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
1350            "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
1351            out[i].x, out[i].y, out[i].z, out[i].rhw,
1352            cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
1353     }
1354     for(i = 0; i < sizeof(outH); i++) {
1355         if(((unsigned char *) outH)[i] != 0xcc) {
1356             ok(FALSE, "Homogeneous output was generated despite UNCLIPPED flag\n");
1357             break;
1358         }
1359     }
1360
1361     SET_VP_DATA(vp_data);
1362     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1363     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1364     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1365                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1366                                              &i);
1367     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1368     ok(i == 0, "Offscreen is %d\n", i);
1369
1370     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
1371         static const struct v_out cmp[] = {
1372             {128.0, 128.0, 0.0, 1}, {133.0, 123.0,  1.0, 1}, {123.0, 133.0, -1, 1},
1373             {130.5, 125.5, 0.5, 1}, {125.5, 130.5, -0.5, 1}, {125.5, 130.5,  0, 1}
1374         };
1375         ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
1376            cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
1377            "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
1378            out[i].x, out[i].y, out[i].z, out[i].rhw,
1379            cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
1380     }
1381
1382     SET_VP_DATA(vp_data);
1383     vp_data.dwX = 10;
1384     vp_data.dwY = 20;
1385     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1386     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1387     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1388                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1389                                              &i);
1390     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1391     ok(i == 0, "Offscreen is %d\n", i);
1392     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
1393         static const struct v_out cmp[] = {
1394             {138.0, 148.0, 0.0, 1}, {143.0, 143.0,  1.0, 1}, {133.0, 153.0, -1, 1},
1395             {140.5, 145.5, 0.5, 1}, {135.5, 150.5, -0.5, 1}, {135.5, 150.5,  0, 1}
1396         };
1397         ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
1398            cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
1399            "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
1400            out[i].x, out[i].y, out[i].z, out[i].rhw,
1401            cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
1402     }
1403
1404     memset(out, 0xcc, sizeof(out));
1405     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1406                                              &transformdata, D3DTRANSFORM_CLIPPED,
1407                                              &i);
1408     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1409     ok(i == 0, "Offscreen is %d\n", i);
1410     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
1411         static const D3DHVERTEX cmpH[] = {
1412             {0,             { 0.0}, { 0.0}, { 0.0}}, {0, { 1.0}, { 1.0}, {1.0}},
1413             {D3DCLIP_FRONT, {-1.0}, {-1.0}, {-1.0}}, {0, { 0.5}, { 0.5}, {0.5}},
1414             {D3DCLIP_FRONT, {-0.5}, {-0.5}, {-0.5}}, {0, {-0.5}, {-0.5}, {0.0}}
1415         };
1416         ok(U1(cmpH[i]).hx == U1(outH[i]).hx && U2(cmpH[i]).hy == U2(outH[i]).hy &&
1417            U3(cmpH[i]).hz == U3(outH[i]).hz && cmpH[i].dwFlags == outH[i].dwFlags,
1418            "HVertex %d differs. Got %08x %f %f %f, expexted %08x %f %f %f\n", i + 1,
1419            outH[i].dwFlags, U1(outH[i]).hx, U2(outH[i]).hy, U3(outH[i]).hz,
1420            cmpH[i].dwFlags, U1(cmpH[i]).hx, U2(cmpH[i]).hy, U3(cmpH[i]).hz);
1421
1422         /* No scheme has been found behind those return values. It seems to be
1423          * whatever data windows has when throwing the vertex away. Modify the
1424          * input test vertices to test this more. Depending on the input data
1425          * it can happen that the z coord gets written into y, or similar things
1426          */
1427         if(0)
1428         {
1429             static const struct v_out cmp[] = {
1430                 {138.0, 148.0, 0.0, 1}, {143.0, 143.0,  1.0, 1}, { -1.0,  -1.0, 0.5, 1},
1431                 {140.5, 145.5, 0.5, 1}, { -0.5,  -0.5, -0.5, 1}, {135.5, 150.5, 0.0, 1}
1432             };
1433             ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
1434                cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
1435                 "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
1436                out[i].x, out[i].y, out[i].z, out[i].rhw,
1437                cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
1438         }
1439     }
1440     for(i = 0; i < sizeof(out) / sizeof(DWORD); i++) {
1441         ok(((DWORD *) out)[i] != 0xcccccccc,
1442                 "Regular output DWORD %d remained untouched\n", i);
1443     }
1444
1445     transformdata.lpIn = cliptest;
1446     transformdata.dwInSize = sizeof(cliptest[0]);
1447     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(cliptest) / sizeof(cliptest[0]),
1448                                              &transformdata, D3DTRANSFORM_CLIPPED,
1449                                              &i);
1450     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1451     ok(i == 0, "Offscreen is %d\n", i);
1452     for(i = 0; i < sizeof(cliptest) / sizeof(cliptest[0]); i++) {
1453         DWORD Flags[sizeof(cliptest) / sizeof(cliptest[0])] =
1454         {
1455             0,
1456             0,
1457             D3DCLIP_RIGHT | D3DCLIP_BACK   | D3DCLIP_TOP,
1458             D3DCLIP_LEFT  | D3DCLIP_BOTTOM | D3DCLIP_FRONT,
1459         };
1460         ok(Flags[i] == outH[i].dwFlags,
1461            "Cliptest %d differs. Got %08x expexted %08x\n", i + 1,
1462            outH[i].dwFlags, Flags[i]);
1463     }
1464
1465     SET_VP_DATA(vp_data);
1466     vp_data.dwWidth = 10;
1467     vp_data.dwHeight = 1000;
1468     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1469     i = 10;
1470     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1471     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(cliptest) / sizeof(cliptest[0]),
1472                                              &transformdata, D3DTRANSFORM_CLIPPED,
1473                                              &i);
1474     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1475     ok(i == 0, "Offscreen is %d\n", i);
1476     for(i = 0; i < sizeof(cliptest) / sizeof(cliptest[0]); i++) {
1477         DWORD Flags[sizeof(cliptest) / sizeof(cliptest[0])] =
1478         {
1479             D3DCLIP_RIGHT,
1480             D3DCLIP_LEFT,
1481             D3DCLIP_RIGHT | D3DCLIP_BACK,
1482             D3DCLIP_LEFT  | D3DCLIP_FRONT,
1483         };
1484         ok(Flags[i] == outH[i].dwFlags,
1485            "Cliptest %d differs. Got %08x expexted %08x\n", i + 1,
1486            outH[i].dwFlags, Flags[i]);
1487     }
1488
1489     SET_VP_DATA(vp_data);
1490     vp_data.dwWidth = 256;
1491     vp_data.dwHeight = 256;
1492     vp_data.dvScaleX = 1;
1493     vp_data.dvScaleY = 1;
1494     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1495     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1496     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(cliptest) / sizeof(cliptest[0]),
1497                                              &transformdata, D3DTRANSFORM_CLIPPED,
1498                                              &i);
1499     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1500     ok(i == 0, "Offscreen is %s\n", i ? "TRUE" : "FALSE");
1501     for(i = 0; i < sizeof(cliptest) / sizeof(cliptest[0]); i++) {
1502         DWORD Flags[sizeof(cliptest) / sizeof(cliptest[0])] =
1503         {
1504             0,
1505             0,
1506             D3DCLIP_BACK,
1507             D3DCLIP_FRONT,
1508         };
1509         ok(Flags[i] == outH[i].dwFlags,
1510            "Cliptest %d differs. Got %08x expexted %08x\n", i + 1,
1511            outH[i].dwFlags, Flags[i]);
1512     }
1513
1514     /* Finally try to figure out how the DWORD dwOffscreen works.
1515      * Apparently no vertex is offscreen with clipping off,
1516      * and with clipping on the offscreen flag is set if only one vertex
1517      * is transformed, and this vertex is offscreen.
1518      */
1519     SET_VP_DATA(vp_data);
1520     vp_data.dwWidth = 5;
1521     vp_data.dwHeight = 5;
1522     vp_data.dvScaleX = 10000;
1523     vp_data.dvScaleY = 10000;
1524     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1525     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1526     transformdata.lpIn = cliptest;
1527     hr = IDirect3DViewport_TransformVertices(Viewport, 1,
1528                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1529                                              &i);
1530     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1531     ok(i == 0, "Offscreen is %d\n", i);
1532     hr = IDirect3DViewport_TransformVertices(Viewport, 1,
1533                                              &transformdata, D3DTRANSFORM_CLIPPED,
1534                                              &i);
1535     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1536     ok(i == (D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %d\n", i);
1537     hr = IDirect3DViewport_TransformVertices(Viewport, 2,
1538                                              &transformdata, D3DTRANSFORM_CLIPPED,
1539                                              &i);
1540     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1541     ok(i == 0, "Offscreen is %d\n", i);
1542     transformdata.lpIn = cliptest + 1;
1543     hr = IDirect3DViewport_TransformVertices(Viewport, 1,
1544                                              &transformdata, D3DTRANSFORM_CLIPPED,
1545                                              &i);
1546     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1547     ok(i == (D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %d\n", i);
1548
1549     transformdata.lpIn = offscreentest;
1550     transformdata.dwInSize = sizeof(offscreentest[0]);
1551     SET_VP_DATA(vp_data);
1552     vp_data.dwWidth = 257;
1553     vp_data.dwHeight = 257;
1554     vp_data.dvScaleX = 1;
1555     vp_data.dvScaleY = 1;
1556     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1557     ok(SUCCEEDED(hr), "IDirect3DViewport_SetViewport returned %#x.\n", hr);
1558     i = 12345;
1559     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(offscreentest) / sizeof(offscreentest[0]),
1560                                              &transformdata, D3DTRANSFORM_CLIPPED,
1561                                              &i);
1562     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1563     ok(i == 0, "Offscreen is %d\n", i);
1564     vp_data.dwWidth = 256;
1565     vp_data.dwHeight = 256;
1566     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1567     ok(SUCCEEDED(hr), "IDirect3DViewport_SetViewport returned %#x.\n", hr);
1568     i = 12345;
1569     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(offscreentest) / sizeof(offscreentest[0]),
1570                                              &transformdata, D3DTRANSFORM_CLIPPED,
1571                                              &i);
1572     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1573     ok(i == D3DCLIP_RIGHT, "Offscreen is %d\n", i);
1574
1575     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1576                                              &transformdata, 0,
1577                                              &i);
1578     ok(hr == DDERR_INVALIDPARAMS, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1579
1580     hr = IDirect3DDevice_DeleteViewport(Direct3DDevice1, Viewport);
1581     ok(hr == D3D_OK, "IDirect3DDevice_DeleteViewport returned %08x\n", hr);
1582
1583     hr = IDirect3DViewport_AddLight(Viewport, Light);
1584     ok(hr == D3D_OK, "IDirect3DViewport_AddLight returned %08x\n", hr);
1585     refcount = getRefcount((IUnknown*) Light);
1586     ok(refcount == 2, "Refcount should be 2, returned is %d\n", refcount);
1587
1588     hr = IDirect3DViewport_NextLight(Viewport, NULL, &d3dlight, D3DNEXT_HEAD);
1589     ok(hr == D3D_OK, "IDirect3DViewport_AddLight returned %08x\n", hr);
1590     ok(d3dlight == Light, "Got different light returned %p, expected %p\n", d3dlight, Light);
1591     refcount = getRefcount((IUnknown*) Light);
1592     ok(refcount == 3, "Refcount should be 2, returned is %d\n", refcount);
1593
1594     hr = IDirect3DViewport_DeleteLight(Viewport, Light);
1595     ok(hr == D3D_OK, "IDirect3DViewport_DeleteLight returned %08x\n", hr);
1596     refcount = getRefcount((IUnknown*) Light);
1597     ok(refcount == 2, "Refcount should be 2, returned is %d\n", refcount);
1598
1599     IDirect3DLight_Release(Light);
1600 }
1601
1602 static BOOL colortables_check_equality(PALETTEENTRY table1[256], PALETTEENTRY table2[256])
1603 {
1604     int i;
1605
1606     for (i = 0; i < 256; i++) {
1607        if (table1[i].peRed != table2[i].peRed || table1[i].peGreen != table2[i].peGreen ||
1608            table1[i].peBlue != table2[i].peBlue) return FALSE;
1609     }
1610
1611     return TRUE;
1612 }
1613
1614 /* test palette handling in IDirect3DTexture_Load */
1615 static void TextureLoadTest(void)
1616 {
1617     IDirectDrawSurface *TexSurface = NULL;
1618     IDirect3DTexture *Texture = NULL;
1619     IDirectDrawSurface *TexSurface2 = NULL;
1620     IDirect3DTexture *Texture2 = NULL;
1621     IDirectDrawPalette *palette = NULL;
1622     IDirectDrawPalette *palette2 = NULL;
1623     IDirectDrawPalette *palette_tmp = NULL;
1624     PALETTEENTRY table1[256], table2[256], table_tmp[256];
1625     HRESULT hr;
1626     DDSURFACEDESC ddsd;
1627     int i;
1628
1629     memset (&ddsd, 0, sizeof (ddsd));
1630     ddsd.dwSize = sizeof (ddsd);
1631     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1632     ddsd.dwHeight = 128;
1633     ddsd.dwWidth = 128;
1634     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1635     ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
1636     ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
1637     U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 8;
1638
1639     hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &TexSurface, NULL);
1640     ok(hr==D3D_OK, "CreateSurface returned: %x\n", hr);
1641     if (FAILED(hr)) {
1642         skip("IDirectDraw_CreateSurface failed; skipping further tests\n");
1643         goto cleanup;
1644     }
1645
1646     hr = IDirectDrawSurface_QueryInterface(TexSurface, &IID_IDirect3DTexture,
1647                 (void *)&Texture);
1648     ok(hr==D3D_OK, "IDirectDrawSurface_QueryInterface returned: %x\n", hr);
1649     if (FAILED(hr)) {
1650         skip("Can't get IDirect3DTexture interface; skipping further tests\n");
1651         goto cleanup;
1652     }
1653
1654     hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &TexSurface2, NULL);
1655     ok(hr==D3D_OK, "CreateSurface returned: %x\n", hr);
1656     if (FAILED(hr)) {
1657         skip("IDirectDraw_CreateSurface failed; skipping further tests\n");
1658         goto cleanup;
1659     }
1660
1661     hr = IDirectDrawSurface_QueryInterface(TexSurface2, &IID_IDirect3DTexture,
1662                 (void *)&Texture2);
1663     ok(hr==D3D_OK, "IDirectDrawSurface_QueryInterface returned: %x\n", hr);
1664     if (FAILED(hr)) {
1665         skip("Can't get IDirect3DTexture interface; skipping further tests\n");
1666         goto cleanup;
1667     }
1668
1669     /* test load of Texture to Texture */
1670     hr = IDirect3DTexture_Load(Texture, Texture);
1671     ok(hr == DD_OK, "IDirect3DTexture_Load returned %08x\n", hr);
1672
1673     /* test Load when both textures have no palette */
1674     hr = IDirect3DTexture_Load(Texture2, Texture);
1675     ok(hr == DD_OK, "IDirect3DTexture_Load returned %08x\n", hr);
1676
1677     for (i = 0; i < 256; i++) {
1678         table1[i].peRed = i;
1679         table1[i].peGreen = i;
1680         table1[i].peBlue = i;
1681         table1[i].peFlags = 0;
1682     }
1683
1684     hr = IDirectDraw_CreatePalette(DirectDraw1, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, table1, &palette, NULL);
1685     ok(hr == DD_OK, "CreatePalette returned %08x\n", hr);
1686     if (FAILED(hr)) {
1687         skip("IDirectDraw_CreatePalette failed; skipping further tests\n");
1688         goto cleanup;
1689     }
1690
1691     /* test Load when source texture has palette and destination has no palette */
1692     hr = IDirectDrawSurface_SetPalette(TexSurface, palette);
1693     ok(hr == DD_OK, "IDirectDrawSurface_SetPalette returned %08x\n", hr);
1694     hr = IDirect3DTexture_Load(Texture2, Texture);
1695     ok(hr == DDERR_NOPALETTEATTACHED, "IDirect3DTexture_Load returned %08x\n", hr);
1696
1697     for (i = 0; i < 256; i++) {
1698         table2[i].peRed = 255 - i;
1699         table2[i].peGreen = 255 - i;
1700         table2[i].peBlue = 255 - i;
1701         table2[i].peFlags = 0;
1702     }
1703
1704     hr = IDirectDraw_CreatePalette(DirectDraw1, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, table2, &palette2, NULL);
1705     ok(hr == DD_OK, "CreatePalette returned %08x\n", hr);
1706     if (FAILED(hr)) {
1707         skip("IDirectDraw_CreatePalette failed; skipping further tests\n");
1708         goto cleanup;
1709     }
1710
1711     /* test Load when source has no palette and destination has a palette */
1712     hr = IDirectDrawSurface_SetPalette(TexSurface, NULL);
1713     ok(hr == DD_OK, "IDirectDrawSurface_SetPalette returned %08x\n", hr);
1714     hr = IDirectDrawSurface_SetPalette(TexSurface2, palette2);
1715     ok(hr == DD_OK, "IDirectDrawSurface_SetPalette returned %08x\n", hr);
1716     hr = IDirect3DTexture_Load(Texture2, Texture);
1717     ok(hr == DD_OK, "IDirect3DTexture_Load returned %08x\n", hr);
1718     hr = IDirectDrawSurface_GetPalette(TexSurface2, &palette_tmp);
1719     ok(hr == DD_OK, "IDirectDrawSurface_GetPalette returned %08x\n", hr);
1720     if (!palette_tmp) {
1721         skip("IDirectDrawSurface_GetPalette failed; skipping color table check\n");
1722         goto cleanup;
1723     } else {
1724         hr = IDirectDrawPalette_GetEntries(palette_tmp, 0, 0, 256, table_tmp);
1725         ok(hr == DD_OK, "IDirectDrawPalette_GetEntries returned %08x\n", hr);
1726         ok(colortables_check_equality(table2, table_tmp), "Unexpected palettized texture color table\n");
1727         IDirectDrawPalette_Release(palette_tmp);
1728     }
1729
1730     /* test Load when both textures have palettes */
1731     hr = IDirectDrawSurface_SetPalette(TexSurface, palette);
1732     ok(hr == DD_OK, "IDirectDrawSurface_SetPalette returned %08x\n", hr);
1733     hr = IDirect3DTexture_Load(Texture2, Texture);
1734     ok(hr == DD_OK, "IDirect3DTexture_Load returned %08x\n", hr);
1735     hr = IDirect3DTexture_Load(Texture2, Texture);
1736     ok(hr == DD_OK, "IDirect3DTexture_Load returned %08x\n", hr);
1737     hr = IDirectDrawSurface_GetPalette(TexSurface2, &palette_tmp);
1738     ok(hr == DD_OK, "IDirectDrawSurface_GetPalette returned %08x\n", hr);
1739     if (!palette_tmp) {
1740         skip("IDirectDrawSurface_GetPalette failed; skipping color table check\n");
1741         goto cleanup;
1742     } else {
1743         hr = IDirectDrawPalette_GetEntries(palette_tmp, 0, 0, 256, table_tmp);
1744         ok(hr == DD_OK, "IDirectDrawPalette_GetEntries returned %08x\n", hr);
1745         ok(colortables_check_equality(table1, table_tmp), "Unexpected palettized texture color table\n");
1746         IDirectDrawPalette_Release(palette_tmp);
1747     }
1748
1749     cleanup:
1750
1751     if (palette) IDirectDrawPalette_Release(palette);
1752     if (palette2) IDirectDrawPalette_Release(palette2);
1753     if (TexSurface) IDirectDrawSurface_Release(TexSurface);
1754     if (Texture) IDirect3DTexture_Release(Texture);
1755     if (TexSurface2) IDirectDrawSurface_Release(TexSurface2);
1756     if (Texture2) IDirect3DTexture_Release(Texture2);
1757 }
1758
1759 static void VertexBufferDescTest(void)
1760 {
1761     HRESULT rc;
1762     D3DVERTEXBUFFERDESC desc;
1763     union mem_t
1764     {
1765         D3DVERTEXBUFFERDESC desc2;
1766         unsigned char buffer[512];
1767     } mem;
1768
1769     memset(&desc, 0, sizeof(desc));
1770     desc.dwSize = sizeof(desc);
1771     desc.dwCaps = 0;
1772     desc.dwFVF = D3DFVF_XYZ;
1773     desc.dwNumVertices = 1;
1774     rc = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &lpVBufSrc, 0);
1775     ok(rc==D3D_OK || rc==E_OUTOFMEMORY, "CreateVertexBuffer returned: %x\n", rc);
1776     if (!lpVBufSrc)
1777     {
1778         trace("IDirect3D7::CreateVertexBuffer() failed with an error %x\n", rc);
1779         goto out;
1780     }
1781
1782     memset(mem.buffer, 0x12, sizeof(mem.buffer));
1783     mem.desc2.dwSize = sizeof(D3DVERTEXBUFFERDESC)*2;
1784     rc = IDirect3DVertexBuffer7_GetVertexBufferDesc(lpVBufSrc, &mem.desc2);
1785     if(rc != D3D_OK)
1786         skip("GetVertexBuffer Failed!\n");
1787     ok( mem.desc2.dwSize == sizeof(D3DVERTEXBUFFERDESC)*2, "Size returned from GetVertexBufferDesc does not match the value put in\n" );
1788     ok( mem.buffer[sizeof(D3DVERTEXBUFFERDESC)] == 0x12, "GetVertexBufferDesc cleared outside of the struct! (dwSize was double the size of the struct)\n");
1789     ok( mem.desc2.dwCaps == desc.dwCaps, "dwCaps returned differs. Got %x, expected %x\n", mem.desc2.dwCaps, desc.dwCaps);
1790     ok( mem.desc2.dwFVF == desc.dwFVF, "dwFVF returned differs. Got %x, expected %x\n", mem.desc2.dwFVF, desc.dwFVF);
1791     ok (mem.desc2.dwNumVertices == desc.dwNumVertices, "dwNumVertices returned differs. Got %x, expected %x\n", mem.desc2.dwNumVertices, desc.dwNumVertices);
1792
1793     memset(mem.buffer, 0x12, sizeof(mem.buffer));
1794     mem.desc2.dwSize = 0;
1795     rc = IDirect3DVertexBuffer7_GetVertexBufferDesc(lpVBufSrc, &mem.desc2);
1796     if(rc != D3D_OK)
1797         skip("GetVertexBuffer Failed!\n");
1798     ok( mem.desc2.dwSize == 0, "Size returned from GetVertexBufferDesc does not match the value put in\n" );
1799     ok( mem.buffer[sizeof(D3DVERTEXBUFFERDESC)] == 0x12, "GetVertexBufferDesc cleared outside of the struct! (dwSize was 0)\n");
1800     ok( mem.desc2.dwCaps == desc.dwCaps, "dwCaps returned differs. Got %x, expected %x\n", mem.desc2.dwCaps, desc.dwCaps);
1801     ok( mem.desc2.dwFVF == desc.dwFVF, "dwFVF returned differs. Got %x, expected %x\n", mem.desc2.dwFVF, desc.dwFVF);
1802     ok (mem.desc2.dwNumVertices == desc.dwNumVertices, "dwNumVertices returned differs. Got %x, expected %x\n", mem.desc2.dwNumVertices, desc.dwNumVertices);
1803
1804     memset(mem.buffer, 0x12, sizeof(mem.buffer));
1805     mem.desc2.dwSize = sizeof(D3DVERTEXBUFFERDESC);
1806     rc = IDirect3DVertexBuffer7_GetVertexBufferDesc(lpVBufSrc, &mem.desc2);
1807     if(rc != D3D_OK)
1808         skip("GetVertexBuffer Failed!\n");
1809     ok( mem.desc2.dwSize == sizeof(D3DVERTEXBUFFERDESC), "Size returned from GetVertexBufferDesc does not match the value put in\n" );
1810     ok( mem.buffer[sizeof(D3DVERTEXBUFFERDESC)] == 0x12, "GetVertexBufferDesc cleared outside of the struct! (dwSize was the size of the struct)\n");
1811     ok( mem.desc2.dwCaps == desc.dwCaps, "dwCaps returned differs. Got %x, expected %x\n", mem.desc2.dwCaps, desc.dwCaps);
1812     ok( mem.desc2.dwFVF == desc.dwFVF, "dwFVF returned differs. Got %x, expected %x\n", mem.desc2.dwFVF, desc.dwFVF);
1813     ok (mem.desc2.dwNumVertices == desc.dwNumVertices, "dwNumVertices returned differs. Got %x, expected %x\n", mem.desc2.dwNumVertices, desc.dwNumVertices);
1814
1815 out:
1816     IDirect3DVertexBuffer7_Release(lpVBufSrc);
1817 }
1818
1819 static void D3D7_OldRenderStateTest(void)
1820 {
1821     HRESULT hr;
1822     DWORD val;
1823
1824     /* Test reaction to some deprecated states in D3D7. */
1825     hr = IDirect3DDevice7_SetRenderState(lpD3DDevice, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1826     ok(hr == DDERR_INVALIDPARAMS, "IDirect3DDevice7_SetRenderState returned %#x.\n", hr);
1827     hr = IDirect3DDevice7_GetRenderState(lpD3DDevice, D3DRENDERSTATE_TEXTUREHANDLE, &val);
1828     ok(hr == DDERR_INVALIDPARAMS, "IDirect3DDevice7_GetRenderState returned %#x.\n", hr);
1829     hr = IDirect3DDevice7_SetRenderState(lpD3DDevice, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
1830     ok(hr == DDERR_INVALIDPARAMS, "IDirect3DDevice7_SetRenderState returned %#x.\n", hr);
1831     hr = IDirect3DDevice7_GetRenderState(lpD3DDevice, D3DRENDERSTATE_TEXTUREMAPBLEND, &val);
1832     ok(hr == DDERR_INVALIDPARAMS, "IDirect3DDevice7_GetRenderState returned %#x.\n", hr);
1833 }
1834
1835 #define IS_VALUE_NEAR(a, b)    ( ((a) == (b)) || ((a) == (b) - 1) || ((a) == (b) + 1) )
1836 #define MIN(a, b)    ((a) < (b) ? (a) : (b))
1837
1838 static void DeviceLoadTest(void)
1839 {
1840     DDSURFACEDESC2 ddsd;
1841     IDirectDrawSurface7 *texture_levels[2][8];
1842     IDirectDrawSurface7 *cube_face_levels[2][6][8];
1843     DWORD flags;
1844     HRESULT hr;
1845     DDBLTFX ddbltfx;
1846     RECT loadrect;
1847     POINT loadpoint;
1848     int i, i1, i2;
1849     unsigned diff_count = 0, diff_count2 = 0;
1850     unsigned x, y;
1851     BOOL load_mip_subset_broken = FALSE;
1852     IDirectDrawPalette *palettes[5];
1853     PALETTEENTRY table1[256];
1854     DDCOLORKEY ddckey;
1855     D3DDEVICEDESC7 d3dcaps;
1856
1857     /* Test loading of texture subrectangle with a mipmap surface. */
1858     memset(texture_levels, 0, sizeof(texture_levels));
1859     memset(cube_face_levels, 0, sizeof(cube_face_levels));
1860     memset(palettes, 0, sizeof(palettes));
1861
1862     for (i = 0; i < 2; i++)
1863     {
1864         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1865         ddsd.dwSize = sizeof(ddsd);
1866         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
1867         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
1868         ddsd.dwWidth = 128;
1869         ddsd.dwHeight = 128;
1870         U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
1871         U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
1872         U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
1873         U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
1874         U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
1875         U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
1876         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[i][0], NULL);
1877         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
1878         if (FAILED(hr)) goto out;
1879
1880         /* Check the number of created mipmaps */
1881         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1882         ddsd.dwSize = sizeof(ddsd);
1883         hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[i][0], &ddsd);
1884         ok(hr==DD_OK,"IDirectDrawSurface7_GetSurfaceDesc returned: %x\n",hr);
1885         ok(U2(ddsd).dwMipMapCount == 8, "unexpected mip count %u\n", U2(ddsd).dwMipMapCount);
1886         if (U2(ddsd).dwMipMapCount != 8) goto out;
1887
1888         for (i1 = 1; i1 < 8; i1++)
1889         {
1890             hr = IDirectDrawSurface7_GetAttachedSurface(texture_levels[i][i1 - 1], &ddsd.ddsCaps, &texture_levels[i][i1]);
1891             ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
1892             if (FAILED(hr)) goto out;
1893         }
1894     }
1895
1896     for (i1 = 0; i1 < 8; i1++)
1897     {
1898         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1899         ddsd.dwSize = sizeof(ddsd);
1900         hr = IDirectDrawSurface7_Lock(texture_levels[0][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
1901         ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
1902         if (FAILED(hr)) goto out;
1903
1904         for (y = 0 ; y < ddsd.dwHeight; y++)
1905         {
1906             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
1907
1908             for (x = 0; x < ddsd.dwWidth;  x++)
1909             {
1910                 /* x stored in green component, y in blue. */
1911                 DWORD color = 0xff0000 | (x << 8)  | y;
1912                 *textureRow++ = color;
1913             }
1914         }
1915
1916         hr = IDirectDrawSurface7_Unlock(texture_levels[0][i1], NULL);
1917         ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
1918     }
1919
1920     for (i1 = 0; i1 < 8; i1++)
1921     {
1922         memset(&ddbltfx, 0, sizeof(ddbltfx));
1923         ddbltfx.dwSize = sizeof(ddbltfx);
1924         U5(ddbltfx).dwFillColor = 0;
1925         hr = IDirectDrawSurface7_Blt(texture_levels[1][i1], NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
1926         ok(hr == DD_OK, "IDirectDrawSurface7_Blt failed with %08x\n", hr);
1927     }
1928
1929     /* First test some broken coordinates. */
1930     loadpoint.x = loadpoint.y = 0;
1931     loadrect.left = 0;
1932     loadrect.top = 0;
1933     loadrect.right = 0;
1934     loadrect.bottom = 0;
1935     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
1936     ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
1937
1938     loadpoint.x = loadpoint.y = 50;
1939     loadrect.left = 0;
1940     loadrect.top = 0;
1941     loadrect.right = 100;
1942     loadrect.bottom = 100;
1943     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
1944     ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
1945
1946     /* Test actual loading. */
1947     loadpoint.x = loadpoint.y = 31;
1948     loadrect.left = 30;
1949     loadrect.top = 20;
1950     loadrect.right = 93;
1951     loadrect.bottom = 52;
1952
1953     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
1954     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
1955
1956     for (i1 = 0; i1 < 8; i1++)
1957     {
1958         diff_count = 0;
1959         diff_count2 = 0;
1960
1961         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1962         ddsd.dwSize = sizeof(ddsd);
1963         hr = IDirectDrawSurface7_Lock(texture_levels[1][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
1964         ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
1965         if (FAILED(hr)) goto out;
1966
1967         for (y = 0 ; y < ddsd.dwHeight; y++)
1968         {
1969             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
1970
1971             for (x = 0; x < ddsd.dwWidth;  x++)
1972             {
1973                 DWORD color = *textureRow++;
1974
1975                 if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
1976                     y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
1977                 {
1978                     if (color & 0xffffff) diff_count++;
1979                 }
1980                 else
1981                 {
1982                     DWORD r = (color & 0xff0000) >> 16;
1983                     DWORD g = (color & 0xff00) >> 8;
1984                     DWORD b = (color & 0xff);
1985
1986                     if (r != 0xff || g != x + loadrect.left - loadpoint.x || b != y + loadrect.top - loadpoint.y) diff_count++;
1987                 }
1988
1989                 /* This codepath is for software RGB device. It has what looks like some weird off by one errors, but may
1990                    technically be correct as it's not precisely defined by docs. */
1991                 if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
1992                     y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top + 1)
1993                 {
1994                     if (color & 0xffffff) diff_count2++;
1995                 }
1996                 else
1997                 {
1998                     DWORD r = (color & 0xff0000) >> 16;
1999                     DWORD g = (color & 0xff00) >> 8;
2000                     DWORD b = (color & 0xff);
2001
2002                     if (r != 0xff || !IS_VALUE_NEAR(g, x + loadrect.left - loadpoint.x) ||
2003                         !IS_VALUE_NEAR(b, y + loadrect.top - loadpoint.y)) diff_count2++;
2004                 }
2005             }
2006         }
2007
2008         hr = IDirectDrawSurface7_Unlock(texture_levels[1][i1], NULL);
2009         ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2010
2011         ok(diff_count == 0 || diff_count2 == 0, "Unexpected destination texture level pixels; %u differences at %d level\n",
2012                 MIN(diff_count, diff_count2), i1);
2013
2014         loadpoint.x /= 2;
2015         loadpoint.y /= 2;
2016         loadrect.top /= 2;
2017         loadrect.left /= 2;
2018         loadrect.right = (loadrect.right + 1) / 2;
2019         loadrect.bottom = (loadrect.bottom + 1) / 2;
2020     }
2021
2022     /* This crashes on native (tested on real windows XP / directx9 / nvidia and
2023      * qemu Win98 / directx7 / RGB software rasterizer):
2024      * passing non toplevel surfaces (sublevels) to Load (DX7 docs tell not to do this)
2025     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][1], NULL, texture_levels[0][1], NULL, 0);
2026     */
2027
2028     /* Freed in reverse order as native seems to dislike and crash on freeing top level surface first. */
2029     for (i = 0; i < 2; i++)
2030     {
2031         for (i1 = 7; i1 >= 0; i1--)
2032         {
2033             if (texture_levels[i][i1]) IDirectDrawSurface7_Release(texture_levels[i][i1]);
2034         }
2035     }
2036     memset(texture_levels, 0, sizeof(texture_levels));
2037
2038     /* Test texture size mismatch. */
2039     for (i = 0; i < 2; i++)
2040     {
2041         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2042         ddsd.dwSize = sizeof(ddsd);
2043         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2044         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
2045         ddsd.dwWidth = i ? 256 : 128;
2046         ddsd.dwHeight = 128;
2047         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[i][0], NULL);
2048         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2049         if (FAILED(hr)) goto out;
2050     }
2051
2052     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], NULL, texture_levels[0][0], NULL, 0);
2053     ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2054
2055     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[0][0], NULL, texture_levels[1][0], NULL, 0);
2056     ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2057
2058     IDirectDrawSurface7_Release(texture_levels[0][0]);
2059     IDirectDrawSurface7_Release(texture_levels[1][0]);
2060     memset(texture_levels, 0, sizeof(texture_levels));
2061
2062     memset(&d3dcaps, 0, sizeof(d3dcaps));
2063     hr = IDirect3DDevice7_GetCaps(lpD3DDevice, &d3dcaps);
2064     ok(hr == D3D_OK, "IDirect3DDevice7_GetCaps returned %08x\n", hr);
2065
2066     if (!(d3dcaps.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_CUBEMAP))
2067     {
2068         skip("No cubemap support\n");
2069     }
2070     else
2071     {
2072         /* Test loading mipmapped cubemap texture subrectangle from another similar texture. */
2073         for (i = 0; i < 2; i++)
2074         {
2075             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2076             ddsd.dwSize = sizeof(ddsd);
2077             ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
2078             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
2079             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES;
2080             ddsd.dwWidth = 128;
2081             ddsd.dwHeight = 128;
2082             U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
2083             U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
2084             U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
2085             U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
2086             U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
2087             U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
2088             hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &cube_face_levels[i][0][0], NULL);
2089             ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2090             if (FAILED(hr)) goto out;
2091
2092             flags = DDSCAPS2_CUBEMAP_NEGATIVEX;
2093             for (i1 = 1; i1 < 6; i1++, flags <<= 1)
2094             {
2095                 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
2096                 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | flags;
2097                 hr = IDirectDrawSurface7_GetAttachedSurface(cube_face_levels[i][0][0], &ddsd.ddsCaps, &cube_face_levels[i][i1][0]);
2098                 ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
2099                 if (FAILED(hr)) goto out;
2100             }
2101
2102             for (i1 = 0; i1 < 6; i1++)
2103             {
2104                 /* Check the number of created mipmaps */
2105                 memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2106                 ddsd.dwSize = sizeof(ddsd);
2107                 hr = IDirectDrawSurface7_GetSurfaceDesc(cube_face_levels[i][i1][0], &ddsd);
2108                 ok(hr==DD_OK,"IDirectDrawSurface7_GetSurfaceDesc returned: %x\n",hr);
2109                 ok(U2(ddsd).dwMipMapCount == 8, "unexpected mip count %u\n", U2(ddsd).dwMipMapCount);
2110                 if (U2(ddsd).dwMipMapCount != 8) goto out;
2111
2112                 for (i2 = 1; i2 < 8; i2++)
2113                 {
2114                     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
2115                     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
2116                     hr = IDirectDrawSurface7_GetAttachedSurface(cube_face_levels[i][i1][i2 - 1], &ddsd.ddsCaps, &cube_face_levels[i][i1][i2]);
2117                     ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
2118                     if (FAILED(hr)) goto out;
2119                 }
2120             }
2121         }
2122
2123         for (i = 0; i < 6; i++)
2124             for (i1 = 0; i1 < 8; i1++)
2125             {
2126                 memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2127                 ddsd.dwSize = sizeof(ddsd);
2128                 hr = IDirectDrawSurface7_Lock(cube_face_levels[0][i][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
2129                 ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2130                 if (FAILED(hr)) goto out;
2131
2132                 for (y = 0 ; y < ddsd.dwHeight; y++)
2133                 {
2134                     DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2135
2136                     for (x = 0; x < ddsd.dwWidth;  x++)
2137                     {
2138                         /* face number in low 4 bits of red, x stored in green component, y in blue. */
2139                         DWORD color = 0xf00000 | (i << 16) | (x << 8)  | y;
2140                         *textureRow++ = color;
2141                     }
2142                 }
2143
2144                 hr = IDirectDrawSurface7_Unlock(cube_face_levels[0][i][i1], NULL);
2145                 ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2146             }
2147
2148         for (i = 0; i < 6; i++)
2149             for (i1 = 0; i1 < 8; i1++)
2150             {
2151                 memset(&ddbltfx, 0, sizeof(ddbltfx));
2152                 ddbltfx.dwSize = sizeof(ddbltfx);
2153                 U5(ddbltfx).dwFillColor = 0;
2154                 hr = IDirectDrawSurface7_Blt(cube_face_levels[1][i][i1], NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
2155                 ok(hr == DD_OK, "IDirectDrawSurface7_Blt failed with %08x\n", hr);
2156             }
2157
2158         loadpoint.x = loadpoint.y = 10;
2159         loadrect.left = 30;
2160         loadrect.top = 20;
2161         loadrect.right = 93;
2162         loadrect.bottom = 52;
2163
2164         hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[1][0][0], &loadpoint, cube_face_levels[0][0][0], &loadrect,
2165                                         DDSCAPS2_CUBEMAP_ALLFACES);
2166         ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2167
2168         for (i = 0; i < 6; i++)
2169         {
2170             loadpoint.x = loadpoint.y = 10;
2171             loadrect.left = 30;
2172             loadrect.top = 20;
2173             loadrect.right = 93;
2174             loadrect.bottom = 52;
2175
2176             for (i1 = 0; i1 < 8; i1++)
2177             {
2178                 diff_count = 0;
2179                 diff_count2 = 0;
2180
2181                 memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2182                 ddsd.dwSize = sizeof(ddsd);
2183                 hr = IDirectDrawSurface7_Lock(cube_face_levels[1][i][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
2184                 ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2185                 if (FAILED(hr)) goto out;
2186
2187                 for (y = 0 ; y < ddsd.dwHeight; y++)
2188                 {
2189                     DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2190
2191                     for (x = 0; x < ddsd.dwWidth;  x++)
2192                     {
2193                         DWORD color = *textureRow++;
2194
2195                         if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
2196                             y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
2197                         {
2198                             if (color & 0xffffff) diff_count++;
2199                         }
2200                         else
2201                         {
2202                             DWORD r = (color & 0xff0000) >> 16;
2203                             DWORD g = (color & 0xff00) >> 8;
2204                             DWORD b = (color & 0xff);
2205
2206                             if (r != (0xf0 | i) || g != x + loadrect.left - loadpoint.x ||
2207                                 b != y + loadrect.top - loadpoint.y) diff_count++;
2208                         }
2209
2210                         /* This codepath is for software RGB device. It has what looks like some weird off by one errors, but may
2211                         technically be correct as it's not precisely defined by docs. */
2212                         if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
2213                             y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top + 1)
2214                         {
2215                             if (color & 0xffffff) diff_count2++;
2216                         }
2217                         else
2218                         {
2219                             DWORD r = (color & 0xff0000) >> 16;
2220                             DWORD g = (color & 0xff00) >> 8;
2221                             DWORD b = (color & 0xff);
2222
2223                             if (r != (0xf0 | i) || !IS_VALUE_NEAR(g, x + loadrect.left - loadpoint.x) ||
2224                                 !IS_VALUE_NEAR(b, y + loadrect.top - loadpoint.y)) diff_count2++;
2225                         }
2226                     }
2227                 }
2228
2229                 hr = IDirectDrawSurface7_Unlock(cube_face_levels[1][i][i1], NULL);
2230                 ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2231
2232                 ok(diff_count == 0 || diff_count2 == 0,
2233                     "Unexpected destination texture level pixels; %u differences at face %x level %d\n",
2234                     MIN(diff_count, diff_count2), i, i1);
2235
2236                 loadpoint.x /= 2;
2237                 loadpoint.y /= 2;
2238                 loadrect.top /= 2;
2239                 loadrect.left /= 2;
2240                 loadrect.right = (loadrect.right + 1) / 2;
2241                 loadrect.bottom = (loadrect.bottom + 1) / 2;
2242             }
2243         }
2244
2245         for (i = 0; i < 2; i++)
2246             for (i1 = 5; i1 >= 0; i1--)
2247                 for (i2 = 7; i2 >= 0; i2--)
2248                 {
2249                     if (cube_face_levels[i][i1][i2]) IDirectDrawSurface7_Release(cube_face_levels[i][i1][i2]);
2250                 }
2251         memset(cube_face_levels, 0, sizeof(cube_face_levels));
2252
2253         /* Test cubemap loading from regular texture. */
2254         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2255         ddsd.dwSize = sizeof(ddsd);
2256         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2257         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
2258         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES;
2259         ddsd.dwWidth = 128;
2260         ddsd.dwHeight = 128;
2261         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &cube_face_levels[0][0][0], NULL);
2262         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2263         if (FAILED(hr)) goto out;
2264
2265         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2266         ddsd.dwSize = sizeof(ddsd);
2267         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2268         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
2269         ddsd.dwWidth = 128;
2270         ddsd.dwHeight = 128;
2271         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[0][0], NULL);
2272         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2273         if (FAILED(hr)) goto out;
2274
2275         hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[0][0][0], NULL, texture_levels[0][0], NULL,
2276                                         DDSCAPS2_CUBEMAP_ALLFACES);
2277         ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2278
2279         IDirectDrawSurface7_Release(cube_face_levels[0][0][0]);
2280         memset(cube_face_levels, 0, sizeof(cube_face_levels));
2281         IDirectDrawSurface7_Release(texture_levels[0][0]);
2282         memset(texture_levels, 0, sizeof(texture_levels));
2283
2284         /* Test cubemap loading from cubemap with different number of faces. */
2285         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2286         ddsd.dwSize = sizeof(ddsd);
2287         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2288         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
2289         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX;
2290         ddsd.dwWidth = 128;
2291         ddsd.dwHeight = 128;
2292         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &cube_face_levels[0][0][0], NULL);
2293         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2294         if (FAILED(hr)) goto out;
2295
2296         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2297         ddsd.dwSize = sizeof(ddsd);
2298         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2299         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
2300         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_POSITIVEY;
2301         ddsd.dwWidth = 128;
2302         ddsd.dwHeight = 128;
2303         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &cube_face_levels[1][0][0], NULL);
2304         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2305         if (FAILED(hr)) goto out;
2306
2307         /* INVALIDPARAMS tests currently would fail because wine doesn't support partial cube faces
2308             (the above created cubemaps will have all faces. */
2309         hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[0][0][0], NULL, cube_face_levels[1][0][0], NULL,
2310                                         DDSCAPS2_CUBEMAP_ALLFACES);
2311         todo_wine ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2312
2313         hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[0][0][0], NULL, cube_face_levels[1][0][0], NULL,
2314                                         DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_POSITIVEY);
2315         todo_wine ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2316
2317         hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[0][0][0], NULL, cube_face_levels[1][0][0], NULL,
2318                                         DDSCAPS2_CUBEMAP_POSITIVEX);
2319         todo_wine ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2320
2321         hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[1][0][0], NULL, cube_face_levels[0][0][0], NULL,
2322                                         DDSCAPS2_CUBEMAP_ALLFACES);
2323         ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2324
2325         hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[1][0][0], NULL, cube_face_levels[0][0][0], NULL,
2326                                         DDSCAPS2_CUBEMAP_POSITIVEX);
2327         ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2328
2329         hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[1][0][0], NULL, cube_face_levels[0][0][0], NULL,
2330                                         DDSCAPS2_CUBEMAP_POSITIVEZ);
2331         ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2332
2333         IDirectDrawSurface7_Release(cube_face_levels[0][0][0]);
2334         IDirectDrawSurface7_Release(cube_face_levels[1][0][0]);
2335         memset(cube_face_levels, 0, sizeof(cube_face_levels));
2336     }
2337
2338     /* Test texture loading with different mip level count (larger levels match, smaller levels missing in destination. */
2339     for (i = 0; i < 2; i++)
2340     {
2341         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2342         ddsd.dwSize = sizeof(ddsd);
2343         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT;
2344         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
2345         ddsd.dwWidth = 128;
2346         ddsd.dwHeight = 128;
2347         U2(ddsd).dwMipMapCount = i ? 4 : 8;
2348         U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
2349         U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
2350         U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
2351         U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
2352         U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
2353         U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
2354         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[i][0], NULL);
2355         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2356         if (FAILED(hr)) goto out;
2357
2358         /* Check the number of created mipmaps */
2359         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2360         ddsd.dwSize = sizeof(ddsd);
2361         hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[i][0], &ddsd);
2362         ok(hr==DD_OK,"IDirectDrawSurface7_GetSurfaceDesc returned: %x\n",hr);
2363         ok(U2(ddsd).dwMipMapCount == (i ? 4 : 8), "unexpected mip count %u\n", U2(ddsd).dwMipMapCount);
2364         if (U2(ddsd).dwMipMapCount != (i ? 4 : 8)) goto out;
2365
2366         for (i1 = 1; i1 < (i ? 4 : 8); i1++)
2367         {
2368             hr = IDirectDrawSurface7_GetAttachedSurface(texture_levels[i][i1 - 1], &ddsd.ddsCaps, &texture_levels[i][i1]);
2369             ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
2370             if (FAILED(hr)) goto out;
2371         }
2372     }
2373
2374     for (i1 = 0; i1 < 8; i1++)
2375     {
2376         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2377         ddsd.dwSize = sizeof(ddsd);
2378         hr = IDirectDrawSurface7_Lock(texture_levels[0][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
2379         ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2380         if (FAILED(hr)) goto out;
2381
2382         for (y = 0 ; y < ddsd.dwHeight; y++)
2383         {
2384             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2385
2386             for (x = 0; x < ddsd.dwWidth;  x++)
2387             {
2388                 /* x stored in green component, y in blue. */
2389                 DWORD color = 0xf00000 | (i1 << 16) | (x << 8)  | y;
2390                 *textureRow++ = color;
2391             }
2392         }
2393
2394         hr = IDirectDrawSurface7_Unlock(texture_levels[0][i1], NULL);
2395         ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2396     }
2397
2398     for (i1 = 0; i1 < 4; i1++)
2399     {
2400         memset(&ddbltfx, 0, sizeof(ddbltfx));
2401         ddbltfx.dwSize = sizeof(ddbltfx);
2402         U5(ddbltfx).dwFillColor = 0;
2403         hr = IDirectDrawSurface7_Blt(texture_levels[1][i1], NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
2404         ok(hr == DD_OK, "IDirectDrawSurface7_Blt failed with %08x\n", hr);
2405     }
2406
2407     loadpoint.x = loadpoint.y = 31;
2408     loadrect.left = 30;
2409     loadrect.top = 20;
2410     loadrect.right = 93;
2411     loadrect.bottom = 52;
2412
2413     /* Destination mip levels are a subset of source mip levels. */
2414     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
2415     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2416
2417     for (i1 = 0; i1 < 4; i1++)
2418     {
2419         diff_count = 0;
2420         diff_count2 = 0;
2421
2422         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2423         ddsd.dwSize = sizeof(ddsd);
2424         hr = IDirectDrawSurface7_Lock(texture_levels[1][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
2425         ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2426         if (FAILED(hr)) goto out;
2427
2428         for (y = 0 ; y < ddsd.dwHeight; y++)
2429         {
2430             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2431
2432             for (x = 0; x < ddsd.dwWidth;  x++)
2433             {
2434                 DWORD color = *textureRow++;
2435
2436                 if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
2437                     y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
2438                 {
2439                     if (color & 0xffffff) diff_count++;
2440                 }
2441                 else
2442                 {
2443                     DWORD r = (color & 0xff0000) >> 16;
2444                     DWORD g = (color & 0xff00) >> 8;
2445                     DWORD b = (color & 0xff);
2446
2447                     if (r != (0xf0 | i1) || g != x + loadrect.left - loadpoint.x ||
2448                         b != y + loadrect.top - loadpoint.y) diff_count++;
2449                 }
2450
2451                 /* This codepath is for software RGB device. It has what looks like some weird off by one errors, but may
2452                 technically be correct as it's not precisely defined by docs. */
2453                 if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
2454                     y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top + 1)
2455                 {
2456                     if (color & 0xffffff) diff_count2++;
2457                 }
2458                 else
2459                 {
2460                     DWORD r = (color & 0xff0000) >> 16;
2461                     DWORD g = (color & 0xff00) >> 8;
2462                     DWORD b = (color & 0xff);
2463
2464                     if (r != (0xf0 | i1) || !IS_VALUE_NEAR(g, x + loadrect.left - loadpoint.x) ||
2465                         !IS_VALUE_NEAR(b, y + loadrect.top - loadpoint.y)) diff_count2++;
2466                 }
2467             }
2468         }
2469
2470         hr = IDirectDrawSurface7_Unlock(texture_levels[1][i1], NULL);
2471         ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2472
2473         ok(diff_count == 0 || diff_count2 == 0, "Unexpected destination texture level pixels; %u differences at %d level\n",
2474              MIN(diff_count, diff_count2), i1);
2475
2476         loadpoint.x /= 2;
2477         loadpoint.y /= 2;
2478         loadrect.top /= 2;
2479         loadrect.left /= 2;
2480         loadrect.right = (loadrect.right + 1) / 2;
2481         loadrect.bottom = (loadrect.bottom + 1) / 2;
2482     }
2483
2484     /* Destination mip levels are a superset of source mip levels (should fail). */
2485     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[0][0], &loadpoint, texture_levels[1][0], &loadrect, 0);
2486     ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2487
2488     for (i = 0; i < 2; i++)
2489     {
2490         for (i1 = 7; i1 >= 0; i1--)
2491         {
2492             if (texture_levels[i][i1]) IDirectDrawSurface7_Release(texture_levels[i][i1]);
2493         }
2494     }
2495     memset(texture_levels, 0, sizeof(texture_levels));
2496
2497     /* Test loading from mipmap texture to a regular texture that matches one sublevel in size. */
2498     memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2499     ddsd.dwSize = sizeof(ddsd);
2500     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
2501     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
2502     ddsd.dwWidth = 128;
2503     ddsd.dwHeight = 128;
2504     U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
2505     U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
2506     U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
2507     U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
2508     U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
2509     U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
2510     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[0][0], NULL);
2511     ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2512     if (FAILED(hr)) goto out;
2513
2514     memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2515     ddsd.dwSize = sizeof(ddsd);
2516     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
2517     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
2518     ddsd.dwWidth = 32;
2519     ddsd.dwHeight = 32;
2520     U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
2521     U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
2522     U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
2523     U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
2524     U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
2525     U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
2526     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[1][0], NULL);
2527     ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2528     if (FAILED(hr)) goto out;
2529
2530     for (i1 = 1; i1 < 8; i1++)
2531     {
2532         hr = IDirectDrawSurface7_GetAttachedSurface(texture_levels[0][i1 - 1], &ddsd.ddsCaps, &texture_levels[0][i1]);
2533         ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
2534         if (FAILED(hr)) goto out;
2535     }
2536
2537     for (i1 = 0; i1 < 8; i1++)
2538     {
2539         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2540         ddsd.dwSize = sizeof(ddsd);
2541         hr = IDirectDrawSurface7_Lock(texture_levels[0][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
2542         ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2543         if (FAILED(hr)) goto out;
2544
2545         for (y = 0 ; y < ddsd.dwHeight; y++)
2546         {
2547             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2548
2549             for (x = 0; x < ddsd.dwWidth;  x++)
2550             {
2551                 /* x stored in green component, y in blue. */
2552                 DWORD color = 0xf00000 | (i1 << 16) | (x << 8)  | y;
2553                 *textureRow++ = color;
2554             }
2555         }
2556
2557         hr = IDirectDrawSurface7_Unlock(texture_levels[0][i1], NULL);
2558         ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2559     }
2560
2561     memset(&ddbltfx, 0, sizeof(ddbltfx));
2562     ddbltfx.dwSize = sizeof(ddbltfx);
2563     U5(ddbltfx).dwFillColor = 0;
2564     hr = IDirectDrawSurface7_Blt(texture_levels[1][0], NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
2565     ok(hr == DD_OK, "IDirectDrawSurface7_Blt failed with %08x\n", hr);
2566
2567     loadpoint.x = loadpoint.y = 32;
2568     loadrect.left = 32;
2569     loadrect.top = 32;
2570     loadrect.right = 96;
2571     loadrect.bottom = 96;
2572
2573     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
2574     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2575
2576     loadpoint.x /= 4;
2577     loadpoint.y /= 4;
2578     loadrect.top /= 4;
2579     loadrect.left /= 4;
2580     loadrect.right = (loadrect.right + 3) / 4;
2581     loadrect.bottom = (loadrect.bottom + 3) / 4;
2582
2583     /* NOTE: something in either nvidia driver or directx9 on WinXP appears to be broken:
2584      * this kind of Load calls (to subset with smaller surface(s)) produces wrong results with
2585      * copied subrectangles divided more than needed, without apparent logic. But it works
2586      * as expected on qemu / Win98 / directx7 / RGB device. Some things are broken on XP, e.g.
2587      * some games don't work that worked in Win98, so it is assumed here XP results are wrong.
2588      * The following code attempts to detect broken results, actual tests will then be skipped
2589      */
2590     load_mip_subset_broken = TRUE;
2591     diff_count = 0;
2592
2593     memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2594     ddsd.dwSize = sizeof(ddsd);
2595     hr = IDirectDrawSurface7_Lock(texture_levels[1][0], NULL, &ddsd, DDLOCK_WAIT, NULL);
2596     ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2597     if (FAILED(hr)) goto out;
2598
2599     for (y = 0 ; y < ddsd.dwHeight; y++)
2600     {
2601         DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2602
2603         for (x = 0; x < ddsd.dwWidth;  x++)
2604         {
2605             DWORD color = *textureRow++;
2606
2607             if (x < 2 || x >= 2 + 4 ||
2608                 y < 2 || y >= 2 + 4)
2609             {
2610                 if (color & 0xffffff) diff_count++;
2611             }
2612             else
2613             {
2614                 DWORD r = (color & 0xff0000) >> 16;
2615
2616                 if ((r & (0xf0)) != 0xf0) diff_count++;
2617             }
2618         }
2619     }
2620
2621     if (diff_count) load_mip_subset_broken = FALSE;
2622
2623     if (load_mip_subset_broken) {
2624         skip("IDirect3DDevice7_Load is broken (happens on some modern Windows installations like XP). Skipping affected tests.\n");
2625     } else {
2626         diff_count = 0;
2627
2628         for (y = 0 ; y < ddsd.dwHeight; y++)
2629         {
2630             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2631
2632             for (x = 0; x < ddsd.dwWidth;  x++)
2633             {
2634                 DWORD color = *textureRow++;
2635
2636                 if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
2637                     y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
2638                 {
2639                     if (color & 0xffffff) diff_count++;
2640                 }
2641                 else
2642                 {
2643                     DWORD r = (color & 0xff0000) >> 16;
2644                     DWORD g = (color & 0xff00) >> 8;
2645                     DWORD b = (color & 0xff);
2646
2647                     if (r != (0xf0 | 2) || g != x + loadrect.left - loadpoint.x ||
2648                         b != y + loadrect.top - loadpoint.y) diff_count++;
2649                 }
2650             }
2651         }
2652     }
2653
2654     hr = IDirectDrawSurface7_Unlock(texture_levels[1][0], NULL);
2655     ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2656
2657     ok(diff_count == 0, "Unexpected destination texture level pixels; %u differences\n", diff_count);
2658
2659     for (i = 0; i < 2; i++)
2660     {
2661         for (i1 = 7; i1 >= 0; i1--)
2662         {
2663             if (texture_levels[i][i1]) IDirectDrawSurface7_Release(texture_levels[i][i1]);
2664         }
2665     }
2666     memset(texture_levels, 0, sizeof(texture_levels));
2667
2668     if (!load_mip_subset_broken)
2669     {
2670         /* Test loading when destination mip levels are a subset of source mip levels and start from smaller
2671         * surface (than first source mip level)
2672         */
2673         for (i = 0; i < 2; i++)
2674         {
2675             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2676             ddsd.dwSize = sizeof(ddsd);
2677             ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
2678             if (i) ddsd.dwFlags |= DDSD_MIPMAPCOUNT;
2679             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
2680             ddsd.dwWidth = i ? 32 : 128;
2681             ddsd.dwHeight = i ? 32 : 128;
2682             if (i) U2(ddsd).dwMipMapCount = 4;
2683             U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
2684             U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
2685             U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
2686             U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
2687             U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
2688             U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
2689             hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[i][0], NULL);
2690             ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2691             if (FAILED(hr)) goto out;
2692
2693             /* Check the number of created mipmaps */
2694             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2695             ddsd.dwSize = sizeof(ddsd);
2696             hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[i][0], &ddsd);
2697             ok(hr==DD_OK,"IDirectDrawSurface7_GetSurfaceDesc returned: %x\n",hr);
2698             ok(U2(ddsd).dwMipMapCount == (i ? 4 : 8), "unexpected mip count %u\n", U2(ddsd).dwMipMapCount);
2699             if (U2(ddsd).dwMipMapCount != (i ? 4 : 8)) goto out;
2700
2701             for (i1 = 1; i1 < (i ? 4 : 8); i1++)
2702             {
2703                 hr = IDirectDrawSurface7_GetAttachedSurface(texture_levels[i][i1 - 1], &ddsd.ddsCaps, &texture_levels[i][i1]);
2704                 ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
2705                 if (FAILED(hr)) goto out;
2706             }
2707         }
2708
2709         for (i1 = 0; i1 < 8; i1++)
2710         {
2711             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2712             ddsd.dwSize = sizeof(ddsd);
2713             hr = IDirectDrawSurface7_Lock(texture_levels[0][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
2714             ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2715             if (FAILED(hr)) goto out;
2716
2717             for (y = 0 ; y < ddsd.dwHeight; y++)
2718             {
2719                 DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2720
2721                 for (x = 0; x < ddsd.dwWidth;  x++)
2722                 {
2723                     /* x stored in green component, y in blue. */
2724                     DWORD color = 0xf00000 | (i1 << 16) | (x << 8)  | y;
2725                     *textureRow++ = color;
2726                 }
2727             }
2728
2729             hr = IDirectDrawSurface7_Unlock(texture_levels[0][i1], NULL);
2730             ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2731         }
2732
2733         for (i1 = 0; i1 < 4; i1++)
2734         {
2735             memset(&ddbltfx, 0, sizeof(ddbltfx));
2736             ddbltfx.dwSize = sizeof(ddbltfx);
2737             U5(ddbltfx).dwFillColor = 0;
2738             hr = IDirectDrawSurface7_Blt(texture_levels[1][i1], NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
2739             ok(hr == DD_OK, "IDirectDrawSurface7_Blt failed with %08x\n", hr);
2740         }
2741
2742         loadpoint.x = loadpoint.y = 0;
2743         loadrect.left = 0;
2744         loadrect.top = 0;
2745         loadrect.right = 64;
2746         loadrect.bottom = 64;
2747
2748         hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
2749         ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2750
2751         i = 0;
2752         for (i1 = 0; i1 < 8 && i < 4; i1++)
2753         {
2754             DDSURFACEDESC2 ddsd2;
2755
2756             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2757             ddsd.dwSize = sizeof(ddsd);
2758             hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[0][i1], &ddsd);
2759             ok(SUCCEEDED(hr), "IDirectDrawSurface7_GetSurfaceDesc returned %#x.\n", hr);
2760
2761             memset(&ddsd2, 0, sizeof(DDSURFACEDESC2));
2762             ddsd2.dwSize = sizeof(ddsd2);
2763             hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[1][i], &ddsd2);
2764             ok(SUCCEEDED(hr), "IDirectDrawSurface7_GetSurfaceDesc returned %#x.\n", hr);
2765
2766             if (ddsd.dwWidth == ddsd2.dwWidth && ddsd.dwHeight == ddsd2.dwHeight)
2767             {
2768                 diff_count = 0;
2769
2770                 memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2771                 ddsd.dwSize = sizeof(ddsd);
2772                 hr = IDirectDrawSurface7_Lock(texture_levels[1][i], NULL, &ddsd, DDLOCK_WAIT, NULL);
2773                 ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2774                 if (FAILED(hr)) goto out;
2775
2776                 for (y = 0 ; y < ddsd.dwHeight; y++)
2777                 {
2778                     DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2779
2780                     for (x = 0; x < ddsd.dwWidth;  x++)
2781                     {
2782                         DWORD color = *textureRow++;
2783
2784                         if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
2785                             y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
2786                         {
2787                             if (color & 0xffffff) diff_count++;
2788                         }
2789                         else
2790                         {
2791                             DWORD r = (color & 0xff0000) >> 16;
2792                             DWORD g = (color & 0xff00) >> 8;
2793                             DWORD b = (color & 0xff);
2794
2795                             if (r != (0xf0 | i1) || g != x + loadrect.left - loadpoint.x ||
2796                                 b != y + loadrect.top - loadpoint.y) diff_count++;
2797                         }
2798                     }
2799                 }
2800
2801                 hr = IDirectDrawSurface7_Unlock(texture_levels[1][i], NULL);
2802                 ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2803
2804                 ok(diff_count == 0, "Unexpected destination texture level pixels; %u differences at %d level\n", diff_count, i1);
2805
2806                 i++;
2807             }
2808
2809             loadpoint.x /= 2;
2810             loadpoint.y /= 2;
2811             loadrect.top /= 2;
2812             loadrect.left /= 2;
2813             loadrect.right = (loadrect.right + 1) / 2;
2814             loadrect.bottom = (loadrect.bottom + 1) / 2;
2815         }
2816
2817         for (i = 0; i < 2; i++)
2818         {
2819             for (i1 = 7; i1 >= 0; i1--)
2820             {
2821                 if (texture_levels[i][i1]) IDirectDrawSurface7_Release(texture_levels[i][i1]);
2822             }
2823         }
2824         memset(texture_levels, 0, sizeof(texture_levels));
2825     }
2826
2827     /* Test palette copying. */
2828     for (i = 0; i < 2; i++)
2829     {
2830         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2831         ddsd.dwSize = sizeof(ddsd);
2832         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
2833         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
2834         ddsd.dwWidth = 128;
2835         ddsd.dwHeight = 128;
2836         U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
2837         U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
2838         U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 8;
2839         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[i][0], NULL);
2840         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2841         if (FAILED(hr)) goto out;
2842
2843         /* Check the number of created mipmaps */
2844         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2845         ddsd.dwSize = sizeof(ddsd);
2846         hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[i][0], &ddsd);
2847         ok(hr==DD_OK,"IDirectDrawSurface7_GetSurfaceDesc returned: %x\n",hr);
2848         ok(U2(ddsd).dwMipMapCount == 8, "unexpected mip count %u\n", U2(ddsd).dwMipMapCount);
2849         if (U2(ddsd).dwMipMapCount != 8) goto out;
2850
2851         for (i1 = 1; i1 < 8; i1++)
2852         {
2853             hr = IDirectDrawSurface7_GetAttachedSurface(texture_levels[i][i1 - 1], &ddsd.ddsCaps, &texture_levels[i][i1]);
2854             ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
2855             if (FAILED(hr)) goto out;
2856         }
2857     }
2858
2859     memset(table1, 0, sizeof(table1));
2860     for (i = 0; i < 3; i++)
2861     {
2862         table1[0].peBlue = i + 1;
2863         hr = IDirectDraw7_CreatePalette(lpDD, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, table1, &palettes[i], NULL);
2864         ok(hr == DD_OK, "CreatePalette returned %08x\n", hr);
2865         if (FAILED(hr))
2866         {
2867             skip("IDirectDraw7_CreatePalette failed; skipping further tests\n");
2868             goto out;
2869         }
2870     }
2871
2872     hr = IDirectDrawSurface7_SetPalette(texture_levels[0][0], palettes[0]);
2873     ok(hr==DD_OK, "IDirectDrawSurface7_SetPalette returned: %x\n", hr);
2874
2875     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], NULL, texture_levels[0][0], NULL, 0);
2876     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2877
2878     hr = IDirectDrawSurface7_GetPalette(texture_levels[1][0], &palettes[4]);
2879     ok(hr==DDERR_NOPALETTEATTACHED, "IDirectDrawSurface7_GetPalette returned: %x\n", hr);
2880
2881     hr = IDirectDrawSurface7_SetPalette(texture_levels[0][1], palettes[1]);
2882     todo_wine ok(hr==DDERR_NOTONMIPMAPSUBLEVEL, "IDirectDrawSurface7_SetPalette returned: %x\n", hr);
2883     hr = IDirectDrawSurface7_SetPalette(texture_levels[1][0], palettes[2]);
2884     ok(hr==DD_OK, "IDirectDrawSurface7_SetPalette returned: %x\n", hr);
2885
2886     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], NULL, texture_levels[0][0], NULL, 0);
2887     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2888
2889     memset(table1, 0, sizeof(table1));
2890     hr = IDirectDrawSurface7_GetPalette(texture_levels[1][0], &palettes[4]);
2891     ok(hr==DD_OK, "IDirectDrawSurface7_GetPalette returned: %x\n", hr);
2892     if (SUCCEEDED(hr))
2893     {
2894         hr = IDirectDrawPalette_GetEntries(palettes[4], 0, 0, 256, table1);
2895         ok(hr == DD_OK, "IDirectDrawPalette_GetEntries returned %08x\n", hr);
2896         ok(table1[0].peBlue == 1, "Unexpected palette color after load: %u\n", (unsigned)table1[0].peBlue);
2897     }
2898
2899     /* Test colorkey copying. */
2900     ddckey.dwColorSpaceLowValue = ddckey.dwColorSpaceHighValue = 64;
2901     hr = IDirectDrawSurface7_SetColorKey(texture_levels[0][0], DDCKEY_SRCBLT, &ddckey);
2902     ok(hr==DD_OK, "IDirectDrawSurface7_SetColorKey returned: %x\n", hr);
2903     hr = IDirectDrawSurface7_SetColorKey(texture_levels[0][1], DDCKEY_SRCBLT, &ddckey);
2904     todo_wine ok(hr==DDERR_NOTONMIPMAPSUBLEVEL, "IDirectDrawSurface7_SetColorKey returned: %x\n", hr);
2905
2906     hr = IDirectDrawSurface7_GetColorKey(texture_levels[1][0], DDCKEY_SRCBLT, &ddckey);
2907     ok(hr==DDERR_NOCOLORKEY, "IDirectDrawSurface7_GetColorKey returned: %x\n", hr);
2908
2909     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], NULL, texture_levels[0][0], NULL, 0);
2910     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2911
2912     hr = IDirectDrawSurface7_GetColorKey(texture_levels[1][0], DDCKEY_SRCBLT, &ddckey);
2913     ok(hr==DD_OK, "IDirectDrawSurface7_GetColorKey returned: %x\n", hr);
2914     ok(ddckey.dwColorSpaceLowValue == ddckey.dwColorSpaceHighValue && ddckey.dwColorSpaceLowValue == 64,
2915         "Unexpected color key values: %u - %u\n", ddckey.dwColorSpaceLowValue, ddckey.dwColorSpaceHighValue);
2916
2917     out:
2918
2919     for (i = 0; i < 5; i++)
2920     {
2921         if (palettes[i]) IDirectDrawPalette_Release(palettes[i]);
2922     }
2923
2924     for (i = 0; i < 2; i++)
2925     {
2926         for (i1 = 7; i1 >= 0; i1--)
2927         {
2928             if (texture_levels[i][i1]) IDirectDrawSurface7_Release(texture_levels[i][i1]);
2929         }
2930     }
2931
2932     for (i = 0; i < 2; i++)
2933         for (i1 = 5; i1 >= 0; i1--)
2934             for (i2 = 7; i2 >= 0; i2--)
2935             {
2936                 if (cube_face_levels[i][i1][i2]) IDirectDrawSurface7_Release(cube_face_levels[i][i1][i2]);
2937             }
2938 }
2939
2940 static void SetMaterialTest(void)
2941 {
2942     HRESULT rc;
2943
2944     rc =IDirect3DDevice7_SetMaterial(lpD3DDevice, NULL);
2945     ok(rc == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %x\n", rc);
2946 }
2947
2948 static void ComputeSphereVisibility(void)
2949 {
2950     D3DMATRIX proj, view, world;
2951     D3DVALUE radius[3];
2952     D3DVECTOR center[3];
2953     DWORD result[3];
2954     HRESULT rc;
2955
2956     world._11=1.0; world._12=0.0; world._13=0.0; world._14=0.0;
2957     world._21=0.0; world._22=1.0; world._23=0.0; world._24=0.0;
2958     world._31=0.0; world._32=0.0; world._33=1.0; world._34=0.0;
2959     world._41=0.0; world._42=0.0; world._43=0.0; world._44=1.0;
2960
2961     view._11=1.000000; view._12=0.000000; view._13=0.000000; view._14=0.000000;
2962     view._21=0.000000; view._22=0.768221; view._23=-0.640185; view._24=0.000000;
2963     view._31=-0.000000; view._32=0.640185; view._33=0.768221; view._34=0.000000;
2964     view._41=-14.852037; view._42=9.857489; view._43=11.600972; view._44=1.000000;
2965
2966     proj._11=1.810660; proj._12=0.000000; proj._13=0.00000; proj._14=0.000000;
2967     proj._21=0.000000; proj._22=2.414213; proj._23=0.000000, proj._24=0.000000;
2968     proj._31=0.000000; proj._32=0.000000; proj._33=1.020408, proj._34=1.000000;
2969     proj._41=0.000000; proj._42=0.000000; proj._43=-0.102041; proj._44=0.000000;
2970
2971     IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_WORLD, &world);
2972     IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_VIEW , &view);
2973     IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_PROJECTION, &proj);
2974
2975     U1(center[0]).x=11.461533;
2976     U2(center[0]).y=-4.761727;
2977     U3(center[0]).z=-1.171646;
2978
2979     radius[0]=38.252632;
2980
2981     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 1, 0, result);
2982
2983     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
2984     ok(result[0] == 0x3f, "Expected 0x3f, got %x\n", result[0]);
2985
2986     U1(center[0]).x=-3.515620; U2(center[0]).y=-1.560661; U3(center[0]).z=-12.464638;
2987     radius[0]=4.354097;
2988     U1(center[1]).x=14.290396; U2(center[1]).y=-2.981143; U3(center[1]).z=-24.311312;
2989     radius[1]=12.500704;
2990     U1(center[2]).x=1.461626; U2(center[2]).y=-6.093709; U3(center[2]).z=-13.901010;
2991     radius[2]=17.251318;
2992
2993     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 3, 0, result);
2994
2995     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
2996     ok(result[0] == 0x103d, "Expected 0x103d, got %x\n", result[0]);
2997     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
2998     ok(result[1] == 0x3f, "Expected 0x3f, got %x\n", result[1]);
2999     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
3000     ok(result[2] == 0x3f, "Expected 0x3f, got %x\n", result[2]);
3001
3002     view._11=1.0; view._12=0.0; view._13=0.0; view._14=0.0;
3003     view._21=0.0; view._22=1.0; view._23=0.0; view._24=0.0;
3004     view._31=0.0; view._32=0.0; view._33=1.0; view._34=0.0;
3005     view._41=0.0; view._42=0.0; view._43=0.0; view._44=1.0;
3006
3007     proj._11=10.0; proj._12=0.0; proj._13=0.0; proj._14=0.0;
3008     proj._21=0.0; proj._22=10.0; proj._23=0.0, proj._24=0.0;
3009     proj._31=0.0; proj._32=0.0; proj._33=10.0, proj._34=0.0;
3010     proj._41=0.0; proj._42=0.0; proj._43=0.0; proj._44=1.0;
3011
3012     U1(center[0]).x=0.0;
3013     U2(center[0]).y=0.0;
3014     U3(center[0]).z=0.05;
3015
3016     radius[0]=0.04;
3017
3018     IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_VIEW , &view);
3019     IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_PROJECTION, &proj);
3020
3021     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 1, 0, result);
3022
3023     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
3024     ok(result[0] == 0x0, "Expected 0x0, got %x\n", result[0]);
3025
3026     proj._11=1.0; proj._12=0.0; proj._13=0.0; proj._14=0.0;
3027     proj._21=0.0; proj._22=1.0; proj._23=0.0, proj._24=0.0;
3028     proj._31=0.0; proj._32=0.0; proj._33=1.0, proj._34=0.0;
3029     proj._41=0.0; proj._42=0.0; proj._43=0.0; proj._44=1.0;
3030
3031     IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_PROJECTION, &proj);
3032
3033     U1(center[0]).x=0.0;
3034     U2(center[0]).y=0.0;
3035     U3(center[0]).z=0.5;
3036
3037     radius[0]=0.5;
3038
3039     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 1, 0, result);
3040
3041     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
3042     ok(result[0] == 0x0, "Expected 0x0, got %x\n", result[0]);
3043
3044     U1(center[0]).x=0.0;
3045     U2(center[0]).y=0.0;
3046     U3(center[0]).z=0.0;
3047
3048     radius[0]=0.0;
3049
3050     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 1, 0, result);
3051
3052     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
3053     ok(result[0] == 0x0, "Expected 0x0, got %x\n", result[0]);
3054
3055     U1(center[0]).x=-1.0;
3056     U2(center[0]).y=-1.0;
3057     U3(center[0]).z=0.50;
3058
3059     radius[0]=0.25;
3060
3061     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 1, 0, result);
3062
3063     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
3064     ok(result[0] == 0x9, "Expected 0x9, got %x\n", result[0]);
3065
3066     U1(center[0]).x=-20.0;
3067     U2(center[0]).y=0.0;
3068     U3(center[0]).z=0.50;
3069
3070     radius[0]=3.0;
3071
3072     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 1, 0, result);
3073
3074     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
3075     ok(result[0] == 0x103d, "Expected 0x103d, got %x\n", result[0]);
3076
3077     U1(center[0]).x=20.0;
3078     U2(center[0]).y=0.0;
3079     U3(center[0]).z=0.50;
3080
3081     radius[0]=3.0f;
3082
3083     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 1, 0, result);
3084
3085     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
3086     ok(result[0] == 0x203e, "Expected 0x203e, got %x\n", result[0]);
3087
3088     U1(center[0]).x=0.0;
3089     U2(center[0]).y=-20.0;
3090     U3(center[0]).z=0.50;
3091
3092     radius[0]=3.0;
3093
3094     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 1, 0, result);
3095
3096     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
3097     ok(result[0] == 0x803b, "Expected 0x803b, got %x\n", result[0]);
3098
3099     U1(center[0]).x=0.0;
3100     U2(center[0]).y=20.0;
3101     U3(center[0]).z=0.5;
3102
3103     radius[0]=3.0;
3104
3105     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 1, 0, result);
3106
3107     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
3108     ok(result[0] == 0x4037, "Expected 0x4037, got %x\n", result[0]);
3109
3110     U1(center[0]).x=0.0;
3111     U2(center[0]).y=0.0;
3112     U3(center[0]).z=-20;
3113
3114     radius[0]=3.0;
3115
3116     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 1, 0, result);
3117
3118     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
3119     ok(result[0] == 0x1001f, "Expected 0x1001f, got %x\n", result[0]);
3120
3121     U1(center[0]).x=0.0;
3122     U2(center[0]).y=0.0;
3123     U3(center[0]).z=20.0;
3124
3125     radius[0]=3.0;
3126
3127     rc = IDirect3DDevice7_ComputeSphereVisibility(lpD3DDevice, center, radius, 1, 0, result);
3128
3129     ok(rc == D3D_OK, "Expected D3D_OK, received %x\n", rc);
3130     ok(result[0] == 0x2002f, "Expected 0x2002f, got %x\n", result[0]);
3131 }
3132
3133 static void SetRenderTargetTest(void)
3134 {
3135     HRESULT hr;
3136     IDirectDrawSurface7 *newrt, *failrt, *oldrt;
3137     D3DVIEWPORT7 vp;
3138     DDSURFACEDESC2 ddsd, ddsd2;
3139     DWORD stateblock;
3140
3141     memset(&ddsd, 0, sizeof(ddsd));
3142     ddsd.dwSize = sizeof(ddsd);
3143     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
3144     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_3DDEVICE;
3145     ddsd.dwWidth = 64;
3146     ddsd.dwHeight = 64;
3147
3148     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &newrt, NULL);
3149     ok(hr == DD_OK, "IDirectDraw7_CreateSurface failed, hr=0x%08x\n", hr);
3150     if(FAILED(hr))
3151     {
3152         skip("Skipping SetRenderTarget test\n");
3153         return;
3154     }
3155
3156     memset(&ddsd2, 0, sizeof(ddsd2));
3157     ddsd2.dwSize = sizeof(ddsd2);
3158     ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
3159     ddsd2.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER;
3160     ddsd2.dwWidth = 64;
3161     ddsd2.dwHeight = 64;
3162     U4(ddsd2).ddpfPixelFormat.dwSize = sizeof(U4(ddsd2).ddpfPixelFormat);
3163     U4(ddsd2).ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
3164     U1(U4(ddsd2).ddpfPixelFormat).dwZBufferBitDepth = 16;
3165     U3(U4(ddsd2).ddpfPixelFormat).dwZBitMask = 0x0000FFFF;
3166
3167     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd2, &failrt, NULL);
3168     ok(hr == DD_OK, "IDirectDraw7_CreateSurface failed, hr=0x%08x\n", hr);
3169
3170     memset(&vp, 0, sizeof(vp));
3171     vp.dwX = 10;
3172     vp.dwY = 10;
3173     vp.dwWidth = 246;
3174     vp.dwHeight = 246;
3175     vp.dvMinZ = 0.25;
3176     vp.dvMaxZ = 0.75;
3177     hr = IDirect3DDevice7_SetViewport(lpD3DDevice, &vp);
3178     ok(hr == D3D_OK, "IDirect3DDevice7_SetViewport failed, hr=0x%08x\n", hr);
3179
3180     hr = IDirect3DDevice7_GetRenderTarget(lpD3DDevice, &oldrt);
3181     ok(hr == DD_OK, "IDirect3DDevice7_GetRenderTarget failed, hr=0x%08x\n", hr);
3182
3183     hr = IDirect3DDevice7_SetRenderTarget(lpD3DDevice, failrt, 0);
3184     ok(hr != D3D_OK, "IDirect3DDevice7_SetRenderTarget succeeded\n");
3185
3186     hr = IDirect3DDevice7_SetRenderTarget(lpD3DDevice, newrt, 0);
3187     ok(hr == D3D_OK, "IDirect3DDevice7_SetRenderTarget failed, hr=0x%08x\n", hr);
3188     memset(&vp, 0xff, sizeof(vp));
3189     hr = IDirect3DDevice7_GetViewport(lpD3DDevice, &vp);
3190     ok(hr == D3D_OK, "IDirect3DDevice7_GetViewport failed, hr=0x%08x\n", hr);
3191     ok(vp.dwX == 10, "vp.dwX is %u, expected 10\n", vp.dwX);
3192     ok(vp.dwY == 10, "vp.dwY is %u, expected 10\n", vp.dwY);
3193     ok(vp.dwWidth == 246, "vp.dwWidth is %u, expected 246\n", vp.dwWidth);
3194     ok(vp.dwHeight == 246, "vp.dwHeight is %u, expected 246\n", vp.dwHeight);
3195     ok(vp.dvMinZ == 0.25, "vp.dvMinZ is %f, expected 0.25\n", vp.dvMinZ);
3196     ok(vp.dvMaxZ == 0.75, "vp.dvMaxZ is %f, expected 0.75\n", vp.dvMaxZ);
3197
3198     memset(&vp, 0, sizeof(vp));
3199     vp.dwX = 0;
3200     vp.dwY = 0;
3201     vp.dwWidth = 64;
3202     vp.dwHeight = 64;
3203     vp.dvMinZ = 0.0;
3204     vp.dvMaxZ = 1.0;
3205     hr = IDirect3DDevice7_SetViewport(lpD3DDevice, &vp);
3206     ok(hr == D3D_OK, "IDirect3DDevice7_SetViewport failed, hr=0x%08x\n", hr);
3207
3208     hr = IDirect3DDevice7_BeginStateBlock(lpD3DDevice);
3209     ok(hr == D3D_OK, "IDirect3DDevice7_BeginStateblock failed, hr=0x%08x\n", hr);
3210     hr = IDirect3DDevice7_SetRenderTarget(lpD3DDevice, oldrt, 0);
3211     ok(hr == D3D_OK, "IDirect3DDevice7_SetRenderTarget failed, hr=0x%08x\n", hr);
3212
3213     /* Check this twice, before and after ending the stateblock */
3214     memset(&vp, 0xff, sizeof(vp));
3215     hr = IDirect3DDevice7_GetViewport(lpD3DDevice, &vp);
3216     ok(hr == D3D_OK, "IDirect3DDevice7_GetViewport failed, hr=0x%08x\n", hr);
3217     ok(vp.dwX == 0, "vp.dwX is %u, expected 0\n", vp.dwX);
3218     ok(vp.dwY == 0, "vp.dwY is %u, expected 0\n", vp.dwY);
3219     ok(vp.dwWidth == 64, "vp.dwWidth is %u, expected 64\n", vp.dwWidth);
3220     ok(vp.dwHeight == 64, "vp.dwHeight is %u, expected 64\n", vp.dwHeight);
3221     ok(vp.dvMinZ == 0.0, "vp.dvMinZ is %f, expected 0.0\n", vp.dvMinZ);
3222     ok(vp.dvMaxZ == 1.0, "vp.dvMaxZ is %f, expected 1.0\n", vp.dvMaxZ);
3223
3224     hr = IDirect3DDevice7_EndStateBlock(lpD3DDevice, &stateblock);
3225     ok(hr == D3D_OK, "IDirect3DDevice7_EndStateblock failed, hr=0x%08x\n", hr);
3226
3227     memset(&vp, 0xff, sizeof(vp));
3228     hr = IDirect3DDevice7_GetViewport(lpD3DDevice, &vp);
3229     ok(hr == D3D_OK, "IDirect3DDevice7_GetViewport failed, hr=0x%08x\n", hr);
3230     ok(vp.dwX == 0, "vp.dwX is %u, expected 0\n", vp.dwX);
3231     ok(vp.dwY == 0, "vp.dwY is %u, expected 0\n", vp.dwY);
3232     ok(vp.dwWidth == 64, "vp.dwWidth is %u, expected 64\n", vp.dwWidth);
3233     ok(vp.dwHeight == 64, "vp.dwHeight is %u, expected 64\n", vp.dwHeight);
3234     ok(vp.dvMinZ == 0.0, "vp.dvMinZ is %f, expected 0.0\n", vp.dvMinZ);
3235     ok(vp.dvMaxZ == 1.0, "vp.dvMaxZ is %f, expected 1.0\n", vp.dvMaxZ);
3236
3237     hr = IDirect3DDevice7_DeleteStateBlock(lpD3DDevice, stateblock);
3238     ok(hr == D3D_OK, "IDirect3DDevice7_DeleteStateblock failed, hr=0x%08x\n", hr);
3239
3240     memset(&vp, 0, sizeof(vp));
3241     vp.dwX = 0;
3242     vp.dwY = 0;
3243     vp.dwWidth = 256;
3244     vp.dwHeight = 256;
3245     vp.dvMinZ = 0.0;
3246     vp.dvMaxZ = 0.0;
3247     hr = IDirect3DDevice7_SetViewport(lpD3DDevice, &vp);
3248     ok(hr == D3D_OK, "IDirect3DDevice7_SetViewport failed, hr=0x%08x\n", hr);
3249
3250     IDirectDrawSurface7_Release(oldrt);
3251     IDirectDrawSurface7_Release(newrt);
3252     IDirectDrawSurface7_Release(failrt);
3253 }
3254
3255 static const UINT *expect_messages;
3256
3257 static LRESULT CALLBACK test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
3258 {
3259     if (expect_messages && message == *expect_messages) ++expect_messages;
3260
3261     return DefWindowProcA(hwnd, message, wparam, lparam);
3262 }
3263
3264 static void test_wndproc(void)
3265 {
3266     LONG_PTR proc, ddraw_proc;
3267     IDirectDraw7 *ddraw7;
3268     WNDCLASSA wc = {0};
3269     HWND window;
3270     HRESULT hr;
3271     ULONG ref;
3272
3273     static const UINT messages[] =
3274     {
3275         WM_WINDOWPOSCHANGING,
3276         WM_MOVE,
3277         WM_SIZE,
3278         WM_WINDOWPOSCHANGING,
3279         WM_ACTIVATE,
3280         WM_SETFOCUS,
3281         0,
3282     };
3283
3284     /* DDSCL_EXCLUSIVE replaces the window's window proc. */
3285     hr = pDirectDrawCreateEx(NULL, (void **)&ddraw7, &IID_IDirectDraw7, NULL);
3286     if (FAILED(hr))
3287     {
3288         skip("Failed to create IDirectDraw7 object (%#x), skipping tests.\n", hr);
3289         return;
3290     }
3291
3292     wc.lpfnWndProc = test_proc;
3293     wc.lpszClassName = "d3d7_test_wndproc_wc";
3294     ok(RegisterClassA(&wc), "Failed to register window class.\n");
3295
3296     window = CreateWindowA("d3d7_test_wndproc_wc", "d3d7_test",
3297             WS_MAXIMIZE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
3298
3299     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3300     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
3301             (LONG_PTR)test_proc, proc);
3302
3303     expect_messages = messages;
3304
3305     hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3306     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3307     if (FAILED(hr))
3308     {
3309         IDirectDraw7_Release(ddraw7);
3310         goto done;
3311     }
3312
3313     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
3314     expect_messages = NULL;
3315
3316     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3317     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
3318             (LONG_PTR)test_proc, proc);
3319
3320     ref = IDirectDraw7_Release(ddraw7);
3321     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3322
3323     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3324     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
3325             (LONG_PTR)test_proc, proc);
3326
3327     /* DDSCL_NORMAL doesn't. */
3328     hr = pDirectDrawCreateEx(NULL, (void **)&ddraw7, &IID_IDirectDraw7, NULL);
3329     if (FAILED(hr))
3330     {
3331         skip("Failed to create IDirectDraw7 object (%#x), skipping tests.\n", hr);
3332         return;
3333     }
3334
3335     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3336     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
3337             (LONG_PTR)test_proc, proc);
3338
3339     hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
3340     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3341     if (FAILED(hr))
3342     {
3343         IDirectDraw7_Release(ddraw7);
3344         goto done;
3345     }
3346
3347     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3348     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
3349             (LONG_PTR)test_proc, proc);
3350
3351     ref = IDirectDraw7_Release(ddraw7);
3352     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3353
3354     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3355     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
3356             (LONG_PTR)test_proc, proc);
3357
3358     /* The original window proc is only restored by ddraw if the current
3359      * window proc matches the one ddraw set. This also affects switching
3360      * from DDSCL_NORMAL to DDSCL_EXCLUSIVE. */
3361     hr = pDirectDrawCreateEx(NULL, (void **)&ddraw7, &IID_IDirectDraw7, NULL);
3362     if (FAILED(hr))
3363     {
3364         skip("Failed to create IDirectDraw7 object (%#x), skipping tests.\n", hr);
3365         return;
3366     }
3367
3368     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3369     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
3370             (LONG_PTR)test_proc, proc);
3371
3372     hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3373     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3374     if (FAILED(hr))
3375     {
3376         IDirectDraw7_Release(ddraw7);
3377         goto done;
3378     }
3379
3380     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3381     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
3382             (LONG_PTR)test_proc, proc);
3383     ddraw_proc = proc;
3384
3385     hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_NORMAL);
3386     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3387     if (FAILED(hr))
3388     {
3389         IDirectDraw7_Release(ddraw7);
3390         goto done;
3391     }
3392
3393     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3394     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
3395             (LONG_PTR)test_proc, proc);
3396
3397     hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3398     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3399     if (FAILED(hr))
3400     {
3401         IDirectDraw7_Release(ddraw7);
3402         goto done;
3403     }
3404
3405     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
3406     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
3407             (LONG_PTR)test_proc, proc);
3408
3409     hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_NORMAL);
3410     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3411     if (FAILED(hr))
3412     {
3413         IDirectDraw7_Release(ddraw7);
3414         goto done;
3415     }
3416
3417     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3418     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
3419             (LONG_PTR)DefWindowProcA, proc);
3420
3421     hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3422     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3423     if (FAILED(hr))
3424     {
3425         IDirectDraw7_Release(ddraw7);
3426         goto done;
3427     }
3428
3429     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)ddraw_proc);
3430     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
3431             (LONG_PTR)DefWindowProcA, proc);
3432
3433     ref = IDirectDraw7_Release(ddraw7);
3434     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3435
3436     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3437     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
3438             (LONG_PTR)test_proc, proc);
3439
3440     hr = pDirectDrawCreateEx(NULL, (void **)&ddraw7, &IID_IDirectDraw7, NULL);
3441     if (FAILED(hr))
3442     {
3443         skip("Failed to create IDirectDraw7 object (%#x), skipping tests.\n", hr);
3444         return;
3445     }
3446
3447     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3448     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
3449             (LONG_PTR)test_proc, proc);
3450
3451     hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3452     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
3453     if (FAILED(hr))
3454     {
3455         IDirectDraw7_Release(ddraw7);
3456         goto done;
3457     }
3458
3459     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
3460     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
3461             (LONG_PTR)test_proc, proc);
3462
3463     ref = IDirectDraw7_Release(ddraw7);
3464     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
3465
3466     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
3467     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
3468             (LONG_PTR)DefWindowProcA, proc);
3469
3470 done:
3471     expect_messages = NULL;
3472     DestroyWindow(window);
3473     UnregisterClassA("d3d7_test_wndproc_wc", GetModuleHandleA(NULL));
3474 }
3475
3476 static void VertexBufferLockRest(void)
3477 {
3478     D3DVERTEXBUFFERDESC desc;
3479     IDirect3DVertexBuffer7 *buffer;
3480     HRESULT hr;
3481     unsigned int i;
3482     void *data;
3483     const struct
3484     {
3485         DWORD flags;
3486         const char *debug_string;
3487         HRESULT result;
3488     }
3489     test_data[] =
3490     {
3491         {0,                                         "(none)",                                       D3D_OK },
3492         {DDLOCK_WAIT,                               "DDLOCK_WAIT",                                  D3D_OK },
3493         {DDLOCK_EVENT,                              "DDLOCK_EVENT",                                 D3D_OK },
3494         {DDLOCK_READONLY,                           "DDLOCK_READONLY",                              D3D_OK },
3495         {DDLOCK_WRITEONLY,                          "DDLOCK_WRITEONLY",                             D3D_OK },
3496         {DDLOCK_NOSYSLOCK,                          "DDLOCK_NOSYSLOCK",                             D3D_OK },
3497         {DDLOCK_NOOVERWRITE,                        "DDLOCK_NOOVERWRITE",                           D3D_OK },
3498         {DDLOCK_DISCARDCONTENTS,                    "DDLOCK_DISCARDCONTENTS",                       D3D_OK },
3499
3500         {DDLOCK_READONLY | DDLOCK_WRITEONLY,        "DDLOCK_READONLY | DDLOCK_WRITEONLY",           D3D_OK },
3501         {DDLOCK_READONLY | DDLOCK_DISCARDCONTENTS,  "DDLOCK_READONLY | DDLOCK_DISCARDCONTENTS",     D3D_OK },
3502         {0xdeadbeef,                                "0xdeadbeef",                                   D3D_OK },
3503     };
3504
3505     memset(&desc, 0 , sizeof(desc));
3506     desc.dwSize = sizeof(desc);
3507     desc.dwCaps = 0;
3508     desc.dwFVF = D3DFVF_XYZ;
3509     desc.dwNumVertices = 64;
3510     hr = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &buffer, 0);
3511     ok(hr == D3D_OK, "IDirect3D7_CreateVertexBuffer failed, 0x%08x\n", hr);
3512
3513     for(i = 0; i < (sizeof(test_data) / sizeof(*test_data)); i++)
3514     {
3515         hr = IDirect3DVertexBuffer7_Lock(buffer, test_data[i].flags, &data, NULL);
3516         ok(hr == test_data[i].result, "Lock flags %s returned 0x%08x, expected 0x%08x\n",
3517             test_data[i].debug_string, hr, test_data[i].result);
3518         if(SUCCEEDED(hr))
3519         {
3520             ok(data != NULL, "The data pointer returned by Lock is NULL\n");
3521             hr = IDirect3DVertexBuffer7_Unlock(buffer);
3522             ok(hr == D3D_OK, "IDirect3DVertexBuffer7_Unlock failed, 0x%08x\n", hr);
3523         }
3524     }
3525
3526     IDirect3DVertexBuffer7_Release(buffer);
3527 }
3528
3529 static void FindDevice(void)
3530 {
3531     static const struct
3532     {
3533         const GUID *guid;
3534         int todo;
3535     } deviceGUIDs[] =
3536     {
3537         {&IID_IDirect3DRampDevice, 1},
3538         {&IID_IDirect3DRGBDevice},
3539     };
3540
3541     static const GUID *nonexistent_deviceGUIDs[] = {&IID_IDirect3DMMXDevice,
3542                                                     &IID_IDirect3DRefDevice,
3543                                                     &IID_IDirect3DTnLHalDevice,
3544                                                     &IID_IDirect3DNullDevice};
3545
3546     D3DFINDDEVICESEARCH search = {0};
3547     D3DFINDDEVICERESULT result = {0};
3548     IDirect3DDevice *d3dhal;
3549     HRESULT hr;
3550     int i;
3551
3552     /* Test invalid parameters. */
3553     hr = IDirect3D_FindDevice(Direct3D1, NULL, NULL);
3554     ok(hr == DDERR_INVALIDPARAMS,
3555        "Expected IDirect3D1::FindDevice to return DDERR_INVALIDPARAMS, got 0x%08x\n", hr);
3556
3557     hr = IDirect3D_FindDevice(Direct3D1, NULL, &result);
3558     ok(hr == DDERR_INVALIDPARAMS,
3559        "Expected IDirect3D1::FindDevice to return DDERR_INVALIDPARAMS, got 0x%08x\n", hr);
3560
3561     hr = IDirect3D_FindDevice(Direct3D1, &search, NULL);
3562     ok(hr == DDERR_INVALIDPARAMS,
3563        "Expected IDirect3D1::FindDevice to return DDERR_INVALIDPARAMS, got 0x%08x\n", hr);
3564
3565     search.dwSize = 0;
3566     result.dwSize = 0;
3567
3568     hr = IDirect3D_FindDevice(Direct3D1, &search, &result);
3569     ok(hr == DDERR_INVALIDPARAMS,
3570        "Expected IDirect3D1::FindDevice to return DDERR_INVALIDPARAMS, got 0x%08x\n", hr);
3571
3572     search.dwSize = sizeof(search) + 1;
3573     result.dwSize = sizeof(result) + 1;
3574
3575     hr = IDirect3D_FindDevice(Direct3D1, &search, &result);
3576     ok(hr == DDERR_INVALIDPARAMS,
3577        "Expected IDirect3D1::FindDevice to return DDERR_INVALIDPARAMS, got 0x%08x\n", hr);
3578
3579     /* Specifying no flags is permitted. */
3580     search.dwSize = sizeof(search);
3581     search.dwFlags = 0;
3582     result.dwSize = sizeof(result);
3583
3584     hr = IDirect3D_FindDevice(Direct3D1, &search, &result);
3585     ok(hr == D3D_OK,
3586        "Expected IDirect3D1::FindDevice to return D3D_OK, got 0x%08x\n", hr);
3587
3588     /* Try an arbitrary non-device GUID. */
3589     search.dwSize = sizeof(search);
3590     search.dwFlags = D3DFDS_GUID;
3591     search.guid = IID_IDirect3D;
3592     result.dwSize = sizeof(result);
3593
3594     hr = IDirect3D_FindDevice(Direct3D1, &search, &result);
3595     ok(hr == DDERR_NOTFOUND,
3596        "Expected IDirect3D1::FindDevice to return DDERR_NOTFOUND, got 0x%08x\n", hr);
3597
3598     /* These GUIDs appear to be never present. */
3599     for (i = 0; i < sizeof(nonexistent_deviceGUIDs)/sizeof(nonexistent_deviceGUIDs[0]); i++)
3600     {
3601         search.dwSize = sizeof(search);
3602         search.dwFlags = D3DFDS_GUID;
3603         search.guid = *nonexistent_deviceGUIDs[i];
3604         result.dwSize = sizeof(result);
3605
3606         hr = IDirect3D_FindDevice(Direct3D1, &search, &result);
3607         ok(hr == DDERR_NOTFOUND,
3608            "[%d] Expected IDirect3D1::FindDevice to return DDERR_NOTFOUND, got 0x%08x\n", i, hr);
3609     }
3610
3611     /* The HAL device can only be enumerated if hardware acceleration is present. */
3612     search.dwSize = sizeof(search);
3613     search.dwFlags = D3DFDS_GUID;
3614     search.guid = IID_IDirect3DHALDevice;
3615     result.dwSize = sizeof(result);
3616
3617     hr = IDirect3D_FindDevice(Direct3D1, &search, &result);
3618     trace("IDirect3D::FindDevice returned 0x%08x for the HAL device GUID\n", hr);
3619     if (SUCCEEDED(hr))
3620     {
3621         hr = IDirectDrawSurface_QueryInterface(Surface1, &IID_IDirect3DHALDevice, (void **)&d3dhal);
3622         /* Currently Wine only supports the creation of one Direct3D device
3623          * for a given DirectDraw instance. */
3624         todo_wine
3625         ok(SUCCEEDED(hr), "Expected IDirectDrawSurface::QueryInterface to succeed, got 0x%08x\n", hr);
3626
3627         if (SUCCEEDED(hr))
3628             IDirect3DDevice_Release(d3dhal);
3629     }
3630     else
3631     {
3632         hr = IDirectDrawSurface_QueryInterface(Surface1, &IID_IDirect3DHALDevice, (void **)&d3dhal);
3633         ok(FAILED(hr), "Expected IDirectDrawSurface::QueryInterface to fail, got 0x%08x\n", hr);
3634
3635         if (SUCCEEDED(hr))
3636             IDirect3DDevice_Release(d3dhal);
3637     }
3638
3639     /* These GUIDs appear to be always present. */
3640     for (i = 0; i < sizeof(deviceGUIDs)/sizeof(deviceGUIDs[0]); i++)
3641     {
3642         search.dwSize = sizeof(search);
3643         search.dwFlags = D3DFDS_GUID;
3644         search.guid = *deviceGUIDs[i].guid;
3645         result.dwSize = sizeof(result);
3646
3647         hr = IDirect3D_FindDevice(Direct3D1, &search, &result);
3648
3649         if (deviceGUIDs[i].todo)
3650         {
3651             todo_wine
3652             ok(hr == D3D_OK,
3653                "[%d] Expected IDirect3D1::FindDevice to return D3D_OK, got 0x%08x\n", i, hr);
3654         }
3655         else
3656         {
3657             ok(hr == D3D_OK,
3658                "[%d] Expected IDirect3D1::FindDevice to return D3D_OK, got 0x%08x\n", i, hr);
3659         }
3660     }
3661
3662     /* Curiously the color model criteria seem to be ignored. */
3663     search.dwSize = sizeof(search);
3664     search.dwFlags = D3DFDS_COLORMODEL;
3665     search.dcmColorModel = 0xdeadbeef;
3666     result.dwSize = sizeof(result);
3667
3668     hr = IDirect3D_FindDevice(Direct3D1, &search, &result);
3669     todo_wine
3670     ok(hr == D3D_OK,
3671        "Expected IDirect3D1::FindDevice to return D3D_OK, got 0x%08x\n", hr);
3672 }
3673
3674 static void BackBuffer3DCreateSurfaceTest(void)
3675 {
3676     DDSURFACEDESC ddsd;
3677     DDSURFACEDESC created_ddsd;
3678     DDSURFACEDESC2 ddsd2;
3679     IDirectDrawSurface *surf;
3680     IDirectDrawSurface4 *surf4;
3681     IDirectDrawSurface7 *surf7;
3682     HRESULT hr;
3683     IDirectDraw2 *dd2;
3684     IDirectDraw4 *dd4;
3685     IDirectDraw7 *dd7;
3686     DDCAPS ddcaps;
3687     IDirect3DDevice *d3dhal;
3688
3689     const DWORD caps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE;
3690     const DWORD expected_caps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
3691
3692     memset(&ddcaps, 0, sizeof(ddcaps));
3693     ddcaps.dwSize = sizeof(DDCAPS);
3694     hr = IDirectDraw_GetCaps(DirectDraw1, &ddcaps, NULL);
3695     if (!(ddcaps.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
3696     {
3697         skip("DDraw reported no VIDEOMEMORY cap. Broken video driver? Skipping surface caps tests.\n");
3698         return ;
3699     }
3700
3701     memset(&ddsd, 0, sizeof(ddsd));
3702     ddsd.dwSize = sizeof(ddsd);
3703     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
3704     ddsd.dwWidth = 64;
3705     ddsd.dwHeight = 64;
3706     ddsd.ddsCaps.dwCaps = caps;
3707     memset(&ddsd2, 0, sizeof(ddsd2));
3708     ddsd2.dwSize = sizeof(ddsd2);
3709     ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
3710     ddsd2.dwWidth = 64;
3711     ddsd2.dwHeight = 64;
3712     ddsd2.ddsCaps.dwCaps = caps;
3713     memset(&created_ddsd, 0, sizeof(created_ddsd));
3714     created_ddsd.dwSize = sizeof(DDSURFACEDESC);
3715
3716     hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &surf, NULL);
3717     ok(SUCCEEDED(hr), "IDirectDraw_CreateSurface failed: 0x%08x\n", hr);
3718     if (surf != NULL)
3719     {
3720         hr = IDirectDrawSurface_GetSurfaceDesc(surf, &created_ddsd);
3721         ok(SUCCEEDED(hr), "IDirectDraw_GetSurfaceDesc failed: 0x%08x\n", hr);
3722         ok(created_ddsd.ddsCaps.dwCaps == expected_caps,
3723            "GetSurfaceDesc returned caps %x, expected %x\n", created_ddsd.ddsCaps.dwCaps,
3724            expected_caps);
3725
3726         hr = IDirectDrawSurface_QueryInterface(surf, &IID_IDirect3DHALDevice, (void **)&d3dhal);
3727         /* Currently Wine only supports the creation of one Direct3D device
3728            for a given DirectDraw instance. It has been created already
3729            in D3D1_createObjects() - IID_IDirect3DRGBDevice */
3730         todo_wine ok(SUCCEEDED(hr), "Expected IDirectDrawSurface::QueryInterface to succeed, got 0x%08x\n", hr);
3731
3732         if (SUCCEEDED(hr))
3733             IDirect3DDevice_Release(d3dhal);
3734
3735         IDirectDrawSurface_Release(surf);
3736     }
3737
3738     hr = IDirectDraw_QueryInterface(DirectDraw1, &IID_IDirectDraw2, (void **) &dd2);
3739     ok(SUCCEEDED(hr), "IDirectDraw_QueryInterface failed: 0x%08x\n", hr);
3740
3741     hr = IDirectDraw2_CreateSurface(dd2, &ddsd, &surf, NULL);
3742     ok(hr == DDERR_INVALIDCAPS, "IDirectDraw2_CreateSurface didn't return %x08x, but %x08x\n",
3743        DDERR_INVALIDCAPS, hr);
3744
3745     IDirectDraw2_Release(dd2);
3746
3747     hr = IDirectDraw_QueryInterface(DirectDraw1, &IID_IDirectDraw4, (void **) &dd4);
3748     ok(SUCCEEDED(hr), "IDirectDraw_QueryInterface failed: 0x%08x\n", hr);
3749
3750     hr = IDirectDraw4_CreateSurface(dd4, &ddsd2, &surf4, NULL);
3751     ok(hr == DDERR_INVALIDCAPS, "IDirectDraw4_CreateSurface didn't return %x08x, but %x08x\n",
3752        DDERR_INVALIDCAPS, hr);
3753
3754     IDirectDraw4_Release(dd4);
3755
3756     hr = IDirectDraw_QueryInterface(DirectDraw1, &IID_IDirectDraw7, (void **) &dd7);
3757     ok(SUCCEEDED(hr), "IDirectDraw_QueryInterface failed: 0x%08x\n", hr);
3758
3759     hr = IDirectDraw7_CreateSurface(dd7, &ddsd2, &surf7, NULL);
3760     ok(hr == DDERR_INVALIDCAPS, "IDirectDraw7_CreateSurface didn't return %x08x, but %x08x\n",
3761        DDERR_INVALIDCAPS, hr);
3762
3763     IDirectDraw7_Release(dd7);
3764 }
3765
3766 static void BackBuffer3DAttachmentTest(void)
3767 {
3768     HRESULT hr;
3769     IDirectDrawSurface *surface1, *surface2, *surface3, *surface4;
3770     DDSURFACEDESC ddsd;
3771     HWND window = CreateWindow( "static", "ddraw_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
3772
3773     hr = IDirectDraw_SetCooperativeLevel(DirectDraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
3774     ok(hr == DD_OK, "SetCooperativeLevel returned %08x\n", hr);
3775
3776     /* Perform attachment tests on a back-buffer */
3777     memset(&ddsd, 0, sizeof(ddsd));
3778     ddsd.dwSize = sizeof(ddsd);
3779     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
3780     ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE;
3781     ddsd.dwWidth = GetSystemMetrics(SM_CXSCREEN);
3782     ddsd.dwHeight = GetSystemMetrics(SM_CYSCREEN);
3783     hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &surface2, NULL);
3784     ok(SUCCEEDED(hr), "CreateSurface returned: %x\n",hr);
3785
3786     if (surface2 != NULL)
3787     {
3788         /* Try a single primary and a two back buffers */
3789         memset(&ddsd, 0, sizeof(ddsd));
3790         ddsd.dwSize = sizeof(ddsd);
3791         ddsd.dwFlags = DDSD_CAPS;
3792         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
3793         hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &surface1, NULL);
3794         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
3795
3796         memset(&ddsd, 0, sizeof(ddsd));
3797         ddsd.dwSize = sizeof(ddsd);
3798         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
3799         ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE;
3800         ddsd.dwWidth = GetSystemMetrics(SM_CXSCREEN);
3801         ddsd.dwHeight = GetSystemMetrics(SM_CYSCREEN);
3802         hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &surface3, NULL);
3803         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
3804
3805         /* This one has a different size */
3806         memset(&ddsd, 0, sizeof(ddsd));
3807         ddsd.dwSize = sizeof(ddsd);
3808         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
3809         ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE;
3810         ddsd.dwWidth = 128;
3811         ddsd.dwHeight = 128;
3812         hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &surface4, NULL);
3813         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
3814
3815         hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
3816         todo_wine ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE),
3817            "Attaching a back buffer to a front buffer returned %08x\n", hr);
3818         if(SUCCEEDED(hr))
3819         {
3820             /* Try the reverse without detaching first */
3821             hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
3822             ok(hr == DDERR_SURFACEALREADYATTACHED, "Attaching an attached surface to its attachee returned %08x\n", hr);
3823             hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
3824             ok(hr == DD_OK, "DeleteAttachedSurface failed with %08x\n", hr);
3825         }
3826         hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
3827         todo_wine ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE),
3828            "Attaching a front buffer to a back buffer returned %08x\n", hr);
3829         if(SUCCEEDED(hr))
3830         {
3831             /* Try to detach reversed */
3832             hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
3833             ok(hr == DDERR_CANNOTDETACHSURFACE, "DeleteAttachedSurface returned %08x\n", hr);
3834             /* Now the proper detach */
3835             hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface1);
3836             ok(hr == DD_OK, "DeleteAttachedSurface failed with %08x\n", hr);
3837         }
3838         hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface3);
3839         todo_wine ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE),
3840            "Attaching a back buffer to another back buffer returned %08x\n", hr);
3841         if(SUCCEEDED(hr))
3842         {
3843             hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface3);
3844             ok(hr == DD_OK, "DeleteAttachedSurface failed with %08x\n", hr);
3845         }
3846         hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
3847         ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a back buffer to a front buffer of different size returned %08x\n", hr);
3848         hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
3849         ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a front buffer to a back buffer of different size returned %08x\n", hr);
3850
3851         IDirectDrawSurface_Release(surface4);
3852         IDirectDrawSurface_Release(surface3);
3853         IDirectDrawSurface_Release(surface2);
3854         IDirectDrawSurface_Release(surface1);
3855     }
3856
3857     hr =IDirectDraw_SetCooperativeLevel(DirectDraw1, NULL, DDSCL_NORMAL);
3858     ok(hr == DD_OK, "SetCooperativeLevel returned %08x\n", hr);
3859
3860     DestroyWindow(window);
3861 }
3862
3863 START_TEST(d3d)
3864 {
3865     init_function_pointers();
3866     if(!pDirectDrawCreateEx) {
3867         win_skip("function DirectDrawCreateEx not available\n");
3868         return;
3869     }
3870
3871     if(!CreateDirect3D()) {
3872         skip("Skipping d3d7 tests\n");
3873     } else {
3874         LightTest();
3875         ProcessVerticesTest();
3876         StateTest();
3877         SceneTest();
3878         LimitTest();
3879         D3D7EnumTest();
3880         SetMaterialTest();
3881         ComputeSphereVisibility();
3882         CapsTest();
3883         VertexBufferDescTest();
3884         D3D7_OldRenderStateTest();
3885         DeviceLoadTest();
3886         SetRenderTargetTest();
3887         VertexBufferLockRest();
3888         ReleaseDirect3D();
3889     }
3890
3891     if (!D3D1_createObjects()) {
3892         skip("Skipping d3d1 tests\n");
3893     } else {
3894         Direct3D1Test();
3895         TextureLoadTest();
3896         ViewportTest();
3897         FindDevice();
3898         BackBuffer3DCreateSurfaceTest();
3899         BackBuffer3DAttachmentTest();
3900         D3D1_releaseObjects();
3901     }
3902
3903     test_wndproc();
3904 }