Revert "winex11.drv: Optimise getting the bits of a DIB after calling SetDIBits."
[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 #include <assert.h>
24 #include "wine/test.h"
25 #include "initguid.h"
26 #include "ddraw.h"
27 #include "d3d.h"
28
29 static LPDIRECTDRAW7           lpDD = NULL;
30 static LPDIRECT3D7             lpD3D = NULL;
31 static LPDIRECTDRAWSURFACE7    lpDDS = NULL;
32 static LPDIRECTDRAWSURFACE7    lpDDSdepth = NULL;
33 static LPDIRECT3DDEVICE7       lpD3DDevice = NULL;
34 static LPDIRECT3DVERTEXBUFFER7 lpVBufSrc = NULL;
35 static LPDIRECT3DVERTEXBUFFER7 lpVBufDest1 = NULL;
36 static LPDIRECT3DVERTEXBUFFER7 lpVBufDest2 = NULL;
37
38 static IDirectDraw *DirectDraw1 = NULL;
39 static IDirectDrawSurface *Surface1 = NULL;
40 static IDirect3D *Direct3D1 = NULL;
41 static IDirect3DDevice *Direct3DDevice1 = NULL;
42 static IDirect3DExecuteBuffer *ExecuteBuffer = NULL;
43 static IDirect3DViewport *Viewport = NULL;
44
45 typedef struct {
46     int total;
47     int rgb;
48     int hal;
49     int tnlhal;
50     int unk;
51 } D3D7ETest;
52
53 /* To compare bad floating point numbers. Not the ideal way to do it,
54  * but it should be enough for here */
55 #define comparefloat(a, b) ( (((a) - (b)) < 0.0001) && (((a) - (b)) > -0.0001) )
56
57 static HRESULT (WINAPI *pDirectDrawCreateEx)(LPGUID,LPVOID*,REFIID,LPUNKNOWN);
58
59 typedef struct _VERTEX
60 {
61     float x, y, z;  /* position */
62 } VERTEX, *LPVERTEX;
63
64 typedef struct _TVERTEX
65 {
66     float x, y, z;  /* position */
67     float rhw;
68 } TVERTEX, *LPTVERTEX;
69
70
71 static void init_function_pointers(void)
72 {
73     HMODULE hmod = GetModuleHandleA("ddraw.dll");
74     pDirectDrawCreateEx = (void*)GetProcAddress(hmod, "DirectDrawCreateEx");
75 }
76
77
78 static BOOL CreateDirect3D(void)
79 {
80     HRESULT rc;
81     DDSURFACEDESC2 ddsd;
82
83     rc = pDirectDrawCreateEx(NULL, (void**)&lpDD,
84         &IID_IDirectDraw7, NULL);
85     ok(rc==DD_OK || rc==DDERR_NODIRECTDRAWSUPPORT, "DirectDrawCreateEx returned: %x\n", rc);
86     if (!lpDD) {
87         trace("DirectDrawCreateEx() failed with an error %x\n", rc);
88         return FALSE;
89     }
90
91     rc = IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_NORMAL);
92     ok(rc==DD_OK, "SetCooperativeLevel returned: %x\n", rc);
93
94     rc = IDirectDraw7_QueryInterface(lpDD, &IID_IDirect3D7, (void**) &lpD3D);
95     if (rc == E_NOINTERFACE) return FALSE;
96     ok(rc==DD_OK, "QueryInterface returned: %x\n", rc);
97
98     memset(&ddsd, 0, sizeof(ddsd));
99     ddsd.dwSize = sizeof(ddsd);
100     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
101     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
102     ddsd.dwWidth = 256;
103     ddsd.dwHeight = 256;
104     rc = IDirectDraw7_CreateSurface(lpDD, &ddsd, &lpDDS, NULL);
105     if (!SUCCEEDED(rc))
106         return FALSE;
107
108     memset(&ddsd, 0, sizeof(ddsd));
109     ddsd.dwSize = sizeof(ddsd);
110     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
111     ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
112     U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
113     U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
114     U1(U4(ddsd).ddpfPixelFormat).dwZBufferBitDepth = 16;
115     U3(U4(ddsd).ddpfPixelFormat).dwZBitMask = 0x0000FFFF;
116     ddsd.dwWidth = 256;
117     ddsd.dwHeight = 256;
118     rc = IDirectDraw7_CreateSurface(lpDD, &ddsd, &lpDDSdepth, NULL);
119     ok(rc==DD_OK, "CreateSurface returned: %x\n", rc);
120     if (!SUCCEEDED(rc)) {
121         lpDDSdepth = NULL;
122     } else {
123         rc = IDirectDrawSurface_AddAttachedSurface(lpDDS, lpDDSdepth);
124         ok(rc == DD_OK, "IDirectDrawSurface_AddAttachedSurface returned %x\n", rc);
125         if (!SUCCEEDED(rc))
126             return FALSE;
127     }
128
129     rc = IDirect3D7_CreateDevice(lpD3D, &IID_IDirect3DTnLHalDevice, lpDDS,
130         &lpD3DDevice);
131     ok(rc==D3D_OK || rc==DDERR_NOPALETTEATTACHED || rc==E_OUTOFMEMORY, "CreateDevice returned: %x\n", rc);
132     if (!lpD3DDevice) {
133         trace("IDirect3D7::CreateDevice() for a TnL Hal device failed with an error %x, trying HAL\n", rc);
134         rc = IDirect3D7_CreateDevice(lpD3D, &IID_IDirect3DHALDevice, lpDDS,
135             &lpD3DDevice);
136         if (!lpD3DDevice) {
137             trace("IDirect3D7::CreateDevice() for a HAL device failed with an error %x, trying RGB\n", rc);
138             rc = IDirect3D7_CreateDevice(lpD3D, &IID_IDirect3DRGBDevice, lpDDS,
139                 &lpD3DDevice);
140             if (!lpD3DDevice) {
141                 trace("IDirect3D7::CreateDevice() for a RGB device failed with an error %x, giving up\n", rc);
142                 return FALSE;
143             }
144         }
145     }
146
147     return TRUE;
148 }
149
150 static void ReleaseDirect3D(void)
151 {
152     if (lpD3DDevice != NULL)
153     {
154         IDirect3DDevice7_Release(lpD3DDevice);
155         lpD3DDevice = NULL;
156     }
157
158     if (lpDDSdepth != NULL)
159     {
160         IDirectDrawSurface_Release(lpDDSdepth);
161         lpDDSdepth = NULL;
162     }
163
164     if (lpDDS != NULL)
165     {
166         IDirectDrawSurface_Release(lpDDS);
167         lpDDS = NULL;
168     }
169
170     if (lpD3D != NULL)
171     {
172         IDirect3D7_Release(lpD3D);
173         lpD3D = NULL;
174     }
175
176     if (lpDD != NULL)
177     {
178         IDirectDraw_Release(lpDD);
179         lpDD = NULL;
180     }
181 }
182
183 static void LightTest(void)
184 {
185     HRESULT rc;
186     D3DLIGHT7 light;
187     D3DLIGHT7 defaultlight;
188     BOOL bEnabled = FALSE;
189     float one = 1.0f;
190     float zero= 0.0f;
191     D3DMATERIAL7 mat;
192     BOOL enabled;
193     unsigned int i;
194     D3DDEVICEDESC7 caps;
195
196     /* Set a few lights with funky indices. */
197     memset(&light, 0, sizeof(light));
198     light.dltType = D3DLIGHT_DIRECTIONAL;
199     U1(light.dcvDiffuse).r = 0.5f;
200     U2(light.dcvDiffuse).g = 0.6f;
201     U3(light.dcvDiffuse).b = 0.7f;
202     U2(light.dvDirection).y = 1.f;
203
204     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 5, &light);
205     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
206     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 10, &light);
207     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
208     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 45, &light);
209     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
210
211
212     /* Try to retrieve a light beyond the indices of the lights that have
213        been set. */
214     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 50, &light);
215     ok(rc==DDERR_INVALIDPARAMS, "GetLight returned: %x\n", rc);
216     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 2, &light);
217     ok(rc==DDERR_INVALIDPARAMS, "GetLight returned: %x\n", rc);
218
219
220     /* Try to retrieve one of the lights that have been set */
221     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 10, &light);
222     ok(rc==D3D_OK, "GetLight returned: %x\n", rc);
223
224
225     /* Enable a light that have been previously set. */
226     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 10, TRUE);
227     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
228
229
230     /* Enable some lights that have not been previously set, and verify that
231        they have been initialized with proper default values. */
232     memset(&defaultlight, 0, sizeof(D3DLIGHT7));
233     defaultlight.dltType = D3DLIGHT_DIRECTIONAL;
234     U1(defaultlight.dcvDiffuse).r = 1.f;
235     U2(defaultlight.dcvDiffuse).g = 1.f;
236     U3(defaultlight.dcvDiffuse).b = 1.f;
237     U3(defaultlight.dvDirection).z = 1.f;
238
239     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 20, TRUE);
240     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
241     memset(&light, 0, sizeof(D3DLIGHT7));
242     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 20, &light);
243     ok(rc==D3D_OK, "GetLight returned: %x\n", rc);
244     ok(!memcmp(&light, &defaultlight, sizeof(D3DLIGHT7)),
245         "light data doesn't match expected default values\n" );
246
247     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 50, TRUE);
248     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
249     memset(&light, 0, sizeof(D3DLIGHT7));
250     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 50, &light);
251     ok(rc==D3D_OK, "GetLight returned: %x\n", rc);
252     ok(!memcmp(&light, &defaultlight, sizeof(D3DLIGHT7)),
253         "light data doesn't match expected default values\n" );
254
255
256     /* Disable one of the light that have been previously enabled. */
257     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 20, FALSE);
258     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
259
260     /* Try to retrieve the enable status of some lights */
261     /* Light 20 is supposed to be disabled */
262     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 20, &bEnabled );
263     ok(rc==D3D_OK, "GetLightEnable returned: %x\n", rc);
264     ok(!bEnabled, "GetLightEnable says the light is enabled\n");
265
266     /* Light 10 is supposed to be enabled */
267     bEnabled = FALSE;
268     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 10, &bEnabled );
269     ok(rc==D3D_OK, "GetLightEnable returned: %x\n", rc);
270     ok(bEnabled, "GetLightEnable says the light is disabled\n");
271
272     /* Light 80 has not been set */
273     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 80, &bEnabled );
274     ok(rc==DDERR_INVALIDPARAMS, "GetLightEnable returned: %x\n", rc);
275
276     /* Light 23 has not been set */
277     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 23, &bEnabled );
278     ok(rc==DDERR_INVALIDPARAMS, "GetLightEnable returned: %x\n", rc);
279
280     /* Set some lights with invalid parameters */
281     memset(&light, 0, sizeof(D3DLIGHT7));
282     light.dltType = 0;
283     U1(light.dcvDiffuse).r = 1.f;
284     U2(light.dcvDiffuse).g = 1.f;
285     U3(light.dcvDiffuse).b = 1.f;
286     U3(light.dvDirection).z = 1.f;
287     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 100, &light);
288     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
289
290     memset(&light, 0, sizeof(D3DLIGHT7));
291     light.dltType = 12345;
292     U1(light.dcvDiffuse).r = 1.f;
293     U2(light.dcvDiffuse).g = 1.f;
294     U3(light.dcvDiffuse).b = 1.f;
295     U3(light.dvDirection).z = 1.f;
296     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 101, &light);
297     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
298
299     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 102, NULL);
300     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
301
302     memset(&light, 0, sizeof(D3DLIGHT7));
303     light.dltType = D3DLIGHT_SPOT;
304     U1(light.dcvDiffuse).r = 1.f;
305     U2(light.dcvDiffuse).g = 1.f;
306     U3(light.dcvDiffuse).b = 1.f;
307     U3(light.dvDirection).z = 1.f;
308
309     light.dvAttenuation0 = -one / zero; /* -INFINITY */
310     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
311     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
312
313     light.dvAttenuation0 = -1.0;
314     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
315     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
316
317     light.dvAttenuation0 = 0.0;
318     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
319     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
320
321     light.dvAttenuation0 = 1.0;
322     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
323     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
324
325     light.dvAttenuation0 = one / zero; /* +INFINITY */
326     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
327     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
328
329     light.dvAttenuation0 = zero / zero; /* NaN */
330     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
331     ok(rc==D3D_OK ||
332        broken(rc==DDERR_INVALIDPARAMS), "SetLight returned: %x\n", rc);
333
334     /* Directional light ignores attenuation */
335     light.dltType = D3DLIGHT_DIRECTIONAL;
336     light.dvAttenuation0 = -1.0;
337     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
338     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
339
340     memset(&mat, 0, sizeof(mat));
341     rc = IDirect3DDevice7_SetMaterial(lpD3DDevice, &mat);
342     ok(rc == D3D_OK, "IDirect3DDevice7_SetMaterial returned: %x\n", rc);
343
344     U4(mat).power = 129.0;
345     rc = IDirect3DDevice7_SetMaterial(lpD3DDevice, &mat);
346     ok(rc == D3D_OK, "IDirect3DDevice7_SetMaterial(power = 129.0) returned: %x\n", rc);
347     memset(&mat, 0, sizeof(mat));
348     rc = IDirect3DDevice7_GetMaterial(lpD3DDevice, &mat);
349     ok(rc == D3D_OK, "IDirect3DDevice7_GetMaterial returned: %x\n", rc);
350     ok(U4(mat).power == 129, "Returned power is %f\n", U4(mat).power);
351
352     U4(mat).power = -1.0;
353     rc = IDirect3DDevice7_SetMaterial(lpD3DDevice, &mat);
354     ok(rc == D3D_OK, "IDirect3DDevice7_SetMaterial(power = -1.0) returned: %x\n", rc);
355     memset(&mat, 0, sizeof(mat));
356     rc = IDirect3DDevice7_GetMaterial(lpD3DDevice, &mat);
357     ok(rc == D3D_OK, "IDirect3DDevice7_GetMaterial returned: %x\n", rc);
358     ok(U4(mat).power == -1, "Returned power is %f\n", U4(mat).power);
359
360     memset(&caps, 0, sizeof(caps));
361     rc = IDirect3DDevice7_GetCaps(lpD3DDevice, &caps);
362     ok(rc == D3D_OK, "IDirect3DDevice7_GetCaps failed with %x\n", rc);
363
364     if ( caps.dwMaxActiveLights == (DWORD) -1) {
365         /* Some cards without T&L Support return -1 (Examples: Voodoo Banshee, RivaTNT / NV4) */
366         skip("T&L not supported\n");
367         return;
368     }
369
370     for(i = 1; i <= caps.dwMaxActiveLights; i++) {
371         rc = IDirect3DDevice7_LightEnable(lpD3DDevice, i, TRUE);
372         ok(rc == D3D_OK, "Enabling light %u failed with %x\n", i, rc);
373         rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, i, &enabled);
374         ok(rc == D3D_OK, "GetLightEnable on light %u failed with %x\n", i, rc);
375         ok(enabled, "Light %d is %s\n", i, enabled ? "enabled" : "disabled");
376     }
377
378     /* TODO: Test the rendering results in this situation */
379     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, i + 1, TRUE);
380     ok(rc == D3D_OK, "Enabling one light more than supported returned %x\n", rc);
381     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, i + 1, &enabled);
382     ok(rc == D3D_OK, "GetLightEnable on light %u failed with %x\n", i + 1,  rc);
383     ok(enabled, "Light %d is %s\n", i + 1, enabled ? "enabled" : "disabled");
384     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, i + 1, FALSE);
385     ok(rc == D3D_OK, "Disabling the additional returned %x\n", rc);
386
387     for(i = 1; i <= caps.dwMaxActiveLights; i++) {
388         rc = IDirect3DDevice7_LightEnable(lpD3DDevice, i, FALSE);
389         ok(rc == D3D_OK, "Disabling light %u failed with %x\n", i, rc);
390     }
391 }
392
393 static void ProcessVerticesTest(void)
394 {
395     D3DVERTEXBUFFERDESC desc;
396     HRESULT rc;
397     VERTEX *in;
398     TVERTEX *out;
399     VERTEX *out2;
400     D3DVIEWPORT7 vp;
401     D3DMATRIX view = {  2.0, 0.0, 0.0, 0.0,
402                         0.0, -1.0, 0.0, 0.0,
403                         0.0, 0.0, 1.0, 0.0,
404                         0.0, 0.0, 0.0, 3.0 };
405
406     D3DMATRIX world = { 0.0, 1.0, 0.0, 0.0,
407                         1.0, 0.0, 0.0, 0.0,
408                         0.0, 0.0, 0.0, 1.0,
409                         0.0, 1.0, 1.0, 1.0 };
410
411     D3DMATRIX proj = {  1.0, 0.0, 0.0, 1.0,
412                         0.0, 1.0, 1.0, 0.0,
413                         0.0, 1.0, 1.0, 0.0,
414                         1.0, 0.0, 0.0, 1.0 };
415     /* Create some vertex buffers */
416
417     memset(&desc, 0, sizeof(desc));
418     desc.dwSize = sizeof(desc);
419     desc.dwCaps = 0;
420     desc.dwFVF = D3DFVF_XYZ;
421     desc.dwNumVertices = 16;
422     rc = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &lpVBufSrc, 0);
423     ok(rc==D3D_OK || rc==E_OUTOFMEMORY, "CreateVertexBuffer returned: %x\n", rc);
424     if (!lpVBufSrc)
425     {
426         trace("IDirect3D7::CreateVertexBuffer() failed with an error %x\n", rc);
427         goto out;
428     }
429
430     memset(&desc, 0, sizeof(desc));
431     desc.dwSize = sizeof(desc);
432     desc.dwCaps = 0;
433     desc.dwFVF = D3DFVF_XYZRHW;
434     desc.dwNumVertices = 16;
435     /* Msdn says that the last parameter must be 0 - check that */
436     rc = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &lpVBufDest1, 4);
437     ok(rc==D3D_OK || rc==E_OUTOFMEMORY, "CreateVertexBuffer returned: %x\n", rc);
438     if (!lpVBufDest1)
439     {
440         trace("IDirect3D7::CreateVertexBuffer() failed with an error %x\n", rc);
441         goto out;
442     }
443
444     memset(&desc, 0, sizeof(desc));
445     desc.dwSize = sizeof(desc);
446     desc.dwCaps = 0;
447     desc.dwFVF = D3DFVF_XYZ;
448     desc.dwNumVertices = 16;
449     /* Msdn says that the last parameter must be 0 - check that */
450     rc = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &lpVBufDest2, 12345678);
451     ok(rc==D3D_OK || rc==E_OUTOFMEMORY, "CreateVertexBuffer returned: %x\n", rc);
452     if (!lpVBufDest2)
453     {
454         trace("IDirect3D7::CreateVertexBuffer() failed with an error %x\n", rc);
455         goto out;
456     }
457
458     rc = IDirect3DVertexBuffer7_Lock(lpVBufSrc, 0, (void **) &in, NULL);
459     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
460     if(!in) goto out;
461
462     /* Check basic transformation */
463
464     in[0].x = 0.0;
465     in[0].y = 0.0;
466     in[0].z = 0.0;
467
468     in[1].x = 1.0;
469     in[1].y = 1.0;
470     in[1].z = 1.0;
471
472     in[2].x = -1.0;
473     in[2].y = -1.0;
474     in[2].z = 0.5;
475
476     in[3].x = 0.5;
477     in[3].y = -0.5;
478     in[3].z = 0.25;
479     rc = IDirect3DVertexBuffer7_Unlock(lpVBufSrc);
480     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
481
482     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest1, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
483     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
484
485     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest2, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
486     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
487
488     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest1, 0, (void **) &out, NULL);
489     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
490     if(!out) goto out;
491
492     /* Check the results */
493     ok( comparefloat(out[0].x, 128.0 ) &&
494         comparefloat(out[0].y, 128.0 ) &&
495         comparefloat(out[0].z, 0.0 ) &&
496         comparefloat(out[0].rhw, 1.0 ),
497         "Output 0 vertex is (%f , %f , %f , %f)\n", out[0].x, out[0].y, out[0].z, out[0].rhw);
498
499     ok( comparefloat(out[1].x, 256.0 ) &&
500         comparefloat(out[1].y, 0.0 ) &&
501         comparefloat(out[1].z, 1.0 ) &&
502         comparefloat(out[1].rhw, 1.0 ),
503         "Output 1 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
504
505     ok( comparefloat(out[2].x, 0.0 ) &&
506         comparefloat(out[2].y, 256.0 ) &&
507         comparefloat(out[2].z, 0.5 ) &&
508         comparefloat(out[2].rhw, 1.0 ),
509         "Output 2 vertex is (%f , %f , %f , %f)\n", out[2].x, out[2].y, out[2].z, out[2].rhw);
510
511     ok( comparefloat(out[3].x, 192.0 ) &&
512         comparefloat(out[3].y, 192.0 ) &&
513         comparefloat(out[3].z, 0.25 ) &&
514         comparefloat(out[3].rhw, 1.0 ),
515         "Output 3 vertex is (%f , %f , %f , %f)\n", out[3].x, out[3].y, out[3].z, out[3].rhw);
516
517     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest1);
518     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
519     out = NULL;
520
521     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest2, 0, (void **) &out2, NULL);
522     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
523     if(!out2) goto out;
524     /* Small thing without much practical meaning, but I stumbled upon it,
525      * so let's check for it: If the output vertex buffer has to RHW value,
526      * The RHW value of the last vertex is written into the next vertex
527      */
528     ok( comparefloat(out2[4].x, 1.0 ) &&
529         comparefloat(out2[4].y, 0.0 ) &&
530         comparefloat(out2[4].z, 0.0 ),
531         "Output 4 vertex is (%f , %f , %f)\n", out2[4].x, out2[4].y, out2[4].z);
532
533     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest2);
534     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
535     out = NULL;
536
537     /* Try a more complicated viewport, same vertices */
538     memset(&vp, 0, sizeof(vp));
539     vp.dwX = 10;
540     vp.dwY = 5;
541     vp.dwWidth = 246;
542     vp.dwHeight = 130;
543     vp.dvMinZ = -2.0;
544     vp.dvMaxZ = 4.0;
545     rc = IDirect3DDevice7_SetViewport(lpD3DDevice, &vp);
546     ok(rc==D3D_OK, "IDirect3DDevice7_SetViewport failed with rc=%x\n", rc);
547
548     /* Process again */
549     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest1, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
550     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
551
552     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest1, 0, (void **) &out, NULL);
553     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
554     if(!out) goto out;
555
556     /* Check the results */
557     ok( comparefloat(out[0].x, 133.0 ) &&
558         comparefloat(out[0].y, 70.0 ) &&
559         comparefloat(out[0].z, -2.0 ) &&
560         comparefloat(out[0].rhw, 1.0 ),
561         "Output 0 vertex is (%f , %f , %f , %f)\n", out[0].x, out[0].y, out[0].z, out[0].rhw);
562
563     ok( comparefloat(out[1].x, 256.0 ) &&
564         comparefloat(out[1].y, 5.0 ) &&
565         comparefloat(out[1].z, 4.0 ) &&
566         comparefloat(out[1].rhw, 1.0 ),
567         "Output 1 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
568
569     ok( comparefloat(out[2].x, 10.0 ) &&
570         comparefloat(out[2].y, 135.0 ) &&
571         comparefloat(out[2].z, 1.0 ) &&
572         comparefloat(out[2].rhw, 1.0 ),
573         "Output 2 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
574
575     ok( comparefloat(out[3].x, 194.5 ) &&
576         comparefloat(out[3].y, 102.5 ) &&
577         comparefloat(out[3].z, -0.5 ) &&
578         comparefloat(out[3].rhw, 1.0 ),
579         "Output 3 vertex is (%f , %f , %f , %f)\n", out[3].x, out[3].y, out[3].z, out[3].rhw);
580
581     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest1);
582     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
583     out = NULL;
584
585     /* Play with some matrices. */
586
587     rc = IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_VIEW, &view);
588     ok(rc==D3D_OK, "IDirect3DDevice7_SetTransform failed\n");
589
590     rc = IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_PROJECTION, &proj);
591     ok(rc==D3D_OK, "IDirect3DDevice7_SetTransform failed\n");
592
593     rc = IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_WORLD, &world);
594     ok(rc==D3D_OK, "IDirect3DDevice7_SetTransform failed\n");
595
596     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest1, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
597     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
598
599     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest1, 0, (void **) &out, NULL);
600     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
601     if(!out) goto out;
602
603     /* Keep the viewport simpler, otherwise we get bad numbers to compare */
604     vp.dwX = 0;
605     vp.dwY = 0;
606     vp.dwWidth = 100;
607     vp.dwHeight = 100;
608     vp.dvMinZ = 1.0;
609     vp.dvMaxZ = 0.0;
610     rc = IDirect3DDevice7_SetViewport(lpD3DDevice, &vp);
611     ok(rc==D3D_OK, "IDirect3DDevice7_SetViewport failed\n");
612
613     /* Check the results */
614     ok( comparefloat(out[0].x, 256.0 ) &&    /* X coordinate is cut at the surface edges */
615         comparefloat(out[0].y, 70.0 ) &&
616         comparefloat(out[0].z, -2.0 ) &&
617         comparefloat(out[0].rhw, (1.0 / 3.0)),
618         "Output 0 vertex is (%f , %f , %f , %f)\n", out[0].x, out[0].y, out[0].z, out[0].rhw);
619
620     ok( comparefloat(out[1].x, 256.0 ) &&
621         comparefloat(out[1].y, 78.125000 ) &&
622         comparefloat(out[1].z, -2.750000 ) &&
623         comparefloat(out[1].rhw, 0.125000 ),
624         "Output 1 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
625
626     ok( comparefloat(out[2].x, 256.0 ) &&
627         comparefloat(out[2].y, 44.000000 ) &&
628         comparefloat(out[2].z, 0.400000 ) &&
629         comparefloat(out[2].rhw, 0.400000 ),
630         "Output 2 vertex is (%f , %f , %f , %f)\n", out[2].x, out[2].y, out[2].z, out[2].rhw);
631
632     ok( comparefloat(out[3].x, 256.0 ) &&
633         comparefloat(out[3].y, 81.818184 ) &&
634         comparefloat(out[3].z, -3.090909 ) &&
635         comparefloat(out[3].rhw, 0.363636 ),
636         "Output 3 vertex is (%f , %f , %f , %f)\n", out[3].x, out[3].y, out[3].z, out[3].rhw);
637
638     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest1);
639     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
640     out = NULL;
641
642 out:
643     IDirect3DVertexBuffer7_Release(lpVBufSrc);
644     IDirect3DVertexBuffer7_Release(lpVBufDest1);
645     IDirect3DVertexBuffer7_Release(lpVBufDest2);
646 }
647
648 static void StateTest( void )
649 {
650     HRESULT rc;
651
652     /* The msdn says its undocumented, does it return an error too? */
653     rc = IDirect3DDevice7_SetRenderState(lpD3DDevice, D3DRENDERSTATE_ZVISIBLE, TRUE);
654     ok(rc == D3D_OK, "IDirect3DDevice7_SetRenderState(D3DRENDERSTATE_ZVISIBLE, TRUE) returned %08x\n", rc);
655     rc = IDirect3DDevice7_SetRenderState(lpD3DDevice, D3DRENDERSTATE_ZVISIBLE, FALSE);
656     ok(rc == D3D_OK, "IDirect3DDevice7_SetRenderState(D3DRENDERSTATE_ZVISIBLE, FALSE) returned %08x\n", rc);
657 }
658
659
660 static void SceneTest(void)
661 {
662     HRESULT                      hr;
663
664     /* Test an EndScene without beginscene. Should return an error */
665     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
666     ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr);
667
668     /* Test a normal BeginScene / EndScene pair, this should work */
669     hr = IDirect3DDevice7_BeginScene(lpD3DDevice);
670     ok(hr == D3D_OK, "IDirect3DDevice7_BeginScene failed with %08x\n", hr);
671     if(SUCCEEDED(hr))
672     {
673         DDBLTFX fx;
674         memset(&fx, 0, sizeof(fx));
675         fx.dwSize = sizeof(fx);
676
677         if(lpDDSdepth) {
678             hr = IDirectDrawSurface7_Blt(lpDDSdepth, NULL, NULL, NULL, DDBLT_DEPTHFILL, &fx);
679             ok(hr == D3D_OK, "Depthfill failed in a BeginScene / EndScene pair\n");
680         } else {
681             skip("Depth stencil creation failed at startup, skipping\n");
682         }
683         hr = IDirect3DDevice7_EndScene(lpD3DDevice);
684         ok(hr == D3D_OK, "IDirect3DDevice7_EndScene failed with %08x\n", hr);
685     }
686
687     /* Test another EndScene without having begun a new scene. Should return an error */
688     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
689     ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr);
690
691     /* Two nested BeginScene and EndScene calls */
692     hr = IDirect3DDevice7_BeginScene(lpD3DDevice);
693     ok(hr == D3D_OK, "IDirect3DDevice7_BeginScene failed with %08x\n", hr);
694     hr = IDirect3DDevice7_BeginScene(lpD3DDevice);
695     ok(hr == D3DERR_SCENE_IN_SCENE, "IDirect3DDevice7_BeginScene returned %08x\n", hr);
696     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
697     ok(hr == D3D_OK, "IDirect3DDevice7_EndScene failed with %08x\n", hr);
698     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
699     ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr);
700
701     /* TODO: Verify that blitting works in the same way as in d3d9 */
702 }
703
704 static void LimitTest(void)
705 {
706     IDirectDrawSurface7 *pTexture = NULL;
707     HRESULT hr;
708     int i;
709     DDSURFACEDESC2 ddsd;
710
711     memset(&ddsd, 0, sizeof(ddsd));
712     ddsd.dwSize = sizeof(ddsd);
713     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
714     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
715     ddsd.dwWidth = 16;
716     ddsd.dwHeight = 16;
717     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &pTexture, NULL);
718     ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
719     if(!pTexture) return;
720
721     for(i = 0; i < 8; i++) {
722         hr = IDirect3DDevice7_SetTexture(lpD3DDevice, i, pTexture);
723         ok(hr == D3D_OK, "IDirect3DDevice8_SetTexture for sampler %d failed with %08x\n", i, hr);
724         hr = IDirect3DDevice7_SetTexture(lpD3DDevice, i, NULL);
725         ok(hr == D3D_OK, "IDirect3DDevice8_SetTexture for sampler %d failed with %08x\n", i, hr);
726         hr = IDirect3DDevice7_SetTextureStageState(lpD3DDevice, i, D3DTSS_COLOROP, D3DTOP_ADD);
727         ok(hr == D3D_OK, "IDirect3DDevice8_SetTextureStageState for texture %d failed with %08x\n", i, hr);
728     }
729
730     IDirectDrawSurface7_Release(pTexture);
731 }
732
733 static HRESULT WINAPI enumDevicesCallback(GUID *Guid,LPSTR DeviceDescription,LPSTR DeviceName, D3DDEVICEDESC *hal, D3DDEVICEDESC *hel, VOID *ctx)
734 {
735     UINT ver = *((UINT *) ctx);
736     if(IsEqualGUID(&IID_IDirect3DRGBDevice, Guid))
737     {
738         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
739            "RGB Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
740         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
741            "RGB Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
742         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
743            "RGB Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
744         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
745            "RGB Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
746
747         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
748            "RGB Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
749         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
750            "RGB Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
751         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
752            "RGB Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
753         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
754            "RGB Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
755     }
756     else if(IsEqualGUID(&IID_IDirect3DHALDevice, Guid))
757     {
758         /* pow2 is hardware dependent */
759
760         ok(hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
761            "HAL Device %d hal line caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
762         ok(hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
763            "HAL Device %d hal tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
764         ok((hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
765            "HAL Device %d hel line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
766         ok((hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
767            "HAL Device %d hel tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
768     }
769     else if(IsEqualGUID(&IID_IDirect3DRefDevice, Guid))
770     {
771         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
772            "REF Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
773         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
774            "REF Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
775         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
776            "REF Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
777         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
778            "REF Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
779
780         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
781            "REF Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
782         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
783            "REF Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
784         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
785            "REF Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
786         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
787            "REF Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
788     }
789     else if(IsEqualGUID(&IID_IDirect3DRampDevice, Guid))
790     {
791         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
792            "Ramp Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
793         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
794            "Ramp Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
795         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
796            "Ramp Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
797         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
798            "Ramp Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
799
800         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
801            "Ramp Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
802         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
803            "Ramp Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
804         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
805            "Ramp Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
806         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
807            "Ramp Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
808     }
809     else if(IsEqualGUID(&IID_IDirect3DMMXDevice, Guid))
810     {
811         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
812            "MMX Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
813         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
814            "MMX Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
815         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
816            "MMX Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
817         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
818            "MMX Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
819
820         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
821            "MMX Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
822         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
823            "MMX Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
824         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
825            "MMX Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
826         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
827            "MMX Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
828     }
829     else
830     {
831         ok(FALSE, "Unexpected device enumerated: \"%s\" \"%s\"\n", DeviceDescription, DeviceName);
832         if(hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hal line has pow2 set\n");
833         else trace("hal line does NOT have pow2 set\n");
834         if(hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hal tri has pow2 set\n");
835         else trace("hal tri does NOT have pow2 set\n");
836         if(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hel line has pow2 set\n");
837         else trace("hel line does NOT have pow2 set\n");
838         if(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hel tri has pow2 set\n");
839         else trace("hel tri does NOT have pow2 set\n");
840     }
841     return DDENUMRET_OK;
842 }
843
844 static HRESULT WINAPI enumDevicesCallbackTest7(LPSTR DeviceDescription, LPSTR DeviceName, LPD3DDEVICEDESC7 lpdd7, LPVOID Context)
845 {
846     D3D7ETest *d3d7et = (D3D7ETest*)Context;
847     if(IsEqualGUID(&lpdd7->deviceGUID, &IID_IDirect3DRGBDevice))
848         d3d7et->rgb++;
849     else if(IsEqualGUID(&lpdd7->deviceGUID, &IID_IDirect3DHALDevice))
850         d3d7et->hal++;
851     else if(IsEqualGUID(&lpdd7->deviceGUID, &IID_IDirect3DTnLHalDevice))
852         d3d7et->tnlhal++;
853     else
854         d3d7et->unk++;
855
856     d3d7et->total++;
857
858     return DDENUMRET_OK;
859 }
860
861
862 /*  Check the deviceGUID of devices enumerated by
863     IDirect3D7_EnumDevices. */
864 static void D3D7EnumTest(void)
865 {
866     D3D7ETest d3d7et;
867
868     if (!lpD3D) {
869         skip("No Direct3D7 interface.\n");
870         return;
871     }
872
873     memset(&d3d7et, 0, sizeof(d3d7et));
874     IDirect3D7_EnumDevices(lpD3D, enumDevicesCallbackTest7, (LPVOID) &d3d7et);
875
876
877     /* A couple of games (Delta Force LW and TFD) rely on this behaviour */
878     ok(d3d7et.tnlhal < d3d7et.total, "TnLHal device enumerated as only device.\n");
879
880     /* We make two additional assumptions. */
881     ok(d3d7et.rgb, "No RGB Device enumerated.\n");
882
883     if(d3d7et.tnlhal)
884         ok(d3d7et.hal, "TnLHal device enumerated, but no Hal device found.\n");
885
886     return;
887 }
888
889 static void CapsTest(void)
890 {
891     IDirect3D3 *d3d3;
892     IDirect3D3 *d3d2;
893     IDirectDraw *dd1;
894     HRESULT hr;
895     UINT ver;
896
897     hr = DirectDrawCreate(NULL, &dd1, NULL);
898     ok(hr == DD_OK, "Cannot create a DirectDraw 1 interface, hr = %08x\n", hr);
899     hr = IDirectDraw_QueryInterface(dd1, &IID_IDirect3D3, (void **) &d3d3);
900     ok(hr == D3D_OK, "IDirectDraw_QueryInterface returned %08x\n", hr);
901     ver = 3;
902     IDirect3D3_EnumDevices(d3d3, enumDevicesCallback, &ver);
903
904     IDirect3D3_Release(d3d3);
905     IDirectDraw_Release(dd1);
906
907     hr = DirectDrawCreate(NULL, &dd1, NULL);
908     ok(hr == DD_OK, "Cannot create a DirectDraw 1 interface, hr = %08x\n", hr);
909     hr = IDirectDraw_QueryInterface(dd1, &IID_IDirect3D2, (void **) &d3d2);
910     ok(hr == D3D_OK, "IDirectDraw_QueryInterface returned %08x\n", hr);
911     ver = 2;
912     IDirect3D2_EnumDevices(d3d2, enumDevicesCallback, &ver);
913
914     IDirect3D2_Release(d3d2);
915     IDirectDraw_Release(dd1);
916 }
917
918 struct v_in {
919     float x, y, z;
920 };
921 struct v_out {
922     float x, y, z, rhw;
923 };
924
925 static BOOL D3D1_createObjects(void)
926 {
927     HRESULT hr;
928     DDSURFACEDESC ddsd;
929     D3DEXECUTEBUFFERDESC desc;
930     D3DVIEWPORT vp_data;
931
932     /* An IDirect3DDevice cannot be queryInterfaced from an IDirect3DDevice7 on windows */
933     hr = DirectDrawCreate(NULL, &DirectDraw1, NULL);
934     ok(hr==DD_OK || hr==DDERR_NODIRECTDRAWSUPPORT, "DirectDrawCreate returned: %x\n", hr);
935     if (!DirectDraw1) {
936         return FALSE;
937     }
938
939     hr = IDirectDraw_SetCooperativeLevel(DirectDraw1, NULL, DDSCL_NORMAL);
940     ok(hr==DD_OK, "SetCooperativeLevel returned: %x\n", hr);
941
942     hr = IDirectDraw_QueryInterface(DirectDraw1, &IID_IDirect3D, (void**) &Direct3D1);
943     ok(hr==DD_OK, "QueryInterface returned: %x\n", hr);
944     if (!Direct3D1) {
945         return FALSE;
946     }
947
948     memset(&ddsd, 0, sizeof(ddsd));
949     ddsd.dwSize = sizeof(ddsd);
950     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
951     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
952     ddsd.dwWidth = 256;
953     ddsd.dwHeight = 256;
954     hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &Surface1, NULL);
955     if (!Surface1) {
956         skip("DDSCAPS_3DDEVICE surface not available\n");
957         return FALSE;
958     }
959
960     hr = IDirectDrawSurface_QueryInterface(Surface1, &IID_IDirect3DRGBDevice, (void **) &Direct3DDevice1);
961     ok(hr==D3D_OK || hr==DDERR_NOPALETTEATTACHED || hr==E_OUTOFMEMORY, "CreateDevice returned: %x\n", hr);
962     if(!Direct3DDevice1) {
963         return FALSE;
964     }
965
966     memset(&desc, 0, sizeof(desc));
967     desc.dwSize = sizeof(desc);
968     desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
969     desc.dwCaps = D3DDEBCAPS_VIDEOMEMORY;
970     desc.dwBufferSize = 128;
971     desc.lpData = NULL;
972     hr = IDirect3DDevice_CreateExecuteBuffer(Direct3DDevice1, &desc, &ExecuteBuffer, NULL);
973     ok(hr == D3D_OK, "IDirect3DDevice_CreateExecuteBuffer failed: %08x\n", hr);
974     if(!ExecuteBuffer) {
975         return FALSE;
976     }
977
978     hr = IDirect3D_CreateViewport(Direct3D1, &Viewport, NULL);
979     ok(hr == D3D_OK, "IDirect3D_CreateViewport failed: %08x\n", hr);
980     if(!Viewport) {
981         return FALSE;
982     }
983
984     hr = IDirect3DViewport_Initialize(Viewport, Direct3D1);
985     ok(hr == DDERR_ALREADYINITIALIZED, "IDirect3DViewport_Initialize returned %08x\n", hr);
986
987     hr = IDirect3DDevice_AddViewport(Direct3DDevice1, Viewport);
988     ok(hr == D3D_OK, "IDirect3DDevice_AddViewport returned %08x\n", hr);
989     vp_data.dwSize = sizeof(vp_data);
990     vp_data.dwX = 0;
991     vp_data.dwY = 0;
992     vp_data.dwWidth = 256;
993     vp_data.dwHeight = 256;
994     vp_data.dvScaleX = 1;
995     vp_data.dvScaleY = 1;
996     vp_data.dvMaxX = 256;
997     vp_data.dvMaxY = 256;
998     vp_data.dvMinZ = 0;
999     vp_data.dvMaxZ = 1;
1000     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1001     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1002
1003     return TRUE;
1004 }
1005
1006 static void D3D1_releaseObjects(void)
1007 {
1008     if (Viewport) IDirect3DViewport_Release(Viewport);
1009     if (ExecuteBuffer) IDirect3DExecuteBuffer_Release(ExecuteBuffer);
1010     if (Direct3DDevice1) IDirect3DDevice_Release(Direct3DDevice1);
1011     if (Surface1) IDirectDrawSurface_Release(Surface1);
1012     if (Direct3D1) IDirect3D_Release(Direct3D1);
1013     if (DirectDraw1) IDirectDraw_Release(DirectDraw1);
1014 }
1015
1016 #define SET_VP_DATA(vp_data) \
1017     vp_data.dwSize = sizeof(vp_data); \
1018     vp_data.dwX = 0; \
1019     vp_data.dwY = 0; \
1020     vp_data.dwWidth = 256; \
1021     vp_data.dwHeight = 256; \
1022     vp_data.dvMaxX = 256; \
1023     vp_data.dvMaxY = 256; \
1024     vp_data.dvScaleX = 5; \
1025     vp_data.dvScaleY = 5; \
1026     vp_data.dvMinZ = -25; \
1027     vp_data.dvMaxZ = 60;
1028
1029 static void Direct3D1Test(void)
1030 {
1031     HRESULT hr;
1032     D3DEXECUTEBUFFERDESC desc;
1033     D3DVIEWPORT vp_data;
1034     D3DINSTRUCTION *instr;
1035     D3DBRANCH *branch;
1036     unsigned int idx = 0;
1037     static struct v_in testverts[] = {
1038         {0.0, 0.0, 0.0},  { 1.0,  1.0,  1.0}, {-1.0, -1.0, -1.0},
1039         {0.5, 0.5, 0.5},  {-0.5, -0.5, -0.5}, {-0.5, -0.5, 0.0},
1040     };
1041     static struct v_in cliptest[] = {
1042         {25.59, 25.59, 1.0},  {-25.59, -25.59,  0.0},
1043         {25.61, 25.61, 1.01}, {-25.61, -25.61, -0.01},
1044     };
1045     static struct v_in offscreentest[] = {
1046         {128.1, 0.0, 0.0},
1047     };
1048     struct v_out out[sizeof(testverts) / sizeof(testverts[0])];
1049     D3DHVERTEX outH[sizeof(testverts) / sizeof(testverts[0])];
1050     D3DTRANSFORMDATA transformdata;
1051     DWORD i = FALSE;
1052
1053     memset(&desc, 0, sizeof(desc));
1054     desc.dwSize = sizeof(desc);
1055     hr = IDirect3DExecuteBuffer_Lock(ExecuteBuffer, &desc);
1056     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Lock failed: %08x\n", hr);
1057
1058     memset(desc.lpData, 0, 128);
1059     instr = desc.lpData;
1060     instr[idx].bOpcode = D3DOP_BRANCHFORWARD;
1061     instr[idx].bSize = sizeof(*branch);
1062     instr[idx].wCount = 1;
1063     idx++;
1064     branch = (D3DBRANCH *) &instr[idx];
1065     branch->dwMask = 0x0;
1066     branch->dwValue = 1;
1067     branch->bNegate = TRUE;
1068     branch->dwOffset = 0;
1069     idx += (sizeof(*branch) / sizeof(*instr));
1070     instr[idx].bOpcode = D3DOP_EXIT;
1071     instr[idx].bSize = 0;
1072     instr[idx].wCount = 0;
1073     hr = IDirect3DExecuteBuffer_Unlock(ExecuteBuffer);
1074     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Unlock failed: %08x\n", hr);
1075
1076     hr = IDirect3DDevice_Execute(Direct3DDevice1, ExecuteBuffer, Viewport, D3DEXECUTE_CLIPPED);
1077     ok(hr == D3D_OK, "IDirect3DDevice_Execute returned %08x\n", hr);
1078
1079     memset(&desc, 0, sizeof(desc));
1080     desc.dwSize = sizeof(desc);
1081
1082     hr = IDirect3DExecuteBuffer_Lock(ExecuteBuffer, &desc);
1083     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Lock failed: %08x\n", hr);
1084
1085     memset(desc.lpData, 0, 128);
1086     instr = desc.lpData;
1087     idx = 0;
1088     instr[idx].bOpcode = D3DOP_BRANCHFORWARD;
1089     instr[idx].bSize = sizeof(*branch);
1090     instr[idx].wCount = 1;
1091     idx++;
1092     branch = (D3DBRANCH *) &instr[idx];
1093     branch->dwMask = 0x0;
1094     branch->dwValue = 1;
1095     branch->bNegate = TRUE;
1096     branch->dwOffset = 64;
1097     instr = (D3DINSTRUCTION*)((char*)desc.lpData + 64);
1098     instr[0].bOpcode = D3DOP_EXIT;
1099     instr[0].bSize = 0;
1100     instr[0].wCount = 0;
1101     hr = IDirect3DExecuteBuffer_Unlock(ExecuteBuffer);
1102     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Unlock failed: %08x\n", hr);
1103
1104     hr = IDirect3DDevice_Execute(Direct3DDevice1, ExecuteBuffer, Viewport, D3DEXECUTE_CLIPPED);
1105     ok(hr == D3D_OK, "IDirect3DDevice_Execute returned %08x\n", hr);
1106
1107     /* Test rendering 0 triangles */
1108     memset(&desc, 0, sizeof(desc));
1109     desc.dwSize = sizeof(desc);
1110
1111     hr = IDirect3DExecuteBuffer_Lock(ExecuteBuffer, &desc);
1112     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Lock failed: %08x\n", hr);
1113
1114     memset(desc.lpData, 0, 128);
1115     instr = desc.lpData;
1116     idx = 0;
1117
1118     instr->bOpcode = D3DOP_TRIANGLE;
1119     instr->bSize = sizeof(D3DOP_TRIANGLE);
1120     instr->wCount = 0;
1121     instr = ((D3DINSTRUCTION*)(instr))+1;
1122     instr->bOpcode = D3DOP_EXIT;
1123     instr->bSize = 0;
1124     instr->wCount = 0;
1125     hr = IDirect3DExecuteBuffer_Unlock(ExecuteBuffer);
1126     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Unlock failed: %08x\n", hr);
1127
1128     hr = IDirect3DDevice_Execute(Direct3DDevice1, ExecuteBuffer, Viewport, D3DEXECUTE_CLIPPED);
1129     ok(hr == D3D_OK, "IDirect3DDevice_Execute returned %08x\n", hr);
1130
1131     memset(&transformdata, 0, sizeof(transformdata));
1132     transformdata.dwSize = sizeof(transformdata);
1133     transformdata.lpIn = (void *) testverts;
1134     transformdata.dwInSize = sizeof(testverts[0]);
1135     transformdata.lpOut = out;
1136     transformdata.dwOutSize = sizeof(out[0]);
1137
1138     transformdata.lpHOut = NULL;
1139     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1140                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1141                                              &i);
1142     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1143
1144     transformdata.lpHOut = outH;
1145     memset(outH, 0xcc, sizeof(outH));
1146     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1147                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1148                                              &i);
1149     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1150     ok(i == 0, "Offscreen is %d\n", i);
1151
1152     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
1153         static const struct v_out cmp[] = {
1154             {128.0, 128.0, 0.0, 1}, {129.0, 127.0,  1.0, 1}, {127.0, 129.0, -1, 1},
1155             {128.5, 127.5, 0.5, 1}, {127.5, 128.5, -0.5, 1}, {127.5, 128.5,  0, 1}
1156         };
1157
1158         ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
1159            cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
1160            "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
1161            out[i].x, out[i].y, out[i].z, out[i].rhw,
1162            cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
1163     }
1164     for(i = 0; i < sizeof(outH); i++) {
1165         if(((unsigned char *) outH)[i] != 0xcc) {
1166             ok(FALSE, "Homogeneous output was generated despite UNCLIPPED flag\n");
1167             break;
1168         }
1169     }
1170
1171     SET_VP_DATA(vp_data);
1172     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1173     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1174     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1175                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1176                                              &i);
1177     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1178     ok(i == 0, "Offscreen is %d\n", i);
1179
1180     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
1181         static const struct v_out cmp[] = {
1182             {128.0, 128.0, 0.0, 1}, {133.0, 123.0,  1.0, 1}, {123.0, 133.0, -1, 1},
1183             {130.5, 125.5, 0.5, 1}, {125.5, 130.5, -0.5, 1}, {125.5, 130.5,  0, 1}
1184         };
1185         ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
1186            cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
1187            "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
1188            out[i].x, out[i].y, out[i].z, out[i].rhw,
1189            cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
1190     }
1191
1192     SET_VP_DATA(vp_data);
1193     vp_data.dwX = 10;
1194     vp_data.dwY = 20;
1195     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1196     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1197     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1198                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1199                                              &i);
1200     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1201     ok(i == 0, "Offscreen is %d\n", i);
1202     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
1203         static const struct v_out cmp[] = {
1204             {138.0, 148.0, 0.0, 1}, {143.0, 143.0,  1.0, 1}, {133.0, 153.0, -1, 1},
1205             {140.5, 145.5, 0.5, 1}, {135.5, 150.5, -0.5, 1}, {135.5, 150.5,  0, 1}
1206         };
1207         ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
1208            cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
1209            "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
1210            out[i].x, out[i].y, out[i].z, out[i].rhw,
1211            cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
1212     }
1213
1214     memset(out, 0xcc, sizeof(out));
1215     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1216                                              &transformdata, D3DTRANSFORM_CLIPPED,
1217                                              &i);
1218     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1219     ok(i == 0, "Offscreen is %d\n", i);
1220     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
1221         static const D3DHVERTEX cmpH[] = {
1222             {0,             { 0.0}, { 0.0}, { 0.0}}, {0, { 1.0}, { 1.0}, {1.0}},
1223             {D3DCLIP_FRONT, {-1.0}, {-1.0}, {-1.0}}, {0, { 0.5}, { 0.5}, {0.5}},
1224             {D3DCLIP_FRONT, {-0.5}, {-0.5}, {-0.5}}, {0, {-0.5}, {-0.5}, {0.0}}
1225         };
1226         ok(U1(cmpH[i]).hx == U1(outH[i]).hx && U2(cmpH[i]).hy == U2(outH[i]).hy &&
1227            U3(cmpH[i]).hz == U3(outH[i]).hz && cmpH[i].dwFlags == outH[i].dwFlags,
1228            "HVertex %d differs. Got %08x %f %f %f, expexted %08x %f %f %f\n", i + 1,
1229            outH[i].dwFlags, U1(outH[i]).hx, U2(outH[i]).hy, U3(outH[i]).hz,
1230            cmpH[i].dwFlags, U1(cmpH[i]).hx, U2(cmpH[i]).hy, U3(cmpH[i]).hz);
1231
1232         /* No scheme has been found behind those return values. It seems to be
1233          * whatever data windows has when throwing the vertex away. Modify the
1234          * input test vertices to test this more. Depending on the input data
1235          * it can happen that the z coord gets written into y, or similar things
1236          */
1237         if(0)
1238         {
1239             static const struct v_out cmp[] = {
1240                 {138.0, 148.0, 0.0, 1}, {143.0, 143.0,  1.0, 1}, { -1.0,  -1.0, 0.5, 1},
1241                 {140.5, 145.5, 0.5, 1}, { -0.5,  -0.5, -0.5, 1}, {135.5, 150.5, 0.0, 1}
1242             };
1243             ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
1244                cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
1245                 "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
1246                out[i].x, out[i].y, out[i].z, out[i].rhw,
1247                cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
1248         }
1249     }
1250     for(i = 0; i < sizeof(out) / sizeof(DWORD); i++) {
1251         ok(((DWORD *) out)[i] != 0xcccccccc,
1252                 "Regular output DWORD %d remained untouched\n", i);
1253     }
1254
1255     transformdata.lpIn = (void *) cliptest;
1256     transformdata.dwInSize = sizeof(cliptest[0]);
1257     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(cliptest) / sizeof(cliptest[0]),
1258                                              &transformdata, D3DTRANSFORM_CLIPPED,
1259                                              &i);
1260     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1261     ok(i == 0, "Offscreen is %d\n", i);
1262     for(i = 0; i < sizeof(cliptest) / sizeof(cliptest[0]); i++) {
1263         DWORD Flags[sizeof(cliptest) / sizeof(cliptest[0])] =
1264         {
1265             0,
1266             0,
1267             D3DCLIP_RIGHT | D3DCLIP_BACK   | D3DCLIP_TOP,
1268             D3DCLIP_LEFT  | D3DCLIP_BOTTOM | D3DCLIP_FRONT,
1269         };
1270         ok(Flags[i] == outH[i].dwFlags,
1271            "Cliptest %d differs. Got %08x expexted %08x\n", i + 1,
1272            outH[i].dwFlags, Flags[i]);
1273     }
1274
1275     SET_VP_DATA(vp_data);
1276     vp_data.dwWidth = 10;
1277     vp_data.dwHeight = 1000;
1278     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1279     i = 10;
1280     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1281     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(cliptest) / sizeof(cliptest[0]),
1282                                              &transformdata, D3DTRANSFORM_CLIPPED,
1283                                              &i);
1284     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1285     ok(i == 0, "Offscreen is %d\n", i);
1286     for(i = 0; i < sizeof(cliptest) / sizeof(cliptest[0]); i++) {
1287         DWORD Flags[sizeof(cliptest) / sizeof(cliptest[0])] =
1288         {
1289             D3DCLIP_RIGHT,
1290             D3DCLIP_LEFT,
1291             D3DCLIP_RIGHT | D3DCLIP_BACK,
1292             D3DCLIP_LEFT  | D3DCLIP_FRONT,
1293         };
1294         ok(Flags[i] == outH[i].dwFlags,
1295            "Cliptest %d differs. Got %08x expexted %08x\n", i + 1,
1296            outH[i].dwFlags, Flags[i]);
1297     }
1298
1299     SET_VP_DATA(vp_data);
1300     vp_data.dwWidth = 256;
1301     vp_data.dwHeight = 256;
1302     vp_data.dvScaleX = 1;
1303     vp_data.dvScaleY = 1;
1304     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1305     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1306     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(cliptest) / sizeof(cliptest[0]),
1307                                              &transformdata, D3DTRANSFORM_CLIPPED,
1308                                              &i);
1309     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1310     ok(i == 0, "Offscreen is %s\n", i ? "TRUE" : "FALSE");
1311     for(i = 0; i < sizeof(cliptest) / sizeof(cliptest[0]); i++) {
1312         DWORD Flags[sizeof(cliptest) / sizeof(cliptest[0])] =
1313         {
1314             0,
1315             0,
1316             D3DCLIP_BACK,
1317             D3DCLIP_FRONT,
1318         };
1319         ok(Flags[i] == outH[i].dwFlags,
1320            "Cliptest %d differs. Got %08x expexted %08x\n", i + 1,
1321            outH[i].dwFlags, Flags[i]);
1322     }
1323
1324     /* Finally try to figure out how the DWORD dwOffscreen works.
1325      * Apparently no vertex is offscreen with clipping off,
1326      * and with clipping on the offscreen flag is set if only one vertex
1327      * is transformed, and this vertex is offscreen.
1328      */
1329     SET_VP_DATA(vp_data);
1330     vp_data.dwWidth = 5;
1331     vp_data.dwHeight = 5;
1332     vp_data.dvScaleX = 10000;
1333     vp_data.dvScaleY = 10000;
1334     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1335     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1336     transformdata.lpIn = cliptest;
1337     hr = IDirect3DViewport_TransformVertices(Viewport, 1,
1338                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1339                                              &i);
1340     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1341     ok(i == 0, "Offscreen is %d\n", i);
1342     hr = IDirect3DViewport_TransformVertices(Viewport, 1,
1343                                              &transformdata, D3DTRANSFORM_CLIPPED,
1344                                              &i);
1345     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1346     ok(i == (D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %d\n", i);
1347     hr = IDirect3DViewport_TransformVertices(Viewport, 2,
1348                                              &transformdata, D3DTRANSFORM_CLIPPED,
1349                                              &i);
1350     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1351     ok(i == 0, "Offscreen is %d\n", i);
1352     transformdata.lpIn = cliptest + 1;
1353     hr = IDirect3DViewport_TransformVertices(Viewport, 1,
1354                                              &transformdata, D3DTRANSFORM_CLIPPED,
1355                                              &i);
1356     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1357     ok(i == (D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %d\n", i);
1358
1359     transformdata.lpIn = (void *) offscreentest;
1360     transformdata.dwInSize = sizeof(offscreentest[0]);
1361     SET_VP_DATA(vp_data);
1362     vp_data.dwWidth = 257;
1363     vp_data.dwHeight = 257;
1364     vp_data.dvScaleX = 1;
1365     vp_data.dvScaleY = 1;
1366     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1367     i = 12345;
1368     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(offscreentest) / sizeof(offscreentest[0]),
1369                                              &transformdata, D3DTRANSFORM_CLIPPED,
1370                                              &i);
1371     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1372     ok(i == 0, "Offscreen is %d\n", i);
1373     vp_data.dwWidth = 256;
1374     vp_data.dwHeight = 256;
1375     hr = IDirect3DViewport_SetViewport(Viewport, &vp_data);
1376     i = 12345;
1377     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(offscreentest) / sizeof(offscreentest[0]),
1378                                              &transformdata, D3DTRANSFORM_CLIPPED,
1379                                              &i);
1380     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1381     ok(i == D3DCLIP_RIGHT, "Offscreen is %d\n", i);
1382
1383     hr = IDirect3DViewport_TransformVertices(Viewport, sizeof(testverts) / sizeof(testverts[0]),
1384                                              &transformdata, 0,
1385                                              &i);
1386     ok(hr == DDERR_INVALIDPARAMS, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1387
1388     hr = IDirect3DDevice_DeleteViewport(Direct3DDevice1, Viewport);
1389     ok(hr == D3D_OK, "IDirect3DDevice_DeleteViewport returned %08x\n", hr);
1390 }
1391
1392 static BOOL colortables_check_equality(PALETTEENTRY table1[256], PALETTEENTRY table2[256])
1393 {
1394     int i;
1395
1396     for (i = 0; i < 256; i++) {
1397        if (table1[i].peRed != table2[i].peRed || table1[i].peGreen != table2[i].peGreen ||
1398            table1[i].peBlue != table2[i].peBlue) return FALSE;
1399     }
1400
1401     return TRUE;
1402 }
1403
1404 /* test palette handling in IDirect3DTexture_Load */
1405 static void TextureLoadTest(void)
1406 {
1407     IDirectDrawSurface *TexSurface = NULL;
1408     IDirect3DTexture *Texture = NULL;
1409     IDirectDrawSurface *TexSurface2 = NULL;
1410     IDirect3DTexture *Texture2 = NULL;
1411     IDirectDrawPalette *palette = NULL;
1412     IDirectDrawPalette *palette2 = NULL;
1413     IDirectDrawPalette *palette_tmp = NULL;
1414     PALETTEENTRY table1[256], table2[256], table_tmp[256];
1415     HRESULT hr;
1416     DDSURFACEDESC ddsd;
1417     int i;
1418
1419     memset (&ddsd, 0, sizeof (ddsd));
1420     ddsd.dwSize = sizeof (ddsd);
1421     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1422     ddsd.dwHeight = 128;
1423     ddsd.dwWidth = 128;
1424     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1425     ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
1426     ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
1427     U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 8;
1428
1429     hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &TexSurface, NULL);
1430     ok(hr==D3D_OK, "CreateSurface returned: %x\n", hr);
1431     if (FAILED(hr)) {
1432         skip("IDirectDraw_CreateSurface failed; skipping further tests\n");
1433         goto cleanup;
1434     }
1435
1436     hr = IDirectDrawSurface_QueryInterface(TexSurface, &IID_IDirect3DTexture,
1437                 (void *)&Texture);
1438     ok(hr==D3D_OK, "IDirectDrawSurface_QueryInterface returned: %x\n", hr);
1439     if (FAILED(hr)) {
1440         skip("Can't get IDirect3DTexture interface; skipping further tests\n");
1441         goto cleanup;
1442     }
1443
1444     hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &TexSurface2, NULL);
1445     ok(hr==D3D_OK, "CreateSurface returned: %x\n", hr);
1446     if (FAILED(hr)) {
1447         skip("IDirectDraw_CreateSurface failed; skipping further tests\n");
1448         goto cleanup;
1449     }
1450
1451     hr = IDirectDrawSurface_QueryInterface(TexSurface2, &IID_IDirect3DTexture,
1452                 (void *)&Texture2);
1453     ok(hr==D3D_OK, "IDirectDrawSurface_QueryInterface returned: %x\n", hr);
1454     if (FAILED(hr)) {
1455         skip("Can't get IDirect3DTexture interface; skipping further tests\n");
1456         goto cleanup;
1457     }
1458
1459     /* test load of Texture to Texture */
1460     hr = IDirect3DTexture_Load(Texture, Texture);
1461     ok(hr == DD_OK, "IDirect3DTexture_Load returned %08x\n", hr);
1462
1463     /* test Load when both textures have no palette */
1464     hr = IDirect3DTexture_Load(Texture2, Texture);
1465     ok(hr == DD_OK, "IDirect3DTexture_Load returned %08x\n", hr);
1466
1467     for (i = 0; i < 256; i++) {
1468         table1[i].peRed = i;
1469         table1[i].peGreen = i;
1470         table1[i].peBlue = i;
1471         table1[i].peFlags = 0;
1472     }
1473
1474     hr = IDirectDraw_CreatePalette(DirectDraw1, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, table1, &palette, NULL);
1475     ok(hr == DD_OK, "CreatePalette returned %08x\n", hr);
1476     if (FAILED(hr)) {
1477         skip("IDirectDraw_CreatePalette failed; skipping further tests\n");
1478         goto cleanup;
1479     }
1480
1481     /* test Load when source texture has palette and destination has no palette */
1482     hr = IDirectDrawSurface_SetPalette(TexSurface, palette);
1483     ok(hr == DD_OK, "IDirectDrawSurface_SetPalette returned %08x\n", hr);
1484     hr = IDirect3DTexture_Load(Texture2, Texture);
1485     ok(hr == DDERR_NOPALETTEATTACHED, "IDirect3DTexture_Load returned %08x\n", hr);
1486
1487     for (i = 0; i < 256; i++) {
1488         table2[i].peRed = 255 - i;
1489         table2[i].peGreen = 255 - i;
1490         table2[i].peBlue = 255 - i;
1491         table2[i].peFlags = 0;
1492     }
1493
1494     hr = IDirectDraw_CreatePalette(DirectDraw1, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, table2, &palette2, NULL);
1495     ok(hr == DD_OK, "CreatePalette returned %08x\n", hr);
1496     if (FAILED(hr)) {
1497         skip("IDirectDraw_CreatePalette failed; skipping further tests\n");
1498         goto cleanup;
1499     }
1500
1501     /* test Load when source has no palette and destination has a palette */
1502     hr = IDirectDrawSurface_SetPalette(TexSurface, NULL);
1503     ok(hr == DD_OK, "IDirectDrawSurface_SetPalette returned %08x\n", hr);
1504     hr = IDirectDrawSurface_SetPalette(TexSurface2, palette2);
1505     ok(hr == DD_OK, "IDirectDrawSurface_SetPalette returned %08x\n", hr);
1506     hr = IDirect3DTexture_Load(Texture2, Texture);
1507     ok(hr == DD_OK, "IDirect3DTexture_Load returned %08x\n", hr);
1508     hr = IDirectDrawSurface_GetPalette(TexSurface2, &palette_tmp);
1509     ok(hr == DD_OK, "IDirectDrawSurface_GetPalette returned %08x\n", hr);
1510     if (!palette_tmp) {
1511         skip("IDirectDrawSurface_GetPalette failed; skipping color table check\n");
1512         goto cleanup;
1513     } else {
1514         hr = IDirectDrawPalette_GetEntries(palette_tmp, 0, 0, 256, table_tmp);
1515         ok(hr == DD_OK, "IDirectDrawPalette_GetEntries returned %08x\n", hr);
1516         ok(colortables_check_equality(table2, table_tmp), "Unexpected palettized texture color table\n");
1517         IDirectDrawPalette_Release(palette_tmp);
1518     }
1519
1520     /* test Load when both textures have palettes */
1521     hr = IDirectDrawSurface_SetPalette(TexSurface, palette);
1522     ok(hr == DD_OK, "IDirectDrawSurface_SetPalette returned %08x\n", hr);
1523     hr = IDirect3DTexture_Load(Texture2, Texture);
1524     ok(hr == DD_OK, "IDirect3DTexture_Load returned %08x\n", hr);
1525     hr = IDirect3DTexture_Load(Texture2, Texture);
1526     ok(hr == DD_OK, "IDirect3DTexture_Load returned %08x\n", hr);
1527     hr = IDirectDrawSurface_GetPalette(TexSurface2, &palette_tmp);
1528     ok(hr == DD_OK, "IDirectDrawSurface_GetPalette returned %08x\n", hr);
1529     if (!palette_tmp) {
1530         skip("IDirectDrawSurface_GetPalette failed; skipping color table check\n");
1531         goto cleanup;
1532     } else {
1533         hr = IDirectDrawPalette_GetEntries(palette_tmp, 0, 0, 256, table_tmp);
1534         ok(hr == DD_OK, "IDirectDrawPalette_GetEntries returned %08x\n", hr);
1535         ok(colortables_check_equality(table1, table_tmp), "Unexpected palettized texture color table\n");
1536         IDirectDrawPalette_Release(palette_tmp);
1537     }
1538
1539     cleanup:
1540
1541     if (palette) IDirectDrawPalette_Release(palette);
1542     if (palette2) IDirectDrawPalette_Release(palette2);
1543     if (TexSurface) IDirectDrawSurface_Release(TexSurface);
1544     if (Texture) IDirect3DTexture_Release(Texture);
1545     if (TexSurface2) IDirectDrawSurface_Release(TexSurface2);
1546     if (Texture2) IDirect3DTexture_Release(Texture2);
1547 }
1548
1549 static void VertexBufferDescTest(void)
1550 {
1551     HRESULT rc;
1552     D3DVERTEXBUFFERDESC desc;
1553     union mem_t
1554     {
1555         D3DVERTEXBUFFERDESC desc2;
1556         unsigned char buffer[512];
1557     } mem;
1558
1559     memset(&desc, 0, sizeof(desc));
1560     desc.dwSize = sizeof(desc);
1561     desc.dwCaps = 0;
1562     desc.dwFVF = D3DFVF_XYZ;
1563     desc.dwNumVertices = 1;
1564     rc = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &lpVBufSrc, 0);
1565     ok(rc==D3D_OK || rc==E_OUTOFMEMORY, "CreateVertexBuffer returned: %x\n", rc);
1566     if (!lpVBufSrc)
1567     {
1568         trace("IDirect3D7::CreateVertexBuffer() failed with an error %x\n", rc);
1569         goto out;
1570     }
1571
1572     memset(mem.buffer, 0x12, sizeof(mem.buffer));
1573     mem.desc2.dwSize = sizeof(D3DVERTEXBUFFERDESC)*2;
1574     rc = IDirect3DVertexBuffer7_GetVertexBufferDesc(lpVBufSrc, &mem.desc2);
1575     if(rc != D3D_OK)
1576         skip("GetVertexBuffer Failed!\n");
1577     ok( mem.desc2.dwSize == sizeof(D3DVERTEXBUFFERDESC)*2, "Size returned from GetVertexBufferDesc does not match the value put in\n" );
1578     ok( mem.buffer[sizeof(D3DVERTEXBUFFERDESC)] == 0x12, "GetVertexBufferDesc cleared outside of the struct! (dwSize was double the size of the struct)\n");
1579     ok( mem.desc2.dwCaps == desc.dwCaps, "dwCaps returned differs. Got %x, expected %x\n", mem.desc2.dwCaps, desc.dwCaps);
1580     ok( mem.desc2.dwFVF == desc.dwFVF, "dwFVF returned differs. Got %x, expected %x\n", mem.desc2.dwFVF, desc.dwFVF);
1581     ok (mem.desc2.dwNumVertices == desc.dwNumVertices, "dwNumVertices returned differs. Got %x, expected %x\n", mem.desc2.dwNumVertices, desc.dwNumVertices);
1582
1583     memset(mem.buffer, 0x12, sizeof(mem.buffer));
1584     mem.desc2.dwSize = 0;
1585     rc = IDirect3DVertexBuffer7_GetVertexBufferDesc(lpVBufSrc, &mem.desc2);
1586     if(rc != D3D_OK)
1587         skip("GetVertexBuffer Failed!\n");
1588     ok( mem.desc2.dwSize == 0, "Size returned from GetVertexBufferDesc does not match the value put in\n" );
1589     ok( mem.buffer[sizeof(D3DVERTEXBUFFERDESC)] == 0x12, "GetVertexBufferDesc cleared outside of the struct! (dwSize was 0)\n");
1590     ok( mem.desc2.dwCaps == desc.dwCaps, "dwCaps returned differs. Got %x, expected %x\n", mem.desc2.dwCaps, desc.dwCaps);
1591     ok( mem.desc2.dwFVF == desc.dwFVF, "dwFVF returned differs. Got %x, expected %x\n", mem.desc2.dwFVF, desc.dwFVF);
1592     ok (mem.desc2.dwNumVertices == desc.dwNumVertices, "dwNumVertices returned differs. Got %x, expected %x\n", mem.desc2.dwNumVertices, desc.dwNumVertices);
1593
1594     memset(mem.buffer, 0x12, sizeof(mem.buffer));
1595     mem.desc2.dwSize = sizeof(D3DVERTEXBUFFERDESC);
1596     rc = IDirect3DVertexBuffer7_GetVertexBufferDesc(lpVBufSrc, &mem.desc2);
1597     if(rc != D3D_OK)
1598         skip("GetVertexBuffer Failed!\n");
1599     ok( mem.desc2.dwSize == sizeof(D3DVERTEXBUFFERDESC), "Size returned from GetVertexBufferDesc does not match the value put in\n" );
1600     ok( mem.buffer[sizeof(D3DVERTEXBUFFERDESC)] == 0x12, "GetVertexBufferDesc cleared outside of the struct! (dwSize was the size of the struct)\n");
1601     ok( mem.desc2.dwCaps == desc.dwCaps, "dwCaps returned differs. Got %x, expected %x\n", mem.desc2.dwCaps, desc.dwCaps);
1602     ok( mem.desc2.dwFVF == desc.dwFVF, "dwFVF returned differs. Got %x, expected %x\n", mem.desc2.dwFVF, desc.dwFVF);
1603     ok (mem.desc2.dwNumVertices == desc.dwNumVertices, "dwNumVertices returned differs. Got %x, expected %x\n", mem.desc2.dwNumVertices, desc.dwNumVertices);
1604
1605 out:
1606     IDirect3DVertexBuffer7_Release(lpVBufSrc);
1607 }
1608
1609 static void D3D7_OldRenderStateTest(void)
1610 {
1611     HRESULT rc;
1612     DWORD val;
1613
1614     /* Test reaction to some deprecated states in D3D7.
1615
1616      * IDirect3DDevice7 in Wine currently relays such states to wined3d where they are do-nothing and return 0, instead
1617      * of INVALIDPARAMS. Unless an app is found which cares this is probably ok. What this test shows is that these states
1618      * need not to be handled in D3D7.
1619      */
1620     todo_wine {
1621         rc = IDirect3DDevice7_SetRenderState(lpD3DDevice, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1622         ok(rc == DDERR_INVALIDPARAMS, "IDirect3DDevice7_SetRenderState returned %08x\n", rc);
1623
1624         rc = IDirect3DDevice7_GetRenderState(lpD3DDevice, D3DRENDERSTATE_TEXTUREHANDLE, &val);
1625         ok(rc == DDERR_INVALIDPARAMS, "IDirect3DDevice7_GetRenderState returned %08x\n", rc);
1626
1627         rc = IDirect3DDevice7_SetRenderState(lpD3DDevice, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
1628         ok(rc == DDERR_INVALIDPARAMS, "IDirect3DDevice7_SetRenderState returned %08x\n", rc);
1629
1630         rc = IDirect3DDevice7_GetRenderState(lpD3DDevice, D3DRENDERSTATE_TEXTUREMAPBLEND, &val);
1631         ok(rc == DDERR_INVALIDPARAMS, "IDirect3DDevice7_GetRenderState returned %08x\n", rc);
1632     }
1633 }
1634
1635 #define IS_VALUE_NEAR(a, b)    ( ((a) == (b)) || ((a) == (b) - 1) || ((a) == (b) + 1) )
1636 #define MIN(a, b)    ((a) < (b) ? (a) : (b))
1637
1638 static void DeviceLoadTest()
1639 {
1640     DDSURFACEDESC2 ddsd;
1641     IDirectDrawSurface7 *texture_levels[2][8];
1642     IDirectDrawSurface7 *cube_face_levels[2][6][8];
1643     DWORD flags;
1644     HRESULT hr;
1645     DDBLTFX ddbltfx;
1646     RECT loadrect;
1647     POINT loadpoint;
1648     int i, i1, i2;
1649     unsigned diff_count = 0, diff_count2 = 0;
1650     unsigned x, y;
1651     BOOL load_mip_subset_broken = FALSE;
1652     IDirectDrawPalette *palettes[5];
1653     PALETTEENTRY table1[256];
1654     DDCOLORKEY ddckey;
1655
1656     /* Test loading of texture subrectangle with a mipmap surface. */
1657     memset(texture_levels, 0, sizeof(texture_levels));
1658     memset(cube_face_levels, 0, sizeof(cube_face_levels));
1659     memset(palettes, 0, sizeof(palettes));
1660
1661     for (i = 0; i < 2; i++)
1662     {
1663         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1664         ddsd.dwSize = sizeof(ddsd);
1665         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
1666         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
1667         ddsd.dwWidth = 128;
1668         ddsd.dwHeight = 128;
1669         U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
1670         U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
1671         U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
1672         U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
1673         U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
1674         U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
1675         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[i][0], NULL);
1676         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
1677         if (FAILED(hr)) goto out;
1678
1679         /* Check the number of created mipmaps */
1680         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1681         ddsd.dwSize = sizeof(ddsd);
1682         hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[i][0], &ddsd);
1683         ok(hr==DD_OK,"IDirectDrawSurface7_GetSurfaceDesc returned: %x\n",hr);
1684         ok(U2(ddsd).dwMipMapCount == 8, "unexpected mip count %u\n", U2(ddsd).dwMipMapCount);
1685         if (U2(ddsd).dwMipMapCount != 8) goto out;
1686
1687         for (i1 = 1; i1 < 8; i1++)
1688         {
1689             hr = IDirectDrawSurface7_GetAttachedSurface(texture_levels[i][i1 - 1], &ddsd.ddsCaps, &texture_levels[i][i1]);
1690             ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
1691             if (FAILED(hr)) goto out;
1692         }
1693     }
1694
1695     for (i1 = 0; i1 < 8; i1++)
1696     {
1697         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1698         ddsd.dwSize = sizeof(ddsd);
1699         hr = IDirectDrawSurface7_Lock(texture_levels[0][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
1700         ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
1701         if (FAILED(hr)) goto out;
1702
1703         for (y = 0 ; y < ddsd.dwHeight; y++)
1704         {
1705             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
1706
1707             for (x = 0; x < ddsd.dwWidth;  x++)
1708             {
1709                 /* x stored in green component, y in blue. */
1710                 DWORD color = 0xff0000 | (x << 8)  | y;
1711                 *textureRow++ = color;
1712             }
1713         }
1714
1715         hr = IDirectDrawSurface7_Unlock(texture_levels[0][i1], NULL);
1716         ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
1717     }
1718
1719     for (i1 = 0; i1 < 8; i1++)
1720     {
1721         memset(&ddbltfx, 0, sizeof(ddbltfx));
1722         ddbltfx.dwSize = sizeof(ddbltfx);
1723         U5(ddbltfx).dwFillColor = 0;
1724         hr = IDirectDrawSurface7_Blt(texture_levels[1][i1], NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
1725         ok(hr == DD_OK, "IDirectDrawSurface7_Blt failed with %08x\n", hr);
1726     }
1727
1728     /* First test some broken coordinates. */
1729     loadpoint.x = loadpoint.y = 0;
1730     loadrect.left = 0;
1731     loadrect.top = 0;
1732     loadrect.right = 0;
1733     loadrect.bottom = 0;
1734     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
1735     ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
1736
1737     loadpoint.x = loadpoint.y = 50;
1738     loadrect.left = 0;
1739     loadrect.top = 0;
1740     loadrect.right = 100;
1741     loadrect.bottom = 100;
1742     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
1743     ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
1744
1745     /* Test actual loading. */
1746     loadpoint.x = loadpoint.y = 31;
1747     loadrect.left = 30;
1748     loadrect.top = 20;
1749     loadrect.right = 93;
1750     loadrect.bottom = 52;
1751
1752     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
1753     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
1754
1755     for (i1 = 0; i1 < 8; i1++)
1756     {
1757         diff_count = 0;
1758         diff_count2 = 0;
1759
1760         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1761         ddsd.dwSize = sizeof(ddsd);
1762         hr = IDirectDrawSurface7_Lock(texture_levels[1][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
1763         ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
1764         if (FAILED(hr)) goto out;
1765
1766         for (y = 0 ; y < ddsd.dwHeight; y++)
1767         {
1768             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
1769
1770             for (x = 0; x < ddsd.dwWidth;  x++)
1771             {
1772                 DWORD color = *textureRow++;
1773
1774                 if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
1775                     y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
1776                 {
1777                     if (color & 0xffffff) diff_count++;
1778                 }
1779                 else
1780                 {
1781                     DWORD r = (color & 0xff0000) >> 16;
1782                     DWORD g = (color & 0xff00) >> 8;
1783                     DWORD b = (color & 0xff);
1784
1785                     if (r != 0xff || g != x + loadrect.left - loadpoint.x || b != y + loadrect.top - loadpoint.y) diff_count++;
1786                 }
1787
1788                 /* This codepath is for software RGB device. It has what looks like some weird off by one errors, but may
1789                    technically be correct as it's not precisely defined by docs. */
1790                 if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
1791                     y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top + 1)
1792                 {
1793                     if (color & 0xffffff) diff_count2++;
1794                 }
1795                 else
1796                 {
1797                     DWORD r = (color & 0xff0000) >> 16;
1798                     DWORD g = (color & 0xff00) >> 8;
1799                     DWORD b = (color & 0xff);
1800
1801                     if (r != 0xff || !IS_VALUE_NEAR(g, x + loadrect.left - loadpoint.x) ||
1802                         !IS_VALUE_NEAR(b, y + loadrect.top - loadpoint.y)) diff_count2++;
1803                 }
1804             }
1805         }
1806
1807         hr = IDirectDrawSurface7_Unlock(texture_levels[1][i1], NULL);
1808         ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
1809
1810         ok(diff_count == 0 || diff_count2 == 0, "Unexpected destination texture level pixels; %u differences at %d level\n",
1811                 MIN(diff_count, diff_count2), i1);
1812
1813         loadpoint.x /= 2;
1814         loadpoint.y /= 2;
1815         loadrect.top /= 2;
1816         loadrect.left /= 2;
1817         loadrect.right = (loadrect.right + 1) / 2;
1818         loadrect.bottom = (loadrect.bottom + 1) / 2;
1819     }
1820
1821     /* This crashes on native (tested on real windows XP / directx9 / nvidia and
1822      * qemu Win98 / directx7 / RGB software rasterizer):
1823      * passing non toplevel surfaces (sublevels) to Load (DX7 docs tell not to do this)
1824     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][1], NULL, texture_levels[0][1], NULL, 0);
1825     */
1826
1827     /* Freed in reverse order as native seems to dislike and crash on freeing top level surface first. */
1828     for (i = 0; i < 2; i++)
1829     {
1830         for (i1 = 7; i1 >= 0; i1--)
1831         {
1832             if (texture_levels[i][i1]) IDirectDrawSurface7_Release(texture_levels[i][i1]);
1833         }
1834     }
1835     memset(texture_levels, 0, sizeof(texture_levels));
1836
1837     /* Test texture size mismatch. */
1838     for (i = 0; i < 2; i++)
1839     {
1840         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1841         ddsd.dwSize = sizeof(ddsd);
1842         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1843         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1844         ddsd.dwWidth = i ? 256 : 128;
1845         ddsd.dwHeight = 128;
1846         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[i][0], NULL);
1847         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
1848         if (FAILED(hr)) goto out;
1849     }
1850
1851     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], NULL, texture_levels[0][0], NULL, 0);
1852     ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
1853
1854     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[0][0], NULL, texture_levels[1][0], NULL, 0);
1855     ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
1856
1857     IDirectDrawSurface7_Release(texture_levels[0][0]);
1858     IDirectDrawSurface7_Release(texture_levels[1][0]);
1859     memset(texture_levels, 0, sizeof(texture_levels));
1860
1861     /* Test loading mipmapped cubemap texture subrectangle from another similar texture. */
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.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES;
1869         ddsd.dwWidth = 128;
1870         ddsd.dwHeight = 128;
1871         U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
1872         U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
1873         U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
1874         U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
1875         U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
1876         U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
1877         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &cube_face_levels[i][0][0], NULL);
1878         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
1879         if (FAILED(hr)) goto out;
1880
1881         flags = DDSCAPS2_CUBEMAP_NEGATIVEX;
1882         for (i1 = 1; i1 < 6; i1++, flags <<= 1)
1883         {
1884             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1885             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | flags;
1886             hr = IDirectDrawSurface7_GetAttachedSurface(cube_face_levels[i][0][0], &ddsd.ddsCaps, &cube_face_levels[i][i1][0]);
1887             ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
1888             if (FAILED(hr)) goto out;
1889         }
1890
1891         for (i1 = 0; i1 < 6; i1++)
1892         {
1893             /* Check the number of created mipmaps */
1894             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1895             ddsd.dwSize = sizeof(ddsd);
1896             hr = IDirectDrawSurface7_GetSurfaceDesc(cube_face_levels[i][i1][0], &ddsd);
1897             ok(hr==DD_OK,"IDirectDrawSurface7_GetSurfaceDesc returned: %x\n",hr);
1898             ok(U2(ddsd).dwMipMapCount == 8, "unexpected mip count %u\n", U2(ddsd).dwMipMapCount);
1899             if (U2(ddsd).dwMipMapCount != 8) goto out;
1900
1901             for (i2 = 1; i2 < 8; i2++)
1902             {
1903                 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
1904                 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
1905                 hr = IDirectDrawSurface7_GetAttachedSurface(cube_face_levels[i][i1][i2 - 1], &ddsd.ddsCaps, &cube_face_levels[i][i1][i2]);
1906                 ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
1907                 if (FAILED(hr)) goto out;
1908             }
1909         }
1910     }
1911
1912     for (i = 0; i < 6; i++)
1913         for (i1 = 0; i1 < 8; i1++)
1914         {
1915             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1916             ddsd.dwSize = sizeof(ddsd);
1917             hr = IDirectDrawSurface7_Lock(cube_face_levels[0][i][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
1918             ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
1919             if (FAILED(hr)) goto out;
1920
1921             for (y = 0 ; y < ddsd.dwHeight; y++)
1922             {
1923                 DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
1924
1925                 for (x = 0; x < ddsd.dwWidth;  x++)
1926                 {
1927                     /* face number in low 4 bits of red, x stored in green component, y in blue. */
1928                     DWORD color = 0xf00000 | (i << 16) | (x << 8)  | y;
1929                     *textureRow++ = color;
1930                 }
1931             }
1932
1933             hr = IDirectDrawSurface7_Unlock(cube_face_levels[0][i][i1], NULL);
1934             ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
1935         }
1936
1937     for (i = 0; i < 6; i++)
1938         for (i1 = 0; i1 < 8; i1++)
1939         {
1940             memset(&ddbltfx, 0, sizeof(ddbltfx));
1941             ddbltfx.dwSize = sizeof(ddbltfx);
1942             U5(ddbltfx).dwFillColor = 0;
1943             hr = IDirectDrawSurface7_Blt(cube_face_levels[1][i][i1], NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
1944             ok(hr == DD_OK, "IDirectDrawSurface7_Blt failed with %08x\n", hr);
1945         }
1946
1947     loadpoint.x = loadpoint.y = 10;
1948     loadrect.left = 30;
1949     loadrect.top = 20;
1950     loadrect.right = 93;
1951     loadrect.bottom = 52;
1952
1953     hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[1][0][0], &loadpoint, cube_face_levels[0][0][0], &loadrect,
1954                                     DDSCAPS2_CUBEMAP_ALLFACES);
1955     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
1956
1957     for (i = 0; i < 6; i++)
1958     {
1959         loadpoint.x = loadpoint.y = 10;
1960         loadrect.left = 30;
1961         loadrect.top = 20;
1962         loadrect.right = 93;
1963         loadrect.bottom = 52;
1964
1965         for (i1 = 0; i1 < 8; i1++)
1966         {
1967             diff_count = 0;
1968             diff_count2 = 0;
1969
1970             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
1971             ddsd.dwSize = sizeof(ddsd);
1972             hr = IDirectDrawSurface7_Lock(cube_face_levels[1][i][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
1973             ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
1974             if (FAILED(hr)) goto out;
1975
1976             for (y = 0 ; y < ddsd.dwHeight; y++)
1977             {
1978                 DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
1979
1980                 for (x = 0; x < ddsd.dwWidth;  x++)
1981                 {
1982                     DWORD color = *textureRow++;
1983
1984                     if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
1985                         y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
1986                     {
1987                         if (color & 0xffffff) diff_count++;
1988                     }
1989                     else
1990                     {
1991                         DWORD r = (color & 0xff0000) >> 16;
1992                         DWORD g = (color & 0xff00) >> 8;
1993                         DWORD b = (color & 0xff);
1994
1995                         if (r != (0xf0 | i) || g != x + loadrect.left - loadpoint.x ||
1996                             b != y + loadrect.top - loadpoint.y) diff_count++;
1997                     }
1998
1999                     /* This codepath is for software RGB device. It has what looks like some weird off by one errors, but may
2000                     technically be correct as it's not precisely defined by docs. */
2001                     if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
2002                         y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top + 1)
2003                     {
2004                         if (color & 0xffffff) diff_count2++;
2005                     }
2006                     else
2007                     {
2008                         DWORD r = (color & 0xff0000) >> 16;
2009                         DWORD g = (color & 0xff00) >> 8;
2010                         DWORD b = (color & 0xff);
2011
2012                         if (r != (0xf0 | i) || !IS_VALUE_NEAR(g, x + loadrect.left - loadpoint.x) ||
2013                             !IS_VALUE_NEAR(b, y + loadrect.top - loadpoint.y)) diff_count2++;
2014                     }
2015                 }
2016             }
2017
2018             hr = IDirectDrawSurface7_Unlock(cube_face_levels[1][i][i1], NULL);
2019             ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2020
2021             ok(diff_count == 0 || diff_count2 == 0,
2022                 "Unexpected destination texture level pixels; %u differences at face %x level %d\n",
2023                 MIN(diff_count, diff_count2), i, i1);
2024
2025             loadpoint.x /= 2;
2026             loadpoint.y /= 2;
2027             loadrect.top /= 2;
2028             loadrect.left /= 2;
2029             loadrect.right = (loadrect.right + 1) / 2;
2030             loadrect.bottom = (loadrect.bottom + 1) / 2;
2031         }
2032     }
2033
2034     for (i = 0; i < 2; i++)
2035         for (i1 = 5; i1 >= 0; i1--)
2036             for (i2 = 7; i2 >= 0; i2--)
2037             {
2038                 if (cube_face_levels[i][i1][i2]) IDirectDrawSurface7_Release(cube_face_levels[i][i1][i2]);
2039             }
2040     memset(cube_face_levels, 0, sizeof(cube_face_levels));
2041
2042     /* Test cubemap loading from regular texture. */
2043     memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2044     ddsd.dwSize = sizeof(ddsd);
2045     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2046     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
2047     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES;
2048     ddsd.dwWidth = 128;
2049     ddsd.dwHeight = 128;
2050     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &cube_face_levels[0][0][0], NULL);
2051     ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2052     if (FAILED(hr)) goto out;
2053
2054     memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2055     ddsd.dwSize = sizeof(ddsd);
2056     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2057     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
2058     ddsd.dwWidth = 128;
2059     ddsd.dwHeight = 128;
2060     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[0][0], NULL);
2061     ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2062     if (FAILED(hr)) goto out;
2063
2064     hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[0][0][0], NULL, texture_levels[0][0], NULL,
2065                                     DDSCAPS2_CUBEMAP_ALLFACES);
2066     ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2067
2068     IDirectDrawSurface7_Release(cube_face_levels[0][0][0]);
2069     memset(cube_face_levels, 0, sizeof(cube_face_levels));
2070     IDirectDrawSurface7_Release(texture_levels[0][0]);
2071     memset(texture_levels, 0, sizeof(texture_levels));
2072
2073     /* Test cubemap loading from cubemap with different number of faces. */
2074     memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2075     ddsd.dwSize = sizeof(ddsd);
2076     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2077     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
2078     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX;
2079     ddsd.dwWidth = 128;
2080     ddsd.dwHeight = 128;
2081     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &cube_face_levels[0][0][0], NULL);
2082     ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2083     if (FAILED(hr)) goto out;
2084
2085     memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2086     ddsd.dwSize = sizeof(ddsd);
2087     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
2088     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
2089     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_POSITIVEY;
2090     ddsd.dwWidth = 128;
2091     ddsd.dwHeight = 128;
2092     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &cube_face_levels[1][0][0], NULL);
2093     ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2094     if (FAILED(hr)) goto out;
2095
2096     /* INVALIDPARAMS tests currently would fail because wine doesn't support partial cube faces
2097         (the above created cubemaps will have all faces. */
2098     hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[0][0][0], NULL, cube_face_levels[1][0][0], NULL,
2099                                     DDSCAPS2_CUBEMAP_ALLFACES);
2100     todo_wine ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2101
2102     hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[0][0][0], NULL, cube_face_levels[1][0][0], NULL,
2103                                     DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_POSITIVEY);
2104     todo_wine ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2105
2106     hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[0][0][0], NULL, cube_face_levels[1][0][0], NULL,
2107                                     DDSCAPS2_CUBEMAP_POSITIVEX);
2108     todo_wine ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2109
2110     hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[1][0][0], NULL, cube_face_levels[0][0][0], NULL,
2111                                     DDSCAPS2_CUBEMAP_ALLFACES);
2112     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2113
2114     hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[1][0][0], NULL, cube_face_levels[0][0][0], NULL,
2115                                     DDSCAPS2_CUBEMAP_POSITIVEX);
2116     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2117
2118     hr = IDirect3DDevice7_Load(lpD3DDevice, cube_face_levels[1][0][0], NULL, cube_face_levels[0][0][0], NULL,
2119                                     DDSCAPS2_CUBEMAP_POSITIVEZ);
2120     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2121
2122     IDirectDrawSurface7_Release(cube_face_levels[0][0][0]);
2123     IDirectDrawSurface7_Release(cube_face_levels[1][0][0]);
2124     memset(cube_face_levels, 0, sizeof(cube_face_levels));
2125
2126     /* Test texture loading with different mip level count (larger levels match, smaller levels missing in destination. */
2127     for (i = 0; i < 2; i++)
2128     {
2129         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2130         ddsd.dwSize = sizeof(ddsd);
2131         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT;
2132         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
2133         ddsd.dwWidth = 128;
2134         ddsd.dwHeight = 128;
2135         U2(ddsd).dwMipMapCount = i ? 4 : 8;
2136         U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
2137         U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
2138         U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
2139         U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
2140         U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
2141         U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
2142         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[i][0], NULL);
2143         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2144         if (FAILED(hr)) goto out;
2145
2146         /* Check the number of created mipmaps */
2147         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2148         ddsd.dwSize = sizeof(ddsd);
2149         hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[i][0], &ddsd);
2150         ok(hr==DD_OK,"IDirectDrawSurface7_GetSurfaceDesc returned: %x\n",hr);
2151         ok(U2(ddsd).dwMipMapCount == (i ? 4 : 8), "unexpected mip count %u\n", U2(ddsd).dwMipMapCount);
2152         if (U2(ddsd).dwMipMapCount != (i ? 4 : 8)) goto out;
2153
2154         for (i1 = 1; i1 < (i ? 4 : 8); i1++)
2155         {
2156             hr = IDirectDrawSurface7_GetAttachedSurface(texture_levels[i][i1 - 1], &ddsd.ddsCaps, &texture_levels[i][i1]);
2157             ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
2158             if (FAILED(hr)) goto out;
2159         }
2160     }
2161
2162     for (i1 = 0; i1 < 8; i1++)
2163     {
2164         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2165         ddsd.dwSize = sizeof(ddsd);
2166         hr = IDirectDrawSurface7_Lock(texture_levels[0][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
2167         ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2168         if (FAILED(hr)) goto out;
2169
2170         for (y = 0 ; y < ddsd.dwHeight; y++)
2171         {
2172             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2173
2174             for (x = 0; x < ddsd.dwWidth;  x++)
2175             {
2176                 /* x stored in green component, y in blue. */
2177                 DWORD color = 0xf00000 | (i1 << 16) | (x << 8)  | y;
2178                 *textureRow++ = color;
2179             }
2180         }
2181
2182         hr = IDirectDrawSurface7_Unlock(texture_levels[0][i1], NULL);
2183         ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2184     }
2185
2186     for (i1 = 0; i1 < 4; i1++)
2187     {
2188         memset(&ddbltfx, 0, sizeof(ddbltfx));
2189         ddbltfx.dwSize = sizeof(ddbltfx);
2190         U5(ddbltfx).dwFillColor = 0;
2191         hr = IDirectDrawSurface7_Blt(texture_levels[1][i1], NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
2192         ok(hr == DD_OK, "IDirectDrawSurface7_Blt failed with %08x\n", hr);
2193     }
2194
2195     loadpoint.x = loadpoint.y = 31;
2196     loadrect.left = 30;
2197     loadrect.top = 20;
2198     loadrect.right = 93;
2199     loadrect.bottom = 52;
2200
2201     /* Destination mip levels are a subset of source mip levels. */
2202     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
2203     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2204
2205     for (i1 = 0; i1 < 4; i1++)
2206     {
2207         diff_count = 0;
2208         diff_count2 = 0;
2209
2210         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2211         ddsd.dwSize = sizeof(ddsd);
2212         hr = IDirectDrawSurface7_Lock(texture_levels[1][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
2213         ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2214         if (FAILED(hr)) goto out;
2215
2216         for (y = 0 ; y < ddsd.dwHeight; y++)
2217         {
2218             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2219
2220             for (x = 0; x < ddsd.dwWidth;  x++)
2221             {
2222                 DWORD color = *textureRow++;
2223
2224                 if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
2225                     y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
2226                 {
2227                     if (color & 0xffffff) diff_count++;
2228                 }
2229                 else
2230                 {
2231                     DWORD r = (color & 0xff0000) >> 16;
2232                     DWORD g = (color & 0xff00) >> 8;
2233                     DWORD b = (color & 0xff);
2234
2235                     if (r != (0xf0 | i1) || g != x + loadrect.left - loadpoint.x ||
2236                         b != y + loadrect.top - loadpoint.y) diff_count++;
2237                 }
2238
2239                 /* This codepath is for software RGB device. It has what looks like some weird off by one errors, but may
2240                 technically be correct as it's not precisely defined by docs. */
2241                 if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
2242                     y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top + 1)
2243                 {
2244                     if (color & 0xffffff) diff_count2++;
2245                 }
2246                 else
2247                 {
2248                     DWORD r = (color & 0xff0000) >> 16;
2249                     DWORD g = (color & 0xff00) >> 8;
2250                     DWORD b = (color & 0xff);
2251
2252                     if (r != (0xf0 | i1) || !IS_VALUE_NEAR(g, x + loadrect.left - loadpoint.x) ||
2253                         !IS_VALUE_NEAR(b, y + loadrect.top - loadpoint.y)) diff_count2++;
2254                 }
2255             }
2256         }
2257
2258         hr = IDirectDrawSurface7_Unlock(texture_levels[1][i1], NULL);
2259         ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2260
2261         ok(diff_count == 0 || diff_count2 == 0, "Unexpected destination texture level pixels; %u differences at %d level\n",
2262              MIN(diff_count, diff_count2), i1);
2263
2264         loadpoint.x /= 2;
2265         loadpoint.y /= 2;
2266         loadrect.top /= 2;
2267         loadrect.left /= 2;
2268         loadrect.right = (loadrect.right + 1) / 2;
2269         loadrect.bottom = (loadrect.bottom + 1) / 2;
2270     }
2271
2272     /* Destination mip levels are a superset of source mip levels (should fail). */
2273     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[0][0], &loadpoint, texture_levels[1][0], &loadrect, 0);
2274     ok(hr==DDERR_INVALIDPARAMS, "IDirect3DDevice7_Load returned: %x\n",hr);
2275
2276     for (i = 0; i < 2; i++)
2277     {
2278         for (i1 = 7; i1 >= 0; i1--)
2279         {
2280             if (texture_levels[i][i1]) IDirectDrawSurface7_Release(texture_levels[i][i1]);
2281         }
2282     }
2283     memset(texture_levels, 0, sizeof(texture_levels));
2284
2285     /* Test loading from mipmap texture to a regular texture that matches one sublevel in size. */
2286     memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2287     ddsd.dwSize = sizeof(ddsd);
2288     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
2289     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
2290     ddsd.dwWidth = 128;
2291     ddsd.dwHeight = 128;
2292     U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
2293     U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
2294     U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
2295     U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
2296     U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
2297     U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
2298     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[0][0], NULL);
2299     ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2300     if (FAILED(hr)) goto out;
2301
2302     memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2303     ddsd.dwSize = sizeof(ddsd);
2304     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
2305     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
2306     ddsd.dwWidth = 32;
2307     ddsd.dwHeight = 32;
2308     U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
2309     U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
2310     U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
2311     U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
2312     U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
2313     U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
2314     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[1][0], NULL);
2315     ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2316     if (FAILED(hr)) goto out;
2317
2318     for (i1 = 1; i1 < 8; i1++)
2319     {
2320         hr = IDirectDrawSurface7_GetAttachedSurface(texture_levels[0][i1 - 1], &ddsd.ddsCaps, &texture_levels[0][i1]);
2321         ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
2322         if (FAILED(hr)) goto out;
2323     }
2324
2325     for (i1 = 0; i1 < 8; i1++)
2326     {
2327         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2328         ddsd.dwSize = sizeof(ddsd);
2329         hr = IDirectDrawSurface7_Lock(texture_levels[0][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
2330         ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2331         if (FAILED(hr)) goto out;
2332
2333         for (y = 0 ; y < ddsd.dwHeight; y++)
2334         {
2335             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2336
2337             for (x = 0; x < ddsd.dwWidth;  x++)
2338             {
2339                 /* x stored in green component, y in blue. */
2340                 DWORD color = 0xf00000 | (i1 << 16) | (x << 8)  | y;
2341                 *textureRow++ = color;
2342             }
2343         }
2344
2345         hr = IDirectDrawSurface7_Unlock(texture_levels[0][i1], NULL);
2346         ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2347     }
2348
2349     memset(&ddbltfx, 0, sizeof(ddbltfx));
2350     ddbltfx.dwSize = sizeof(ddbltfx);
2351     U5(ddbltfx).dwFillColor = 0;
2352     hr = IDirectDrawSurface7_Blt(texture_levels[1][0], NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
2353     ok(hr == DD_OK, "IDirectDrawSurface7_Blt failed with %08x\n", hr);
2354
2355     loadpoint.x = loadpoint.y = 32;
2356     loadrect.left = 32;
2357     loadrect.top = 32;
2358     loadrect.right = 96;
2359     loadrect.bottom = 96;
2360
2361     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
2362     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2363
2364     loadpoint.x /= 4;
2365     loadpoint.y /= 4;
2366     loadrect.top /= 4;
2367     loadrect.left /= 4;
2368     loadrect.right = (loadrect.right + 3) / 4;
2369     loadrect.bottom = (loadrect.bottom + 3) / 4;
2370
2371     /* NOTE: something in either nvidia driver or directx9 on WinXP appears to be broken:
2372      * this kind of Load calls (to subset with smaller surface(s)) produces wrong results with
2373      * copied subrectangles divided more than needed, without apparent logic. But it works
2374      * as expected on qemu / Win98 / directx7 / RGB device. Some things are broken on XP, e.g.
2375      * some games don't work that worked in Win98, so it is assumed here XP results are wrong.
2376      * The following code attempts to detect broken results, actual tests will then be skipped
2377      */
2378     load_mip_subset_broken = TRUE;
2379     diff_count = 0;
2380
2381     memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2382     ddsd.dwSize = sizeof(ddsd);
2383     hr = IDirectDrawSurface7_Lock(texture_levels[1][0], NULL, &ddsd, DDLOCK_WAIT, NULL);
2384     ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2385     if (FAILED(hr)) goto out;
2386
2387     for (y = 0 ; y < ddsd.dwHeight; y++)
2388     {
2389         DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2390
2391         for (x = 0; x < ddsd.dwWidth;  x++)
2392         {
2393             DWORD color = *textureRow++;
2394
2395             if (x < 2 || x >= 2 + 4 ||
2396                 y < 2 || y >= 2 + 4)
2397             {
2398                 if (color & 0xffffff) diff_count++;
2399             }
2400             else
2401             {
2402                 DWORD r = (color & 0xff0000) >> 16;
2403
2404                 if ((r & (0xf0)) != 0xf0) diff_count++;
2405             }
2406         }
2407     }
2408
2409     if (diff_count) load_mip_subset_broken = FALSE;
2410
2411     if (load_mip_subset_broken) {
2412         skip("IDirect3DDevice7_Load is broken (happens on some modern Windows installations like XP). Skipping affected tests.\n");
2413     } else {
2414         diff_count = 0;
2415
2416         for (y = 0 ; y < ddsd.dwHeight; y++)
2417         {
2418             DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2419
2420             for (x = 0; x < ddsd.dwWidth;  x++)
2421             {
2422                 DWORD color = *textureRow++;
2423
2424                 if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
2425                     y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
2426                 {
2427                     if (color & 0xffffff) diff_count++;
2428                 }
2429                 else
2430                 {
2431                     DWORD r = (color & 0xff0000) >> 16;
2432                     DWORD g = (color & 0xff00) >> 8;
2433                     DWORD b = (color & 0xff);
2434
2435                     if (r != (0xf0 | 2) || g != x + loadrect.left - loadpoint.x ||
2436                         b != y + loadrect.top - loadpoint.y) diff_count++;
2437                 }
2438             }
2439         }
2440     }
2441
2442     hr = IDirectDrawSurface7_Unlock(texture_levels[1][0], NULL);
2443     ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2444
2445     ok(diff_count == 0, "Unexpected destination texture level pixels; %u differences\n", diff_count);
2446
2447     for (i = 0; i < 2; i++)
2448     {
2449         for (i1 = 7; i1 >= 0; i1--)
2450         {
2451             if (texture_levels[i][i1]) IDirectDrawSurface7_Release(texture_levels[i][i1]);
2452         }
2453     }
2454     memset(texture_levels, 0, sizeof(texture_levels));
2455
2456     if (!load_mip_subset_broken)
2457     {
2458         /* Test loading when destination mip levels are a subset of source mip levels and start from smaller
2459         * surface (than first source mip level)
2460         */
2461         for (i = 0; i < 2; i++)
2462         {
2463             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2464             ddsd.dwSize = sizeof(ddsd);
2465             ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
2466             if (i) ddsd.dwFlags |= DDSD_MIPMAPCOUNT;
2467             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
2468             ddsd.dwWidth = i ? 32 : 128;
2469             ddsd.dwHeight = i ? 32 : 128;
2470             if (i) U2(ddsd).dwMipMapCount = 4;
2471             U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
2472             U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB;
2473             U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 32;
2474             U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0x00FF0000;
2475             U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x0000FF00;
2476             U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x000000FF;
2477             hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[i][0], NULL);
2478             ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2479             if (FAILED(hr)) goto out;
2480
2481             /* Check the number of created mipmaps */
2482             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2483             ddsd.dwSize = sizeof(ddsd);
2484             hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[i][0], &ddsd);
2485             ok(hr==DD_OK,"IDirectDrawSurface7_GetSurfaceDesc returned: %x\n",hr);
2486             ok(U2(ddsd).dwMipMapCount == (i ? 4 : 8), "unexpected mip count %u\n", U2(ddsd).dwMipMapCount);
2487             if (U2(ddsd).dwMipMapCount != (i ? 4 : 8)) goto out;
2488
2489             for (i1 = 1; i1 < (i ? 4 : 8); i1++)
2490             {
2491                 hr = IDirectDrawSurface7_GetAttachedSurface(texture_levels[i][i1 - 1], &ddsd.ddsCaps, &texture_levels[i][i1]);
2492                 ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
2493                 if (FAILED(hr)) goto out;
2494             }
2495         }
2496
2497         for (i1 = 0; i1 < 8; i1++)
2498         {
2499             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2500             ddsd.dwSize = sizeof(ddsd);
2501             hr = IDirectDrawSurface7_Lock(texture_levels[0][i1], NULL, &ddsd, DDLOCK_WAIT, NULL);
2502             ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2503             if (FAILED(hr)) goto out;
2504
2505             for (y = 0 ; y < ddsd.dwHeight; y++)
2506             {
2507                 DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2508
2509                 for (x = 0; x < ddsd.dwWidth;  x++)
2510                 {
2511                     /* x stored in green component, y in blue. */
2512                     DWORD color = 0xf00000 | (i1 << 16) | (x << 8)  | y;
2513                     *textureRow++ = color;
2514                 }
2515             }
2516
2517             hr = IDirectDrawSurface7_Unlock(texture_levels[0][i1], NULL);
2518             ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2519         }
2520
2521         for (i1 = 0; i1 < 4; i1++)
2522         {
2523             memset(&ddbltfx, 0, sizeof(ddbltfx));
2524             ddbltfx.dwSize = sizeof(ddbltfx);
2525             U5(ddbltfx).dwFillColor = 0;
2526             hr = IDirectDrawSurface7_Blt(texture_levels[1][i1], NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
2527             ok(hr == DD_OK, "IDirectDrawSurface7_Blt failed with %08x\n", hr);
2528         }
2529
2530         loadpoint.x = loadpoint.y = 0;
2531         loadrect.left = 0;
2532         loadrect.top = 0;
2533         loadrect.right = 64;
2534         loadrect.bottom = 64;
2535
2536         hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], &loadpoint, texture_levels[0][0], &loadrect, 0);
2537         ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2538
2539         i = 0;
2540         for (i1 = 0; i1 < 8 && i < 4; i1++)
2541         {
2542             DDSURFACEDESC2 ddsd2;
2543
2544             memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2545             ddsd.dwSize = sizeof(ddsd);
2546             hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[0][i1], &ddsd);
2547
2548             memset(&ddsd2, 0, sizeof(DDSURFACEDESC2));
2549             ddsd2.dwSize = sizeof(ddsd2);
2550             hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[1][i], &ddsd2);
2551
2552             if (ddsd.dwWidth == ddsd2.dwWidth && ddsd.dwHeight == ddsd2.dwHeight)
2553             {
2554                 diff_count = 0;
2555
2556                 memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2557                 ddsd.dwSize = sizeof(ddsd);
2558                 hr = IDirectDrawSurface7_Lock(texture_levels[1][i], NULL, &ddsd, DDLOCK_WAIT, NULL);
2559                 ok(hr==DD_OK, "IDirectDrawSurface7_Lock returned: %x\n",hr);
2560                 if (FAILED(hr)) goto out;
2561
2562                 for (y = 0 ; y < ddsd.dwHeight; y++)
2563                 {
2564                     DWORD *textureRow = (DWORD*)((char*)ddsd.lpSurface + y * U1(ddsd).lPitch);
2565
2566                     for (x = 0; x < ddsd.dwWidth;  x++)
2567                     {
2568                         DWORD color = *textureRow++;
2569
2570                         if (x < loadpoint.x || x >= loadpoint.x + loadrect.right - loadrect.left ||
2571                             y < loadpoint.y || y >= loadpoint.y + loadrect.bottom - loadrect.top)
2572                         {
2573                             if (color & 0xffffff) diff_count++;
2574                         }
2575                         else
2576                         {
2577                             DWORD r = (color & 0xff0000) >> 16;
2578                             DWORD g = (color & 0xff00) >> 8;
2579                             DWORD b = (color & 0xff);
2580
2581                             if (r != (0xf0 | i1) || g != x + loadrect.left - loadpoint.x ||
2582                                 b != y + loadrect.top - loadpoint.y) diff_count++;
2583                         }
2584                     }
2585                 }
2586
2587                 hr = IDirectDrawSurface7_Unlock(texture_levels[1][i], NULL);
2588                 ok(hr==DD_OK, "IDirectDrawSurface7_Unlock returned: %x\n",hr);
2589
2590                 ok(diff_count == 0, "Unexpected destination texture level pixels; %u differences at %d level\n", diff_count, i1);
2591
2592                 i++;
2593             }
2594
2595             loadpoint.x /= 2;
2596             loadpoint.y /= 2;
2597             loadrect.top /= 2;
2598             loadrect.left /= 2;
2599             loadrect.right = (loadrect.right + 1) / 2;
2600             loadrect.bottom = (loadrect.bottom + 1) / 2;
2601         }
2602
2603         for (i = 0; i < 2; i++)
2604         {
2605             for (i1 = 7; i1 >= 0; i1--)
2606             {
2607                 if (texture_levels[i][i1]) IDirectDrawSurface7_Release(texture_levels[i][i1]);
2608             }
2609         }
2610         memset(texture_levels, 0, sizeof(texture_levels));
2611     }
2612
2613     /* Test palette copying. */
2614     for (i = 0; i < 2; i++)
2615     {
2616         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2617         ddsd.dwSize = sizeof(ddsd);
2618         ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
2619         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
2620         ddsd.dwWidth = 128;
2621         ddsd.dwHeight = 128;
2622         U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
2623         U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
2624         U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 8;
2625         hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &texture_levels[i][0], NULL);
2626         ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
2627         if (FAILED(hr)) goto out;
2628
2629         /* Check the number of created mipmaps */
2630         memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
2631         ddsd.dwSize = sizeof(ddsd);
2632         hr = IDirectDrawSurface7_GetSurfaceDesc(texture_levels[i][0], &ddsd);
2633         ok(hr==DD_OK,"IDirectDrawSurface7_GetSurfaceDesc returned: %x\n",hr);
2634         ok(U2(ddsd).dwMipMapCount == 8, "unexpected mip count %u\n", U2(ddsd).dwMipMapCount);
2635         if (U2(ddsd).dwMipMapCount != 8) goto out;
2636
2637         for (i1 = 1; i1 < 8; i1++)
2638         {
2639             hr = IDirectDrawSurface7_GetAttachedSurface(texture_levels[i][i1 - 1], &ddsd.ddsCaps, &texture_levels[i][i1]);
2640             ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
2641             if (FAILED(hr)) goto out;
2642         }
2643     }
2644
2645     memset(table1, 0, sizeof(table1));
2646     for (i = 0; i < 3; i++)
2647     {
2648         table1[0].peBlue = i + 1;
2649         hr = IDirectDraw7_CreatePalette(lpDD, DDPCAPS_ALLOW256 | DDPCAPS_8BIT, table1, &palettes[i], NULL);
2650         ok(hr == DD_OK, "CreatePalette returned %08x\n", hr);
2651         if (FAILED(hr))
2652         {
2653             skip("IDirectDraw7_CreatePalette failed; skipping further tests\n");
2654             goto out;
2655         }
2656     }
2657
2658     hr = IDirectDrawSurface7_SetPalette(texture_levels[0][0], palettes[0]);
2659     ok(hr==DD_OK, "IDirectDrawSurface7_SetPalette returned: %x\n", hr);
2660
2661     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], NULL, texture_levels[0][0], NULL, 0);
2662     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2663
2664     hr = IDirectDrawSurface7_GetPalette(texture_levels[1][0], &palettes[4]);
2665     ok(hr==DDERR_NOPALETTEATTACHED, "IDirectDrawSurface7_GetPalette returned: %x\n", hr);
2666
2667     hr = IDirectDrawSurface7_SetPalette(texture_levels[0][1], palettes[1]);
2668     todo_wine ok(hr==DDERR_NOTONMIPMAPSUBLEVEL, "IDirectDrawSurface7_SetPalette returned: %x\n", hr);
2669     hr = IDirectDrawSurface7_SetPalette(texture_levels[1][0], palettes[2]);
2670     ok(hr==DD_OK, "IDirectDrawSurface7_SetPalette returned: %x\n", hr);
2671
2672     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], NULL, texture_levels[0][0], NULL, 0);
2673     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2674
2675     memset(table1, 0, sizeof(table1));
2676     hr = IDirectDrawSurface7_GetPalette(texture_levels[1][0], &palettes[4]);
2677     ok(hr==DD_OK, "IDirectDrawSurface7_GetPalette returned: %x\n", hr);
2678     if (SUCCEEDED(hr))
2679     {
2680         hr = IDirectDrawPalette_GetEntries(palettes[4], 0, 0, 256, table1);
2681         ok(hr == DD_OK, "IDirectDrawPalette_GetEntries returned %08x\n", hr);
2682         ok(table1[0].peBlue == 1, "Unexpected palette color after load: %u\n", (unsigned)table1[0].peBlue);
2683     }
2684
2685     /* Test colorkey copying. */
2686     ddckey.dwColorSpaceLowValue = ddckey.dwColorSpaceHighValue = 64;
2687     hr = IDirectDrawSurface7_SetColorKey(texture_levels[0][0], DDCKEY_SRCBLT, &ddckey);
2688     ok(hr==DD_OK, "IDirectDrawSurface7_SetColorKey returned: %x\n", hr);
2689     hr = IDirectDrawSurface7_SetColorKey(texture_levels[0][1], DDCKEY_SRCBLT, &ddckey);
2690     todo_wine ok(hr==DDERR_NOTONMIPMAPSUBLEVEL, "IDirectDrawSurface7_SetColorKey returned: %x\n", hr);
2691
2692     hr = IDirectDrawSurface7_GetColorKey(texture_levels[1][0], DDCKEY_SRCBLT, &ddckey);
2693     ok(hr==DDERR_NOCOLORKEY, "IDirectDrawSurface7_GetColorKey returned: %x\n", hr);
2694
2695     hr = IDirect3DDevice7_Load(lpD3DDevice, texture_levels[1][0], NULL, texture_levels[0][0], NULL, 0);
2696     ok(hr==D3D_OK, "IDirect3DDevice7_Load returned: %x\n",hr);
2697
2698     hr = IDirectDrawSurface7_GetColorKey(texture_levels[1][0], DDCKEY_SRCBLT, &ddckey);
2699     ok(hr==DD_OK, "IDirectDrawSurface7_GetColorKey returned: %x\n", hr);
2700     ok(ddckey.dwColorSpaceLowValue == ddckey.dwColorSpaceHighValue && ddckey.dwColorSpaceLowValue == 64,
2701         "Unexpected color key values: %u - %u\n", ddckey.dwColorSpaceLowValue, ddckey.dwColorSpaceHighValue);
2702
2703     out:
2704
2705     for (i = 0; i < 5; i++)
2706     {
2707         if (palettes[i]) IDirectDrawPalette_Release(palettes[i]);
2708     }
2709
2710     for (i = 0; i < 2; i++)
2711     {
2712         for (i1 = 7; i1 >= 0; i1--)
2713         {
2714             if (texture_levels[i][i1]) IDirectDrawSurface7_Release(texture_levels[i][i1]);
2715         }
2716     }
2717
2718     for (i = 0; i < 2; i++)
2719         for (i1 = 5; i1 >= 0; i1--)
2720             for (i2 = 7; i2 >= 0; i2--)
2721             {
2722                 if (cube_face_levels[i][i1][i2]) IDirectDrawSurface7_Release(cube_face_levels[i][i1][i2]);
2723             }
2724 }
2725
2726 START_TEST(d3d)
2727 {
2728     init_function_pointers();
2729     if(!pDirectDrawCreateEx) {
2730         skip("function DirectDrawCreateEx not available\n");
2731         return;
2732     }
2733
2734     if(!CreateDirect3D()) {
2735         skip("Skipping d3d7 tests\n");
2736     } else {
2737         LightTest();
2738         ProcessVerticesTest();
2739         StateTest();
2740         SceneTest();
2741         LimitTest();
2742         D3D7EnumTest();
2743         CapsTest();
2744         VertexBufferDescTest();
2745         D3D7_OldRenderStateTest();
2746         DeviceLoadTest();
2747         ReleaseDirect3D();
2748     }
2749
2750     if (!D3D1_createObjects()) {
2751         skip("Skipping d3d1 tests\n");
2752     } else {
2753         Direct3D1Test();
2754         TextureLoadTest();
2755         D3D1_releaseObjects();
2756     }
2757 }