d3d9/tests: Merge query.c into device.c.
[wine] / dlls / d3d9 / tests / shader.c
1 /*
2  * Copyright (C) 2005 Henri Verbeet
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #define COBJMACROS
20 #include <d3d9.h>
21 #include "wine/test.h"
22
23 static HMODULE d3d9_handle = 0;
24
25 static HWND create_window(void)
26 {
27     WNDCLASS wc = {0};
28     wc.lpfnWndProc = DefWindowProc;
29     wc.lpszClassName = "d3d9_test_wc";
30     RegisterClass(&wc);
31
32     return CreateWindow("d3d9_test_wc", "d3d9_test",
33             0, 0, 0, 0, 0, 0, 0, 0, 0);
34 }
35
36 static IDirect3DDevice9 *init_d3d9(void)
37 {
38     IDirect3D9 * (__stdcall * d3d9_create)(UINT SDKVersion) = 0;
39     IDirect3D9 *d3d9_ptr = 0;
40     IDirect3DDevice9 *device_ptr = 0;
41     D3DPRESENT_PARAMETERS present_parameters;
42     HRESULT hres;
43
44     d3d9_create = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9");
45     ok(d3d9_create != NULL, "Failed to get address of Direct3DCreate9\n");
46     if (!d3d9_create) return NULL;
47
48     d3d9_ptr = d3d9_create(D3D_SDK_VERSION);
49     if (!d3d9_ptr)
50     {
51         skip("could not create D3D9\n");
52         return NULL;
53     }
54
55     ZeroMemory(&present_parameters, sizeof(present_parameters));
56     present_parameters.Windowed = TRUE;
57     present_parameters.hDeviceWindow = create_window();
58     present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
59
60     hres = IDirect3D9_CreateDevice(d3d9_ptr, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &device_ptr);
61
62     if(FAILED(hres))
63     {
64         skip("could not create device, IDirect3D9_CreateDevice returned %#x\n", hres);
65         return NULL;
66     }
67
68     return device_ptr;
69 }
70
71 static int get_refcount(IUnknown *object)
72 {
73     IUnknown_AddRef(object);
74     return IUnknown_Release(object);
75 }
76
77 static void test_get_set_vertex_shader(IDirect3DDevice9 *device_ptr)
78 {
79
80     static DWORD simple_vs[] = {0xFFFE0101,             /* vs_1_1               */
81         0x0000001F, 0x80000000, 0x900F0000,             /* dcl_position0 v0     */
82         0x00000009, 0xC0010000, 0x90E40000, 0xA0E40000, /* dp4 oPos.x, v0, c0   */
83         0x00000009, 0xC0020000, 0x90E40000, 0xA0E40001, /* dp4 oPos.y, v0, c1   */
84         0x00000009, 0xC0040000, 0x90E40000, 0xA0E40002, /* dp4 oPos.z, v0, c2   */
85         0x00000009, 0xC0080000, 0x90E40000, 0xA0E40003, /* dp4 oPos.w, v0, c3   */
86         0x0000FFFF};                                    /* END                  */
87
88     IDirect3DVertexShader9 *shader_ptr = 0;
89     IDirect3DVertexShader9 *current_shader_ptr = 0;
90     HRESULT hret = 0;
91     int shader_refcount = 0;
92     int i = 0;
93
94     hret = IDirect3DDevice9_CreateVertexShader(device_ptr, simple_vs, &shader_ptr);
95     ok(hret == D3D_OK && shader_ptr != NULL, "CreateVertexShader returned: hret 0x%x, shader_ptr %p. "
96         "Expected hret 0x%x, shader_ptr != %p. Aborting.\n", hret, shader_ptr, D3D_OK, NULL);
97     if (hret != D3D_OK || shader_ptr == NULL) return;
98
99     /* SetVertexShader should not touch the shader's refcount. */
100     i = get_refcount((IUnknown *)shader_ptr);
101     hret = IDirect3DDevice9_SetVertexShader(device_ptr, shader_ptr);
102     shader_refcount = get_refcount((IUnknown *)shader_ptr);
103     ok(hret == D3D_OK && shader_refcount == i, "SetVertexShader returned: hret 0x%x, refcount %d. "
104         "Expected hret 0x%x, refcount %d.\n", hret, shader_refcount, D3D_OK, i);
105
106     /* GetVertexShader should increase the shader's refcount by one. */
107     i = shader_refcount+1;
108     hret = IDirect3DDevice9_GetVertexShader(device_ptr, &current_shader_ptr);
109     shader_refcount = get_refcount((IUnknown *)shader_ptr);
110     ok(hret == D3D_OK && shader_refcount == i && current_shader_ptr == shader_ptr,
111         "GetVertexShader returned: hret 0x%x, current_shader_ptr %p refcount %d. "
112         "Expected hret 0x%x, current_shader_ptr %p, refcount %d.\n", hret, current_shader_ptr, shader_refcount, D3D_OK, shader_ptr, i);
113     IDirect3DVertexShader9_Release(current_shader_ptr);
114
115     IDirect3DVertexShader9_Release(shader_ptr);
116 }
117
118 static void test_vertex_shader_constant(IDirect3DDevice9 *device_ptr, DWORD consts)
119 {
120     float c[4] = { 0.0, 0.0, 0.0, 0.0 };
121     float d[16] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
122     HRESULT hr;
123
124     /* A simple check that the stuff works at all */
125     hr = IDirect3DDevice9_SetVertexShaderConstantF(device_ptr, 0, c, 1);
126     ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexShaderConstantF returned 0x%08x\n", hr);
127
128     /* Test corner cases: Write to const MAX - 1, MAX, MAX + 1, and writing 4 consts from
129      * MAX - 1
130      */
131     hr = IDirect3DDevice9_SetVertexShaderConstantF(device_ptr, consts - 1, c, 1);
132     ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexShaderConstantF returned 0x%08x\n", hr);
133     hr = IDirect3DDevice9_SetVertexShaderConstantF(device_ptr, consts + 0, c, 1);
134     ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_SetVertexShaderConstantF returned 0x%08x\n", hr);
135     hr = IDirect3DDevice9_SetVertexShaderConstantF(device_ptr, consts + 1, c, 1);
136     ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_SetVertexShaderConstantF returned 0x%08x\n", hr);
137     hr = IDirect3DDevice9_SetVertexShaderConstantF(device_ptr, consts - 1, d, 4);
138     ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_SetVertexShaderConstantF returned 0x%08x\n", hr);
139
140     /* Constant -1 */
141     hr = IDirect3DDevice9_SetVertexShaderConstantF(device_ptr, -1, c, 1);
142     ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_SetVertexShaderConstantF returned 0x%08x\n", hr);
143 }
144
145 static void test_get_set_pixel_shader(IDirect3DDevice9 *device_ptr)
146 {
147     static DWORD simple_ps[] = {0xFFFF0101,                                     /* ps_1_1                       */
148         0x00000051, 0xA00F0001, 0x3F800000, 0x00000000, 0x00000000, 0x00000000, /* def c1 = 1.0, 0.0, 0.0, 0.0  */
149         0x00000042, 0xB00F0000,                                                 /* tex t0                       */
150         0x00000008, 0x800F0000, 0xA0E40001, 0xA0E40000,                         /* dp3 r0, c1, c0               */
151         0x00000005, 0x800F0000, 0x90E40000, 0x80E40000,                         /* mul r0, v0, r0               */
152         0x00000005, 0x800F0000, 0xB0E40000, 0x80E40000,                         /* mul r0, t0, r0               */
153         0x0000FFFF};                                                            /* END                          */
154
155     IDirect3DPixelShader9 *shader_ptr = 0;
156     IDirect3DPixelShader9 *current_shader_ptr = 0;
157     HRESULT hret = 0;
158     int shader_refcount = 0;
159     int i = 0;
160
161     hret = IDirect3DDevice9_CreatePixelShader(device_ptr, simple_ps, &shader_ptr);
162     ok(hret == D3D_OK && shader_ptr != NULL, "CreatePixelShader returned: hret 0x%x, shader_ptr %p. "
163         "Expected hret 0x%x, shader_ptr != %p. Aborting.\n", hret, shader_ptr, D3D_OK, NULL);
164     if (hret != D3D_OK || shader_ptr == NULL) return;
165
166     /* SetPixelsShader should not touch the shader's refcount. */
167     i = get_refcount((IUnknown *)shader_ptr);
168     hret = IDirect3DDevice9_SetPixelShader(device_ptr, shader_ptr);
169     shader_refcount = get_refcount((IUnknown *)shader_ptr);
170     ok(hret == D3D_OK && shader_refcount == i, "SetPixelShader returned: hret 0x%x, refcount %d. "
171         "Expected hret 0x%x, refcount %d.\n", hret, shader_refcount, D3D_OK, i);
172
173     /* GetPixelShader should increase the shader's refcount by one. */
174     i = shader_refcount+1;
175     hret = IDirect3DDevice9_GetPixelShader(device_ptr, &current_shader_ptr);
176     shader_refcount = get_refcount((IUnknown *)shader_ptr);
177     ok(hret == D3D_OK && shader_refcount == i && current_shader_ptr == shader_ptr,
178         "GetPixelShader returned: hret 0x%x, current_shader_ptr %p refcount %d. "
179         "Expected hret 0x%x, current_shader_ptr %p, refcount %d.\n", hret, current_shader_ptr, shader_refcount, D3D_OK, shader_ptr, i);
180     IDirect3DPixelShader9_Release(current_shader_ptr);
181
182     IDirect3DPixelShader9_Release(shader_ptr);
183 }
184
185 static void test_pixel_shader_constant(IDirect3DDevice9 *device_ptr)
186 {
187     float c[4] = { 0.0, 0.0, 0.0, 0.0 };
188     float d[16] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
189     HRESULT hr;
190     DWORD consts = 0;
191
192     /* A simple check that the stuff works at all */
193     hr = IDirect3DDevice9_SetPixelShaderConstantF(device_ptr, 0, c, 1);
194     ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexShaderConstantF returned 0x%08x\n", hr);
195
196     /* Is there really no max pixel shader constant value??? Test how far I can go */
197     while(SUCCEEDED(IDirect3DDevice9_SetPixelShaderConstantF(device_ptr, consts++, c, 1)));
198     consts = consts - 1;
199     trace("SetPixelShaderConstantF was able to set %d shader constants\n", consts);
200
201     /* Test corner cases: writing 4 consts from MAX - 1, everything else is pointless
202      * given the way the constant limit was found out
203      */
204     hr = IDirect3DDevice9_SetPixelShaderConstantF(device_ptr, consts - 1, d, 4);
205     ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_SetPixelShaderConstantF returned 0x%08x\n", hr);
206
207     /* Constant -1 */
208     hr = IDirect3DDevice9_SetPixelShaderConstantF(device_ptr, -1, c, 1);
209     ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_SetPixelShaderConstantF returned 0x%08x\n", hr);
210 }
211
212 static void test_wrong_shader(IDirect3DDevice9 *device_ptr)
213 {
214     static const DWORD simple_vs[] =
215     {
216         0xfffe0101,                                     /* vs_1_1               */
217         0x0000001f, 0x80000000, 0x900f0000,             /* dcl_position0 v0     */
218         0x00000009, 0xc0010000, 0x90e40000, 0xa0e40000, /* dp4 oPos.x, v0, c0   */
219         0x00000009, 0xc0020000, 0x90e40000, 0xa0e40001, /* dp4 oPos.y, v0, c1   */
220         0x00000009, 0xc0040000, 0x90e40000, 0xa0e40002, /* dp4 oPos.z, v0, c2   */
221         0x00000009, 0xc0080000, 0x90e40000, 0xa0e40003, /* dp4 oPos.w, v0, c3   */
222         0x0000ffff                                      /* END                  */
223     };
224
225     static const DWORD simple_ps[] =
226     {
227         0xffff0101,                                                             /* ps_1_1                       */
228         0x00000051, 0xa00f0001, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, /* def c1 = 1.0, 0.0, 0.0, 0.0  */
229         0x00000042, 0xb00f0000,                                                 /* tex t0                       */
230         0x00000008, 0x800f0000, 0xa0e40001, 0xa0e40000,                         /* dp3 r0, c1, c0               */
231         0x00000005, 0x800f0000, 0x90e40000, 0x80e40000,                         /* mul r0, v0, r0               */
232         0x00000005, 0x800f0000, 0xb0e40000, 0x80e40000,                         /* mul r0, t0, r0               */
233         0x0000ffff                                                              /* END                          */
234     };
235
236     const DWORD vs_3_0[] = {
237         0xfffe0300,                                                             /* vs_3_0               */
238         0x0200001f, 0x80000000, 0x900f0000,                                     /* dcl_position v0      */
239         0x0200001f, 0x80000000, 0xe00f0000,                                     /* dcl_position o0      */
240         0x02000001, 0xe00f0000, 0x90e40000,                                     /* mov o0, v0           */
241         0x0000ffff                                                              /* end                  */
242     };
243
244 #if 0
245 float4 main(const float4 color : COLOR) : SV_TARGET
246 {
247     float4 o;
248
249     o = color;
250
251     return o;
252 }
253 #endif
254     static const DWORD ps_4_0[] =
255     {
256         0x43425844, 0x4da9446f, 0xfbe1f259, 0x3fdb3009, 0x517521fa, 0x00000001, 0x000001ac,
257         0x00000005, 0x00000034, 0x0000008c, 0x000000bc, 0x000000f0, 0x00000130, 0x46454452,
258         0x00000050, 0x00000000, 0x00000000, 0x00000000, 0x0000001c, 0xffff0400, 0x00000100,
259         0x0000001c, 0x7263694d, 0x666f736f, 0x52282074, 0x4c482029, 0x53204c53, 0x65646168,
260         0x6f432072, 0x6c69706d, 0x39207265, 0x2e39322e, 0x2e323539, 0x31313133, 0xababab00,
261         0x4e475349, 0x00000028, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000,
262         0x00000003, 0x00000000, 0x00000f0f, 0x4f4c4f43, 0xabab0052, 0x4e47534f, 0x0000002c,
263         0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, 0x00000000,
264         0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x52444853, 0x00000038, 0x00000040,
265         0x0000000e, 0x03001062, 0x001010f2, 0x00000000, 0x03000065, 0x001020f2, 0x00000000,
266         0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e, 0x54415453,
267         0x00000074, 0x00000002, 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00000000,
268         0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
269         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
270         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
271         0x00000000, 0x00000000,
272     };
273
274     IDirect3DVertexShader9 *vs = NULL;
275     IDirect3DPixelShader9 *ps = NULL;
276     HRESULT hret;
277     D3DCAPS9 caps;
278
279     hret = IDirect3DDevice9_CreateVertexShader(device_ptr, simple_ps, &vs);
280     ok(hret == D3DERR_INVALIDCALL, "CreateVertexShader returned: hret 0x%x, shader_ptr %p.\n", hret, vs);
281     hret = IDirect3DDevice9_CreatePixelShader(device_ptr, simple_vs, &ps);
282     ok(hret == D3DERR_INVALIDCALL, "CreatePixelShader returned: hret 0x%x, shader_ptr %p.\n", hret, ps);
283
284     hret = IDirect3DDevice9_CreatePixelShader(device_ptr, ps_4_0, &ps);
285     ok(hret == D3DERR_INVALIDCALL, "CreatePixelShader returned: hret 0x%x, shader_ptr %p.\n", hret, ps);
286
287     IDirect3DDevice9_GetDeviceCaps(device_ptr, &caps);
288     if (caps.VertexShaderVersion < D3DVS_VERSION(3, 0))
289     {
290         hret = IDirect3DDevice9_CreateVertexShader(device_ptr, vs_3_0, &vs);
291         ok(hret == D3DERR_INVALIDCALL, "CreateVertexShader returned: hret 0x%x, shader_ptr %p.\n", hret, vs);
292     }
293     else
294         skip("This GPU supports SM3, skipping unsupported shader test.\n");
295 }
296
297 START_TEST(shader)
298 {
299     D3DCAPS9 caps;
300     IDirect3DDevice9 *device_ptr;
301     ULONG refcount;
302
303     d3d9_handle = LoadLibraryA("d3d9.dll");
304     if (!d3d9_handle)
305     {
306         skip("Could not load d3d9.dll\n");
307         return;
308     }
309
310     device_ptr = init_d3d9();
311     if (!device_ptr) return;
312
313     IDirect3DDevice9_GetDeviceCaps(device_ptr, &caps);
314
315     if (caps.VertexShaderVersion & 0xffff)
316     {
317         test_get_set_vertex_shader(device_ptr);
318         test_vertex_shader_constant(device_ptr, caps.MaxVertexShaderConst);
319     }
320     else skip("No vertex shader support\n");
321
322     if (caps.PixelShaderVersion & 0xffff)
323     {
324         test_get_set_pixel_shader(device_ptr);
325         /* No max pixel shader constant value??? */
326         test_pixel_shader_constant(device_ptr);
327         if (caps.VertexShaderVersion & 0xffff)
328             test_wrong_shader(device_ptr);
329     }
330     else skip("No pixel shader support\n");
331
332     refcount = IDirect3DDevice9_Release(device_ptr);
333     ok(!refcount, "Device has %u references left\n", refcount);
334 }