d3d8/tests: Add some message processing to test_wndproc().
[wine] / dlls / d3d8 / tests / stateblock.c
1 /*
2  * Copyright 2006 Ivan Gyurdiev
3  * Copyright 2005, 2008 Henri Verbeet
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #define COBJMACROS
21 #include <d3d8.h>
22 #include "wine/test.h"
23
24 static DWORD texture_stages;
25
26 static HWND create_window(void)
27 {
28     WNDCLASS wc = {0};
29     wc.lpfnWndProc = DefWindowProc;
30     wc.lpszClassName = "d3d8_test_wc";
31     RegisterClass(&wc);
32
33     return CreateWindow("d3d8_test_wc", "d3d8_test", 0, 0, 0, 0, 0, 0, 0, 0, 0);
34 }
35
36 static HRESULT init_d3d8(HMODULE d3d8_module, IDirect3DDevice8 **device, D3DPRESENT_PARAMETERS *device_pparams)
37 {
38     IDirect3D8 * (WINAPI *d3d8_create)(UINT SDKVersion) = 0;
39     D3DDISPLAYMODE d3ddm;
40     IDirect3D8 *d3d8 = 0;
41     HWND window;
42     HRESULT hr;
43
44     d3d8_create = (void *)GetProcAddress(d3d8_module, "Direct3DCreate8");
45     if (!d3d8_create) return E_FAIL;
46
47     d3d8 = d3d8_create(D3D_SDK_VERSION);
48     if (!d3d8)
49     {
50         skip("Failed to create D3D8 object.\n");
51         return E_FAIL;
52     }
53
54     window = create_window();
55
56     IDirect3D8_GetAdapterDisplayMode(d3d8, D3DADAPTER_DEFAULT, &d3ddm);
57     memset(device_pparams, 0, sizeof(*device_pparams));
58     device_pparams->Windowed = TRUE;
59     device_pparams->SwapEffect = D3DSWAPEFFECT_DISCARD;
60     device_pparams->BackBufferFormat = d3ddm.Format;
61
62     hr = IDirect3D8_CreateDevice(d3d8, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
63             D3DCREATE_SOFTWARE_VERTEXPROCESSING, device_pparams, device);
64     ok(SUCCEEDED(hr) || hr == D3DERR_NOTAVAILABLE || broken(hr == D3DERR_INVALIDCALL),
65             "IDirect3D8_CreateDevice failed, hr %#x.\n", hr);
66
67     return hr;
68 }
69
70 static void test_begin_end_state_block(IDirect3DDevice8 *device)
71 {
72     DWORD state_block;
73     HRESULT hr;
74
75     /* Should succeed */
76     hr = IDirect3DDevice8_BeginStateBlock(device);
77     ok(SUCCEEDED(hr), "BeginStateBlock failed, hr %#x.\n", hr);
78     if (FAILED(hr)) return;
79
80     /* Calling BeginStateBlock while recording should return D3DERR_INVALIDCALL */
81     hr = IDirect3DDevice8_BeginStateBlock(device);
82     ok(hr == D3DERR_INVALIDCALL, "BeginStateBlock returned %#x, expected %#x.\n", hr, D3DERR_INVALIDCALL);
83     if (hr != D3DERR_INVALIDCALL) return;
84
85     /* Should succeed */
86     state_block = 0xdeadbeef;
87     hr = IDirect3DDevice8_EndStateBlock(device, &state_block);
88     ok(SUCCEEDED(hr) && state_block && state_block != 0xdeadbeef,
89             "EndStateBlock returned: hr %#x, state_block %#x. "
90             "Expected hr %#x, state_block != 0, state_block != 0xdeadbeef.\n", hr, state_block, D3D_OK);
91     IDirect3DDevice8_DeleteStateBlock(device, state_block);
92
93     /* Calling EndStateBlock while not recording should return D3DERR_INVALIDCALL.
94      * state_block should not be touched. */
95     state_block = 0xdeadbeef;
96     hr = IDirect3DDevice8_EndStateBlock(device, &state_block);
97     ok(hr == D3DERR_INVALIDCALL && state_block == 0xdeadbeef,
98             "EndStateBlock returned: hr %#x, state_block %#x. "
99             "Expected hr %#x, state_block 0xdeadbeef.\n", hr, state_block, D3DERR_INVALIDCALL);
100 }
101
102 /* ============================ State Testing Framework ========================== */
103
104 struct state_test
105 {
106     const char *test_name;
107
108     /* The initial data is usually the same
109      * as the default data, but a write can have side effects.
110      * The initial data is tested first, before any writes take place
111      * The default data can be tested after a write */
112     const void *initial_data;
113
114     /* The default data is the standard state to compare
115      * against, and restore to */
116     const void *default_data;
117
118     /* The test data is the experiment data to try
119      * in - what we want to write
120      * out - what windows will actually write (not necessarily the same)  */
121     const void *test_data_in;
122     const void *test_data_out_all;
123     const void *test_data_out_vertex;
124     const void *test_data_out_pixel;
125
126     HRESULT (*init)(IDirect3DDevice8 *device, struct state_test *test);
127     void (*cleanup)(IDirect3DDevice8 *device, struct state_test *test);
128     void (*apply_data)(IDirect3DDevice8 *device, const struct state_test *test,
129             const void *data);
130     void (*check_data)(IDirect3DDevice8 *device, const struct state_test *test,
131             const void *data_expected, unsigned int chain_stage);
132
133     /* Test arguments */
134     const void *test_arg;
135
136     /* Test-specific context data */
137     void *test_context;
138 };
139
140 /* See below for explanation of the flags */
141 #define EVENT_OK    0
142 #define EVENT_ERROR -1
143
144 struct event_data
145 {
146     DWORD stateblock;
147     IDirect3DSurface8 *original_render_target;
148     IDirect3DSwapChain8 *new_swap_chain;
149 };
150
151 enum stateblock_data
152 {
153     SB_DATA_NONE = 0,
154     SB_DATA_DEFAULT,
155     SB_DATA_INITIAL,
156     SB_DATA_TEST_IN,
157     SB_DATA_TEST_ALL,
158     SB_DATA_TEST_VERTEX,
159     SB_DATA_TEST_PIXEL,
160 };
161
162 struct event
163 {
164     int (*event_fn)(IDirect3DDevice8 *device, struct event_data *event_data);
165     enum stateblock_data check;
166     enum stateblock_data apply;
167 };
168
169 static const void *get_event_data(const struct state_test *test, enum stateblock_data data)
170 {
171     switch (data)
172     {
173         case SB_DATA_DEFAULT:
174             return test->default_data;
175
176         case SB_DATA_INITIAL:
177             return test->initial_data;
178
179         case SB_DATA_TEST_IN:
180             return test->test_data_in;
181
182         case SB_DATA_TEST_ALL:
183             return test->test_data_out_all;
184
185         case SB_DATA_TEST_VERTEX:
186             return test->test_data_out_vertex;
187
188         case SB_DATA_TEST_PIXEL:
189             return test->test_data_out_pixel;
190
191         default:
192             return NULL;
193     }
194 }
195
196 /* This is an event-machine, which tests things.
197  * It tests get and set operations for a batch of states, based on
198  * results from the event function, which directs what's to be done */
199 static void execute_test_chain(IDirect3DDevice8 *device, struct state_test *test,
200         unsigned int ntests, struct event *event, unsigned int nevents, struct event_data *event_data)
201 {
202     unsigned int i, j;
203
204     /* For each queued event */
205     for (j = 0; j < nevents; ++j)
206     {
207         const void *data;
208
209         /* Execute the next event handler (if available). */
210         if (event[j].event_fn)
211         {
212             if (event[j].event_fn(device, event_data) == EVENT_ERROR)
213             {
214                 trace("Stage %u in error state, aborting.\n", j);
215                 break;
216             }
217         }
218
219         if (event[j].check != SB_DATA_NONE)
220         {
221             for (i = 0; i < ntests; ++i)
222             {
223                 data = get_event_data(&test[i], event[j].check);
224                 test[i].check_data(device, &test[i], data, j);
225             }
226         }
227
228         if (event[j].apply != SB_DATA_NONE)
229         {
230             for (i = 0; i < ntests; ++i)
231             {
232                 data = get_event_data(&test[i], event[j].apply);
233                 test[i].apply_data(device, &test[i], data);
234             }
235         }
236     }
237
238     /* Attempt to reset any changes made. */
239     for (i = 0; i < ntests; ++i)
240     {
241         test[i].apply_data(device, &test[i], test[i].default_data);
242     }
243 }
244
245 static int switch_render_target(IDirect3DDevice8* device, struct event_data *event_data)
246 {
247     D3DPRESENT_PARAMETERS present_parameters;
248     IDirect3DSwapChain8 *swapchain = NULL;
249     IDirect3DSurface8 *backbuffer = NULL;
250     D3DDISPLAYMODE d3ddm;
251     HRESULT hr;
252
253     /* Parameters for new swapchain */
254     IDirect3DDevice8_GetDisplayMode(device, &d3ddm);
255     memset(&present_parameters, 0, sizeof(present_parameters));
256     present_parameters.Windowed = TRUE;
257     present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
258     present_parameters.BackBufferFormat = d3ddm.Format;
259
260     /* Create new swapchain */
261     hr = IDirect3DDevice8_CreateAdditionalSwapChain(device, &present_parameters, &swapchain);
262     ok(SUCCEEDED(hr), "CreateAdditionalSwapChain returned %#x.\n", hr);
263     if (FAILED(hr)) goto error;
264
265     /* Get its backbuffer */
266     hr = IDirect3DSwapChain8_GetBackBuffer(swapchain, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
267     ok(SUCCEEDED(hr), "GetBackBuffer returned %#x.\n", hr);
268     if (FAILED(hr)) goto error;
269
270     /* Save the current render target */
271     hr = IDirect3DDevice8_GetRenderTarget(device, &event_data->original_render_target);
272     ok(SUCCEEDED(hr), "GetRenderTarget returned %#x.\n", hr);
273     if (FAILED(hr)) goto error;
274
275     /* Set the new swapchain's backbuffer as a render target */
276     hr = IDirect3DDevice8_SetRenderTarget(device, backbuffer, NULL);
277     ok(SUCCEEDED(hr), "SetRenderTarget returned %#x.\n", hr);
278     if (FAILED(hr)) goto error;
279
280     IDirect3DSurface8_Release(backbuffer);
281     event_data->new_swap_chain = swapchain;
282     return EVENT_OK;
283
284 error:
285     if (backbuffer) IDirect3DSurface8_Release(backbuffer);
286     if (swapchain) IDirect3DSwapChain8_Release(swapchain);
287     return EVENT_ERROR;
288 }
289
290 static int revert_render_target(IDirect3DDevice8 *device, struct event_data *event_data)
291 {
292     HRESULT hr;
293
294     /* Reset the old render target */
295     hr = IDirect3DDevice8_SetRenderTarget(device, event_data->original_render_target, NULL);
296     ok(SUCCEEDED(hr), "SetRenderTarget returned %#x.\n", hr);
297     if (FAILED(hr))
298     {
299         IDirect3DSurface8_Release(event_data->original_render_target);
300         return EVENT_ERROR;
301     }
302
303     IDirect3DSurface8_Release(event_data->original_render_target);
304     IDirect3DSwapChain8_Release(event_data->new_swap_chain);
305     return EVENT_OK;
306 }
307
308 static int create_stateblock_all(IDirect3DDevice8 *device, struct event_data *event_data)
309 {
310     HRESULT hr;
311
312     hr = IDirect3DDevice8_CreateStateBlock(device, D3DSBT_ALL, &event_data->stateblock);
313     ok(SUCCEEDED(hr), "CreateStateBlock returned %#x.\n", hr);
314     if (FAILED(hr)) return EVENT_ERROR;
315     return EVENT_OK;
316 }
317
318 static int create_stateblock_vertex(IDirect3DDevice8 *device, struct event_data *event_data)
319 {
320     HRESULT hr;
321
322     hr = IDirect3DDevice8_CreateStateBlock(device, D3DSBT_VERTEXSTATE, &event_data->stateblock);
323     ok(SUCCEEDED(hr), "CreateStateBlock returned %#x.\n", hr);
324     if (FAILED(hr)) return EVENT_ERROR;
325     return EVENT_OK;
326 }
327
328 static int create_stateblock_pixel(IDirect3DDevice8 *device, struct event_data *event_data)
329 {
330     HRESULT hr;
331
332     hr = IDirect3DDevice8_CreateStateBlock(device, D3DSBT_PIXELSTATE, &event_data->stateblock);
333     ok(SUCCEEDED(hr), "CreateStateBlock returned %#x.\n", hr);
334     if (FAILED(hr)) return EVENT_ERROR;
335     return EVENT_OK;
336 }
337
338 static int begin_stateblock(IDirect3DDevice8 *device, struct event_data *event_data)
339 {
340     HRESULT hr;
341
342     hr = IDirect3DDevice8_BeginStateBlock(device);
343     ok(SUCCEEDED(hr), "BeginStateBlock returned %#x.\n", hr);
344     if (FAILED(hr)) return EVENT_ERROR;
345     return EVENT_OK;
346 }
347
348 static int end_stateblock(IDirect3DDevice8 *device, struct event_data *event_data)
349 {
350     HRESULT hr;
351
352     hr = IDirect3DDevice8_EndStateBlock(device, &event_data->stateblock);
353     ok(SUCCEEDED(hr), "EndStateBlock returned %#x.\n", hr);
354     if (FAILED(hr)) return EVENT_ERROR;
355     return EVENT_OK;
356 }
357
358 static int delete_stateblock(IDirect3DDevice8 *device, struct event_data *event_data)
359 {
360     IDirect3DDevice8_DeleteStateBlock(device, event_data->stateblock);
361     return EVENT_OK;
362 }
363
364 static int apply_stateblock(IDirect3DDevice8 *device, struct event_data *event_data)
365 {
366     HRESULT hr;
367
368     hr = IDirect3DDevice8_ApplyStateBlock(device, event_data->stateblock);
369     ok(SUCCEEDED(hr), "Apply returned %#x.\n", hr);
370
371     IDirect3DDevice8_DeleteStateBlock(device, event_data->stateblock);
372     if (FAILED(hr)) return EVENT_ERROR;
373     return EVENT_OK;
374 }
375
376 static int capture_stateblock(IDirect3DDevice8 *device, struct event_data *event_data)
377 {
378     HRESULT hr;
379
380     hr = IDirect3DDevice8_CaptureStateBlock(device, event_data->stateblock);
381     ok(SUCCEEDED(hr), "Capture returned %#x.\n", hr);
382     if (FAILED(hr)) return EVENT_ERROR;
383
384     return EVENT_OK;
385 }
386
387 static void execute_test_chain_all(IDirect3DDevice8 *device, struct state_test *test, unsigned int ntests)
388 {
389     struct event_data arg;
390     unsigned int i;
391     HRESULT hr;
392
393     struct event read_events[] =
394     {
395         {NULL,                      SB_DATA_INITIAL,        SB_DATA_NONE},
396     };
397
398     struct event write_read_events[] =
399     {
400         {NULL,                      SB_DATA_NONE,           SB_DATA_TEST_IN},
401         {NULL,                      SB_DATA_TEST_ALL,       SB_DATA_NONE},
402     };
403
404     struct event abort_stateblock_events[] =
405     {
406         {begin_stateblock,          SB_DATA_NONE,           SB_DATA_TEST_IN},
407         {end_stateblock,            SB_DATA_NONE,           SB_DATA_NONE},
408         {delete_stateblock,         SB_DATA_DEFAULT,        SB_DATA_NONE},
409     };
410
411     struct event apply_stateblock_events[] =
412     {
413         {begin_stateblock,          SB_DATA_NONE,           SB_DATA_TEST_IN},
414         {end_stateblock,            SB_DATA_NONE,           SB_DATA_NONE},
415         {apply_stateblock,          SB_DATA_TEST_ALL,       SB_DATA_NONE},
416     };
417
418     struct event capture_reapply_stateblock_events[] =
419     {
420         {begin_stateblock,          SB_DATA_NONE,           SB_DATA_TEST_IN},
421         {end_stateblock,            SB_DATA_NONE,           SB_DATA_NONE},
422         {capture_stateblock,        SB_DATA_DEFAULT,        SB_DATA_TEST_IN},
423         {apply_stateblock,          SB_DATA_DEFAULT,        SB_DATA_NONE},
424     };
425
426     struct event create_stateblock_capture_apply_all_events[] =
427     {
428         {create_stateblock_all,     SB_DATA_DEFAULT,        SB_DATA_TEST_IN},
429         {capture_stateblock,        SB_DATA_TEST_ALL,       SB_DATA_DEFAULT},
430         {apply_stateblock,          SB_DATA_TEST_ALL,       SB_DATA_NONE},
431     };
432
433     struct event create_stateblock_apply_all_events[] =
434     {
435         {NULL,                      SB_DATA_DEFAULT,        SB_DATA_TEST_IN},
436         {create_stateblock_all,     SB_DATA_TEST_ALL,       SB_DATA_DEFAULT},
437         {apply_stateblock,          SB_DATA_TEST_ALL,       SB_DATA_NONE},
438     };
439
440     struct event create_stateblock_capture_apply_vertex_events[] =
441     {
442         {create_stateblock_vertex,  SB_DATA_DEFAULT,        SB_DATA_TEST_IN},
443         {capture_stateblock,        SB_DATA_TEST_ALL,       SB_DATA_DEFAULT},
444         {apply_stateblock,          SB_DATA_TEST_VERTEX,    SB_DATA_NONE},
445     };
446
447     struct event create_stateblock_apply_vertex_events[] =
448     {
449         {NULL,                      SB_DATA_DEFAULT,        SB_DATA_TEST_IN},
450         {create_stateblock_vertex,  SB_DATA_TEST_ALL,       SB_DATA_DEFAULT},
451         {apply_stateblock,          SB_DATA_TEST_VERTEX,    SB_DATA_NONE},
452     };
453
454     struct event create_stateblock_capture_apply_pixel_events[] =
455     {
456         {create_stateblock_pixel,   SB_DATA_DEFAULT,        SB_DATA_TEST_IN},
457         {capture_stateblock,        SB_DATA_TEST_ALL,       SB_DATA_DEFAULT},
458         {apply_stateblock,          SB_DATA_TEST_PIXEL,     SB_DATA_NONE},
459     };
460
461     struct event create_stateblock_apply_pixel_events[] =
462     {
463         {NULL,                      SB_DATA_DEFAULT,        SB_DATA_TEST_IN},
464         {create_stateblock_pixel,   SB_DATA_TEST_ALL,       SB_DATA_DEFAULT},
465         {apply_stateblock,          SB_DATA_TEST_PIXEL,     SB_DATA_NONE},
466     };
467
468     struct event rendertarget_switch_events[] =
469     {
470         {NULL,                      SB_DATA_NONE,           SB_DATA_TEST_IN},
471         {switch_render_target,      SB_DATA_TEST_ALL,       SB_DATA_NONE},
472         {revert_render_target,      SB_DATA_NONE,           SB_DATA_NONE},
473     };
474
475     struct event rendertarget_stateblock_events[] =
476     {
477         {begin_stateblock,          SB_DATA_NONE,           SB_DATA_TEST_IN},
478         {switch_render_target,      SB_DATA_DEFAULT,        SB_DATA_NONE},
479         {end_stateblock,            SB_DATA_NONE,           SB_DATA_NONE},
480         {revert_render_target,      SB_DATA_NONE,           SB_DATA_NONE},
481         {apply_stateblock,          SB_DATA_TEST_ALL,       SB_DATA_NONE},
482     };
483
484     /* Setup each test for execution */
485     for (i = 0; i < ntests; ++i)
486     {
487         hr = test[i].init(device, &test[i]);
488         ok(SUCCEEDED(hr), "Test \"%s\" failed setup, aborting\n", test[i].test_name);
489         if (FAILED(hr)) return;
490     }
491
492     trace("Running initial read state tests\n");
493     execute_test_chain(device, test, ntests, read_events, 1, NULL);
494
495     trace("Running write-read state tests\n");
496     execute_test_chain(device, test, ntests, write_read_events, 2, NULL);
497
498     trace("Running stateblock abort state tests\n");
499     execute_test_chain(device, test, ntests, abort_stateblock_events, 3, &arg);
500
501     trace("Running stateblock apply state tests\n");
502     execute_test_chain(device, test, ntests, apply_stateblock_events, 3, &arg);
503
504     trace("Running stateblock capture/reapply state tests\n");
505     execute_test_chain(device, test, ntests, capture_reapply_stateblock_events, 4, &arg);
506
507     trace("Running create stateblock capture/apply all state tests\n");
508     execute_test_chain(device, test, ntests, create_stateblock_capture_apply_all_events, 3, &arg);
509
510     trace("Running create stateblock apply all state tests\n");
511     execute_test_chain(device, test, ntests, create_stateblock_apply_all_events, 3, &arg);
512
513     trace("Running create stateblock capture/apply vertex state tests\n");
514     execute_test_chain(device, test, ntests, create_stateblock_capture_apply_vertex_events, 3, &arg);
515
516     trace("Running create stateblock apply vertex state tests\n");
517     execute_test_chain(device, test, ntests, create_stateblock_apply_vertex_events, 3, &arg);
518
519     trace("Running create stateblock capture/apply pixel state tests\n");
520     execute_test_chain(device, test, ntests, create_stateblock_capture_apply_pixel_events, 3, &arg);
521
522     trace("Running create stateblock apply pixel state tests\n");
523     execute_test_chain(device, test, ntests, create_stateblock_apply_pixel_events, 3, &arg);
524
525     trace("Running rendertarget switch state tests\n");
526     execute_test_chain(device, test, ntests, rendertarget_switch_events, 3, &arg);
527
528     trace("Running stateblock apply over rendertarget switch interrupt tests\n");
529     execute_test_chain(device, test, ntests, rendertarget_stateblock_events, 5, &arg);
530
531     /* Cleanup resources */
532     for (i = 0; i < ntests; ++i)
533     {
534         if (test[i].cleanup) test[i].cleanup(device, &test[i]);
535     }
536 }
537
538 /* =================== State test: Pixel and Vertex Shader constants ============ */
539
540 struct shader_constant_data
541 {
542     float float_constant[4]; /* 1x4 float constant */
543 };
544
545 struct shader_constant_arg
546 {
547     unsigned int idx;
548     BOOL pshader;
549 };
550
551 static const struct shader_constant_data shader_constant_poison_data =
552 {
553     {1.0f, 2.0f, 3.0f, 4.0f},
554 };
555
556 static const struct shader_constant_data shader_constant_default_data =
557 {
558     {0.0f, 0.0f, 0.0f, 0.0f},
559 };
560
561 static const struct shader_constant_data shader_constant_test_data =
562 {
563     {5.0f, 6.0f, 7.0f, 8.0f},
564 };
565
566 static void shader_constant_apply_data(IDirect3DDevice8 *device, const struct state_test *test, const void *data)
567 {
568     const struct shader_constant_data *scdata = data;
569     const struct shader_constant_arg *scarg = test->test_arg;
570     unsigned int index = scarg->idx;
571     HRESULT hr;
572
573     if (!scarg->pshader)
574     {
575         hr = IDirect3DDevice8_SetVertexShaderConstant(device, index, scdata->float_constant, 1);
576         ok(SUCCEEDED(hr), "SetVertexShaderConstant returned %#x.\n", hr);
577     }
578     else
579     {
580         hr = IDirect3DDevice8_SetPixelShaderConstant(device, index, scdata->float_constant, 1);
581         ok(SUCCEEDED(hr), "SetPixelShaderConstant returned %#x.\n", hr);
582     }
583 }
584
585 static void shader_constant_check_data(IDirect3DDevice8 *device, const struct state_test *test,
586         const void *expected_data, unsigned int chain_stage)
587 {
588     const struct shader_constant_data *scdata = expected_data;
589     const struct shader_constant_arg *scarg = test->test_arg;
590     struct shader_constant_data value;
591     HRESULT hr;
592
593     value = shader_constant_poison_data;
594
595     if (!scarg->pshader)
596     {
597         hr = IDirect3DDevice8_GetVertexShaderConstant(device, scarg->idx, value.float_constant, 1);
598         ok(SUCCEEDED(hr), "GetVertexShaderConstant returned %#x.\n", hr);
599     }
600     else
601     {
602         hr = IDirect3DDevice8_GetPixelShaderConstant(device, scarg->idx, value.float_constant, 1);
603         ok(SUCCEEDED(hr), "GetPixelShaderConstant returned %#x.\n", hr);
604     }
605
606     ok(!memcmp(value.float_constant, scdata->float_constant, sizeof(scdata->float_constant)),
607             "Chain stage %u, %s constant:\n\t{%.8e, %.8e, %.8e, %.8e} expected\n\t{%.8e, %.8e, %.8e, %.8e} received\n",
608             chain_stage, scarg->pshader ? "pixel shader" : "vertex shader",
609             scdata->float_constant[0], scdata->float_constant[1],
610             scdata->float_constant[2], scdata->float_constant[3],
611             value.float_constant[0], value.float_constant[1],
612             value.float_constant[2], value.float_constant[3]);
613 }
614
615 static HRESULT shader_constant_test_init(IDirect3DDevice8 *device, struct state_test *test)
616 {
617     const struct shader_constant_arg *test_arg = test->test_arg;
618
619     test->test_context = NULL;
620     test->test_data_in = &shader_constant_test_data;
621     test->test_data_out_all = &shader_constant_test_data;
622     if (test_arg->pshader)
623     {
624         test->test_data_out_vertex = &shader_constant_default_data;
625         test->test_data_out_pixel = &shader_constant_test_data;
626     }
627     else
628     {
629         test->test_data_out_vertex = &shader_constant_test_data;
630         test->test_data_out_pixel = &shader_constant_default_data;
631     }
632     test->default_data = &shader_constant_default_data;
633     test->initial_data = &shader_constant_default_data;
634
635     return D3D_OK;
636 }
637
638 static void shader_constants_queue_test(struct state_test *test, const struct shader_constant_arg *test_arg)
639 {
640     test->init = shader_constant_test_init;
641     test->cleanup = NULL;
642     test->apply_data = shader_constant_apply_data;
643     test->check_data = shader_constant_check_data;
644     test->test_name = test_arg->pshader ? "set_get_pshader_constants" : "set_get_vshader_constants";
645     test->test_arg = test_arg;
646 }
647
648 /* =================== State test: Lights ===================================== */
649
650 struct light_data
651 {
652     D3DLIGHT8 light;
653     BOOL enabled;
654     HRESULT get_light_result;
655     HRESULT get_enabled_result;
656 };
657
658 struct light_arg
659 {
660     unsigned int idx;
661 };
662
663 static const struct light_data light_poison_data =
664 {
665     {
666         0x1337c0de,
667         {7.0, 4.0, 2.0, 1.0},
668         {7.0, 4.0, 2.0, 1.0},
669         {7.0, 4.0, 2.0, 1.0},
670         {3.3f, 4.4f, 5.5f},
671         {6.6f, 7.7f, 8.8f},
672         12.12f, 13.13f, 14.14f, 15.15f, 16.16f, 17.17f, 18.18f,
673     },
674     TRUE,
675     0x1337c0de,
676     0x1337c0de,
677 };
678
679 static const struct light_data light_default_data =
680 {
681     {
682         D3DLIGHT_DIRECTIONAL,
683         {1.0, 1.0, 1.0, 0.0},
684         {0.0, 0.0, 0.0, 0.0},
685         {0.0, 0.0, 0.0, 0.0},
686         {0.0, 0.0, 0.0},
687         {0.0, 0.0, 1.0},
688         0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
689     },
690     FALSE,
691     D3D_OK,
692     D3D_OK,
693 };
694
695 /* This is used for the initial read state (before a write causes side effects)
696  * The proper return status is D3DERR_INVALIDCALL */
697 static const struct light_data light_initial_data =
698 {
699     {
700         0x1337c0de,
701         {7.0, 4.0, 2.0, 1.0},
702         {7.0, 4.0, 2.0, 1.0},
703         {7.0, 4.0, 2.0, 1.0},
704         {3.3f, 4.4f, 5.5f},
705         {6.6f, 7.7f, 8.8f},
706         12.12f, 13.13f, 14.14f, 15.15f, 16.16f, 17.17f, 18.18f,
707     },
708     TRUE,
709     D3DERR_INVALIDCALL,
710     D3DERR_INVALIDCALL,
711 };
712
713 static const struct light_data light_test_data_in =
714 {
715     {
716         1,
717         {2.0, 2.0, 2.0, 2.0},
718         {3.0, 3.0, 3.0, 3.0},
719         {4.0, 4.0, 4.0, 4.0},
720         {5.0, 5.0, 5.0},
721         {6.0, 6.0, 6.0},
722         7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0,
723     },
724     TRUE,
725     D3D_OK,
726     D3D_OK,
727 };
728
729 /* SetLight will use 128 as the "enabled" value */
730 static const struct light_data light_test_data_out =
731 {
732     {
733         1,
734         {2.0, 2.0, 2.0, 2.0},
735         {3.0, 3.0, 3.0, 3.0},
736         {4.0, 4.0, 4.0, 4.0},
737         {5.0, 5.0, 5.0},
738         {6.0, 6.0, 6.0},
739         7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0,
740     },
741     128,
742     D3D_OK,
743     D3D_OK,
744 };
745
746 static void light_apply_data(IDirect3DDevice8 *device, const struct state_test *test, const void *data)
747 {
748     const struct light_data *ldata = data;
749     const struct light_arg *larg = test->test_arg;
750     unsigned int index = larg->idx;
751     HRESULT hr;
752
753     hr = IDirect3DDevice8_SetLight(device, index, &ldata->light);
754     ok(SUCCEEDED(hr), "SetLight returned %#x.\n", hr);
755
756     hr = IDirect3DDevice8_LightEnable(device, index, ldata->enabled);
757     ok(SUCCEEDED(hr), "SetLightEnable returned %#x.\n", hr);
758 }
759
760 static void light_check_data(IDirect3DDevice8 *device, const struct state_test *test,
761         const void *expected_data, unsigned int chain_stage)
762 {
763     const struct light_arg *larg = test->test_arg;
764     const struct light_data *ldata = expected_data;
765     struct light_data value;
766
767     value = light_poison_data;
768
769     value.get_enabled_result = IDirect3DDevice8_GetLightEnable(device, larg->idx, &value.enabled);
770     value.get_light_result = IDirect3DDevice8_GetLight(device, larg->idx, &value.light);
771
772     ok(value.get_enabled_result == ldata->get_enabled_result,
773             "Chain stage %u: expected get_enabled_result %#x, got %#x.\n",
774             chain_stage, ldata->get_enabled_result, value.get_enabled_result);
775     ok(value.get_light_result == ldata->get_light_result,
776             "Chain stage %u: expected get_light_result %#x, got %#x.\n",
777             chain_stage, ldata->get_light_result, value.get_light_result);
778
779     ok(value.enabled == ldata->enabled,
780             "Chain stage %u: expected enabled %#x, got %#x.\n",
781             chain_stage, ldata->enabled, value.enabled);
782     ok(value.light.Type == ldata->light.Type,
783             "Chain stage %u: expected light.Type %#x, got %#x.\n",
784             chain_stage, ldata->light.Type, value.light.Type);
785     ok(!memcmp(&value.light.Diffuse, &ldata->light.Diffuse, sizeof(value.light.Diffuse)),
786             "Chain stage %u, light.Diffuse:\n\t{%.8e, %.8e, %.8e, %.8e} expected\n"
787             "\t{%.8e, %.8e, %.8e, %.8e} received.\n", chain_stage,
788             ldata->light.Diffuse.r, ldata->light.Diffuse.g,
789             ldata->light.Diffuse.b, ldata->light.Diffuse.a,
790             value.light.Diffuse.r, value.light.Diffuse.g,
791             value.light.Diffuse.b, value.light.Diffuse.a);
792     ok(!memcmp(&value.light.Specular, &ldata->light.Specular, sizeof(value.light.Specular)),
793             "Chain stage %u, light.Specular:\n\t{%.8e, %.8e, %.8e, %.8e} expected\n"
794             "\t{%.8e, %.8e, %.8e, %.8e} received.\n", chain_stage,
795             ldata->light.Specular.r, ldata->light.Specular.g,
796             ldata->light.Specular.b, ldata->light.Specular.a,
797             value.light.Specular.r, value.light.Specular.g,
798             value.light.Specular.b, value.light.Specular.a);
799     ok(!memcmp(&value.light.Ambient, &ldata->light.Ambient, sizeof(value.light.Ambient)),
800             "Chain stage %u, light.Ambient:\n\t{%.8e, %.8e, %.8e, %.8e} expected\n"
801             "\t{%.8e, %.8e, %.8e, %.8e} received.\n", chain_stage,
802             ldata->light.Ambient.r, ldata->light.Ambient.g,
803             ldata->light.Ambient.b, ldata->light.Ambient.a,
804             value.light.Ambient.r, value.light.Ambient.g,
805             value.light.Ambient.b, value.light.Ambient.a);
806     ok(!memcmp(&value.light.Position, &ldata->light.Position, sizeof(value.light.Position)),
807             "Chain stage %u, light.Position:\n\t{%.8e, %.8e, %.8e} expected\n\t{%.8e, %.8e, %.8e} received.\n",
808             chain_stage, ldata->light.Position.x, ldata->light.Position.y, ldata->light.Position.z,
809             value.light.Position.x, value.light.Position.y, value.light.Position.z);
810     ok(!memcmp(&value.light.Direction, &ldata->light.Direction, sizeof(value.light.Direction)),
811             "Chain stage %u, light.Direction:\n\t{%.8e, %.8e, %.8e} expected\n\t{%.8e, %.8e, %.8e} received.\n",
812             chain_stage, ldata->light.Direction.x, ldata->light.Direction.y, ldata->light.Direction.z,
813             value.light.Direction.x, value.light.Direction.y, value.light.Direction.z);
814     ok(value.light.Range == ldata->light.Range,
815             "Chain stage %u: expected light.Range %.8e, got %.8e.\n",
816             chain_stage, ldata->light.Range, value.light.Range);
817     ok(value.light.Falloff == ldata->light.Falloff,
818             "Chain stage %u: expected light.Falloff %.8e, got %.8e.\n",
819             chain_stage, ldata->light.Falloff, value.light.Falloff);
820     ok(value.light.Attenuation0 == ldata->light.Attenuation0,
821             "Chain stage %u: expected light.Attenuation0 %.8e, got %.8e.\n",
822             chain_stage, ldata->light.Attenuation0, value.light.Attenuation0);
823     ok(value.light.Attenuation1 == ldata->light.Attenuation1,
824             "Chain stage %u: expected light.Attenuation1 %.8e, got %.8e.\n",
825             chain_stage, ldata->light.Attenuation1, value.light.Attenuation1);
826     ok(value.light.Attenuation2 == ldata->light.Attenuation2,
827             "Chain stage %u: expected light.Attenuation2 %.8e, got %.8e.\n",
828             chain_stage, ldata->light.Attenuation2, value.light.Attenuation2);
829     ok(value.light.Theta == ldata->light.Theta,
830             "Chain stage %u: expected light.Theta %.8e, got %.8e.\n",
831             chain_stage, ldata->light.Theta, value.light.Theta);
832     ok(value.light.Phi == ldata->light.Phi,
833             "Chain stage %u: expected light.Phi %.8e, got %.8e.\n",
834             chain_stage, ldata->light.Phi, value.light.Phi);
835 }
836
837 static HRESULT light_test_init(IDirect3DDevice8 *device, struct state_test *test)
838 {
839     test->test_context = NULL;
840     test->test_data_in = &light_test_data_in;
841     test->test_data_out_all = &light_test_data_out;
842     test->test_data_out_vertex = &light_test_data_out;
843     test->test_data_out_pixel = &light_default_data;
844     test->default_data = &light_default_data;
845     test->initial_data = &light_initial_data;
846
847     return D3D_OK;
848 }
849
850 static void lights_queue_test(struct state_test *test, const struct light_arg *test_arg)
851 {
852     test->init = light_test_init;
853     test->cleanup = NULL;
854     test->apply_data = light_apply_data;
855     test->check_data = light_check_data;
856     test->test_name = "set_get_light";
857     test->test_arg = test_arg;
858 }
859
860 /* =================== State test: Transforms ===================================== */
861
862 struct transform_data
863 {
864     D3DMATRIX view;
865     D3DMATRIX projection;
866     D3DMATRIX texture0;
867     D3DMATRIX texture7;
868     D3DMATRIX world0;
869     D3DMATRIX world255;
870 };
871
872 static const struct transform_data transform_default_data =
873 {
874     {{{
875         1.0f, 0.0f, 0.0f, 0.0f,
876         0.0f, 1.0f, 0.0f, 0.0f,
877         0.0f, 0.0f, 1.0f, 0.0f,
878         0.0f, 0.0f, 0.0f, 1.0f,
879     }}},
880     {{{
881         1.0f, 0.0f, 0.0f, 0.0f,
882         0.0f, 1.0f, 0.0f, 0.0f,
883         0.0f, 0.0f, 1.0f, 0.0f,
884         0.0f, 0.0f, 0.0f, 1.0f,
885     }}},
886     {{{
887         1.0f, 0.0f, 0.0f, 0.0f,
888         0.0f, 1.0f, 0.0f, 0.0f,
889         0.0f, 0.0f, 1.0f, 0.0f,
890         0.0f, 0.0f, 0.0f, 1.0f,
891     }}},
892     {{{
893         1.0f, 0.0f, 0.0f, 0.0f,
894         0.0f, 1.0f, 0.0f, 0.0f,
895         0.0f, 0.0f, 1.0f, 0.0f,
896         0.0f, 0.0f, 0.0f, 1.0f,
897     }}},
898     {{{
899         1.0f, 0.0f, 0.0f, 0.0f,
900         0.0f, 1.0f, 0.0f, 0.0f,
901         0.0f, 0.0f, 1.0f, 0.0f,
902         0.0f, 0.0f, 0.0f, 1.0f,
903     }}},
904     {{{
905         1.0f, 0.0f, 0.0f, 0.0f,
906         0.0f, 1.0f, 0.0f, 0.0f,
907         0.0f, 0.0f, 1.0f, 0.0f,
908         0.0f, 0.0f, 0.0f, 1.0f,
909     }}},
910 };
911
912 static const struct transform_data transform_poison_data =
913 {
914     {{{
915          1.0f,  2.0f,  3.0f,  4.0f,
916          5.0f,  6.0f,  7.0f,  8.0f,
917          9.0f, 10.0f, 11.0f, 12.0f,
918         13.0f, 14.0f, 15.0f, 16.0f,
919     }}},
920     {{{
921         17.0f, 18.0f, 19.0f, 20.0f,
922         21.0f, 22.0f, 23.0f, 24.0f,
923         25.0f, 26.0f, 27.0f, 28.0f,
924         29.0f, 30.0f, 31.0f, 32.0f,
925     }}},
926     {{{
927         33.0f, 34.0f, 35.0f, 36.0f,
928         37.0f, 38.0f, 39.0f, 40.0f,
929         41.0f, 42.0f, 43.0f, 44.0f,
930         45.0f, 46.0f, 47.0f, 48.0f,
931     }}},
932     {{{
933         49.0f, 50.0f, 51.0f, 52.0f,
934         53.0f, 54.0f, 55.0f, 56.0f,
935         57.0f, 58.0f, 59.0f, 60.0f,
936         61.0f, 62.0f, 63.0f, 64.0f,
937     }}},
938     {{{
939         64.0f, 66.0f, 67.0f, 68.0f,
940         69.0f, 70.0f, 71.0f, 72.0f,
941         73.0f, 74.0f, 75.0f, 76.0f,
942         77.0f, 78.0f, 79.0f, 80.0f,
943     }}},
944     {{{
945         81.0f, 82.0f, 83.0f, 84.0f,
946         85.0f, 86.0f, 87.0f, 88.0f,
947         89.0f, 90.0f, 91.0f, 92.0f,
948         93.0f, 94.0f, 95.0f, 96.0f,
949     }}},
950 };
951
952 static const struct transform_data transform_test_data =
953 {
954     {{{
955           1.2f,     3.4f,  -5.6f,  7.2f,
956         10.11f,  -12.13f, 14.15f, -1.5f,
957         23.56f,   12.89f, 44.56f, -1.0f,
958           2.3f,     0.0f,   4.4f,  5.5f,
959     }}},
960     {{{
961           9.2f,    38.7f,  -6.6f,  7.2f,
962         10.11f,  -12.13f, 77.15f, -1.5f,
963         23.56f,   12.89f, 14.56f, -1.0f,
964          12.3f,     0.0f,   4.4f,  5.5f,
965     }}},
966     {{{
967          10.2f,     3.4f,   0.6f,  7.2f,
968         10.11f,  -12.13f, 14.15f, -1.5f,
969         23.54f,    12.9f, 44.56f, -1.0f,
970           2.3f,     0.0f,   4.4f,  5.5f,
971     }}},
972     {{{
973           1.2f,     3.4f,  -5.6f,  7.2f,
974         10.11f,  -12.13f, -14.5f, -1.5f,
975          2.56f,   12.89f, 23.56f, -1.0f,
976         112.3f,     0.0f,   4.4f,  2.5f,
977     }}},
978     {{{
979           1.2f,   31.41f,  58.6f,  7.2f,
980         10.11f,  -12.13f, -14.5f, -1.5f,
981          2.56f,   12.89f, 11.56f, -1.0f,
982         112.3f,     0.0f,  44.4f,  2.5f,
983     }}},
984
985     {{{
986          1.20f,     3.4f,  -5.6f,  7.0f,
987         10.11f, -12.156f, -14.5f, -1.5f,
988          2.56f,   1.829f,  23.6f, -1.0f,
989         112.3f,     0.0f,  41.4f,  2.5f,
990     }}},
991 };
992
993
994 static void transform_apply_data(IDirect3DDevice8 *device, const struct state_test *test, const void *data)
995 {
996     const struct transform_data *tdata = data;
997     HRESULT hr;
998
999     hr = IDirect3DDevice8_SetTransform(device, D3DTS_VIEW, &tdata->view);
1000     ok(SUCCEEDED(hr), "SetTransform returned %#x.\n", hr);
1001
1002     hr = IDirect3DDevice8_SetTransform(device, D3DTS_PROJECTION, &tdata->projection);
1003     ok(SUCCEEDED(hr), "SetTransform returned %#x.\n", hr);
1004
1005     hr = IDirect3DDevice8_SetTransform(device, D3DTS_TEXTURE0, &tdata->texture0);
1006     ok(SUCCEEDED(hr), "SetTransform returned %#x.\n", hr);
1007
1008     hr = IDirect3DDevice8_SetTransform(device, D3DTS_TEXTURE0 + texture_stages - 1, &tdata->texture7);
1009     ok(SUCCEEDED(hr), "SetTransform returned %#x.\n", hr);
1010
1011     hr = IDirect3DDevice8_SetTransform(device, D3DTS_WORLD, &tdata->world0);
1012     ok(SUCCEEDED(hr), "SetTransform returned %#x.\n", hr);
1013
1014     hr = IDirect3DDevice8_SetTransform(device, D3DTS_WORLDMATRIX(255), &tdata->world255);
1015     ok(SUCCEEDED(hr), "SetTransform returned %#x.\n", hr);
1016 }
1017
1018 static void compare_matrix(const char *name, unsigned int chain_stage,
1019         const D3DMATRIX *received, const D3DMATRIX *expected)
1020 {
1021     ok(!memcmp(expected, received, sizeof(*expected)),
1022             "Chain stage %u, matrix %s:\n"
1023             "\t{\n"
1024             "\t\t%.8e, %.8e, %.8e, %.8e,\n"
1025             "\t\t%.8e, %.8e, %.8e, %.8e,\n"
1026             "\t\t%.8e, %.8e, %.8e, %.8e,\n"
1027             "\t\t%.8e, %.8e, %.8e, %.8e,\n"
1028             "\t} expected\n"
1029             "\t{\n"
1030             "\t\t%.8e, %.8e, %.8e, %.8e,\n"
1031             "\t\t%.8e, %.8e, %.8e, %.8e,\n"
1032             "\t\t%.8e, %.8e, %.8e, %.8e,\n"
1033             "\t\t%.8e, %.8e, %.8e, %.8e,\n"
1034             "\t} received\n",
1035             chain_stage, name,
1036             U(*expected).m[0][0], U(*expected).m[1][0], U(*expected).m[2][0], U(*expected).m[3][0],
1037             U(*expected).m[0][1], U(*expected).m[1][1], U(*expected).m[2][1], U(*expected).m[3][1],
1038             U(*expected).m[0][2], U(*expected).m[1][2], U(*expected).m[2][2], U(*expected).m[3][2],
1039             U(*expected).m[0][3], U(*expected).m[1][3], U(*expected).m[2][3], U(*expected).m[3][3],
1040             U(*received).m[0][0], U(*received).m[1][0], U(*received).m[2][0], U(*received).m[3][0],
1041             U(*received).m[0][1], U(*received).m[1][1], U(*received).m[2][1], U(*received).m[3][1],
1042             U(*received).m[0][2], U(*received).m[1][2], U(*received).m[2][2], U(*received).m[3][2],
1043             U(*received).m[0][3], U(*received).m[1][3], U(*received).m[2][3], U(*received).m[3][3]);
1044 }
1045
1046 static void transform_check_data(IDirect3DDevice8 *device, const struct state_test *test,
1047         const void *expected_data, unsigned int chain_stage)
1048 {
1049     const struct transform_data *tdata = expected_data;
1050     D3DMATRIX value;
1051     HRESULT hr;
1052
1053     value = transform_poison_data.view;
1054     hr = IDirect3DDevice8_GetTransform(device, D3DTS_VIEW, &value);
1055     ok(SUCCEEDED(hr), "GetTransform returned %#x.\n", hr);
1056     compare_matrix("View", chain_stage, &value, &tdata->view);
1057
1058     value = transform_poison_data.projection;
1059     hr = IDirect3DDevice8_GetTransform(device, D3DTS_PROJECTION, &value);
1060     ok(SUCCEEDED(hr), "GetTransform returned %#x.\n", hr);
1061     compare_matrix("Projection", chain_stage, &value, &tdata->projection);
1062
1063     value = transform_poison_data.texture0;
1064     hr = IDirect3DDevice8_GetTransform(device, D3DTS_TEXTURE0, &value);
1065     ok(SUCCEEDED(hr), "GetTransform returned %#x.\n", hr);
1066     compare_matrix("Texture0", chain_stage, &value, &tdata->texture0);
1067
1068     value = transform_poison_data.texture7;
1069     hr = IDirect3DDevice8_GetTransform(device, D3DTS_TEXTURE0 + texture_stages - 1, &value);
1070     ok(SUCCEEDED(hr), "GetTransform returned %#x.\n", hr);
1071     compare_matrix("Texture7", chain_stage, &value, &tdata->texture7);
1072
1073     value = transform_poison_data.world0;
1074     hr = IDirect3DDevice8_GetTransform(device, D3DTS_WORLD, &value);
1075     ok(SUCCEEDED(hr), "GetTransform returned %#x.\n", hr);
1076     compare_matrix("World0", chain_stage, &value, &tdata->world0);
1077
1078     value = transform_poison_data.world255;
1079     hr = IDirect3DDevice8_GetTransform(device, D3DTS_WORLDMATRIX(255), &value);
1080     ok(SUCCEEDED(hr), "GetTransform returned %#x.\n", hr);
1081     compare_matrix("World255", chain_stage, &value, &tdata->world255);
1082 }
1083
1084 static HRESULT transform_test_init(IDirect3DDevice8 *device, struct state_test *test)
1085 {
1086     test->test_context = NULL;
1087     test->test_data_in = &transform_test_data;
1088     test->test_data_out_all = &transform_test_data;
1089     test->test_data_out_vertex = &transform_default_data;
1090     test->test_data_out_pixel = &transform_default_data;
1091     test->default_data = &transform_default_data;
1092     test->initial_data = &transform_default_data;
1093
1094     return D3D_OK;
1095 }
1096
1097 static void transform_queue_test(struct state_test *test)
1098 {
1099     test->init = transform_test_init;
1100     test->cleanup = NULL;
1101     test->apply_data = transform_apply_data;
1102     test->check_data = transform_check_data;
1103     test->test_name = "set_get_transforms";
1104     test->test_arg = NULL;
1105 }
1106
1107 /* =================== State test: Render States ===================================== */
1108
1109 const D3DRENDERSTATETYPE render_state_indices[] =
1110 {
1111     D3DRS_ZENABLE,
1112     D3DRS_FILLMODE,
1113     D3DRS_SHADEMODE,
1114     D3DRS_ZWRITEENABLE,
1115     D3DRS_ALPHATESTENABLE,
1116     D3DRS_LASTPIXEL,
1117     D3DRS_SRCBLEND,
1118     D3DRS_DESTBLEND,
1119     D3DRS_CULLMODE,
1120     D3DRS_ZFUNC,
1121     D3DRS_ALPHAREF,
1122     D3DRS_ALPHAFUNC,
1123     D3DRS_DITHERENABLE,
1124     D3DRS_ALPHABLENDENABLE,
1125     D3DRS_FOGENABLE,
1126     D3DRS_SPECULARENABLE,
1127     D3DRS_FOGCOLOR,
1128     D3DRS_FOGTABLEMODE,
1129     D3DRS_FOGSTART,
1130     D3DRS_FOGEND,
1131     D3DRS_FOGDENSITY,
1132     D3DRS_RANGEFOGENABLE,
1133     D3DRS_STENCILENABLE,
1134     D3DRS_STENCILFAIL,
1135     D3DRS_STENCILZFAIL,
1136     D3DRS_STENCILPASS,
1137     D3DRS_STENCILFUNC,
1138     D3DRS_STENCILREF,
1139     D3DRS_STENCILMASK,
1140     D3DRS_STENCILWRITEMASK,
1141     D3DRS_TEXTUREFACTOR,
1142     D3DRS_WRAP0,
1143     D3DRS_WRAP1,
1144     D3DRS_WRAP2,
1145     D3DRS_WRAP3,
1146     D3DRS_WRAP4,
1147     D3DRS_WRAP5,
1148     D3DRS_WRAP6,
1149     D3DRS_WRAP7,
1150     D3DRS_CLIPPING,
1151     D3DRS_LIGHTING,
1152     D3DRS_AMBIENT,
1153     D3DRS_FOGVERTEXMODE,
1154     D3DRS_COLORVERTEX,
1155     D3DRS_LOCALVIEWER,
1156     D3DRS_NORMALIZENORMALS,
1157     D3DRS_DIFFUSEMATERIALSOURCE,
1158     D3DRS_SPECULARMATERIALSOURCE,
1159     D3DRS_AMBIENTMATERIALSOURCE,
1160     D3DRS_EMISSIVEMATERIALSOURCE,
1161     D3DRS_VERTEXBLEND,
1162     D3DRS_CLIPPLANEENABLE,
1163 #if 0 /* Driver dependent */
1164     D3DRS_POINTSIZE,
1165 #endif
1166     D3DRS_POINTSIZE_MIN,
1167     D3DRS_POINTSPRITEENABLE,
1168     D3DRS_POINTSCALEENABLE,
1169     D3DRS_POINTSCALE_A,
1170     D3DRS_POINTSCALE_B,
1171     D3DRS_POINTSCALE_C,
1172     D3DRS_MULTISAMPLEANTIALIAS,
1173     D3DRS_MULTISAMPLEMASK,
1174     D3DRS_PATCHEDGESTYLE,
1175 #if 0 /* Apparently not recorded in the stateblock */
1176     D3DRS_DEBUGMONITORTOKEN,
1177 #endif
1178     D3DRS_POINTSIZE_MAX,
1179     D3DRS_INDEXEDVERTEXBLENDENABLE,
1180     D3DRS_COLORWRITEENABLE,
1181     D3DRS_TWEENFACTOR,
1182     D3DRS_BLENDOP,
1183 };
1184
1185 struct render_state_data
1186 {
1187     DWORD states[sizeof(render_state_indices) / sizeof(*render_state_indices)];
1188 };
1189
1190 struct render_state_arg
1191 {
1192     D3DPRESENT_PARAMETERS *device_pparams;
1193     float pointsize_max;
1194 };
1195
1196 struct render_state_context
1197 {
1198     struct render_state_data default_data_buffer;
1199     struct render_state_data test_data_all_buffer;
1200     struct render_state_data test_data_vertex_buffer;
1201     struct render_state_data test_data_pixel_buffer;
1202     struct render_state_data poison_data_buffer;
1203 };
1204
1205 static void render_state_apply_data(IDirect3DDevice8 *device, const struct state_test *test, const void *data)
1206 {
1207     const struct render_state_data *rsdata = data;
1208     unsigned int i;
1209     HRESULT hr;
1210
1211     for (i = 0; i < sizeof(render_state_indices) / sizeof(*render_state_indices); ++i)
1212     {
1213         hr = IDirect3DDevice8_SetRenderState(device, render_state_indices[i], rsdata->states[i]);
1214         ok(SUCCEEDED(hr), "SetRenderState returned %#x.\n", hr);
1215     }
1216 }
1217
1218 static void render_state_check_data(IDirect3DDevice8 *device, const struct state_test *test,
1219         const void *expected_data, unsigned int chain_stage)
1220 {
1221     const struct render_state_context *ctx = test->test_context;
1222     const struct render_state_data *rsdata = expected_data;
1223     unsigned int i;
1224     HRESULT hr;
1225
1226     for (i = 0; i < sizeof(render_state_indices) / sizeof(*render_state_indices); ++i)
1227     {
1228         DWORD value = ctx->poison_data_buffer.states[i];
1229         hr = IDirect3DDevice8_GetRenderState(device, render_state_indices[i], &value);
1230         ok(SUCCEEDED(hr), "GetRenderState returned %#x.\n", hr);
1231         ok(value == rsdata->states[i], "Chain stage %u, render state %#x: expected %#x, got %#x.\n",
1232                 chain_stage, render_state_indices[i], rsdata->states[i], value);
1233     }
1234 }
1235
1236 static inline DWORD to_dword(float fl)
1237 {
1238     union {float f; DWORD d;} ret;
1239
1240     ret.f = fl;
1241     return ret.d;
1242 }
1243
1244 static void render_state_default_data_init(const struct render_state_arg *rsarg, struct render_state_data *data)
1245 {
1246     DWORD zenable = rsarg->device_pparams->EnableAutoDepthStencil ? D3DZB_TRUE : D3DZB_FALSE;
1247     unsigned int idx = 0;
1248
1249     data->states[idx++] = zenable;               /* ZENABLE */
1250     data->states[idx++] = D3DFILL_SOLID;         /* FILLMODE */
1251     data->states[idx++] = D3DSHADE_GOURAUD;      /* SHADEMODE */
1252     data->states[idx++] = TRUE;                  /* ZWRITEENABLE */
1253     data->states[idx++] = FALSE;                 /* ALPHATESTENABLE */
1254     data->states[idx++] = TRUE;                  /* LASTPIXEL */
1255     data->states[idx++] = D3DBLEND_ONE;          /* SRCBLEND */
1256     data->states[idx++] = D3DBLEND_ZERO;         /* DESTBLEND */
1257     data->states[idx++] = D3DCULL_CCW;           /* CULLMODE */
1258     data->states[idx++] = D3DCMP_LESSEQUAL;      /* ZFUNC */
1259     data->states[idx++] = 0;                     /* ALPHAREF */
1260     data->states[idx++] = D3DCMP_ALWAYS;         /* ALPHAFUNC */
1261     data->states[idx++] = FALSE;                 /* DITHERENABLE */
1262     data->states[idx++] = FALSE;                 /* ALPHABLENDENABLE */
1263     data->states[idx++] = FALSE;                 /* FOGENABLE */
1264     data->states[idx++] = FALSE;                 /* SPECULARENABLE */
1265     data->states[idx++] = 0;                     /* FOGCOLOR */
1266     data->states[idx++] = D3DFOG_NONE;           /* FOGTABLEMODE */
1267     data->states[idx++] = to_dword(0.0f);        /* FOGSTART */
1268     data->states[idx++] = to_dword(1.0f);        /* FOGEND */
1269     data->states[idx++] = to_dword(1.0f);        /* FOGDENSITY */
1270     data->states[idx++] = FALSE;                 /* RANGEFOGENABLE */
1271     data->states[idx++] = FALSE;                 /* STENCILENABLE */
1272     data->states[idx++] = D3DSTENCILOP_KEEP;     /* STENCILFAIL */
1273     data->states[idx++] = D3DSTENCILOP_KEEP;     /* STENCILZFAIL */
1274     data->states[idx++] = D3DSTENCILOP_KEEP;     /* STENCILPASS */
1275     data->states[idx++] = D3DCMP_ALWAYS;         /* STENCILFUNC */
1276     data->states[idx++] = 0;                     /* STENCILREF */
1277     data->states[idx++] = 0xFFFFFFFF;            /* STENCILMASK */
1278     data->states[idx++] = 0xFFFFFFFF;            /* STENCILWRITEMASK */
1279     data->states[idx++] = 0xFFFFFFFF;            /* TEXTUREFACTOR */
1280     data->states[idx++] = 0;                     /* WRAP 0 */
1281     data->states[idx++] = 0;                     /* WRAP 1 */
1282     data->states[idx++] = 0;                     /* WRAP 2 */
1283     data->states[idx++] = 0;                     /* WRAP 3 */
1284     data->states[idx++] = 0;                     /* WRAP 4 */
1285     data->states[idx++] = 0;                     /* WRAP 5 */
1286     data->states[idx++] = 0;                     /* WRAP 6 */
1287     data->states[idx++] = 0;                     /* WRAP 7 */
1288     data->states[idx++] = TRUE;                  /* CLIPPING */
1289     data->states[idx++] = TRUE;                  /* LIGHTING */
1290     data->states[idx++] = 0;                     /* AMBIENT */
1291     data->states[idx++] = D3DFOG_NONE;           /* FOGVERTEXMODE */
1292     data->states[idx++] = TRUE;                  /* COLORVERTEX */
1293     data->states[idx++] = TRUE;                  /* LOCALVIEWER */
1294     data->states[idx++] = FALSE;                 /* NORMALIZENORMALS */
1295     data->states[idx++] = D3DMCS_COLOR1;         /* DIFFUSEMATERIALSOURCE */
1296     data->states[idx++] = D3DMCS_COLOR2;         /* SPECULARMATERIALSOURCE */
1297     data->states[idx++] = D3DMCS_MATERIAL;       /* AMBIENTMATERIALSOURCE */
1298     data->states[idx++] = D3DMCS_MATERIAL;       /* EMISSIVEMATERIALSOURCE */
1299     data->states[idx++] = D3DVBF_DISABLE;        /* VERTEXBLEND */
1300     data->states[idx++] = 0;                     /* CLIPPLANEENABLE */
1301     if (0) data->states[idx++] = to_dword(1.0f); /* POINTSIZE, driver dependent, increase array size to enable */
1302     data->states[idx++] = to_dword(0.0f);        /* POINTSIZEMIN */
1303     data->states[idx++] = FALSE;                 /* POINTSPRITEENABLE */
1304     data->states[idx++] = FALSE;                 /* POINTSCALEENABLE */
1305     data->states[idx++] = to_dword(1.0f);        /* POINTSCALE_A */
1306     data->states[idx++] = to_dword(0.0f);        /* POINTSCALE_B */
1307     data->states[idx++] = to_dword(0.0f);        /* POINTSCALE_C */
1308     data->states[idx++] = TRUE;                  /* MULTISAMPLEANTIALIAS */
1309     data->states[idx++] = 0xFFFFFFFF;            /* MULTISAMPLEMASK */
1310     data->states[idx++] = D3DPATCHEDGE_DISCRETE; /* PATCHEDGESTYLE */
1311     if (0) data->states[idx++] = 0xbaadcafe;     /* DEBUGMONITORTOKEN, not recorded in the stateblock */
1312     data->states[idx++] = to_dword(rsarg->pointsize_max); /* POINTSIZE_MAX */
1313     data->states[idx++] = FALSE;                 /* INDEXEDVERTEXBLENDENABLE */
1314     data->states[idx++] = 0x0000000F;            /* COLORWRITEENABLE */
1315     data->states[idx++] = to_dword(0.0f);        /* TWEENFACTOR */
1316     data->states[idx++] = D3DBLENDOP_ADD;        /* BLENDOP */
1317 }
1318
1319 static void render_state_poison_data_init(struct render_state_data *data)
1320 {
1321     unsigned int i;
1322
1323     for (i = 0; i < sizeof(render_state_indices) / sizeof(*render_state_indices); ++i)
1324     {
1325         data->states[i] = 0x1337c0de;
1326     }
1327 }
1328
1329 static void render_state_test_data_init(struct render_state_data *data)
1330 {
1331     unsigned int idx = 0;
1332
1333     data->states[idx++] = D3DZB_USEW;            /* ZENABLE */
1334     data->states[idx++] = D3DFILL_WIREFRAME;     /* FILLMODE */
1335     data->states[idx++] = D3DSHADE_PHONG;        /* SHADEMODE */
1336     data->states[idx++] = FALSE;                 /* ZWRITEENABLE */
1337     data->states[idx++] = TRUE;                  /* ALPHATESTENABLE */
1338     data->states[idx++] = FALSE;                 /* LASTPIXEL */
1339     data->states[idx++] = D3DBLEND_SRCALPHASAT;  /* SRCBLEND */
1340     data->states[idx++] = D3DBLEND_INVDESTALPHA; /* DESTBLEND */
1341     data->states[idx++] = D3DCULL_CW;            /* CULLMODE */
1342     data->states[idx++] = D3DCMP_NOTEQUAL;       /* ZFUNC */
1343     data->states[idx++] = 10;                    /* ALPHAREF */
1344     data->states[idx++] = D3DCMP_GREATER;        /* ALPHAFUNC */
1345     data->states[idx++] = TRUE;                  /* DITHERENABLE */
1346     data->states[idx++] = TRUE;                  /* ALPHABLENDENABLE */
1347     data->states[idx++] = TRUE;                  /* FOGENABLE */
1348     data->states[idx++] = TRUE;                  /* SPECULARENABLE */
1349     data->states[idx++] = 255 << 31;             /* FOGCOLOR */
1350     data->states[idx++] = D3DFOG_EXP;            /* FOGTABLEMODE */
1351     data->states[idx++] = to_dword(0.1f);        /* FOGSTART */
1352     data->states[idx++] = to_dword(0.8f);        /* FOGEND */
1353     data->states[idx++] = to_dword(0.5f);        /* FOGDENSITY */
1354     data->states[idx++] = TRUE;                  /* RANGEFOGENABLE */
1355     data->states[idx++] = TRUE;                  /* STENCILENABLE */
1356     data->states[idx++] = D3DSTENCILOP_INCRSAT;  /* STENCILFAIL */
1357     data->states[idx++] = D3DSTENCILOP_REPLACE;  /* STENCILZFAIL */
1358     data->states[idx++] = D3DSTENCILOP_INVERT;   /* STENCILPASS */
1359     data->states[idx++] = D3DCMP_LESS;           /* STENCILFUNC */
1360     data->states[idx++] = 10;                    /* STENCILREF */
1361     data->states[idx++] = 0xFF00FF00;            /* STENCILMASK */
1362     data->states[idx++] = 0x00FF00FF;            /* STENCILWRITEMASK */
1363     data->states[idx++] = 0xF0F0F0F0;            /* TEXTUREFACTOR */
1364     data->states[idx++] = D3DWRAPCOORD_0 | D3DWRAPCOORD_2;                                   /* WRAP 0 */
1365     data->states[idx++] = D3DWRAPCOORD_1 | D3DWRAPCOORD_3;                                   /* WRAP 1 */
1366     data->states[idx++] = D3DWRAPCOORD_2 | D3DWRAPCOORD_3;                                   /* WRAP 2 */
1367     data->states[idx++] = D3DWRAPCOORD_3 | D3DWRAPCOORD_0;                                   /* WRAP 4 */
1368     data->states[idx++] = D3DWRAPCOORD_0 | D3DWRAPCOORD_1 | D3DWRAPCOORD_2;                  /* WRAP 5 */
1369     data->states[idx++] = D3DWRAPCOORD_1 | D3DWRAPCOORD_3 | D3DWRAPCOORD_2;                  /* WRAP 6 */
1370     data->states[idx++] = D3DWRAPCOORD_2 | D3DWRAPCOORD_1 | D3DWRAPCOORD_0;                  /* WRAP 7 */
1371     data->states[idx++] = D3DWRAPCOORD_1 | D3DWRAPCOORD_0 | D3DWRAPCOORD_2 | D3DWRAPCOORD_3; /* WRAP 8 */
1372     data->states[idx++] = FALSE;                 /* CLIPPING */
1373     data->states[idx++] = FALSE;                 /* LIGHTING */
1374     data->states[idx++] = 255 << 16;             /* AMBIENT */
1375     data->states[idx++] = D3DFOG_EXP2;           /* FOGVERTEXMODE */
1376     data->states[idx++] = FALSE;                 /* COLORVERTEX */
1377     data->states[idx++] = FALSE;                 /* LOCALVIEWER */
1378     data->states[idx++] = TRUE;                  /* NORMALIZENORMALS */
1379     data->states[idx++] = D3DMCS_COLOR2;         /* DIFFUSEMATERIALSOURCE */
1380     data->states[idx++] = D3DMCS_MATERIAL;       /* SPECULARMATERIALSOURCE */
1381     data->states[idx++] = D3DMCS_COLOR1;         /* AMBIENTMATERIALSOURCE */
1382     data->states[idx++] = D3DMCS_COLOR2;         /* EMISSIVEMATERIALSOURCE */
1383     data->states[idx++] = D3DVBF_3WEIGHTS;       /* VERTEXBLEND */
1384     data->states[idx++] = 0xf1f1f1f1;            /* CLIPPLANEENABLE */
1385     if (0) data->states[idx++] = to_dword(32.0f);/* POINTSIZE, driver dependent, increase array size to enable */
1386     data->states[idx++] = to_dword(0.7f);        /* POINTSIZEMIN */
1387     data->states[idx++] = TRUE;                  /* POINTSPRITEENABLE */
1388     data->states[idx++] = TRUE;                  /* POINTSCALEENABLE */
1389     data->states[idx++] = to_dword(0.7f);        /* POINTSCALE_A */
1390     data->states[idx++] = to_dword(0.5f);        /* POINTSCALE_B */
1391     data->states[idx++] = to_dword(0.4f);        /* POINTSCALE_C */
1392     data->states[idx++] = FALSE;                 /* MULTISAMPLEANTIALIAS */
1393     data->states[idx++] = 0xABCDDBCA;            /* MULTISAMPLEMASK */
1394     data->states[idx++] = D3DPATCHEDGE_CONTINUOUS; /* PATCHEDGESTYLE */
1395     if (0) data->states[idx++] = D3DDMT_DISABLE; /* DEBUGMONITORTOKEN, not recorded in the stateblock */
1396     data->states[idx++] = to_dword(77.0f);       /* POINTSIZE_MAX */
1397     data->states[idx++] = TRUE;                  /* INDEXEDVERTEXBLENDENABLE */
1398     data->states[idx++] = 0x00000009;            /* COLORWRITEENABLE */
1399     data->states[idx++] = to_dword(0.2f);        /* TWEENFACTOR */
1400     data->states[idx++] = D3DBLENDOP_REVSUBTRACT;/* BLENDOP */
1401 }
1402
1403 static HRESULT render_state_test_init(IDirect3DDevice8 *device, struct state_test *test)
1404 {
1405     static const DWORD states_vertex[] =
1406     {
1407         D3DRS_AMBIENT,
1408         D3DRS_AMBIENTMATERIALSOURCE,
1409         D3DRS_CLIPPING,
1410         D3DRS_CLIPPLANEENABLE,
1411         D3DRS_COLORVERTEX,
1412         D3DRS_CULLMODE,
1413         D3DRS_DIFFUSEMATERIALSOURCE,
1414         D3DRS_EMISSIVEMATERIALSOURCE,
1415         D3DRS_FOGCOLOR,
1416         D3DRS_FOGDENSITY,
1417         D3DRS_FOGENABLE,
1418         D3DRS_FOGEND,
1419         D3DRS_FOGSTART,
1420         D3DRS_FOGTABLEMODE,
1421         D3DRS_FOGVERTEXMODE,
1422         D3DRS_INDEXEDVERTEXBLENDENABLE,
1423         D3DRS_LIGHTING,
1424         D3DRS_LOCALVIEWER,
1425         D3DRS_MULTISAMPLEANTIALIAS,
1426         D3DRS_MULTISAMPLEMASK,
1427         D3DRS_NORMALIZENORMALS,
1428         D3DRS_PATCHEDGESTYLE,
1429         D3DRS_POINTSCALE_A,
1430         D3DRS_POINTSCALE_B,
1431         D3DRS_POINTSCALE_C,
1432         D3DRS_POINTSCALEENABLE,
1433         D3DRS_POINTSIZE,
1434         D3DRS_POINTSIZE_MAX,
1435         D3DRS_POINTSIZE_MIN,
1436         D3DRS_POINTSPRITEENABLE,
1437         D3DRS_RANGEFOGENABLE,
1438         D3DRS_SHADEMODE,
1439         D3DRS_SPECULARENABLE,
1440         D3DRS_SPECULARMATERIALSOURCE,
1441         D3DRS_TWEENFACTOR,
1442         D3DRS_VERTEXBLEND,
1443     };
1444
1445     static const DWORD states_pixel[] =
1446     {
1447         D3DRS_ALPHABLENDENABLE,
1448         D3DRS_ALPHAFUNC,
1449         D3DRS_ALPHAREF,
1450         D3DRS_ALPHATESTENABLE,
1451         D3DRS_BLENDOP,
1452         D3DRS_COLORWRITEENABLE,
1453         D3DRS_DESTBLEND,
1454         D3DRS_DITHERENABLE,
1455         D3DRS_FILLMODE,
1456         D3DRS_FOGDENSITY,
1457         D3DRS_FOGEND,
1458         D3DRS_FOGSTART,
1459         D3DRS_LASTPIXEL,
1460         D3DRS_SHADEMODE,
1461         D3DRS_SRCBLEND,
1462         D3DRS_STENCILENABLE,
1463         D3DRS_STENCILFAIL,
1464         D3DRS_STENCILFUNC,
1465         D3DRS_STENCILMASK,
1466         D3DRS_STENCILPASS,
1467         D3DRS_STENCILREF,
1468         D3DRS_STENCILWRITEMASK,
1469         D3DRS_STENCILZFAIL,
1470         D3DRS_TEXTUREFACTOR,
1471         D3DRS_WRAP0,
1472         D3DRS_WRAP1,
1473         D3DRS_WRAP2,
1474         D3DRS_WRAP3,
1475         D3DRS_WRAP4,
1476         D3DRS_WRAP5,
1477         D3DRS_WRAP6,
1478         D3DRS_WRAP7,
1479         D3DRS_ZENABLE,
1480         D3DRS_ZFUNC,
1481         D3DRS_ZWRITEENABLE,
1482     };
1483
1484     const struct render_state_arg *rsarg = test->test_arg;
1485     unsigned int i, j;
1486
1487     struct render_state_context *ctx = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ctx));
1488     if (!ctx) return E_FAIL;
1489     test->test_context = ctx;
1490
1491     test->default_data = &ctx->default_data_buffer;
1492     test->initial_data = &ctx->default_data_buffer;
1493     test->test_data_in = &ctx->test_data_all_buffer;
1494     test->test_data_out_all = &ctx->test_data_all_buffer;
1495     test->test_data_out_vertex = &ctx->test_data_vertex_buffer;
1496     test->test_data_out_pixel = &ctx->test_data_pixel_buffer;
1497
1498     render_state_default_data_init(rsarg, &ctx->default_data_buffer);
1499     render_state_test_data_init(&ctx->test_data_all_buffer);
1500     render_state_poison_data_init(&ctx->poison_data_buffer);
1501
1502     for (i = 0; i < sizeof(render_state_indices) / sizeof(*render_state_indices); ++i)
1503     {
1504         ctx->test_data_vertex_buffer.states[i] = ctx->default_data_buffer.states[i];
1505         for (j = 0; j < sizeof(states_vertex) / sizeof(*states_vertex); ++j)
1506         {
1507             if (render_state_indices[i] == states_vertex[j])
1508             {
1509                 ctx->test_data_vertex_buffer.states[i] = ctx->test_data_all_buffer.states[i];
1510                 break;
1511             }
1512         }
1513
1514         ctx->test_data_pixel_buffer.states[i] = ctx->default_data_buffer.states[i];
1515         for (j = 0; j < sizeof(states_pixel) / sizeof(*states_pixel); ++j)
1516         {
1517             if (render_state_indices[i] == states_pixel[j])
1518             {
1519                 ctx->test_data_pixel_buffer.states[i] = ctx->test_data_all_buffer.states[i];
1520                 break;
1521             }
1522         }
1523     }
1524
1525     return D3D_OK;
1526 }
1527
1528 static void render_state_test_cleanup(IDirect3DDevice8 *device, struct state_test *test)
1529 {
1530     HeapFree(GetProcessHeap(), 0, test->test_context);
1531 }
1532
1533 static void render_states_queue_test(struct state_test *test, const struct render_state_arg *test_arg)
1534 {
1535     test->init = render_state_test_init;
1536     test->cleanup = render_state_test_cleanup;
1537     test->apply_data = render_state_apply_data;
1538     test->check_data = render_state_check_data;
1539     test->test_name = "set_get_render_states";
1540     test->test_arg = test_arg;
1541 }
1542
1543 /* resource tests */
1544
1545 struct resource_test_arg
1546 {
1547     DWORD vs_version;
1548     DWORD ps_version;
1549     UINT stream_count;
1550     UINT tex_count;
1551 };
1552
1553 struct resource_test_data
1554 {
1555     DWORD vs;
1556     DWORD ps;
1557     IDirect3DIndexBuffer8 *ib;
1558     IDirect3DVertexBuffer8 **vb;
1559     IDirect3DTexture8 **tex;
1560 };
1561
1562 struct resource_test_context
1563 {
1564     struct resource_test_data default_data;
1565     struct resource_test_data test_data_all;
1566     struct resource_test_data test_data_vertex;
1567     struct resource_test_data test_data_pixel;
1568     struct resource_test_data poison_data;
1569 };
1570
1571 static void resource_apply_data(IDirect3DDevice8 *device, const struct state_test *test, const void *data)
1572 {
1573     const struct resource_test_arg *arg = test->test_arg;
1574     const struct resource_test_data *d = data;
1575     unsigned int i;
1576     HRESULT hr;
1577
1578     hr = IDirect3DDevice8_SetVertexShader(device, d->vs);
1579     ok(SUCCEEDED(hr), "SetVertexShader (%u) returned %#x.\n", d->vs, hr);
1580
1581     hr = IDirect3DDevice8_SetPixelShader(device, d->ps);
1582     ok(SUCCEEDED(hr), "SetPixelShader (%u) returned %#x.\n", d->ps, hr);
1583
1584     hr = IDirect3DDevice8_SetIndices(device, d->ib, 0);
1585     ok(SUCCEEDED(hr), "SetIndices (%p) returned %#x.\n", d->ib, hr);
1586
1587     for (i = 0; i < arg->stream_count; ++i)
1588     {
1589         hr = IDirect3DDevice8_SetStreamSource(device, i, d->vb[i], 64);
1590         ok(SUCCEEDED(hr), "SetStreamSource (%u, %p, 64) returned %#x.\n",
1591                 i, d->vb[i], hr);
1592     }
1593
1594     for (i = 0; i < arg->tex_count; ++i)
1595     {
1596         hr = IDirect3DDevice8_SetTexture(device, i, (IDirect3DBaseTexture8 *)d->tex[i]);
1597         ok(SUCCEEDED(hr), "SetTexture (%u, %p) returned %#x.\n", i, d->tex[i], hr);
1598     }
1599 }
1600
1601 static void resource_check_data(IDirect3DDevice8 *device, const struct state_test *test,
1602         const void *expected_data, unsigned int chain_stage)
1603 {
1604     const struct resource_test_context *ctx = test->test_context;
1605     const struct resource_test_data *poison = &ctx->poison_data;
1606     const struct resource_test_arg *arg = test->test_arg;
1607     const struct resource_test_data *d = expected_data;
1608     unsigned int i;
1609     HRESULT hr;
1610     void *ptr;
1611     DWORD v;
1612
1613     v = poison->vs;
1614     hr = IDirect3DDevice8_GetVertexShader(device, &v);
1615     ok(SUCCEEDED(hr), "GetVertexShader returned %#x.\n", hr);
1616     ok(v == d->vs, "Chain stage %u, expected vertex shader %#x, received %#x.\n",
1617             chain_stage, d->vs, v);
1618
1619     v = poison->ps;
1620     hr = IDirect3DDevice8_GetPixelShader(device, &v);
1621     ok(SUCCEEDED(hr), "GetPixelShader returned %#x.\n", hr);
1622     ok(v == d->ps, "Chain stage %u, expected pixel shader %#x, received %#x.\n",
1623             chain_stage, d->ps, v);
1624
1625     ptr = poison->ib;
1626     hr = IDirect3DDevice8_GetIndices(device, (IDirect3DIndexBuffer8 **)&ptr, &v);
1627     ok(SUCCEEDED(hr), "GetIndices returned %#x.\n", hr);
1628     ok(ptr == d->ib, "Chain stage %u, expected index buffer %p, received %p.\n",
1629             chain_stage, d->ib, ptr);
1630     if (SUCCEEDED(hr) && ptr)
1631     {
1632         IDirect3DIndexBuffer8_Release((IDirect3DIndexBuffer8 *)ptr);
1633     }
1634
1635     for (i = 0; i < arg->stream_count; ++i)
1636     {
1637         ptr = poison->vb[i];
1638         hr = IDirect3DDevice8_GetStreamSource(device, i, (IDirect3DVertexBuffer8 **)&ptr, &v);
1639         ok(SUCCEEDED(hr), "GetStreamSource (%u) returned %#x.\n", i, hr);
1640         ok(ptr == d->vb[i], "Chain stage %u, stream %u, expected vertex buffer %p, received %p.\n",
1641                 chain_stage, i, d->vb[i], ptr);
1642         if (SUCCEEDED(hr) && ptr)
1643         {
1644             IDirect3DIndexBuffer8_Release((IDirect3DVertexBuffer8 *)ptr);
1645         }
1646     }
1647
1648     for (i = 0; i < arg->tex_count; ++i)
1649     {
1650         ptr = poison->tex[i];
1651         hr = IDirect3DDevice8_GetTexture(device, i, (IDirect3DBaseTexture8 **)&ptr);
1652         ok(SUCCEEDED(hr), "SetTexture (%u) returned %#x.\n", i, hr);
1653         ok(ptr == d->tex[i], "Chain stage %u, texture stage %u, expected texture %p, received %p.\n",
1654                 chain_stage, i, d->tex[i], ptr);
1655         if (SUCCEEDED(hr) && ptr)
1656         {
1657             IDirect3DBaseTexture8_Release((IDirect3DBaseTexture8 *)ptr);
1658         }
1659     }
1660 }
1661
1662 static void resource_default_data_init(struct resource_test_data *data, const struct resource_test_arg *arg)
1663 {
1664     unsigned int i;
1665
1666     data->vs = 0;
1667     data->ps = 0;
1668     data->ib = NULL;
1669     data->vb = HeapAlloc(GetProcessHeap(), 0, arg->stream_count * sizeof(*data->vb));
1670     for (i = 0; i < arg->stream_count; ++i)
1671     {
1672         data->vb[i] = NULL;
1673     }
1674     data->tex = HeapAlloc(GetProcessHeap(), 0, arg->tex_count * sizeof(*data->tex));
1675     for (i = 0; i < arg->tex_count; ++i)
1676     {
1677         data->tex[i] = NULL;
1678     }
1679 }
1680
1681 static void resource_test_data_init(IDirect3DDevice8 *device,
1682         struct resource_test_data *data, const struct resource_test_arg *arg)
1683 {
1684     static const DWORD vs_code[] =
1685     {
1686         0xfffe0101,                                                             /* vs_1_1                       */
1687         0x00000009, 0xc0010000, 0x90e40000, 0xa0e40000,                         /* dp4 oPos.x, v0, c0           */
1688         0x00000009, 0xc0020000, 0x90e40000, 0xa0e40001,                         /* dp4 oPos.y, v0, c1           */
1689         0x00000009, 0xc0040000, 0x90e40000, 0xa0e40002,                         /* dp4 oPos.z, v0, c2           */
1690         0x00000009, 0xc0080000, 0x90e40000, 0xa0e40003,                         /* dp4 oPos.w, v0, c3           */
1691         0x0000ffff,                                                             /* END                          */
1692     };
1693     static const DWORD ps_code[] =
1694     {
1695         0xffff0101,                                                             /* ps_1_1                       */
1696         0x00000051, 0xa00f0001, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, /* def c1 = 1.0, 0.0, 0.0, 0.0  */
1697         0x00000042, 0xb00f0000,                                                 /* tex t0                       */
1698         0x00000008, 0x800f0000, 0xa0e40001, 0xa0e40000,                         /* dp3 r0, c1, c0               */
1699         0x00000005, 0x800f0000, 0x90e40000, 0x80e40000,                         /* mul r0, v0, r0               */
1700         0x00000005, 0x800f0000, 0xb0e40000, 0x80e40000,                         /* mul r0, t0, r0               */
1701         0x0000ffff,                                                             /* END                          */
1702     };
1703     static const DWORD decl[] =
1704     {
1705         D3DVSD_STREAM(0),
1706         D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
1707         D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR),
1708         D3DVSD_END(),
1709     };
1710
1711     unsigned int i;
1712     HRESULT hr;
1713
1714     if (arg->vs_version)
1715     {
1716         hr = IDirect3DDevice8_CreateVertexShader(device, decl, vs_code, &data->vs, 0);
1717         ok(SUCCEEDED(hr), "CreateVertexShader returned hr %#x.\n", hr);
1718     }
1719
1720     if (arg->ps_version)
1721     {
1722         hr = IDirect3DDevice8_CreatePixelShader(device, ps_code, &data->ps);
1723         ok(SUCCEEDED(hr), "CreatePixelShader returned hr %#x.\n", hr);
1724     }
1725
1726     hr = IDirect3DDevice8_CreateIndexBuffer(device, 64, D3DUSAGE_DYNAMIC, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &data->ib);
1727     ok(SUCCEEDED(hr), "CreateIndexBuffer returned hr %#x.\n", hr);
1728
1729     data->vb = HeapAlloc(GetProcessHeap(), 0, arg->stream_count * sizeof(*data->vb));
1730     for (i = 0; i < arg->stream_count; ++i)
1731     {
1732         hr = IDirect3DDevice8_CreateVertexBuffer(device, 64, D3DUSAGE_DYNAMIC,
1733                 0, D3DPOOL_DEFAULT, &data->vb[i]);
1734         ok(SUCCEEDED(hr), "CreateVertexBuffer (%u) returned hr %#x.\n", i, hr);
1735     }
1736
1737     data->tex = HeapAlloc(GetProcessHeap(), 0, arg->tex_count * sizeof(*data->tex));
1738     for (i = 0; i < arg->tex_count; ++i)
1739     {
1740         hr = IDirect3DDevice8_CreateTexture(device, 64, 64, 0, 0,
1741                 D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &data->tex[i]);
1742         ok(SUCCEEDED(hr), "CreateTexture (%u) returned hr %#x.\n", i, hr);
1743     }
1744 }
1745
1746 static void resource_poison_data_init(struct resource_test_data *data, const struct resource_test_arg *arg)
1747 {
1748     DWORD_PTR poison = 0xdeadbeef;
1749     unsigned int i;
1750
1751     data->vs = poison++;
1752     data->ps = poison++;
1753     data->ib = (IDirect3DIndexBuffer8 *)poison++;
1754     data->vb = HeapAlloc(GetProcessHeap(), 0, arg->stream_count * sizeof(*data->vb));
1755     for (i = 0; i < arg->stream_count; ++i)
1756     {
1757         data->vb[i] = (IDirect3DVertexBuffer8 *)poison++;
1758     }
1759     data->tex = HeapAlloc(GetProcessHeap(), 0, arg->tex_count * sizeof(*data->tex));
1760     for (i = 0; i < arg->tex_count; ++i)
1761     {
1762         data->tex[i] = (IDirect3DTexture8 *)poison++;
1763     }
1764 }
1765
1766 static HRESULT resource_test_init(IDirect3DDevice8 *device, struct state_test *test)
1767 {
1768     const struct resource_test_arg *arg = test->test_arg;
1769     struct resource_test_context *ctx;
1770
1771     ctx = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ctx));
1772     if (!ctx) return E_OUTOFMEMORY;
1773
1774     test->test_context = ctx;
1775     test->test_data_in = &ctx->test_data_all;
1776     test->test_data_out_all = &ctx->test_data_all;
1777     test->test_data_out_vertex = &ctx->test_data_vertex;
1778     test->test_data_out_pixel = &ctx->test_data_pixel;
1779     test->default_data = &ctx->default_data;
1780     test->initial_data = &ctx->default_data;
1781
1782     resource_default_data_init(&ctx->default_data, arg);
1783     resource_test_data_init(device, &ctx->test_data_all, arg);
1784     resource_default_data_init(&ctx->test_data_vertex, arg);
1785     resource_default_data_init(&ctx->test_data_pixel, arg);
1786     resource_poison_data_init(&ctx->poison_data, arg);
1787
1788     ctx->test_data_vertex.vs = ctx->test_data_all.vs;
1789     ctx->test_data_pixel.ps = ctx->test_data_all.ps;
1790
1791     return D3D_OK;
1792 }
1793
1794 static void resource_test_cleanup(IDirect3DDevice8 *device, struct state_test *test)
1795 {
1796     struct resource_test_context *ctx = test->test_context;
1797     const struct resource_test_arg *arg = test->test_arg;
1798     unsigned int i;
1799     HRESULT hr;
1800
1801     resource_apply_data(device, test, &ctx->default_data);
1802
1803     if (ctx->test_data_all.vs)
1804     {
1805         hr = IDirect3DDevice8_DeleteVertexShader(device, ctx->test_data_all.vs);
1806         ok(SUCCEEDED(hr), "DeleteVertexShader (%u) returned %#x.\n", ctx->test_data_all.vs, hr);
1807     }
1808
1809     if (ctx->test_data_all.ps)
1810     {
1811         hr = IDirect3DDevice8_DeletePixelShader(device, ctx->test_data_all.ps);
1812         ok(SUCCEEDED(hr), "DeletePixelShader (%u) returned %#x.\n", ctx->test_data_all.ps, hr);
1813     }
1814
1815     IDirect3DIndexBuffer8_Release(ctx->test_data_all.ib);
1816     for (i = 0; i < arg->stream_count; ++i)
1817     {
1818         IDirect3DVertexBuffer8_Release(ctx->test_data_all.vb[i]);
1819     }
1820
1821     for (i = 0; i < arg->tex_count; ++i)
1822     {
1823         hr = IDirect3DBaseTexture8_Release(ctx->test_data_all.tex[i]);
1824     }
1825
1826     HeapFree(GetProcessHeap(), 0, ctx->default_data.vb);
1827     HeapFree(GetProcessHeap(), 0, ctx->default_data.tex);
1828     HeapFree(GetProcessHeap(), 0, ctx->test_data_all.vb);
1829     HeapFree(GetProcessHeap(), 0, ctx->test_data_all.tex);
1830     HeapFree(GetProcessHeap(), 0, ctx->test_data_vertex.vb);
1831     HeapFree(GetProcessHeap(), 0, ctx->test_data_vertex.tex);
1832     HeapFree(GetProcessHeap(), 0, ctx->test_data_pixel.vb);
1833     HeapFree(GetProcessHeap(), 0, ctx->test_data_pixel.tex);
1834     HeapFree(GetProcessHeap(), 0, ctx->poison_data.vb);
1835     HeapFree(GetProcessHeap(), 0, ctx->poison_data.tex);
1836     HeapFree(GetProcessHeap(), 0, ctx);
1837 }
1838
1839 static void resource_test_queue(struct state_test *test, const struct resource_test_arg *test_arg)
1840 {
1841     test->init = resource_test_init;
1842     test->cleanup = resource_test_cleanup;
1843     test->apply_data = resource_apply_data;
1844     test->check_data = resource_check_data;
1845     test->test_name = "set_get_resources";
1846     test->test_arg = test_arg;
1847 }
1848
1849 /* =================== Main state tests function =============================== */
1850
1851 static void test_state_management(IDirect3DDevice8 *device, D3DPRESENT_PARAMETERS *device_pparams)
1852 {
1853     D3DCAPS8 caps;
1854     HRESULT hr;
1855
1856     /* Test count: 2 for shader constants
1857      *             1 for lights
1858      *             1 for transforms
1859      *             1 for render states
1860      *             1 for resources
1861      */
1862     struct state_test tests[6];
1863     unsigned int tcount = 0;
1864
1865     struct shader_constant_arg pshader_constant_arg;
1866     struct shader_constant_arg vshader_constant_arg;
1867     struct resource_test_arg resource_test_arg;
1868     struct render_state_arg render_state_arg;
1869     struct light_arg light_arg;
1870
1871     hr = IDirect3DDevice8_GetDeviceCaps(device, &caps);
1872     ok(SUCCEEDED(hr), "GetDeviceCaps returned %#x.\n", hr);
1873     if (FAILED(hr)) return;
1874
1875     texture_stages = caps.MaxTextureBlendStages;
1876
1877     /* Zero test memory */
1878     memset(tests, 0, sizeof(tests));
1879
1880     if (caps.VertexShaderVersion & 0xffff)
1881     {
1882         vshader_constant_arg.idx = 0;
1883         vshader_constant_arg.pshader = FALSE;
1884         shader_constants_queue_test(&tests[tcount++], &vshader_constant_arg);
1885     }
1886
1887     if (caps.PixelShaderVersion & 0xffff)
1888     {
1889         pshader_constant_arg.idx = 0;
1890         pshader_constant_arg.pshader = TRUE;
1891         shader_constants_queue_test(&tests[tcount++], &pshader_constant_arg);
1892     }
1893
1894     light_arg.idx = 0;
1895     lights_queue_test(&tests[tcount++], &light_arg);
1896
1897     transform_queue_test(&tests[tcount++]);
1898
1899     render_state_arg.device_pparams = device_pparams;
1900     render_state_arg.pointsize_max = caps.MaxPointSize;
1901     render_states_queue_test(&tests[tcount++], &render_state_arg);
1902
1903     resource_test_arg.vs_version = caps.VertexShaderVersion & 0xffff;
1904     resource_test_arg.ps_version = caps.PixelShaderVersion & 0xffff;
1905     resource_test_arg.stream_count = caps.MaxStreams;
1906     resource_test_arg.tex_count = caps.MaxTextureBlendStages;
1907     resource_test_queue(&tests[tcount++], &resource_test_arg);
1908
1909     execute_test_chain_all(device, tests, tcount);
1910 }
1911
1912 static void test_shader_constant_apply(IDirect3DDevice8 *device)
1913 {
1914     static const float initial[] = {0.0f, 0.0f, 0.0f, 0.0f};
1915     static const float vs_const[] = {1.0f, 2.0f, 3.0f, 4.0f};
1916     static const float ps_const[] = {5.0f, 6.0f, 7.0f, 8.0f};
1917     DWORD vs_version, ps_version;
1918     DWORD stateblock;
1919     D3DCAPS8 caps;
1920     float ret[4];
1921     HRESULT hr;
1922
1923     hr = IDirect3DDevice8_GetDeviceCaps(device, &caps);
1924     ok(SUCCEEDED(hr), "GetDeviceCaps returned %#x.\n", hr);
1925     vs_version = caps.VertexShaderVersion & 0xffff;
1926     ps_version = caps.PixelShaderVersion & 0xffff;
1927
1928     if (vs_version)
1929     {
1930         hr = IDirect3DDevice8_SetVertexShaderConstant(device, 0, initial, 1);
1931         ok(SUCCEEDED(hr), "SetVertexShaderConstant returned %#x.\n", hr);
1932         hr = IDirect3DDevice8_SetVertexShaderConstant(device, 1, initial, 1);
1933         ok(SUCCEEDED(hr), "SetVertexShaderConstant returned %#x.\n", hr);
1934
1935         hr = IDirect3DDevice8_GetVertexShaderConstant(device, 0, ret, 1);
1936         ok(SUCCEEDED(hr), "GetVertexShaderConstant returned %#x.\n", hr);
1937         ok(!memcmp(ret, initial, sizeof(initial)),
1938                 "GetVertexShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
1939                 ret[0], ret[1], ret[2], ret[3], initial[0], initial[1], initial[2], initial[3]);
1940         hr = IDirect3DDevice8_GetVertexShaderConstant(device, 1, ret, 1);
1941         ok(SUCCEEDED(hr), "GetVertexShaderConstant returned %#x\n", hr);
1942         ok(!memcmp(ret, initial, sizeof(initial)),
1943                 "GetVertexShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
1944                 ret[0], ret[1], ret[2], ret[3], initial[0], initial[1], initial[2], initial[3]);
1945
1946         hr = IDirect3DDevice8_SetVertexShaderConstant(device, 0, vs_const, 1);
1947         ok(SUCCEEDED(hr), "SetVertexShaderConstant returned %#x.\n", hr);
1948     }
1949     if (ps_version)
1950     {
1951         hr = IDirect3DDevice8_SetPixelShaderConstant(device, 0, initial, 1);
1952         ok(SUCCEEDED(hr), "SetPixelShaderConstant returned %#x.\n", hr);
1953         hr = IDirect3DDevice8_SetPixelShaderConstant(device, 1, initial, 1);
1954         ok(SUCCEEDED(hr), "SetPixelShaderConstant returned %#x.\n", hr);
1955
1956         hr = IDirect3DDevice8_GetPixelShaderConstant(device, 0, ret, 1);
1957         ok(SUCCEEDED(hr), "GetPixelShaderConstant returned %#x.\n", hr);
1958         ok(!memcmp(ret, initial, sizeof(initial)),
1959                 "GetpixelShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
1960                 ret[0], ret[1], ret[2], ret[3], initial[0], initial[1], initial[2], initial[3]);
1961         hr = IDirect3DDevice8_GetPixelShaderConstant(device, 1, ret, 1);
1962         ok(SUCCEEDED(hr), "GetPixelShaderConstant returned %#x.\n", hr);
1963         ok(!memcmp(ret, initial, sizeof(initial)),
1964                 "GetPixelShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
1965                 ret[0], ret[1], ret[2], ret[3], initial[0], initial[1], initial[2], initial[3]);
1966
1967         hr = IDirect3DDevice8_SetPixelShaderConstant(device, 0, ps_const, 1);
1968         ok(SUCCEEDED(hr), "SetPixelShaderConstant returned %#x.\n", hr);
1969     }
1970
1971     hr = IDirect3DDevice8_BeginStateBlock(device);
1972     ok(SUCCEEDED(hr), "BeginStateBlock returned %#x\n", hr);
1973
1974     if (vs_version)
1975     {
1976         hr = IDirect3DDevice8_SetVertexShaderConstant(device, 1, vs_const, 1);
1977         ok(SUCCEEDED(hr), "SetVertexShaderConstant returned %#x.\n", hr);
1978     }
1979     if (ps_version)
1980     {
1981         hr = IDirect3DDevice8_SetPixelShaderConstant(device, 1, ps_const, 1);
1982         ok(SUCCEEDED(hr), "SetPixelShaderConstant returned %#x.\n", hr);
1983     }
1984
1985     hr = IDirect3DDevice8_EndStateBlock(device, &stateblock);
1986     ok(SUCCEEDED(hr), "EndStateBlock returned %#x\n", hr);
1987
1988     if (vs_version)
1989     {
1990         hr = IDirect3DDevice8_GetVertexShaderConstant(device, 0, ret, 1);
1991         ok(SUCCEEDED(hr), "GetVertexShaderConstant returned %#x.\n", hr);
1992         ok(!memcmp(ret, vs_const, sizeof(vs_const)),
1993                 "GetVertexShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
1994                 ret[0], ret[1], ret[2], ret[3], vs_const[0], vs_const[1], vs_const[2], vs_const[3]);
1995         hr = IDirect3DDevice8_GetVertexShaderConstant(device, 1, ret, 1);
1996         ok(SUCCEEDED(hr), "GetVertexShaderConstant returned %#x.\n", hr);
1997         ok(!memcmp(ret, initial, sizeof(initial)),
1998                 "GetVertexShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
1999                 ret[0], ret[1], ret[2], ret[3], initial[0], initial[1], initial[2], initial[3]);
2000     }
2001     if (ps_version)
2002     {
2003         hr = IDirect3DDevice8_GetPixelShaderConstant(device, 0, ret, 1);
2004         ok(SUCCEEDED(hr), "GetPixelShaderConstant returned %#x.\n", hr);
2005         ok(!memcmp(ret, ps_const, sizeof(ps_const)),
2006                 "GetPixelShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
2007                 ret[0], ret[1], ret[2], ret[3], ps_const[0], ps_const[1], ps_const[2], ps_const[3]);
2008         hr = IDirect3DDevice8_GetPixelShaderConstant(device, 1, ret, 1);
2009         ok(SUCCEEDED(hr), "GetPixelShaderConstant returned %#x.\n", hr);
2010         ok(!memcmp(ret, initial, sizeof(initial)),
2011                 "GetPixelShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
2012                 ret[0], ret[1], ret[2], ret[3], initial[0], initial[1], initial[2], initial[3]);
2013     }
2014
2015     /* Apply doesn't overwrite constants that aren't explicitly set on the source stateblock. */
2016     hr = IDirect3DDevice8_ApplyStateBlock(device, stateblock);
2017     ok(SUCCEEDED(hr), "Apply returned %#x\n", hr);
2018
2019     if (vs_version)
2020     {
2021         hr = IDirect3DDevice8_GetVertexShaderConstant(device, 0, ret, 1);
2022         ok(SUCCEEDED(hr), "GetVertexShaderConstant returned %#x.\n", hr);
2023         ok(!memcmp(ret, vs_const, sizeof(vs_const)),
2024                 "GetVertexShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
2025                 ret[0], ret[1], ret[2], ret[3], vs_const[0], vs_const[1], vs_const[2], vs_const[3]);
2026         hr = IDirect3DDevice8_GetVertexShaderConstant(device, 1, ret, 1);
2027         ok(SUCCEEDED(hr), "GetVertexShaderConstant returned %#x.\n", hr);
2028         ok(!memcmp(ret, vs_const, sizeof(vs_const)),
2029                 "GetVertexShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
2030                 ret[0], ret[1], ret[2], ret[3], vs_const[0], vs_const[1], vs_const[2], vs_const[3]);
2031     }
2032     if (ps_version)
2033     {
2034         hr = IDirect3DDevice8_GetPixelShaderConstant(device, 0, ret, 1);
2035         ok(SUCCEEDED(hr), "GetPixelShaderConstant returned %#x.\n", hr);
2036         ok(!memcmp(ret, ps_const, sizeof(ps_const)),
2037                 "GetPixelShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
2038                 ret[0], ret[1], ret[2], ret[3], ps_const[0], ps_const[1], ps_const[2], ps_const[3]);
2039         hr = IDirect3DDevice8_GetPixelShaderConstant(device, 1, ret, 1);
2040         ok(SUCCEEDED(hr), "GetPixelShaderConstant returned %#x.\n", hr);
2041         ok(!memcmp(ret, ps_const, sizeof(ps_const)),
2042                 "GetPixelShaderConstant got {%f, %f, %f, %f}, expected {%f, %f, %f, %f}\n",
2043                 ret[0], ret[1], ret[2], ret[3], ps_const[0], ps_const[1], ps_const[2], ps_const[3]);
2044     }
2045
2046     IDirect3DDevice8_DeleteStateBlock(device, stateblock);
2047 }
2048
2049 START_TEST(stateblock)
2050 {
2051     IDirect3DDevice8 *device = NULL;
2052     D3DPRESENT_PARAMETERS device_pparams;
2053     HMODULE d3d8_module;
2054     ULONG refcount;
2055     HRESULT hr;
2056
2057     d3d8_module = LoadLibraryA("d3d8.dll");
2058     if (!d3d8_module)
2059     {
2060         skip("Could not load d3d8.dll\n");
2061         return;
2062     }
2063
2064     hr = init_d3d8(d3d8_module, &device, &device_pparams);
2065     if (FAILED(hr))
2066     {
2067         FreeLibrary(d3d8_module);
2068         return;
2069     }
2070
2071     test_begin_end_state_block(device);
2072     test_state_management(device, &device_pparams);
2073     test_shader_constant_apply(device);
2074
2075     refcount = IDirect3DDevice8_Release(device);
2076     ok(!refcount, "Device has %u references left\n", refcount);
2077
2078     FreeLibrary(d3d8_module);
2079 }