device9.c revision b13b217243f1700e9c88bfc91a4d85cc2c17ab60
1/*
2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23#include "device9.h"
24#include "stateblock9.h"
25#include "surface9.h"
26#include "swapchain9.h"
27#include "swapchain9ex.h"
28#include "indexbuffer9.h"
29#include "vertexbuffer9.h"
30#include "vertexdeclaration9.h"
31#include "vertexshader9.h"
32#include "pixelshader9.h"
33#include "query9.h"
34#include "texture9.h"
35#include "cubetexture9.h"
36#include "volumetexture9.h"
37#include "nine_helpers.h"
38#include "nine_pipe.h"
39#include "nine_ff.h"
40#include "nine_dump.h"
41#include "nine_limits.h"
42
43#include "pipe/p_screen.h"
44#include "pipe/p_context.h"
45#include "pipe/p_config.h"
46#include "util/u_math.h"
47#include "util/u_inlines.h"
48#include "util/u_hash_table.h"
49#include "util/u_format.h"
50#include "util/u_surface.h"
51#include "util/u_upload_mgr.h"
52#include "hud/hud_context.h"
53
54#include "cso_cache/cso_context.h"
55
56#define DBG_CHANNEL DBG_DEVICE
57
58#if defined(PIPE_CC_GCC) && (defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64))
59
60static void nine_setup_fpu()
61{
62    uint16_t c;
63
64    __asm__ __volatile__ ("fnstcw %0" : "=m" (*&c));
65
66    /* clear the control word */
67    c &= 0xF0C0;
68    /* d3d9 doc/wine tests: mask all exceptions, use single-precision
69     * and round to nearest */
70    c |= 0x003F;
71
72    __asm__ __volatile__ ("fldcw %0" : : "m" (*&c));
73}
74
75#else
76
77static void nine_setup_fpu(void)
78{
79    WARN_ONCE("FPU setup not supported on non-x86 platforms\n");
80}
81
82#endif
83
84void
85NineDevice9_SetDefaultState( struct NineDevice9 *This, boolean is_reset )
86{
87    struct NineSurface9 *refSurf = NULL;
88
89    DBG("This=%p is_reset=%d\n", This, (int) is_reset);
90
91    assert(!This->is_recording);
92
93    nine_state_set_defaults(This, &This->caps, is_reset);
94
95    refSurf = This->swapchains[0]->buffers[0];
96    assert(refSurf);
97
98    This->state.viewport.X = 0;
99    This->state.viewport.Y = 0;
100    This->state.viewport.Width = refSurf->desc.Width;
101    This->state.viewport.Height = refSurf->desc.Height;
102
103    This->state.scissor.minx = 0;
104    This->state.scissor.miny = 0;
105    This->state.scissor.maxx = refSurf->desc.Width;
106    This->state.scissor.maxy = refSurf->desc.Height;
107
108    if (This->nswapchains && This->swapchains[0]->params.EnableAutoDepthStencil) {
109        nine_context_set_render_state(This, D3DRS_ZENABLE, TRUE);
110        This->state.rs_advertised[D3DRS_ZENABLE] = TRUE;
111    }
112    if (This->state.rs_advertised[D3DRS_ZENABLE])
113        NineDevice9_SetDepthStencilSurface(
114            This, (IDirect3DSurface9 *)This->swapchains[0]->zsbuf);
115}
116
117#define GET_PCAP(n) pScreen->get_param(pScreen, PIPE_CAP_##n)
118HRESULT
119NineDevice9_ctor( struct NineDevice9 *This,
120                  struct NineUnknownParams *pParams,
121                  struct pipe_screen *pScreen,
122                  D3DDEVICE_CREATION_PARAMETERS *pCreationParameters,
123                  D3DCAPS9 *pCaps,
124                  D3DPRESENT_PARAMETERS *pPresentationParameters,
125                  IDirect3D9 *pD3D9,
126                  ID3DPresentGroup *pPresentationGroup,
127                  struct d3dadapter9_context *pCTX,
128                  boolean ex,
129                  D3DDISPLAYMODEEX *pFullscreenDisplayMode,
130                  int minorVersionNum )
131{
132    unsigned i;
133    HRESULT hr = NineUnknown_ctor(&This->base, pParams);
134
135    DBG("This=%p pParams=%p pScreen=%p pCreationParameters=%p pCaps=%p pPresentationParameters=%p "
136        "pD3D9=%p pPresentationGroup=%p pCTX=%p ex=%d pFullscreenDisplayMode=%p\n",
137        This, pParams, pScreen, pCreationParameters, pCaps, pPresentationParameters, pD3D9,
138        pPresentationGroup, pCTX, (int) ex, pFullscreenDisplayMode);
139
140    if (FAILED(hr)) { return hr; }
141
142    list_inithead(&This->update_buffers);
143    list_inithead(&This->update_textures);
144    list_inithead(&This->managed_buffers);
145    list_inithead(&This->managed_textures);
146
147    This->screen = pScreen;
148    This->screen_sw = pCTX->ref;
149    This->caps = *pCaps;
150    This->d3d9 = pD3D9;
151    This->params = *pCreationParameters;
152    This->ex = ex;
153    This->present = pPresentationGroup;
154    This->minor_version_num = minorVersionNum;
155
156    IDirect3D9_AddRef(This->d3d9);
157    ID3DPresentGroup_AddRef(This->present);
158
159    if (!(This->params.BehaviorFlags & D3DCREATE_FPU_PRESERVE))
160        nine_setup_fpu();
161
162    if (This->params.BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) {
163        DBG("Application asked full Software Vertex Processing.\n");
164        This->swvp = true;
165        This->may_swvp = true;
166    } else
167        This->swvp = false;
168    if (This->params.BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) {
169        DBG("Application asked mixed Software Vertex Processing.\n");
170        This->may_swvp = true;
171    }
172    /* TODO: check if swvp is resetted by device Resets */
173
174    if (This->may_swvp &&
175        (This->screen->get_shader_param(This->screen, PIPE_SHADER_VERTEX,
176                                        PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE)
177                                     < (NINE_MAX_CONST_F_SWVP/2) * sizeof(float[4]) ||
178         This->screen->get_shader_param(This->screen, PIPE_SHADER_VERTEX,
179                                        PIPE_SHADER_CAP_MAX_CONST_BUFFERS) < 5)) {
180        /* Note: We just go on, some apps never use the abilities of
181         * swvp, and just set more constants than allowed at init.
182         * Only cards we support that are affected are the r500 */
183        WARN("Card unable to handle Software Vertex Processing. Game may fail\n");
184    }
185
186    /* When may_swvp, SetConstant* limits are different */
187    if (This->may_swvp)
188        This->caps.MaxVertexShaderConst = NINE_MAX_CONST_F_SWVP;
189
190    This->pipe = This->screen->context_create(This->screen, NULL, 0);
191    if (!This->pipe) { return E_OUTOFMEMORY; } /* guess */
192    This->pipe_sw = This->screen_sw->context_create(This->screen_sw, NULL, 0);
193    if (!This->pipe_sw) { return E_OUTOFMEMORY; }
194
195    This->cso = cso_create_context(This->pipe);
196    if (!This->cso) { return E_OUTOFMEMORY; } /* also a guess */
197    This->cso_sw = cso_create_context(This->pipe_sw);
198    if (!This->cso_sw) { return E_OUTOFMEMORY; }
199
200    /* Create first, it messes up our state. */
201    This->hud = hud_create(This->pipe, This->cso); /* NULL result is fine */
202
203    /* Available memory counter. Updated only for allocations with this device
204     * instance. This is the Win 7 behavior.
205     * Win XP shares this counter across multiple devices. */
206    This->available_texture_mem = This->screen->get_param(This->screen, PIPE_CAP_VIDEO_MEMORY);
207    if (This->available_texture_mem < 4096)
208        This->available_texture_mem <<= 20;
209    else
210        This->available_texture_mem = UINT_MAX;
211    /* We cap texture memory usage to 80% of what is reported free initially
212     * This helps get closer Win behaviour. For example VertexBuffer allocation
213     * still succeeds when texture allocation fails. */
214    This->available_texture_limit = This->available_texture_mem * 20LL / 100LL;
215
216    /* create implicit swapchains */
217    This->nswapchains = ID3DPresentGroup_GetMultiheadCount(This->present);
218    This->swapchains = CALLOC(This->nswapchains,
219                              sizeof(struct NineSwapChain9 *));
220    if (!This->swapchains) { return E_OUTOFMEMORY; }
221
222    for (i = 0; i < This->nswapchains; ++i) {
223        ID3DPresent *present;
224
225        hr = ID3DPresentGroup_GetPresent(This->present, i, &present);
226        if (FAILED(hr))
227            return hr;
228
229        if (ex) {
230            D3DDISPLAYMODEEX *mode = NULL;
231            struct NineSwapChain9Ex **ret =
232                (struct NineSwapChain9Ex **)&This->swapchains[i];
233
234            if (pFullscreenDisplayMode) mode = &(pFullscreenDisplayMode[i]);
235            /* when this is a Device9Ex, it should create SwapChain9Exs */
236            hr = NineSwapChain9Ex_new(This, TRUE, present,
237                                      &pPresentationParameters[i], pCTX,
238                                      This->params.hFocusWindow, mode, ret);
239        } else {
240            hr = NineSwapChain9_new(This, TRUE, present,
241                                    &pPresentationParameters[i], pCTX,
242                                    This->params.hFocusWindow,
243                                    &This->swapchains[i]);
244        }
245
246        ID3DPresent_Release(present);
247        if (FAILED(hr))
248            return hr;
249        NineUnknown_ConvertRefToBind(NineUnknown(This->swapchains[i]));
250
251        hr = NineSwapChain9_GetBackBuffer(This->swapchains[i], 0,
252                                          D3DBACKBUFFER_TYPE_MONO,
253                                          (IDirect3DSurface9 **)
254                                          &This->state.rt[i]);
255        if (FAILED(hr))
256            return hr;
257        NineUnknown_ConvertRefToBind(NineUnknown(This->state.rt[i]));
258    }
259
260    /* Initialize a dummy VBO to be used when a vertex declaration does not
261     * specify all the inputs needed by vertex shader, on win default behavior
262     * is to pass 0,0,0,0 to the shader */
263    {
264        struct pipe_transfer *transfer;
265        struct pipe_resource tmpl;
266        struct pipe_box box;
267        unsigned char *data;
268
269        memset(&tmpl, 0, sizeof(tmpl));
270        tmpl.target = PIPE_BUFFER;
271        tmpl.format = PIPE_FORMAT_R8_UNORM;
272        tmpl.width0 = 16; /* 4 floats */
273        tmpl.height0 = 1;
274        tmpl.depth0 = 1;
275        tmpl.array_size = 1;
276        tmpl.last_level = 0;
277        tmpl.nr_samples = 0;
278        tmpl.usage = PIPE_USAGE_DEFAULT;
279        tmpl.bind = PIPE_BIND_VERTEX_BUFFER;
280        tmpl.flags = 0;
281        This->dummy_vbo = pScreen->resource_create(pScreen, &tmpl);
282
283        if (!This->dummy_vbo)
284            return D3DERR_OUTOFVIDEOMEMORY;
285
286        u_box_1d(0, 16, &box);
287        data = This->pipe->transfer_map(This->pipe, This->dummy_vbo, 0,
288                                        PIPE_TRANSFER_WRITE |
289                                        PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE,
290                                        &box, &transfer);
291        assert(data);
292        assert(transfer);
293        memset(data, 0, 16);
294        This->pipe->transfer_unmap(This->pipe, transfer);
295    }
296
297    This->cursor.software = FALSE;
298    This->cursor.hotspot.x = -1;
299    This->cursor.hotspot.y = -1;
300    {
301        struct pipe_resource tmpl;
302        memset(&tmpl, 0, sizeof(tmpl));
303        tmpl.target = PIPE_TEXTURE_2D;
304        tmpl.format = PIPE_FORMAT_R8G8B8A8_UNORM;
305        tmpl.width0 = 64;
306        tmpl.height0 = 64;
307        tmpl.depth0 = 1;
308        tmpl.array_size = 1;
309        tmpl.last_level = 0;
310        tmpl.nr_samples = 0;
311        tmpl.usage = PIPE_USAGE_DEFAULT;
312        tmpl.bind = PIPE_BIND_CURSOR | PIPE_BIND_SAMPLER_VIEW;
313        tmpl.flags = 0;
314
315        This->cursor.image = pScreen->resource_create(pScreen, &tmpl);
316        if (!This->cursor.image)
317            return D3DERR_OUTOFVIDEOMEMORY;
318
319        /* For uploading 32x32 (argb) cursor */
320        This->cursor.hw_upload_temp = MALLOC(32 * 4 * 32);
321        if (!This->cursor.hw_upload_temp)
322            return D3DERR_OUTOFVIDEOMEMORY;
323    }
324
325    /* Create constant buffers. */
326    {
327        unsigned max_const_vs, max_const_ps;
328
329        /* vs 3.0: >= 256 float constants, but for cards with exactly 256 slots,
330         * we have to take in some more slots for int and bool*/
331        max_const_vs = _min(pScreen->get_shader_param(pScreen, PIPE_SHADER_VERTEX,
332                                PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE) /
333                                sizeof(float[4]),
334                            NINE_MAX_CONST_ALL);
335        /* ps 3.0: 224 float constants. All cards supported support at least
336         * 256 constants for ps */
337        max_const_ps = NINE_MAX_CONST_F_PS3 + (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4);
338
339        This->max_vs_const_f = max_const_vs -
340                               (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4);
341        This->max_ps_const_f = max_const_ps -
342                               (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4);
343
344        This->vs_const_size = max_const_vs * sizeof(float[4]);
345        This->ps_const_size = max_const_ps * sizeof(float[4]);
346        /* Include space for I,B constants for user constbuf. */
347        if (This->may_swvp) {
348            This->state.vs_const_f = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1);
349            This->context.vs_const_f_swvp = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1);
350            if (!This->context.vs_const_f_swvp)
351                return E_OUTOFMEMORY;
352            This->state.vs_lconstf_temp = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1);
353            This->context.vs_lconstf_temp = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1);
354            This->state.vs_const_i = CALLOC(NINE_MAX_CONST_I_SWVP * sizeof(int[4]), 1);
355            This->context.vs_const_i = CALLOC(NINE_MAX_CONST_I_SWVP * sizeof(int[4]), 1);
356            This->state.vs_const_b = CALLOC(NINE_MAX_CONST_B_SWVP * sizeof(BOOL), 1);
357            This->context.vs_const_b = CALLOC(NINE_MAX_CONST_B_SWVP * sizeof(BOOL), 1);
358        } else {
359            This->state.vs_const_f = CALLOC(NINE_MAX_CONST_F * sizeof(float[4]), 1);
360            This->context.vs_const_f_swvp = NULL;
361            This->state.vs_lconstf_temp = CALLOC(This->vs_const_size,1);
362            This->context.vs_lconstf_temp = CALLOC(This->vs_const_size,1);
363            This->state.vs_const_i = CALLOC(NINE_MAX_CONST_I * sizeof(int[4]), 1);
364            This->context.vs_const_i = CALLOC(NINE_MAX_CONST_I * sizeof(int[4]), 1);
365            This->state.vs_const_b = CALLOC(NINE_MAX_CONST_B * sizeof(BOOL), 1);
366            This->context.vs_const_b = CALLOC(NINE_MAX_CONST_B * sizeof(BOOL), 1);
367        }
368        This->context.vs_const_f = CALLOC(This->vs_const_size, 1);
369        This->state.ps_const_f = CALLOC(This->ps_const_size, 1);
370        This->context.ps_const_f = CALLOC(This->ps_const_size, 1);
371        This->context.ps_lconstf_temp = CALLOC(This->ps_const_size,1);
372        if (!This->state.vs_const_f || !This->context.vs_const_f ||
373            !This->state.ps_const_f || !This->context.ps_const_f ||
374            !This->state.vs_lconstf_temp || !This->context.vs_lconstf_temp ||
375            !This->context.ps_lconstf_temp ||
376            !This->state.vs_const_i || !This->context.vs_const_i ||
377            !This->state.vs_const_b || !This->context.vs_const_b)
378            return E_OUTOFMEMORY;
379
380        if (strstr(pScreen->get_name(pScreen), "AMD") ||
381            strstr(pScreen->get_name(pScreen), "ATI")) {
382            This->driver_bugs.buggy_barycentrics = TRUE;
383        }
384    }
385
386    /* allocate dummy texture/sampler for when there are missing ones bound */
387    {
388        struct pipe_resource tmplt;
389        struct pipe_sampler_view templ;
390        struct pipe_sampler_state samp;
391        memset(&tmplt, 0, sizeof(tmplt));
392        memset(&samp, 0, sizeof(samp));
393
394        tmplt.target = PIPE_TEXTURE_2D;
395        tmplt.width0 = 1;
396        tmplt.height0 = 1;
397        tmplt.depth0 = 1;
398        tmplt.last_level = 0;
399        tmplt.array_size = 1;
400        tmplt.usage = PIPE_USAGE_DEFAULT;
401        tmplt.flags = 0;
402        tmplt.format = PIPE_FORMAT_B8G8R8A8_UNORM;
403        tmplt.bind = PIPE_BIND_SAMPLER_VIEW;
404        tmplt.nr_samples = 0;
405
406        This->dummy_texture = This->screen->resource_create(This->screen, &tmplt);
407        if (!This->dummy_texture)
408            return D3DERR_DRIVERINTERNALERROR;
409
410        templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
411        templ.u.tex.first_layer = 0;
412        templ.u.tex.last_layer = 0;
413        templ.u.tex.first_level = 0;
414        templ.u.tex.last_level = 0;
415        templ.swizzle_r = PIPE_SWIZZLE_0;
416        templ.swizzle_g = PIPE_SWIZZLE_0;
417        templ.swizzle_b = PIPE_SWIZZLE_0;
418        templ.swizzle_a = PIPE_SWIZZLE_1;
419        templ.target = This->dummy_texture->target;
420
421        This->dummy_sampler_view = This->pipe->create_sampler_view(This->pipe, This->dummy_texture, &templ);
422        if (!This->dummy_sampler_view)
423            return D3DERR_DRIVERINTERNALERROR;
424
425        samp.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
426        samp.max_lod = 15.0f;
427        samp.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
428        samp.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
429        samp.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
430        samp.min_img_filter = PIPE_TEX_FILTER_NEAREST;
431        samp.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
432        samp.compare_mode = PIPE_TEX_COMPARE_NONE;
433        samp.compare_func = PIPE_FUNC_LEQUAL;
434        samp.normalized_coords = 1;
435        samp.seamless_cube_map = 0;
436        This->dummy_sampler_state = samp;
437    }
438
439    /* Allocate upload helper for drivers that suck (from st pov ;). */
440
441    This->driver_caps.user_vbufs = GET_PCAP(USER_VERTEX_BUFFERS);
442    This->driver_caps.user_ibufs = GET_PCAP(USER_INDEX_BUFFERS);
443    This->driver_caps.user_cbufs = GET_PCAP(USER_CONSTANT_BUFFERS);
444    This->driver_caps.user_sw_vbufs = This->screen_sw->get_param(This->screen_sw, PIPE_CAP_USER_VERTEX_BUFFERS);
445    This->driver_caps.user_sw_cbufs = This->screen_sw->get_param(This->screen_sw, PIPE_CAP_USER_CONSTANT_BUFFERS);
446
447    if (!This->driver_caps.user_vbufs)
448        This->vertex_uploader = u_upload_create(This->pipe, 65536,
449                                                PIPE_BIND_VERTEX_BUFFER, PIPE_USAGE_STREAM);
450    This->vertex_sw_uploader = u_upload_create(This->pipe_sw, 65536,
451                                            PIPE_BIND_VERTEX_BUFFER, PIPE_USAGE_STREAM);
452    if (!This->driver_caps.user_ibufs)
453        This->index_uploader = u_upload_create(This->pipe, 128 * 1024,
454                                               PIPE_BIND_INDEX_BUFFER, PIPE_USAGE_STREAM);
455    if (!This->driver_caps.user_cbufs) {
456        This->constbuf_alignment = GET_PCAP(CONSTANT_BUFFER_OFFSET_ALIGNMENT);
457        This->constbuf_uploader = u_upload_create(This->pipe, This->vs_const_size,
458                                                  PIPE_BIND_CONSTANT_BUFFER, PIPE_USAGE_STREAM);
459    }
460
461    This->constbuf_sw_uploader = u_upload_create(This->pipe_sw, 128 * 1024,
462                                                 PIPE_BIND_CONSTANT_BUFFER, PIPE_USAGE_STREAM);
463
464    This->driver_caps.window_space_position_support = GET_PCAP(TGSI_VS_WINDOW_SPACE_POSITION);
465    This->driver_caps.vs_integer = pScreen->get_shader_param(pScreen, PIPE_SHADER_VERTEX, PIPE_SHADER_CAP_INTEGERS);
466    This->driver_caps.ps_integer = pScreen->get_shader_param(pScreen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_INTEGERS);
467    This->driver_caps.offset_units_unscaled = GET_PCAP(POLYGON_OFFSET_UNITS_UNSCALED);
468
469    nine_ff_init(This); /* initialize fixed function code */
470
471    NineDevice9_SetDefaultState(This, FALSE);
472
473    {
474        struct pipe_poly_stipple stipple;
475        memset(&stipple, ~0, sizeof(stipple));
476        This->pipe->set_polygon_stipple(This->pipe, &stipple);
477    }
478
479    This->update = &This->state;
480
481    nine_state_init_sw(This);
482
483    ID3DPresentGroup_Release(This->present);
484
485    return D3D_OK;
486}
487#undef GET_PCAP
488
489void
490NineDevice9_dtor( struct NineDevice9 *This )
491{
492    unsigned i;
493
494    DBG("This=%p\n", This);
495
496    if (This->pipe && This->cso)
497        nine_pipe_context_clear(This);
498    nine_ff_fini(This);
499    nine_state_destroy_sw(This);
500    nine_state_clear(&This->state, TRUE);
501    nine_context_clear(&This->context);
502
503    if (This->vertex_uploader)
504        u_upload_destroy(This->vertex_uploader);
505    if (This->index_uploader)
506        u_upload_destroy(This->index_uploader);
507    if (This->constbuf_uploader)
508        u_upload_destroy(This->constbuf_uploader);
509    if (This->vertex_sw_uploader)
510        u_upload_destroy(This->vertex_sw_uploader);
511    if (This->constbuf_sw_uploader)
512        u_upload_destroy(This->constbuf_sw_uploader);
513
514    nine_bind(&This->record, NULL);
515
516    pipe_sampler_view_reference(&This->dummy_sampler_view, NULL);
517    pipe_resource_reference(&This->dummy_texture, NULL);
518    pipe_resource_reference(&This->dummy_vbo, NULL);
519    FREE(This->state.vs_const_f);
520    FREE(This->context.vs_const_f);
521    FREE(This->state.ps_const_f);
522    FREE(This->context.ps_const_f);
523    FREE(This->state.vs_lconstf_temp);
524    FREE(This->context.vs_lconstf_temp);
525    FREE(This->context.ps_lconstf_temp);
526    FREE(This->state.vs_const_i);
527    FREE(This->context.vs_const_i);
528    FREE(This->state.vs_const_b);
529    FREE(This->context.vs_const_b);
530    FREE(This->context.vs_const_f_swvp);
531
532    pipe_resource_reference(&This->cursor.image, NULL);
533    FREE(This->cursor.hw_upload_temp);
534
535    if (This->swapchains) {
536        for (i = 0; i < This->nswapchains; ++i)
537            if (This->swapchains[i])
538                NineUnknown_Unbind(NineUnknown(This->swapchains[i]));
539        FREE(This->swapchains);
540    }
541
542    /* Destroy cso first */
543    if (This->cso) { cso_destroy_context(This->cso); }
544    if (This->cso_sw) { cso_destroy_context(This->cso_sw); }
545    if (This->pipe && This->pipe->destroy) { This->pipe->destroy(This->pipe); }
546    if (This->pipe_sw && This->pipe_sw->destroy) { This->pipe_sw->destroy(This->pipe_sw); }
547
548    if (This->present) { ID3DPresentGroup_Release(This->present); }
549    if (This->d3d9) { IDirect3D9_Release(This->d3d9); }
550
551    NineUnknown_dtor(&This->base);
552}
553
554struct pipe_screen *
555NineDevice9_GetScreen( struct NineDevice9 *This )
556{
557    return This->screen;
558}
559
560struct pipe_context *
561NineDevice9_GetPipe( struct NineDevice9 *This )
562{
563    return This->pipe;
564}
565
566struct cso_context *
567NineDevice9_GetCSO( struct NineDevice9 *This )
568{
569    return This->cso;
570}
571
572const D3DCAPS9 *
573NineDevice9_GetCaps( struct NineDevice9 *This )
574{
575    return &This->caps;
576}
577
578static inline void
579NineDevice9_PauseRecording( struct NineDevice9 *This )
580{
581    if (This->record) {
582        This->update = &This->state;
583        This->is_recording = FALSE;
584    }
585}
586
587static inline void
588NineDevice9_ResumeRecording( struct NineDevice9 *This )
589{
590    if (This->record) {
591        This->update = &This->record->state;
592        This->is_recording = TRUE;
593    }
594}
595
596HRESULT NINE_WINAPI
597NineDevice9_TestCooperativeLevel( struct NineDevice9 *This )
598{
599    if (NineSwapChain9_GetOccluded(This->swapchains[0])) {
600        This->device_needs_reset = TRUE;
601        return D3DERR_DEVICELOST;
602    } else if (NineSwapChain9_ResolutionMismatch(This->swapchains[0])) {
603        This->device_needs_reset = TRUE;
604        return D3DERR_DEVICENOTRESET;
605    } else if (This->device_needs_reset) {
606        return D3DERR_DEVICENOTRESET;
607    }
608
609    return D3D_OK;
610}
611
612UINT NINE_WINAPI
613NineDevice9_GetAvailableTextureMem( struct NineDevice9 *This )
614{
615    return This->available_texture_mem;
616}
617
618HRESULT NINE_WINAPI
619NineDevice9_EvictManagedResources( struct NineDevice9 *This )
620{
621    struct NineBaseTexture9 *tex;
622    struct NineBuffer9 *buf;
623
624    DBG("This=%p\n", This);
625    LIST_FOR_EACH_ENTRY(tex, &This->managed_textures, list2) {
626        NineBaseTexture9_UnLoad(tex);
627    }
628    /* Vertex/index buffers don't take a lot of space and aren't accounted
629     * for d3d memory usage. Instead of actually freeing from memory,
630     * just mark the buffer dirty to trigger a re-upload later. We
631     * could just ignore, but some bad behaving apps could rely on it (if
632     * they write outside the locked regions typically). */
633    LIST_FOR_EACH_ENTRY(buf, &This->managed_buffers, managed.list2) {
634        NineBuffer9_SetDirty(buf);
635    }
636
637    return D3D_OK;
638}
639
640HRESULT NINE_WINAPI
641NineDevice9_GetDirect3D( struct NineDevice9 *This,
642                         IDirect3D9 **ppD3D9 )
643{
644    user_assert(ppD3D9 != NULL, E_POINTER);
645    IDirect3D9_AddRef(This->d3d9);
646    *ppD3D9 = This->d3d9;
647    return D3D_OK;
648}
649
650HRESULT NINE_WINAPI
651NineDevice9_GetDeviceCaps( struct NineDevice9 *This,
652                           D3DCAPS9 *pCaps )
653{
654    user_assert(pCaps != NULL, D3DERR_INVALIDCALL);
655    *pCaps = This->caps;
656    return D3D_OK;
657}
658
659HRESULT NINE_WINAPI
660NineDevice9_GetDisplayMode( struct NineDevice9 *This,
661                            UINT iSwapChain,
662                            D3DDISPLAYMODE *pMode )
663{
664    DBG("This=%p iSwapChain=%u pMode=%p\n", This, iSwapChain, pMode);
665
666    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
667
668    return NineSwapChain9_GetDisplayMode(This->swapchains[iSwapChain], pMode);
669}
670
671HRESULT NINE_WINAPI
672NineDevice9_GetCreationParameters( struct NineDevice9 *This,
673                                   D3DDEVICE_CREATION_PARAMETERS *pParameters )
674{
675    user_assert(pParameters != NULL, D3DERR_INVALIDCALL);
676    *pParameters = This->params;
677    return D3D_OK;
678}
679
680HRESULT NINE_WINAPI
681NineDevice9_SetCursorProperties( struct NineDevice9 *This,
682                                 UINT XHotSpot,
683                                 UINT YHotSpot,
684                                 IDirect3DSurface9 *pCursorBitmap )
685{
686    struct NineSurface9 *surf = NineSurface9(pCursorBitmap);
687    struct pipe_context *pipe = This->pipe;
688    struct pipe_box box;
689    struct pipe_transfer *transfer;
690    BOOL hw_cursor;
691    void *ptr;
692
693    DBG_FLAG(DBG_SWAPCHAIN, "This=%p XHotSpot=%u YHotSpot=%u "
694             "pCursorBitmap=%p\n", This, XHotSpot, YHotSpot, pCursorBitmap);
695
696    user_assert(pCursorBitmap, D3DERR_INVALIDCALL);
697    user_assert(surf->desc.Format == D3DFMT_A8R8G8B8, D3DERR_INVALIDCALL);
698
699    if (This->swapchains[0]->params.Windowed) {
700        This->cursor.w = MIN2(surf->desc.Width, 32);
701        This->cursor.h = MIN2(surf->desc.Height, 32);
702        hw_cursor = 1; /* always use hw cursor for windowed mode */
703    } else {
704        This->cursor.w = MIN2(surf->desc.Width, This->cursor.image->width0);
705        This->cursor.h = MIN2(surf->desc.Height, This->cursor.image->height0);
706        hw_cursor = This->cursor.w == 32 && This->cursor.h == 32;
707    }
708
709    u_box_origin_2d(This->cursor.w, This->cursor.h, &box);
710
711    ptr = pipe->transfer_map(pipe, This->cursor.image, 0,
712                             PIPE_TRANSFER_WRITE |
713                             PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE,
714                             &box, &transfer);
715    if (!ptr)
716        ret_err("Failed to update cursor image.\n", D3DERR_DRIVERINTERNALERROR);
717
718    This->cursor.hotspot.x = XHotSpot;
719    This->cursor.hotspot.y = YHotSpot;
720
721    /* Copy cursor image to internal storage. */
722    {
723        D3DLOCKED_RECT lock;
724        HRESULT hr;
725        const struct util_format_description *sfmt =
726            util_format_description(surf->base.info.format);
727        assert(sfmt);
728
729        hr = NineSurface9_LockRect(surf, &lock, NULL, D3DLOCK_READONLY);
730        if (FAILED(hr))
731            ret_err("Failed to map cursor source image.\n",
732                    D3DERR_DRIVERINTERNALERROR);
733
734        sfmt->unpack_rgba_8unorm(ptr, transfer->stride,
735                                 lock.pBits, lock.Pitch,
736                                 This->cursor.w, This->cursor.h);
737
738        if (hw_cursor) {
739            void *data = lock.pBits;
740            /* SetCursor assumes 32x32 argb with pitch 128 */
741            if (lock.Pitch != 128) {
742                sfmt->unpack_rgba_8unorm(This->cursor.hw_upload_temp, 128,
743                                         lock.pBits, lock.Pitch,
744                                         32, 32);
745                data = This->cursor.hw_upload_temp;
746            }
747            hw_cursor = ID3DPresent_SetCursor(This->swapchains[0]->present,
748                                              data,
749                                              &This->cursor.hotspot,
750                                              This->cursor.visible) == D3D_OK;
751        }
752
753        NineSurface9_UnlockRect(surf);
754    }
755    pipe->transfer_unmap(pipe, transfer);
756
757    /* hide cursor if we emulate it */
758    if (!hw_cursor)
759        ID3DPresent_SetCursor(This->swapchains[0]->present, NULL, NULL, FALSE);
760    This->cursor.software = !hw_cursor;
761
762    return D3D_OK;
763}
764
765void NINE_WINAPI
766NineDevice9_SetCursorPosition( struct NineDevice9 *This,
767                               int X,
768                               int Y,
769                               DWORD Flags )
770{
771    struct NineSwapChain9 *swap = This->swapchains[0];
772
773    DBG("This=%p X=%d Y=%d Flags=%d\n", This, X, Y, Flags);
774
775    This->cursor.pos.x = X;
776    This->cursor.pos.y = Y;
777
778    if (!This->cursor.software)
779        This->cursor.software = ID3DPresent_SetCursorPos(swap->present, &This->cursor.pos) != D3D_OK;
780}
781
782BOOL NINE_WINAPI
783NineDevice9_ShowCursor( struct NineDevice9 *This,
784                        BOOL bShow )
785{
786    BOOL old = This->cursor.visible;
787
788    DBG("This=%p bShow=%d\n", This, (int) bShow);
789
790    This->cursor.visible = bShow && (This->cursor.hotspot.x != -1);
791    if (!This->cursor.software)
792        This->cursor.software = ID3DPresent_SetCursor(This->swapchains[0]->present, NULL, NULL, bShow) != D3D_OK;
793
794    return old;
795}
796
797HRESULT NINE_WINAPI
798NineDevice9_CreateAdditionalSwapChain( struct NineDevice9 *This,
799                                       D3DPRESENT_PARAMETERS *pPresentationParameters,
800                                       IDirect3DSwapChain9 **pSwapChain )
801{
802    struct NineSwapChain9 *swapchain, *tmplt = This->swapchains[0];
803    ID3DPresent *present;
804    HRESULT hr;
805
806    DBG("This=%p pPresentationParameters=%p pSwapChain=%p\n",
807        This, pPresentationParameters, pSwapChain);
808
809    user_assert(pPresentationParameters, D3DERR_INVALIDCALL);
810    user_assert(tmplt->params.Windowed && pPresentationParameters->Windowed, D3DERR_INVALIDCALL);
811
812    /* TODO: this deserves more tests */
813    if (!pPresentationParameters->hDeviceWindow)
814        pPresentationParameters->hDeviceWindow = This->params.hFocusWindow;
815
816    hr = ID3DPresentGroup_CreateAdditionalPresent(This->present, pPresentationParameters, &present);
817
818    if (FAILED(hr))
819        return hr;
820
821    hr = NineSwapChain9_new(This, FALSE, present, pPresentationParameters,
822                            tmplt->actx,
823                            tmplt->params.hDeviceWindow,
824                            &swapchain);
825    if (FAILED(hr))
826        return hr;
827
828    *pSwapChain = (IDirect3DSwapChain9 *)swapchain;
829    return D3D_OK;
830}
831
832HRESULT NINE_WINAPI
833NineDevice9_GetSwapChain( struct NineDevice9 *This,
834                          UINT iSwapChain,
835                          IDirect3DSwapChain9 **pSwapChain )
836{
837    user_assert(pSwapChain != NULL, D3DERR_INVALIDCALL);
838
839    *pSwapChain = NULL;
840    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
841
842    NineUnknown_AddRef(NineUnknown(This->swapchains[iSwapChain]));
843    *pSwapChain = (IDirect3DSwapChain9 *)This->swapchains[iSwapChain];
844
845    return D3D_OK;
846}
847
848UINT NINE_WINAPI
849NineDevice9_GetNumberOfSwapChains( struct NineDevice9 *This )
850{
851    return This->nswapchains;
852}
853
854HRESULT NINE_WINAPI
855NineDevice9_Reset( struct NineDevice9 *This,
856                   D3DPRESENT_PARAMETERS *pPresentationParameters )
857{
858    HRESULT hr = D3D_OK;
859    unsigned i;
860
861    DBG("This=%p pPresentationParameters=%p\n", This, pPresentationParameters);
862
863    if (NineSwapChain9_GetOccluded(This->swapchains[0])) {
864        This->device_needs_reset = TRUE;
865        return D3DERR_DEVICELOST;
866    }
867
868    for (i = 0; i < This->nswapchains; ++i) {
869        D3DPRESENT_PARAMETERS *params = &pPresentationParameters[i];
870        hr = NineSwapChain9_Resize(This->swapchains[i], params, NULL);
871        if (hr != D3D_OK)
872            break;
873    }
874
875    nine_pipe_context_clear(This);
876    nine_state_clear(&This->state, TRUE);
877    nine_context_clear(&This->context);
878
879    NineDevice9_SetDefaultState(This, TRUE);
880    NineDevice9_SetRenderTarget(
881        This, 0, (IDirect3DSurface9 *)This->swapchains[0]->buffers[0]);
882    /* XXX: better use GetBackBuffer here ? */
883
884    This->device_needs_reset = (hr != D3D_OK);
885    return hr;
886}
887
888HRESULT NINE_WINAPI
889NineDevice9_Present( struct NineDevice9 *This,
890                     const RECT *pSourceRect,
891                     const RECT *pDestRect,
892                     HWND hDestWindowOverride,
893                     const RGNDATA *pDirtyRegion )
894{
895    unsigned i;
896    HRESULT hr;
897
898    DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p pDirtyRegion=%p\n",
899        This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
900
901    /* XXX is this right? */
902    for (i = 0; i < This->nswapchains; ++i) {
903        hr = NineSwapChain9_Present(This->swapchains[i], pSourceRect, pDestRect,
904                                    hDestWindowOverride, pDirtyRegion, 0);
905        if (FAILED(hr)) { return hr; }
906    }
907
908    return D3D_OK;
909}
910
911HRESULT NINE_WINAPI
912NineDevice9_GetBackBuffer( struct NineDevice9 *This,
913                           UINT iSwapChain,
914                           UINT iBackBuffer,
915                           D3DBACKBUFFER_TYPE Type,
916                           IDirect3DSurface9 **ppBackBuffer )
917{
918    user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL);
919    /* return NULL on error */
920    *ppBackBuffer = NULL;
921    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
922
923    return NineSwapChain9_GetBackBuffer(This->swapchains[iSwapChain],
924                                        iBackBuffer, Type, ppBackBuffer);
925}
926
927HRESULT NINE_WINAPI
928NineDevice9_GetRasterStatus( struct NineDevice9 *This,
929                             UINT iSwapChain,
930                             D3DRASTER_STATUS *pRasterStatus )
931{
932    user_assert(pRasterStatus != NULL, D3DERR_INVALIDCALL);
933    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
934
935    return NineSwapChain9_GetRasterStatus(This->swapchains[iSwapChain],
936                                          pRasterStatus);
937}
938
939HRESULT NINE_WINAPI
940NineDevice9_SetDialogBoxMode( struct NineDevice9 *This,
941                              BOOL bEnableDialogs )
942{
943    STUB(D3DERR_INVALIDCALL);
944}
945
946void NINE_WINAPI
947NineDevice9_SetGammaRamp( struct NineDevice9 *This,
948                          UINT iSwapChain,
949                          DWORD Flags,
950                          const D3DGAMMARAMP *pRamp )
951{
952    DBG("This=%p iSwapChain=%u Flags=%x pRamp=%p\n", This,
953        iSwapChain, Flags, pRamp);
954
955    user_warn(iSwapChain >= This->nswapchains);
956    user_warn(!pRamp);
957
958    if (pRamp && (iSwapChain < This->nswapchains)) {
959        struct NineSwapChain9 *swap = This->swapchains[iSwapChain];
960        swap->gamma = *pRamp;
961        ID3DPresent_SetGammaRamp(swap->present, pRamp, swap->params.hDeviceWindow);
962    }
963}
964
965void NINE_WINAPI
966NineDevice9_GetGammaRamp( struct NineDevice9 *This,
967                          UINT iSwapChain,
968                          D3DGAMMARAMP *pRamp )
969{
970    DBG("This=%p iSwapChain=%u pRamp=%p\n", This, iSwapChain, pRamp);
971
972    user_warn(iSwapChain >= This->nswapchains);
973    user_warn(!pRamp);
974
975    if (pRamp && (iSwapChain < This->nswapchains))
976        *pRamp = This->swapchains[iSwapChain]->gamma;
977}
978
979HRESULT NINE_WINAPI
980NineDevice9_CreateTexture( struct NineDevice9 *This,
981                           UINT Width,
982                           UINT Height,
983                           UINT Levels,
984                           DWORD Usage,
985                           D3DFORMAT Format,
986                           D3DPOOL Pool,
987                           IDirect3DTexture9 **ppTexture,
988                           HANDLE *pSharedHandle )
989{
990    struct NineTexture9 *tex;
991    HRESULT hr;
992
993    DBG("This=%p Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s "
994        "ppOut=%p pSharedHandle=%p\n", This, Width, Height, Levels,
995        nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format),
996        nine_D3DPOOL_to_str(Pool), ppTexture, pSharedHandle);
997
998    Usage &= D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DMAP |
999             D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE | D3DUSAGE_RENDERTARGET |
1000             D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_TEXTAPI;
1001
1002    *ppTexture = NULL;
1003
1004    hr = NineTexture9_new(This, Width, Height, Levels, Usage, Format, Pool,
1005                          &tex, pSharedHandle);
1006    if (SUCCEEDED(hr))
1007        *ppTexture = (IDirect3DTexture9 *)tex;
1008
1009    return hr;
1010}
1011
1012HRESULT NINE_WINAPI
1013NineDevice9_CreateVolumeTexture( struct NineDevice9 *This,
1014                                 UINT Width,
1015                                 UINT Height,
1016                                 UINT Depth,
1017                                 UINT Levels,
1018                                 DWORD Usage,
1019                                 D3DFORMAT Format,
1020                                 D3DPOOL Pool,
1021                                 IDirect3DVolumeTexture9 **ppVolumeTexture,
1022                                 HANDLE *pSharedHandle )
1023{
1024    struct NineVolumeTexture9 *tex;
1025    HRESULT hr;
1026
1027    DBG("This=%p Width=%u Height=%u Depth=%u Levels=%u Usage=%s Format=%s Pool=%s "
1028        "ppOut=%p pSharedHandle=%p\n", This, Width, Height, Depth, Levels,
1029        nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format),
1030        nine_D3DPOOL_to_str(Pool), ppVolumeTexture, pSharedHandle);
1031
1032    Usage &= D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE |
1033             D3DUSAGE_SOFTWAREPROCESSING;
1034
1035    *ppVolumeTexture = NULL;
1036
1037    hr = NineVolumeTexture9_new(This, Width, Height, Depth, Levels,
1038                                Usage, Format, Pool, &tex, pSharedHandle);
1039    if (SUCCEEDED(hr))
1040        *ppVolumeTexture = (IDirect3DVolumeTexture9 *)tex;
1041
1042    return hr;
1043}
1044
1045HRESULT NINE_WINAPI
1046NineDevice9_CreateCubeTexture( struct NineDevice9 *This,
1047                               UINT EdgeLength,
1048                               UINT Levels,
1049                               DWORD Usage,
1050                               D3DFORMAT Format,
1051                               D3DPOOL Pool,
1052                               IDirect3DCubeTexture9 **ppCubeTexture,
1053                               HANDLE *pSharedHandle )
1054{
1055    struct NineCubeTexture9 *tex;
1056    HRESULT hr;
1057
1058    DBG("This=%p EdgeLength=%u Levels=%u Usage=%s Format=%s Pool=%s ppOut=%p "
1059        "pSharedHandle=%p\n", This, EdgeLength, Levels,
1060        nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format),
1061        nine_D3DPOOL_to_str(Pool), ppCubeTexture, pSharedHandle);
1062
1063    Usage &= D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DYNAMIC |
1064             D3DUSAGE_NONSECURE | D3DUSAGE_RENDERTARGET |
1065             D3DUSAGE_SOFTWAREPROCESSING;
1066
1067    *ppCubeTexture = NULL;
1068
1069    hr = NineCubeTexture9_new(This, EdgeLength, Levels, Usage, Format, Pool,
1070                              &tex, pSharedHandle);
1071    if (SUCCEEDED(hr))
1072        *ppCubeTexture = (IDirect3DCubeTexture9 *)tex;
1073
1074    return hr;
1075}
1076
1077HRESULT NINE_WINAPI
1078NineDevice9_CreateVertexBuffer( struct NineDevice9 *This,
1079                                UINT Length,
1080                                DWORD Usage,
1081                                DWORD FVF,
1082                                D3DPOOL Pool,
1083                                IDirect3DVertexBuffer9 **ppVertexBuffer,
1084                                HANDLE *pSharedHandle )
1085{
1086    struct NineVertexBuffer9 *buf;
1087    HRESULT hr;
1088    D3DVERTEXBUFFER_DESC desc;
1089
1090    DBG("This=%p Length=%u Usage=%x FVF=%x Pool=%u ppOut=%p pSharedHandle=%p\n",
1091        This, Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
1092
1093    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_NOTAVAILABLE);
1094
1095    desc.Format = D3DFMT_VERTEXDATA;
1096    desc.Type = D3DRTYPE_VERTEXBUFFER;
1097    desc.Usage = Usage &
1098        (D3DUSAGE_DONOTCLIP | D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE |
1099         D3DUSAGE_NPATCHES | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES |
1100         D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_TEXTAPI |
1101         D3DUSAGE_WRITEONLY);
1102    desc.Pool = Pool;
1103    desc.Size = Length;
1104    desc.FVF = FVF;
1105
1106    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
1107    user_assert(desc.Usage == Usage, D3DERR_INVALIDCALL);
1108
1109    hr = NineVertexBuffer9_new(This, &desc, &buf);
1110    if (SUCCEEDED(hr))
1111        *ppVertexBuffer = (IDirect3DVertexBuffer9 *)buf;
1112    return hr;
1113}
1114
1115HRESULT NINE_WINAPI
1116NineDevice9_CreateIndexBuffer( struct NineDevice9 *This,
1117                               UINT Length,
1118                               DWORD Usage,
1119                               D3DFORMAT Format,
1120                               D3DPOOL Pool,
1121                               IDirect3DIndexBuffer9 **ppIndexBuffer,
1122                               HANDLE *pSharedHandle )
1123{
1124    struct NineIndexBuffer9 *buf;
1125    HRESULT hr;
1126    D3DINDEXBUFFER_DESC desc;
1127
1128    DBG("This=%p Length=%u Usage=%x Format=%s Pool=%u ppOut=%p "
1129        "pSharedHandle=%p\n", This, Length, Usage,
1130        d3dformat_to_string(Format), Pool, ppIndexBuffer, pSharedHandle);
1131
1132    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_NOTAVAILABLE);
1133
1134    desc.Format = Format;
1135    desc.Type = D3DRTYPE_INDEXBUFFER;
1136    desc.Usage = Usage &
1137        (D3DUSAGE_DONOTCLIP | D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE |
1138         D3DUSAGE_NPATCHES | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES |
1139         D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_WRITEONLY);
1140    desc.Pool = Pool;
1141    desc.Size = Length;
1142
1143    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
1144    user_assert(desc.Usage == Usage, D3DERR_INVALIDCALL);
1145
1146    hr = NineIndexBuffer9_new(This, &desc, &buf);
1147    if (SUCCEEDED(hr))
1148        *ppIndexBuffer = (IDirect3DIndexBuffer9 *)buf;
1149    return hr;
1150}
1151
1152static HRESULT
1153create_zs_or_rt_surface(struct NineDevice9 *This,
1154                        unsigned type, /* 0 = RT, 1 = ZS, 2 = plain */
1155                        D3DPOOL Pool,
1156                        UINT Width, UINT Height,
1157                        D3DFORMAT Format,
1158                        D3DMULTISAMPLE_TYPE MultiSample,
1159                        DWORD MultisampleQuality,
1160                        BOOL Discard_or_Lockable,
1161                        IDirect3DSurface9 **ppSurface,
1162                        HANDLE *pSharedHandle)
1163{
1164    struct NineSurface9 *surface;
1165    HRESULT hr;
1166    D3DSURFACE_DESC desc;
1167
1168    DBG("This=%p type=%u Pool=%s Width=%u Height=%u Format=%s MS=%u Quality=%u "
1169        "Discard_or_Lockable=%i ppSurface=%p pSharedHandle=%p\n",
1170        This, type, nine_D3DPOOL_to_str(Pool), Width, Height,
1171        d3dformat_to_string(Format), MultiSample, MultisampleQuality,
1172        Discard_or_Lockable, ppSurface, pSharedHandle);
1173
1174    if (pSharedHandle)
1175      DBG("FIXME Used shared handle! This option isn't probably handled correctly!\n");
1176
1177    user_assert(Width && Height, D3DERR_INVALIDCALL);
1178    user_assert(Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL);
1179
1180    desc.Format = Format;
1181    desc.Type = D3DRTYPE_SURFACE;
1182    desc.Usage = 0;
1183    desc.Pool = Pool;
1184    desc.MultiSampleType = MultiSample;
1185    desc.MultiSampleQuality = MultisampleQuality;
1186    desc.Width = Width;
1187    desc.Height = Height;
1188    switch (type) {
1189    case 0: desc.Usage = D3DUSAGE_RENDERTARGET; break;
1190    case 1: desc.Usage = D3DUSAGE_DEPTHSTENCIL; break;
1191    default: assert(type == 2); break;
1192    }
1193
1194    hr = NineSurface9_new(This, NULL, NULL, NULL, 0, 0, 0, &desc, &surface);
1195    if (SUCCEEDED(hr)) {
1196        *ppSurface = (IDirect3DSurface9 *)surface;
1197
1198        if (surface->base.resource && Discard_or_Lockable && (type != 1))
1199            surface->base.resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
1200    }
1201
1202    return hr;
1203}
1204
1205HRESULT NINE_WINAPI
1206NineDevice9_CreateRenderTarget( struct NineDevice9 *This,
1207                                UINT Width,
1208                                UINT Height,
1209                                D3DFORMAT Format,
1210                                D3DMULTISAMPLE_TYPE MultiSample,
1211                                DWORD MultisampleQuality,
1212                                BOOL Lockable,
1213                                IDirect3DSurface9 **ppSurface,
1214                                HANDLE *pSharedHandle )
1215{
1216    *ppSurface = NULL;
1217    return create_zs_or_rt_surface(This, 0, D3DPOOL_DEFAULT,
1218                                   Width, Height, Format,
1219                                   MultiSample, MultisampleQuality,
1220                                   Lockable, ppSurface, pSharedHandle);
1221}
1222
1223HRESULT NINE_WINAPI
1224NineDevice9_CreateDepthStencilSurface( struct NineDevice9 *This,
1225                                       UINT Width,
1226                                       UINT Height,
1227                                       D3DFORMAT Format,
1228                                       D3DMULTISAMPLE_TYPE MultiSample,
1229                                       DWORD MultisampleQuality,
1230                                       BOOL Discard,
1231                                       IDirect3DSurface9 **ppSurface,
1232                                       HANDLE *pSharedHandle )
1233{
1234    *ppSurface = NULL;
1235    if (!depth_stencil_format(Format))
1236        return D3DERR_NOTAVAILABLE;
1237    return create_zs_or_rt_surface(This, 1, D3DPOOL_DEFAULT,
1238                                   Width, Height, Format,
1239                                   MultiSample, MultisampleQuality,
1240                                   Discard, ppSurface, pSharedHandle);
1241}
1242
1243HRESULT NINE_WINAPI
1244NineDevice9_UpdateSurface( struct NineDevice9 *This,
1245                           IDirect3DSurface9 *pSourceSurface,
1246                           const RECT *pSourceRect,
1247                           IDirect3DSurface9 *pDestinationSurface,
1248                           const POINT *pDestPoint )
1249{
1250    struct NineSurface9 *dst = NineSurface9(pDestinationSurface);
1251    struct NineSurface9 *src = NineSurface9(pSourceSurface);
1252    int copy_width, copy_height;
1253    RECT destRect;
1254
1255    DBG("This=%p pSourceSurface=%p pDestinationSurface=%p "
1256        "pSourceRect=%p pDestPoint=%p\n", This,
1257        pSourceSurface, pDestinationSurface, pSourceRect, pDestPoint);
1258    if (pSourceRect)
1259        DBG("pSourceRect = (%u,%u)-(%u,%u)\n",
1260            pSourceRect->left, pSourceRect->top,
1261            pSourceRect->right, pSourceRect->bottom);
1262    if (pDestPoint)
1263        DBG("pDestPoint = (%u,%u)\n", pDestPoint->x, pDestPoint->y);
1264
1265    user_assert(dst && src, D3DERR_INVALIDCALL);
1266
1267    user_assert(dst->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
1268    user_assert(src->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
1269
1270    user_assert(dst->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL);
1271    user_assert(src->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL);
1272
1273    user_assert(!src->lock_count, D3DERR_INVALIDCALL);
1274    user_assert(!dst->lock_count, D3DERR_INVALIDCALL);
1275
1276    user_assert(dst->desc.Format == src->desc.Format, D3DERR_INVALIDCALL);
1277    user_assert(!depth_stencil_format(dst->desc.Format), D3DERR_INVALIDCALL);
1278
1279    if (pSourceRect) {
1280        copy_width = pSourceRect->right - pSourceRect->left;
1281        copy_height = pSourceRect->bottom - pSourceRect->top;
1282
1283        user_assert(pSourceRect->left >= 0 &&
1284                    copy_width > 0 &&
1285                    pSourceRect->right <= src->desc.Width &&
1286                    pSourceRect->top >= 0 &&
1287                    copy_height > 0 &&
1288                    pSourceRect->bottom <= src->desc.Height,
1289                    D3DERR_INVALIDCALL);
1290    } else {
1291        copy_width = src->desc.Width;
1292        copy_height = src->desc.Height;
1293    }
1294
1295    destRect.right = copy_width;
1296    destRect.bottom = copy_height;
1297
1298    if (pDestPoint) {
1299        user_assert(pDestPoint->x >= 0 && pDestPoint->y >= 0,
1300                    D3DERR_INVALIDCALL);
1301        destRect.right += pDestPoint->x;
1302        destRect.bottom += pDestPoint->y;
1303    }
1304
1305    user_assert(destRect.right <= dst->desc.Width &&
1306                destRect.bottom <= dst->desc.Height,
1307                D3DERR_INVALIDCALL);
1308
1309    if (compressed_format(dst->desc.Format)) {
1310        const unsigned w = util_format_get_blockwidth(dst->base.info.format);
1311        const unsigned h = util_format_get_blockheight(dst->base.info.format);
1312
1313        if (pDestPoint) {
1314            user_assert(!(pDestPoint->x % w) && !(pDestPoint->y % h),
1315                        D3DERR_INVALIDCALL);
1316        }
1317
1318        if (pSourceRect) {
1319            user_assert(!(pSourceRect->left % w) && !(pSourceRect->top % h),
1320                        D3DERR_INVALIDCALL);
1321        }
1322        if (!(copy_width == src->desc.Width &&
1323              copy_width == dst->desc.Width &&
1324              copy_height == src->desc.Height &&
1325              copy_height == dst->desc.Height)) {
1326            user_assert(!(copy_width  % w) && !(copy_height % h),
1327                        D3DERR_INVALIDCALL);
1328        }
1329    }
1330
1331    NineSurface9_CopyMemToDefault(dst, src, pDestPoint, pSourceRect);
1332
1333    return D3D_OK;
1334}
1335
1336HRESULT NINE_WINAPI
1337NineDevice9_UpdateTexture( struct NineDevice9 *This,
1338                           IDirect3DBaseTexture9 *pSourceTexture,
1339                           IDirect3DBaseTexture9 *pDestinationTexture )
1340{
1341    struct NineBaseTexture9 *dstb = NineBaseTexture9(pDestinationTexture);
1342    struct NineBaseTexture9 *srcb = NineBaseTexture9(pSourceTexture);
1343    unsigned l, m;
1344    unsigned last_src_level, last_dst_level;
1345    RECT rect;
1346
1347    DBG("This=%p pSourceTexture=%p pDestinationTexture=%p\n", This,
1348        pSourceTexture, pDestinationTexture);
1349
1350    user_assert(pSourceTexture && pDestinationTexture, D3DERR_INVALIDCALL);
1351    user_assert(pSourceTexture != pDestinationTexture, D3DERR_INVALIDCALL);
1352
1353    user_assert(dstb->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
1354    user_assert(srcb->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
1355    user_assert(dstb->base.type == srcb->base.type, D3DERR_INVALIDCALL);
1356    user_assert(!(srcb->base.usage & D3DUSAGE_AUTOGENMIPMAP) ||
1357                dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP, D3DERR_INVALIDCALL);
1358
1359    /* Spec: Failure if
1360     * . Different formats
1361     * . Fewer src levels than dst levels (if the opposite, only matching levels
1362     *   are supposed to be copied)
1363     * . Levels do not match
1364     * DDI: Actually the above should pass because of legacy applications
1365     * Do what you want about these, but you shouldn't crash.
1366     * However driver can expect that the top dimension is greater for src than dst.
1367     * Wine tests: Every combination that passes the initial checks should pass.
1368     * . Different formats => conversion driver and format dependent.
1369     * . 1 level, but size not matching => copy is done (and even crash if src bigger
1370     * than dst. For the case where dst bigger, wine doesn't test if a stretch is applied
1371     * or if a subrect is copied).
1372     * . 8x8 4 sublevels -> 7x7 2 sublevels => driver dependent, On NV seems to be 4x4 subrect
1373     * copied to 7x7.
1374     *
1375     * From these, the proposal is:
1376     * . Different formats -> use util_format_translate to translate if possible for surfaces.
1377     * Accept ARGB/XRGB for Volumes. Do nothing for the other combinations
1378     * . First level copied -> the first level such that src is smaller or equal to dst first level
1379     * . number of levels copied -> as long as it fits and textures have levels
1380     * That should satisfy the constraints (and instead of crashing for some cases we return D3D_OK)
1381     */
1382
1383    last_src_level = (srcb->base.usage & D3DUSAGE_AUTOGENMIPMAP) ? 0 : srcb->base.info.last_level;
1384    last_dst_level = (dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP) ? 0 : dstb->base.info.last_level;
1385
1386    for (m = 0; m <= last_src_level; ++m) {
1387        unsigned w = u_minify(srcb->base.info.width0, m);
1388        unsigned h = u_minify(srcb->base.info.height0, m);
1389        unsigned d = u_minify(srcb->base.info.depth0, m);
1390
1391        if (w <= dstb->base.info.width0 &&
1392            h <= dstb->base.info.height0 &&
1393            d <= dstb->base.info.depth0)
1394            break;
1395    }
1396    user_assert(m <= last_src_level, D3D_OK);
1397
1398    last_dst_level = MIN2(srcb->base.info.last_level - m, last_dst_level);
1399
1400    if (dstb->base.type == D3DRTYPE_TEXTURE) {
1401        struct NineTexture9 *dst = NineTexture9(dstb);
1402        struct NineTexture9 *src = NineTexture9(srcb);
1403
1404        if (src->dirty_rect.width == 0)
1405            return D3D_OK;
1406
1407        pipe_box_to_rect(&rect, &src->dirty_rect);
1408        for (l = 0; l < m; ++l)
1409            rect_minify_inclusive(&rect);
1410
1411        for (l = 0; l <= last_dst_level; ++l, ++m) {
1412            fit_rect_format_inclusive(dst->base.base.info.format,
1413                                      &rect,
1414                                      dst->surfaces[l]->desc.Width,
1415                                      dst->surfaces[l]->desc.Height);
1416            NineSurface9_CopyMemToDefault(dst->surfaces[l],
1417                                          src->surfaces[m],
1418                                          (POINT *)&rect,
1419                                          &rect);
1420            rect_minify_inclusive(&rect);
1421        }
1422        u_box_origin_2d(0, 0, &src->dirty_rect);
1423    } else
1424    if (dstb->base.type == D3DRTYPE_CUBETEXTURE) {
1425        struct NineCubeTexture9 *dst = NineCubeTexture9(dstb);
1426        struct NineCubeTexture9 *src = NineCubeTexture9(srcb);
1427        unsigned z;
1428
1429        /* GPUs usually have them stored as arrays of mip-mapped 2D textures. */
1430        for (z = 0; z < 6; ++z) {
1431            if (src->dirty_rect[z].width == 0)
1432                continue;
1433
1434            pipe_box_to_rect(&rect, &src->dirty_rect[z]);
1435            for (l = 0; l < m; ++l)
1436                rect_minify_inclusive(&rect);
1437
1438            for (l = 0; l <= last_dst_level; ++l, ++m) {
1439                fit_rect_format_inclusive(dst->base.base.info.format,
1440                                          &rect,
1441                                          dst->surfaces[l * 6 + z]->desc.Width,
1442                                          dst->surfaces[l * 6 + z]->desc.Height);
1443                NineSurface9_CopyMemToDefault(dst->surfaces[l * 6 + z],
1444                                              src->surfaces[m * 6 + z],
1445                                              (POINT *)&rect,
1446                                              &rect);
1447                rect_minify_inclusive(&rect);
1448            }
1449            u_box_origin_2d(0, 0, &src->dirty_rect[z]);
1450            m -= l;
1451        }
1452    } else
1453    if (dstb->base.type == D3DRTYPE_VOLUMETEXTURE) {
1454        struct NineVolumeTexture9 *dst = NineVolumeTexture9(dstb);
1455        struct NineVolumeTexture9 *src = NineVolumeTexture9(srcb);
1456
1457        if (src->dirty_box.width == 0)
1458            return D3D_OK;
1459        for (l = 0; l <= last_dst_level; ++l, ++m)
1460            NineVolume9_CopyMemToDefault(dst->volumes[l],
1461                                         src->volumes[m], 0, 0, 0, NULL);
1462        u_box_3d(0, 0, 0, 0, 0, 0, &src->dirty_box);
1463    } else{
1464        assert(!"invalid texture type");
1465    }
1466
1467    if (dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP) {
1468        dstb->dirty_mip = TRUE;
1469        NineBaseTexture9_GenerateMipSubLevels(dstb);
1470    }
1471
1472    return D3D_OK;
1473}
1474
1475HRESULT NINE_WINAPI
1476NineDevice9_GetRenderTargetData( struct NineDevice9 *This,
1477                                 IDirect3DSurface9 *pRenderTarget,
1478                                 IDirect3DSurface9 *pDestSurface )
1479{
1480    struct NineSurface9 *dst = NineSurface9(pDestSurface);
1481    struct NineSurface9 *src = NineSurface9(pRenderTarget);
1482
1483    DBG("This=%p pRenderTarget=%p pDestSurface=%p\n",
1484        This, pRenderTarget, pDestSurface);
1485
1486    user_assert(pRenderTarget && pDestSurface, D3DERR_INVALIDCALL);
1487
1488    user_assert(dst->desc.Pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
1489    user_assert(src->desc.Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
1490
1491    user_assert(dst->desc.MultiSampleType < 2, D3DERR_INVALIDCALL);
1492    user_assert(src->desc.MultiSampleType < 2, D3DERR_INVALIDCALL);
1493
1494    user_assert(src->desc.Width == dst->desc.Width, D3DERR_INVALIDCALL);
1495    user_assert(src->desc.Height == dst->desc.Height, D3DERR_INVALIDCALL);
1496
1497    user_assert(src->desc.Format != D3DFMT_NULL, D3DERR_INVALIDCALL);
1498
1499    NineSurface9_CopyDefaultToMem(dst, src);
1500
1501    return D3D_OK;
1502}
1503
1504HRESULT NINE_WINAPI
1505NineDevice9_GetFrontBufferData( struct NineDevice9 *This,
1506                                UINT iSwapChain,
1507                                IDirect3DSurface9 *pDestSurface )
1508{
1509    DBG("This=%p iSwapChain=%u pDestSurface=%p\n", This,
1510        iSwapChain, pDestSurface);
1511
1512    user_assert(pDestSurface != NULL, D3DERR_INVALIDCALL);
1513    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
1514
1515    return NineSwapChain9_GetFrontBufferData(This->swapchains[iSwapChain],
1516                                             pDestSurface);
1517}
1518
1519HRESULT NINE_WINAPI
1520NineDevice9_StretchRect( struct NineDevice9 *This,
1521                         IDirect3DSurface9 *pSourceSurface,
1522                         const RECT *pSourceRect,
1523                         IDirect3DSurface9 *pDestSurface,
1524                         const RECT *pDestRect,
1525                         D3DTEXTUREFILTERTYPE Filter )
1526{
1527    struct pipe_screen *screen = This->screen;
1528    struct pipe_context *pipe = This->pipe;
1529    struct NineSurface9 *dst = NineSurface9(pDestSurface);
1530    struct NineSurface9 *src = NineSurface9(pSourceSurface);
1531    struct pipe_resource *dst_res = NineSurface9_GetResource(dst);
1532    struct pipe_resource *src_res = NineSurface9_GetResource(src);
1533    boolean zs;
1534    struct pipe_blit_info blit;
1535    boolean scaled, clamped, ms, flip_x = FALSE, flip_y = FALSE;
1536
1537    DBG("This=%p pSourceSurface=%p pSourceRect=%p pDestSurface=%p "
1538        "pDestRect=%p Filter=%u\n",
1539        This, pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter);
1540    if (pSourceRect)
1541        DBG("pSourceRect=(%u,%u)-(%u,%u)\n",
1542            pSourceRect->left, pSourceRect->top,
1543            pSourceRect->right, pSourceRect->bottom);
1544    if (pDestRect)
1545        DBG("pDestRect=(%u,%u)-(%u,%u)\n", pDestRect->left, pDestRect->top,
1546            pDestRect->right, pDestRect->bottom);
1547
1548    user_assert(dst->base.pool == D3DPOOL_DEFAULT &&
1549                src->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
1550    zs = util_format_is_depth_or_stencil(dst_res->format);
1551    user_assert(!zs || !This->in_scene, D3DERR_INVALIDCALL);
1552    user_assert(!zs || !pSourceRect ||
1553                (pSourceRect->left == 0 &&
1554                 pSourceRect->top == 0 &&
1555                 pSourceRect->right == src->desc.Width &&
1556                 pSourceRect->bottom == src->desc.Height), D3DERR_INVALIDCALL);
1557    user_assert(!zs || !pDestRect ||
1558                (pDestRect->left == 0 &&
1559                 pDestRect->top == 0 &&
1560                 pDestRect->right == dst->desc.Width &&
1561                 pDestRect->bottom == dst->desc.Height), D3DERR_INVALIDCALL);
1562    user_assert(!zs ||
1563                (dst->desc.Width == src->desc.Width &&
1564                 dst->desc.Height == src->desc.Height), D3DERR_INVALIDCALL);
1565    user_assert(zs || !util_format_is_depth_or_stencil(src_res->format),
1566                D3DERR_INVALIDCALL);
1567    user_assert(!zs || dst->desc.Format == src->desc.Format,
1568                D3DERR_INVALIDCALL);
1569    user_assert(screen->is_format_supported(screen, src_res->format,
1570                                            src_res->target,
1571                                            src_res->nr_samples,
1572                                            PIPE_BIND_SAMPLER_VIEW),
1573                D3DERR_INVALIDCALL);
1574
1575    /* We might want to permit these, but wine thinks we shouldn't. */
1576    user_assert(!pDestRect ||
1577                (pDestRect->left <= pDestRect->right &&
1578                 pDestRect->top <= pDestRect->bottom), D3DERR_INVALIDCALL);
1579    user_assert(!pSourceRect ||
1580                (pSourceRect->left <= pSourceRect->right &&
1581                 pSourceRect->top <= pSourceRect->bottom), D3DERR_INVALIDCALL);
1582
1583    memset(&blit, 0, sizeof(blit));
1584    blit.dst.resource = dst_res;
1585    blit.dst.level = dst->level;
1586    blit.dst.box.z = dst->layer;
1587    blit.dst.box.depth = 1;
1588    blit.dst.format = dst_res->format;
1589    if (pDestRect) {
1590        flip_x = pDestRect->left > pDestRect->right;
1591        if (flip_x) {
1592            blit.dst.box.x = pDestRect->right;
1593            blit.dst.box.width = pDestRect->left - pDestRect->right;
1594        } else {
1595            blit.dst.box.x = pDestRect->left;
1596            blit.dst.box.width = pDestRect->right - pDestRect->left;
1597        }
1598        flip_y = pDestRect->top > pDestRect->bottom;
1599        if (flip_y) {
1600            blit.dst.box.y = pDestRect->bottom;
1601            blit.dst.box.height = pDestRect->top - pDestRect->bottom;
1602        } else {
1603            blit.dst.box.y = pDestRect->top;
1604            blit.dst.box.height = pDestRect->bottom - pDestRect->top;
1605        }
1606    } else {
1607        blit.dst.box.x = 0;
1608        blit.dst.box.y = 0;
1609        blit.dst.box.width = dst->desc.Width;
1610        blit.dst.box.height = dst->desc.Height;
1611    }
1612    blit.src.resource = src_res;
1613    blit.src.level = src->level;
1614    blit.src.box.z = src->layer;
1615    blit.src.box.depth = 1;
1616    blit.src.format = src_res->format;
1617    if (pSourceRect) {
1618        if (flip_x ^ (pSourceRect->left > pSourceRect->right)) {
1619            blit.src.box.x = pSourceRect->right;
1620            blit.src.box.width = pSourceRect->left - pSourceRect->right;
1621        } else {
1622            blit.src.box.x = pSourceRect->left;
1623            blit.src.box.width = pSourceRect->right - pSourceRect->left;
1624        }
1625        if (flip_y ^ (pSourceRect->top > pSourceRect->bottom)) {
1626            blit.src.box.y = pSourceRect->bottom;
1627            blit.src.box.height = pSourceRect->top - pSourceRect->bottom;
1628        } else {
1629            blit.src.box.y = pSourceRect->top;
1630            blit.src.box.height = pSourceRect->bottom - pSourceRect->top;
1631        }
1632    } else {
1633        blit.src.box.x = flip_x ? src->desc.Width : 0;
1634        blit.src.box.y = flip_y ? src->desc.Height : 0;
1635        blit.src.box.width = flip_x ? -src->desc.Width : src->desc.Width;
1636        blit.src.box.height = flip_y ? -src->desc.Height : src->desc.Height;
1637    }
1638    blit.mask = zs ? PIPE_MASK_ZS : PIPE_MASK_RGBA;
1639    blit.filter = Filter == D3DTEXF_LINEAR ?
1640       PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST;
1641    blit.scissor_enable = FALSE;
1642    blit.alpha_blend = FALSE;
1643
1644    /* If both of a src and dst dimension are negative, flip them. */
1645    if (blit.dst.box.width < 0 && blit.src.box.width < 0) {
1646        blit.dst.box.width = -blit.dst.box.width;
1647        blit.src.box.width = -blit.src.box.width;
1648    }
1649    if (blit.dst.box.height < 0 && blit.src.box.height < 0) {
1650        blit.dst.box.height = -blit.dst.box.height;
1651        blit.src.box.height = -blit.src.box.height;
1652    }
1653    scaled =
1654        blit.dst.box.width != blit.src.box.width ||
1655        blit.dst.box.height != blit.src.box.height;
1656
1657    user_assert(!scaled || dst != src, D3DERR_INVALIDCALL);
1658    user_assert(!scaled ||
1659                !NineSurface9_IsOffscreenPlain(dst), D3DERR_INVALIDCALL);
1660    user_assert(!NineSurface9_IsOffscreenPlain(dst) ||
1661                NineSurface9_IsOffscreenPlain(src), D3DERR_INVALIDCALL);
1662    user_assert(NineSurface9_IsOffscreenPlain(dst) ||
1663                dst->desc.Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL),
1664                D3DERR_INVALIDCALL);
1665    user_assert(!scaled ||
1666                (!util_format_is_compressed(dst->base.info.format) &&
1667                 !util_format_is_compressed(src->base.info.format)),
1668                D3DERR_INVALIDCALL);
1669
1670    user_warn(src == dst &&
1671              u_box_test_intersection_2d(&blit.src.box, &blit.dst.box));
1672
1673    /* Check for clipping/clamping: */
1674    {
1675        struct pipe_box box;
1676        int xy;
1677
1678        xy = u_box_clip_2d(&box, &blit.dst.box,
1679                           dst->desc.Width, dst->desc.Height);
1680        if (xy < 0)
1681            return D3D_OK;
1682        if (xy == 0)
1683            xy = u_box_clip_2d(&box, &blit.src.box,
1684                               src->desc.Width, src->desc.Height);
1685        clamped = !!xy;
1686    }
1687
1688    ms = (dst->desc.MultiSampleType != src->desc.MultiSampleType) ||
1689         (dst->desc.MultiSampleQuality != src->desc.MultiSampleQuality);
1690
1691    if (clamped || scaled || (blit.dst.format != blit.src.format) || ms) {
1692        DBG("using pipe->blit()\n");
1693        /* TODO: software scaling */
1694        user_assert(screen->is_format_supported(screen, dst_res->format,
1695                                                dst_res->target,
1696                                                dst_res->nr_samples,
1697                                                zs ? PIPE_BIND_DEPTH_STENCIL :
1698                                                PIPE_BIND_RENDER_TARGET),
1699                    D3DERR_INVALIDCALL);
1700
1701        pipe->blit(pipe, &blit);
1702    } else {
1703        assert(blit.dst.box.x >= 0 && blit.dst.box.y >= 0 &&
1704               blit.src.box.x >= 0 && blit.src.box.y >= 0 &&
1705               blit.dst.box.x + blit.dst.box.width <= dst->desc.Width &&
1706               blit.src.box.x + blit.src.box.width <= src->desc.Width &&
1707               blit.dst.box.y + blit.dst.box.height <= dst->desc.Height &&
1708               blit.src.box.y + blit.src.box.height <= src->desc.Height);
1709        /* Or drivers might crash ... */
1710        DBG("Using resource_copy_region.\n");
1711        pipe->resource_copy_region(pipe,
1712            blit.dst.resource, blit.dst.level,
1713            blit.dst.box.x, blit.dst.box.y, blit.dst.box.z,
1714            blit.src.resource, blit.src.level,
1715            &blit.src.box);
1716    }
1717
1718    /* Communicate the container it needs to update sublevels - if apply */
1719    NineSurface9_MarkContainerDirty(dst);
1720
1721    return D3D_OK;
1722}
1723
1724HRESULT NINE_WINAPI
1725NineDevice9_ColorFill( struct NineDevice9 *This,
1726                       IDirect3DSurface9 *pSurface,
1727                       const RECT *pRect,
1728                       D3DCOLOR color )
1729{
1730    struct pipe_context *pipe = This->pipe;
1731    struct NineSurface9 *surf = NineSurface9(pSurface);
1732    struct pipe_surface *psurf;
1733    unsigned x, y, w, h;
1734    union pipe_color_union rgba;
1735    boolean fallback;
1736
1737    DBG("This=%p pSurface=%p pRect=%p color=%08x\n", This,
1738        pSurface, pRect, color);
1739    if (pRect)
1740        DBG("pRect=(%u,%u)-(%u,%u)\n", pRect->left, pRect->top,
1741            pRect->right, pRect->bottom);
1742
1743    user_assert(surf->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
1744
1745    user_assert((surf->base.usage & D3DUSAGE_RENDERTARGET) ||
1746                NineSurface9_IsOffscreenPlain(surf), D3DERR_INVALIDCALL);
1747
1748    user_assert(surf->desc.Format != D3DFMT_NULL, D3D_OK);
1749
1750    if (pRect) {
1751        x = pRect->left;
1752        y = pRect->top;
1753        w = pRect->right - pRect->left;
1754        h = pRect->bottom - pRect->top;
1755        /* Wine tests: */
1756        if (compressed_format(surf->desc.Format)) {
1757           const unsigned bw = util_format_get_blockwidth(surf->base.info.format);
1758           const unsigned bh = util_format_get_blockheight(surf->base.info.format);
1759
1760           user_assert(!(x % bw) && !(y % bh) && !(w % bw) && !(h % bh),
1761                       D3DERR_INVALIDCALL);
1762        }
1763    } else{
1764        x = 0;
1765        y = 0;
1766        w = surf->desc.Width;
1767        h = surf->desc.Height;
1768    }
1769    d3dcolor_to_pipe_color_union(&rgba, color);
1770
1771    fallback = !(surf->base.info.bind & PIPE_BIND_RENDER_TARGET);
1772
1773    if (!fallback) {
1774        psurf = NineSurface9_GetSurface(surf, 0);
1775        if (!psurf)
1776            fallback = TRUE;
1777    }
1778
1779    if (!fallback) {
1780        pipe->clear_render_target(pipe, psurf, &rgba, x, y, w, h, false);
1781    } else {
1782        D3DLOCKED_RECT lock;
1783        union util_color uc;
1784        HRESULT hr;
1785        /* XXX: lock pRect and fix util_fill_rect */
1786        hr = NineSurface9_LockRect(surf, &lock, NULL, 0);
1787        if (FAILED(hr))
1788            return hr;
1789        util_pack_color_ub(color >> 16, color >> 8, color >> 0, color >> 24,
1790                           surf->base.info.format, &uc);
1791        util_fill_rect(lock.pBits, surf->base.info.format,lock.Pitch,
1792                       x, y, w, h, &uc);
1793        NineSurface9_UnlockRect(surf);
1794    }
1795
1796    return D3D_OK;
1797}
1798
1799HRESULT NINE_WINAPI
1800NineDevice9_CreateOffscreenPlainSurface( struct NineDevice9 *This,
1801                                         UINT Width,
1802                                         UINT Height,
1803                                         D3DFORMAT Format,
1804                                         D3DPOOL Pool,
1805                                         IDirect3DSurface9 **ppSurface,
1806                                         HANDLE *pSharedHandle )
1807{
1808    HRESULT hr;
1809
1810    DBG("This=%p Width=%u Height=%u Format=%s(0x%x) Pool=%u "
1811        "ppSurface=%p pSharedHandle=%p\n", This,
1812        Width, Height, d3dformat_to_string(Format), Format, Pool,
1813        ppSurface, pSharedHandle);
1814
1815    *ppSurface = NULL;
1816    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT
1817                               || Pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
1818    user_assert(Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL);
1819
1820    /* Can be used with StretchRect and ColorFill. It's also always lockable.
1821     */
1822    hr = create_zs_or_rt_surface(This, 2, Pool, Width, Height,
1823                                 Format,
1824                                 D3DMULTISAMPLE_NONE, 0,
1825                                 TRUE,
1826                                 ppSurface, pSharedHandle);
1827    if (FAILED(hr))
1828        DBG("Failed to create surface.\n");
1829    return hr;
1830}
1831
1832HRESULT NINE_WINAPI
1833NineDevice9_SetRenderTarget( struct NineDevice9 *This,
1834                             DWORD RenderTargetIndex,
1835                             IDirect3DSurface9 *pRenderTarget )
1836{
1837    struct NineSurface9 *rt = NineSurface9(pRenderTarget);
1838    const unsigned i = RenderTargetIndex;
1839
1840    DBG("This=%p RenderTargetIndex=%u pRenderTarget=%p\n", This,
1841        RenderTargetIndex, pRenderTarget);
1842
1843    user_assert(i < This->caps.NumSimultaneousRTs, D3DERR_INVALIDCALL);
1844    user_assert(i != 0 || pRenderTarget, D3DERR_INVALIDCALL);
1845    user_assert(!pRenderTarget ||
1846                rt->desc.Usage & D3DUSAGE_RENDERTARGET, D3DERR_INVALIDCALL);
1847
1848    if (i == 0) {
1849        This->state.viewport.X = 0;
1850        This->state.viewport.Y = 0;
1851        This->state.viewport.Width = rt->desc.Width;
1852        This->state.viewport.Height = rt->desc.Height;
1853        This->state.viewport.MinZ = 0.0f;
1854        This->state.viewport.MaxZ = 1.0f;
1855
1856        This->state.scissor.minx = 0;
1857        This->state.scissor.miny = 0;
1858        This->state.scissor.maxx = rt->desc.Width;
1859        This->state.scissor.maxy = rt->desc.Height;
1860
1861        This->state.changed.group |= NINE_STATE_VIEWPORT | NINE_STATE_SCISSOR | NINE_STATE_MULTISAMPLE;
1862
1863        if (This->state.rt[0] &&
1864            (This->state.rt[0]->desc.MultiSampleType <= D3DMULTISAMPLE_NONMASKABLE) !=
1865            (rt->desc.MultiSampleType <= D3DMULTISAMPLE_NONMASKABLE))
1866            This->state.changed.group |= NINE_STATE_SAMPLE_MASK;
1867    }
1868
1869    if (This->state.rt[i] != NineSurface9(pRenderTarget)) {
1870       nine_bind(&This->state.rt[i], pRenderTarget);
1871       This->state.changed.group |= NINE_STATE_FB;
1872    }
1873    return D3D_OK;
1874}
1875
1876HRESULT NINE_WINAPI
1877NineDevice9_GetRenderTarget( struct NineDevice9 *This,
1878                             DWORD RenderTargetIndex,
1879                             IDirect3DSurface9 **ppRenderTarget )
1880{
1881    const unsigned i = RenderTargetIndex;
1882
1883    user_assert(i < This->caps.NumSimultaneousRTs, D3DERR_INVALIDCALL);
1884    user_assert(ppRenderTarget, D3DERR_INVALIDCALL);
1885
1886    *ppRenderTarget = (IDirect3DSurface9 *)This->state.rt[i];
1887    if (!This->state.rt[i])
1888        return D3DERR_NOTFOUND;
1889
1890    NineUnknown_AddRef(NineUnknown(This->state.rt[i]));
1891    return D3D_OK;
1892}
1893
1894HRESULT NINE_WINAPI
1895NineDevice9_SetDepthStencilSurface( struct NineDevice9 *This,
1896                                    IDirect3DSurface9 *pNewZStencil )
1897{
1898    DBG("This=%p pNewZStencil=%p\n", This, pNewZStencil);
1899
1900    if (This->state.ds != NineSurface9(pNewZStencil)) {
1901        nine_bind(&This->state.ds, pNewZStencil);
1902        This->state.changed.group |= NINE_STATE_FB;
1903    }
1904    return D3D_OK;
1905}
1906
1907HRESULT NINE_WINAPI
1908NineDevice9_GetDepthStencilSurface( struct NineDevice9 *This,
1909                                    IDirect3DSurface9 **ppZStencilSurface )
1910{
1911    user_assert(ppZStencilSurface, D3DERR_INVALIDCALL);
1912
1913    *ppZStencilSurface = (IDirect3DSurface9 *)This->state.ds;
1914    if (!This->state.ds)
1915        return D3DERR_NOTFOUND;
1916
1917    NineUnknown_AddRef(NineUnknown(This->state.ds));
1918    return D3D_OK;
1919}
1920
1921HRESULT NINE_WINAPI
1922NineDevice9_BeginScene( struct NineDevice9 *This )
1923{
1924    DBG("This=%p\n", This);
1925    user_assert(!This->in_scene, D3DERR_INVALIDCALL);
1926    This->in_scene = TRUE;
1927    /* Do we want to do anything else here ? */
1928    return D3D_OK;
1929}
1930
1931HRESULT NINE_WINAPI
1932NineDevice9_EndScene( struct NineDevice9 *This )
1933{
1934    DBG("This=%p\n", This);
1935    user_assert(This->in_scene, D3DERR_INVALIDCALL);
1936    This->in_scene = FALSE;
1937    return D3D_OK;
1938}
1939
1940HRESULT NINE_WINAPI
1941NineDevice9_Clear( struct NineDevice9 *This,
1942                   DWORD Count,
1943                   const D3DRECT *pRects,
1944                   DWORD Flags,
1945                   D3DCOLOR Color,
1946                   float Z,
1947                   DWORD Stencil )
1948{
1949    struct NineSurface9 *zsbuf_surf = This->state.ds;
1950
1951    DBG("This=%p Count=%u pRects=%p Flags=%x Color=%08x Z=%f Stencil=%x\n",
1952        This, Count, pRects, Flags, Color, Z, Stencil);
1953
1954    user_assert(This->state.ds || !(Flags & NINED3DCLEAR_DEPTHSTENCIL),
1955                D3DERR_INVALIDCALL);
1956    user_assert(!(Flags & D3DCLEAR_STENCIL) ||
1957                (zsbuf_surf &&
1958                 util_format_is_depth_and_stencil(zsbuf_surf->base.info.format)),
1959                D3DERR_INVALIDCALL);
1960#ifdef NINE_STRICT
1961    user_assert((Count && pRects) || (!Count && !pRects), D3DERR_INVALIDCALL);
1962#else
1963    user_warn((pRects && !Count) || (!pRects && Count));
1964    if (pRects && !Count)
1965        return D3D_OK;
1966    if (!pRects)
1967        Count = 0;
1968#endif
1969
1970    nine_context_clear_fb(This, Count, pRects, Flags, Color, Z, Stencil);
1971    return D3D_OK;
1972}
1973
1974HRESULT NINE_WINAPI
1975NineDevice9_SetTransform( struct NineDevice9 *This,
1976                          D3DTRANSFORMSTATETYPE State,
1977                          const D3DMATRIX *pMatrix )
1978{
1979    struct nine_state *state = This->update;
1980    D3DMATRIX *M = nine_state_access_transform(state, State, TRUE);
1981
1982    DBG("This=%p State=%d pMatrix=%p\n", This, State, pMatrix);
1983
1984    user_assert(M, D3DERR_INVALIDCALL);
1985
1986    *M = *pMatrix;
1987    state->ff.changed.transform[State / 32] |= 1 << (State % 32);
1988    state->changed.group |= NINE_STATE_FF;
1989
1990    return D3D_OK;
1991}
1992
1993HRESULT NINE_WINAPI
1994NineDevice9_GetTransform( struct NineDevice9 *This,
1995                          D3DTRANSFORMSTATETYPE State,
1996                          D3DMATRIX *pMatrix )
1997{
1998    D3DMATRIX *M = nine_state_access_transform(&This->state, State, FALSE);
1999    user_assert(M, D3DERR_INVALIDCALL);
2000    *pMatrix = *M;
2001    return D3D_OK;
2002}
2003
2004HRESULT NINE_WINAPI
2005NineDevice9_MultiplyTransform( struct NineDevice9 *This,
2006                               D3DTRANSFORMSTATETYPE State,
2007                               const D3DMATRIX *pMatrix )
2008{
2009    struct nine_state *state = This->update;
2010    D3DMATRIX T;
2011    D3DMATRIX *M = nine_state_access_transform(state, State, TRUE);
2012
2013    DBG("This=%p State=%d pMatrix=%p\n", This, State, pMatrix);
2014
2015    user_assert(M, D3DERR_INVALIDCALL);
2016
2017    nine_d3d_matrix_matrix_mul(&T, pMatrix, M);
2018    return NineDevice9_SetTransform(This, State, &T);
2019}
2020
2021HRESULT NINE_WINAPI
2022NineDevice9_SetViewport( struct NineDevice9 *This,
2023                         const D3DVIEWPORT9 *pViewport )
2024{
2025    struct nine_state *state = This->update;
2026
2027    DBG("X=%u Y=%u W=%u H=%u MinZ=%f MaxZ=%f\n",
2028        pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height,
2029        pViewport->MinZ, pViewport->MaxZ);
2030
2031    state->viewport = *pViewport;
2032    state->changed.group |= NINE_STATE_VIEWPORT;
2033
2034    return D3D_OK;
2035}
2036
2037HRESULT NINE_WINAPI
2038NineDevice9_GetViewport( struct NineDevice9 *This,
2039                         D3DVIEWPORT9 *pViewport )
2040{
2041    *pViewport = This->state.viewport;
2042    return D3D_OK;
2043}
2044
2045HRESULT NINE_WINAPI
2046NineDevice9_SetMaterial( struct NineDevice9 *This,
2047                         const D3DMATERIAL9 *pMaterial )
2048{
2049    struct nine_state *state = This->update;
2050
2051    DBG("This=%p pMaterial=%p\n", This, pMaterial);
2052    if (pMaterial)
2053        nine_dump_D3DMATERIAL9(DBG_FF, pMaterial);
2054
2055    user_assert(pMaterial, E_POINTER);
2056
2057    state->ff.material = *pMaterial;
2058    state->changed.group |= NINE_STATE_FF_MATERIAL;
2059
2060    return D3D_OK;
2061}
2062
2063HRESULT NINE_WINAPI
2064NineDevice9_GetMaterial( struct NineDevice9 *This,
2065                         D3DMATERIAL9 *pMaterial )
2066{
2067    user_assert(pMaterial, E_POINTER);
2068    *pMaterial = This->state.ff.material;
2069    return D3D_OK;
2070}
2071
2072HRESULT NINE_WINAPI
2073NineDevice9_SetLight( struct NineDevice9 *This,
2074                      DWORD Index,
2075                      const D3DLIGHT9 *pLight )
2076{
2077    struct nine_state *state = This->update;
2078
2079    DBG("This=%p Index=%u pLight=%p\n", This, Index, pLight);
2080    if (pLight)
2081        nine_dump_D3DLIGHT9(DBG_FF, pLight);
2082
2083    user_assert(pLight, D3DERR_INVALIDCALL);
2084    user_assert(pLight->Type < NINED3DLIGHT_INVALID, D3DERR_INVALIDCALL);
2085
2086    user_assert(Index < NINE_MAX_LIGHTS, D3DERR_INVALIDCALL); /* sanity */
2087
2088    if (Index >= state->ff.num_lights) {
2089        unsigned n = state->ff.num_lights;
2090        unsigned N = Index + 1;
2091
2092        state->ff.light = REALLOC(state->ff.light, n * sizeof(D3DLIGHT9),
2093                                                   N * sizeof(D3DLIGHT9));
2094        if (!state->ff.light)
2095            return E_OUTOFMEMORY;
2096        state->ff.num_lights = N;
2097
2098        for (; n < Index; ++n) {
2099            memset(&state->ff.light[n], 0, sizeof(D3DLIGHT9));
2100            state->ff.light[n].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID;
2101        }
2102    }
2103    state->ff.light[Index] = *pLight;
2104
2105    if (pLight->Type == D3DLIGHT_SPOT && pLight->Theta >= pLight->Phi) {
2106        DBG("Warning: clamping D3DLIGHT9.Theta\n");
2107        state->ff.light[Index].Theta = state->ff.light[Index].Phi;
2108    }
2109    if (pLight->Type != D3DLIGHT_DIRECTIONAL &&
2110        pLight->Attenuation0 == 0.0f &&
2111        pLight->Attenuation1 == 0.0f &&
2112        pLight->Attenuation2 == 0.0f) {
2113        DBG("Warning: all D3DLIGHT9.Attenuation[i] are 0\n");
2114    }
2115
2116    state->changed.group |= NINE_STATE_FF_LIGHTING;
2117
2118    return D3D_OK;
2119}
2120
2121HRESULT NINE_WINAPI
2122NineDevice9_GetLight( struct NineDevice9 *This,
2123                      DWORD Index,
2124                      D3DLIGHT9 *pLight )
2125{
2126    const struct nine_state *state = &This->state;
2127
2128    user_assert(pLight, D3DERR_INVALIDCALL);
2129    user_assert(Index < state->ff.num_lights, D3DERR_INVALIDCALL);
2130    user_assert(state->ff.light[Index].Type < NINED3DLIGHT_INVALID,
2131                D3DERR_INVALIDCALL);
2132
2133    *pLight = state->ff.light[Index];
2134
2135    return D3D_OK;
2136}
2137
2138HRESULT NINE_WINAPI
2139NineDevice9_LightEnable( struct NineDevice9 *This,
2140                         DWORD Index,
2141                         BOOL Enable )
2142{
2143    struct nine_state *state = This->update;
2144    unsigned i;
2145
2146    DBG("This=%p Index=%u Enable=%i\n", This, Index, Enable);
2147
2148    if (Index >= state->ff.num_lights ||
2149        state->ff.light[Index].Type == NINED3DLIGHT_INVALID) {
2150        /* This should create a default light. */
2151        D3DLIGHT9 light;
2152        memset(&light, 0, sizeof(light));
2153        light.Type = D3DLIGHT_DIRECTIONAL;
2154        light.Diffuse.r = 1.0f;
2155        light.Diffuse.g = 1.0f;
2156        light.Diffuse.b = 1.0f;
2157        light.Direction.z = 1.0f;
2158        NineDevice9_SetLight(This, Index, &light);
2159    }
2160    user_assert(Index < state->ff.num_lights, D3DERR_INVALIDCALL);
2161
2162    for (i = 0; i < state->ff.num_lights_active; ++i) {
2163        if (state->ff.active_light[i] == Index)
2164            break;
2165    }
2166
2167    if (Enable) {
2168        if (i < state->ff.num_lights_active)
2169            return D3D_OK;
2170        /* XXX wine thinks this should still succeed:
2171         */
2172        user_assert(i < NINE_MAX_LIGHTS_ACTIVE, D3DERR_INVALIDCALL);
2173
2174        state->ff.active_light[i] = Index;
2175        state->ff.num_lights_active++;
2176    } else {
2177        if (i == state->ff.num_lights_active)
2178            return D3D_OK;
2179        --state->ff.num_lights_active;
2180        for (; i < state->ff.num_lights_active; ++i)
2181            state->ff.active_light[i] = state->ff.active_light[i + 1];
2182    }
2183    state->changed.group |= NINE_STATE_FF_LIGHTING;
2184
2185    return D3D_OK;
2186}
2187
2188HRESULT NINE_WINAPI
2189NineDevice9_GetLightEnable( struct NineDevice9 *This,
2190                            DWORD Index,
2191                            BOOL *pEnable )
2192{
2193    const struct nine_state *state = &This->state;
2194    unsigned i;
2195
2196    user_assert(Index < state->ff.num_lights, D3DERR_INVALIDCALL);
2197    user_assert(state->ff.light[Index].Type < NINED3DLIGHT_INVALID,
2198                D3DERR_INVALIDCALL);
2199
2200    for (i = 0; i < state->ff.num_lights_active; ++i)
2201        if (state->ff.active_light[i] == Index)
2202            break;
2203
2204    *pEnable = i != state->ff.num_lights_active ? 128 : 0; // Taken from wine
2205
2206    return D3D_OK;
2207}
2208
2209HRESULT NINE_WINAPI
2210NineDevice9_SetClipPlane( struct NineDevice9 *This,
2211                          DWORD Index,
2212                          const float *pPlane )
2213{
2214    struct nine_state *state = This->update;
2215
2216    user_assert(pPlane, D3DERR_INVALIDCALL);
2217
2218    DBG("This=%p Index=%u pPlane=%f %f %f %f\n", This, Index,
2219        pPlane[0], pPlane[1],
2220        pPlane[2], pPlane[3]);
2221
2222    user_assert(Index < PIPE_MAX_CLIP_PLANES, D3DERR_INVALIDCALL);
2223
2224    memcpy(&state->clip.ucp[Index][0], pPlane, sizeof(state->clip.ucp[0]));
2225    state->changed.ucp |= 1 << Index;
2226
2227    return D3D_OK;
2228}
2229
2230HRESULT NINE_WINAPI
2231NineDevice9_GetClipPlane( struct NineDevice9 *This,
2232                          DWORD Index,
2233                          float *pPlane )
2234{
2235    const struct nine_state *state = &This->state;
2236
2237    user_assert(Index < PIPE_MAX_CLIP_PLANES, D3DERR_INVALIDCALL);
2238
2239    memcpy(pPlane, &state->clip.ucp[Index][0], sizeof(state->clip.ucp[0]));
2240    return D3D_OK;
2241}
2242
2243HRESULT NINE_WINAPI
2244NineDevice9_SetRenderState( struct NineDevice9 *This,
2245                            D3DRENDERSTATETYPE State,
2246                            DWORD Value )
2247{
2248    struct nine_state *state = This->update;
2249
2250    DBG("This=%p State=%u(%s) Value=%08x\n", This,
2251        State, nine_d3drs_to_string(State), Value);
2252
2253    user_assert(State < D3DRS_COUNT, D3DERR_INVALIDCALL);
2254
2255    if (unlikely(This->is_recording)) {
2256        state->rs_advertised[State] = Value;
2257        /* only need to record changed render states for stateblocks */
2258        state->changed.rs[State / 32] |= 1 << (State % 32);
2259        state->changed.group |= nine_render_state_group[State];
2260        return D3D_OK;
2261    }
2262
2263    if (state->rs_advertised[State] == Value)
2264        return D3D_OK;
2265
2266    state->rs_advertised[State] = Value;
2267    nine_context_set_render_state(This, State, Value);
2268
2269    return D3D_OK;
2270}
2271
2272HRESULT NINE_WINAPI
2273NineDevice9_GetRenderState( struct NineDevice9 *This,
2274                            D3DRENDERSTATETYPE State,
2275                            DWORD *pValue )
2276{
2277    user_assert(State < D3DRS_COUNT, D3DERR_INVALIDCALL);
2278
2279    *pValue = This->state.rs_advertised[State];
2280    return D3D_OK;
2281}
2282
2283HRESULT NINE_WINAPI
2284NineDevice9_CreateStateBlock( struct NineDevice9 *This,
2285                              D3DSTATEBLOCKTYPE Type,
2286                              IDirect3DStateBlock9 **ppSB )
2287{
2288    struct NineStateBlock9 *nsb;
2289    struct nine_state *dst;
2290    HRESULT hr;
2291    enum nine_stateblock_type type;
2292    unsigned s;
2293
2294    DBG("This=%p Type=%u ppSB=%p\n", This, Type, ppSB);
2295
2296    user_assert(Type == D3DSBT_ALL ||
2297                Type == D3DSBT_VERTEXSTATE ||
2298                Type == D3DSBT_PIXELSTATE, D3DERR_INVALIDCALL);
2299
2300    switch (Type) {
2301    case D3DSBT_VERTEXSTATE: type = NINESBT_VERTEXSTATE; break;
2302    case D3DSBT_PIXELSTATE:  type = NINESBT_PIXELSTATE; break;
2303    default:
2304       type = NINESBT_ALL;
2305       break;
2306    }
2307
2308    hr = NineStateBlock9_new(This, &nsb, type);
2309    if (FAILED(hr))
2310       return hr;
2311    *ppSB = (IDirect3DStateBlock9 *)nsb;
2312    dst = &nsb->state;
2313
2314    dst->changed.group =
2315       NINE_STATE_TEXTURE |
2316       NINE_STATE_SAMPLER;
2317
2318    if (Type == D3DSBT_ALL || Type == D3DSBT_VERTEXSTATE) {
2319       dst->changed.group |=
2320           NINE_STATE_FF_LIGHTING |
2321           NINE_STATE_VS | NINE_STATE_VS_CONST |
2322           NINE_STATE_VDECL;
2323       /* TODO: texture/sampler state */
2324       memcpy(dst->changed.rs,
2325              nine_render_states_vertex, sizeof(dst->changed.rs));
2326       nine_ranges_insert(&dst->changed.vs_const_f, 0, This->may_swvp ? NINE_MAX_CONST_F_SWVP : This->max_vs_const_f,
2327                          &This->range_pool);
2328       nine_ranges_insert(&dst->changed.vs_const_i, 0, This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I,
2329                          &This->range_pool);
2330       nine_ranges_insert(&dst->changed.vs_const_b, 0, This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B,
2331                          &This->range_pool);
2332       for (s = 0; s < NINE_MAX_SAMPLERS; ++s)
2333           dst->changed.sampler[s] |= 1 << D3DSAMP_DMAPOFFSET;
2334       if (This->state.ff.num_lights) {
2335           dst->ff.num_lights = This->state.ff.num_lights;
2336           /* zero'd -> light type won't be NINED3DLIGHT_INVALID, so
2337            * all currently existing lights will be captured
2338            */
2339           dst->ff.light = CALLOC(This->state.ff.num_lights,
2340                                  sizeof(D3DLIGHT9));
2341           if (!dst->ff.light) {
2342               nine_bind(ppSB, NULL);
2343               return E_OUTOFMEMORY;
2344           }
2345       }
2346    }
2347    if (Type == D3DSBT_ALL || Type == D3DSBT_PIXELSTATE) {
2348       dst->changed.group |=
2349          NINE_STATE_PS | NINE_STATE_PS_CONST | NINE_STATE_BLEND |
2350          NINE_STATE_FF_OTHER | NINE_STATE_FF_PSSTAGES | NINE_STATE_PS_CONST |
2351          NINE_STATE_FB | NINE_STATE_DSA | NINE_STATE_MULTISAMPLE |
2352          NINE_STATE_RASTERIZER | NINE_STATE_STENCIL_REF;
2353       memcpy(dst->changed.rs,
2354              nine_render_states_pixel, sizeof(dst->changed.rs));
2355       nine_ranges_insert(&dst->changed.ps_const_f, 0, This->max_ps_const_f,
2356                          &This->range_pool);
2357       dst->changed.ps_const_i = 0xffff;
2358       dst->changed.ps_const_b = 0xffff;
2359       for (s = 0; s < NINE_MAX_SAMPLERS; ++s)
2360           dst->changed.sampler[s] |= 0x1ffe;
2361       for (s = 0; s < NINE_MAX_TEXTURE_STAGES; ++s) {
2362           dst->ff.changed.tex_stage[s][0] |= 0xffffffff;
2363           dst->ff.changed.tex_stage[s][1] |= 0xffffffff;
2364       }
2365    }
2366    if (Type == D3DSBT_ALL) {
2367       dst->changed.group |=
2368          NINE_STATE_VIEWPORT |
2369          NINE_STATE_SCISSOR |
2370          NINE_STATE_RASTERIZER |
2371          NINE_STATE_BLEND |
2372          NINE_STATE_DSA |
2373          NINE_STATE_IDXBUF |
2374          NINE_STATE_MATERIAL |
2375          NINE_STATE_BLEND_COLOR |
2376          NINE_STATE_SAMPLE_MASK;
2377       memset(dst->changed.rs, ~0, (D3DRS_COUNT / 32) * sizeof(uint32_t));
2378       dst->changed.rs[D3DRS_LAST / 32] |= (1 << (D3DRS_COUNT % 32)) - 1;
2379       dst->changed.vtxbuf = (1ULL << This->caps.MaxStreams) - 1;
2380       dst->changed.stream_freq = dst->changed.vtxbuf;
2381       dst->changed.ucp = (1 << PIPE_MAX_CLIP_PLANES) - 1;
2382       dst->changed.texture = (1 << NINE_MAX_SAMPLERS) - 1;
2383    }
2384    NineStateBlock9_Capture(NineStateBlock9(*ppSB));
2385
2386    /* TODO: fixed function state */
2387
2388    return D3D_OK;
2389}
2390
2391HRESULT NINE_WINAPI
2392NineDevice9_BeginStateBlock( struct NineDevice9 *This )
2393{
2394    HRESULT hr;
2395
2396    DBG("This=%p\n", This);
2397
2398    user_assert(!This->record, D3DERR_INVALIDCALL);
2399
2400    hr = NineStateBlock9_new(This, &This->record, NINESBT_CUSTOM);
2401    if (FAILED(hr))
2402        return hr;
2403    NineUnknown_ConvertRefToBind(NineUnknown(This->record));
2404
2405    This->update = &This->record->state;
2406    This->is_recording = TRUE;
2407
2408    return D3D_OK;
2409}
2410
2411HRESULT NINE_WINAPI
2412NineDevice9_EndStateBlock( struct NineDevice9 *This,
2413                           IDirect3DStateBlock9 **ppSB )
2414{
2415    DBG("This=%p ppSB=%p\n", This, ppSB);
2416
2417    user_assert(This->record, D3DERR_INVALIDCALL);
2418
2419    This->update = &This->state;
2420    This->is_recording = FALSE;
2421
2422    NineUnknown_AddRef(NineUnknown(This->record));
2423    *ppSB = (IDirect3DStateBlock9 *)This->record;
2424    NineUnknown_Unbind(NineUnknown(This->record));
2425    This->record = NULL;
2426
2427    return D3D_OK;
2428}
2429
2430HRESULT NINE_WINAPI
2431NineDevice9_SetClipStatus( struct NineDevice9 *This,
2432                           const D3DCLIPSTATUS9 *pClipStatus )
2433{
2434    STUB(D3DERR_INVALIDCALL);
2435}
2436
2437HRESULT NINE_WINAPI
2438NineDevice9_GetClipStatus( struct NineDevice9 *This,
2439                           D3DCLIPSTATUS9 *pClipStatus )
2440{
2441    STUB(D3DERR_INVALIDCALL);
2442}
2443
2444HRESULT NINE_WINAPI
2445NineDevice9_GetTexture( struct NineDevice9 *This,
2446                        DWORD Stage,
2447                        IDirect3DBaseTexture9 **ppTexture )
2448{
2449    user_assert(Stage < This->caps.MaxSimultaneousTextures ||
2450                Stage == D3DDMAPSAMPLER ||
2451                (Stage >= D3DVERTEXTEXTURESAMPLER0 &&
2452                 Stage <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
2453    user_assert(ppTexture, D3DERR_INVALIDCALL);
2454
2455    if (Stage >= D3DDMAPSAMPLER)
2456        Stage = Stage - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
2457
2458    *ppTexture = (IDirect3DBaseTexture9 *)This->state.texture[Stage];
2459
2460    if (This->state.texture[Stage])
2461        NineUnknown_AddRef(NineUnknown(This->state.texture[Stage]));
2462    return D3D_OK;
2463}
2464
2465HRESULT NINE_WINAPI
2466NineDevice9_SetTexture( struct NineDevice9 *This,
2467                        DWORD Stage,
2468                        IDirect3DBaseTexture9 *pTexture )
2469{
2470    struct nine_state *state = This->update;
2471    struct NineBaseTexture9 *tex = NineBaseTexture9(pTexture);
2472    struct NineBaseTexture9 *old;
2473
2474    DBG("This=%p Stage=%u pTexture=%p\n", This, Stage, pTexture);
2475
2476    user_assert(Stage < This->caps.MaxSimultaneousTextures ||
2477                Stage == D3DDMAPSAMPLER ||
2478                (Stage >= D3DVERTEXTEXTURESAMPLER0 &&
2479                 Stage <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
2480    user_assert(!tex || (tex->base.pool != D3DPOOL_SCRATCH &&
2481                tex->base.pool != D3DPOOL_SYSTEMMEM), D3DERR_INVALIDCALL);
2482
2483    if (Stage >= D3DDMAPSAMPLER)
2484        Stage = Stage - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
2485
2486    if (This->is_recording) {
2487        state->changed.texture |= 1 << Stage;
2488        state->changed.group |= NINE_STATE_TEXTURE;
2489        nine_bind(&state->texture[Stage], pTexture);
2490        return D3D_OK;
2491    }
2492
2493    old = state->texture[Stage];
2494    if (old == tex)
2495        return D3D_OK;
2496
2497    if (tex) {
2498        if ((tex->managed.dirty | tex->dirty_mip) && LIST_IS_EMPTY(&tex->list))
2499            list_add(&tex->list, &This->update_textures);
2500
2501        tex->bind_count++;
2502    }
2503    if (old)
2504        old->bind_count--;
2505
2506    nine_context_set_texture(This, Stage, tex);
2507
2508    nine_bind(&state->texture[Stage], pTexture);
2509
2510    return D3D_OK;
2511}
2512
2513HRESULT NINE_WINAPI
2514NineDevice9_GetTextureStageState( struct NineDevice9 *This,
2515                                  DWORD Stage,
2516                                  D3DTEXTURESTAGESTATETYPE Type,
2517                                  DWORD *pValue )
2518{
2519    const struct nine_state *state = &This->state;
2520
2521    user_assert(Stage < ARRAY_SIZE(state->ff.tex_stage), D3DERR_INVALIDCALL);
2522    user_assert(Type < ARRAY_SIZE(state->ff.tex_stage[0]), D3DERR_INVALIDCALL);
2523
2524    *pValue = state->ff.tex_stage[Stage][Type];
2525
2526    return D3D_OK;
2527}
2528
2529HRESULT NINE_WINAPI
2530NineDevice9_SetTextureStageState( struct NineDevice9 *This,
2531                                  DWORD Stage,
2532                                  D3DTEXTURESTAGESTATETYPE Type,
2533                                  DWORD Value )
2534{
2535    struct nine_state *state = This->update;
2536    struct nine_context *context = &This->context;
2537    int bumpmap_index = -1;
2538
2539    DBG("Stage=%u Type=%u Value=%08x\n", Stage, Type, Value);
2540    nine_dump_D3DTSS_value(DBG_FF, Type, Value);
2541
2542    user_assert(Stage < ARRAY_SIZE(state->ff.tex_stage), D3DERR_INVALIDCALL);
2543    user_assert(Type < ARRAY_SIZE(state->ff.tex_stage[0]), D3DERR_INVALIDCALL);
2544
2545    state->ff.tex_stage[Stage][Type] = Value;
2546    switch (Type) {
2547    case D3DTSS_BUMPENVMAT00:
2548        bumpmap_index = 4 * Stage;
2549        break;
2550    case D3DTSS_BUMPENVMAT01:
2551        bumpmap_index = 4 * Stage + 1;
2552        break;
2553    case D3DTSS_BUMPENVMAT10:
2554        bumpmap_index = 4 * Stage + 2;
2555        break;
2556    case D3DTSS_BUMPENVMAT11:
2557        bumpmap_index = 4 * Stage + 3;
2558        break;
2559    case D3DTSS_BUMPENVLSCALE:
2560        bumpmap_index = 4 * 8 + 2 * Stage;
2561        break;
2562    case D3DTSS_BUMPENVLOFFSET:
2563        bumpmap_index = 4 * 8 + 2 * Stage + 1;
2564        break;
2565    case D3DTSS_TEXTURETRANSFORMFLAGS:
2566        state->changed.group |= NINE_STATE_PS1X_SHADER;
2567        break;
2568    default:
2569        break;
2570    }
2571
2572    if (bumpmap_index >= 0 && !This->is_recording) {
2573        context->bumpmap_vars[bumpmap_index] = Value;
2574        state->changed.group |= NINE_STATE_PS_CONST;
2575    }
2576
2577    state->changed.group |= NINE_STATE_FF_PSSTAGES;
2578    state->ff.changed.tex_stage[Stage][Type / 32] |= 1 << (Type % 32);
2579
2580    return D3D_OK;
2581}
2582
2583HRESULT NINE_WINAPI
2584NineDevice9_GetSamplerState( struct NineDevice9 *This,
2585                             DWORD Sampler,
2586                             D3DSAMPLERSTATETYPE Type,
2587                             DWORD *pValue )
2588{
2589    user_assert(Sampler < This->caps.MaxSimultaneousTextures ||
2590                Sampler == D3DDMAPSAMPLER ||
2591                (Sampler >= D3DVERTEXTEXTURESAMPLER0 &&
2592                 Sampler <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
2593
2594    if (Sampler >= D3DDMAPSAMPLER)
2595        Sampler = Sampler - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
2596
2597    *pValue = This->state.samp_advertised[Sampler][Type];
2598    return D3D_OK;
2599}
2600
2601HRESULT NINE_WINAPI
2602NineDevice9_SetSamplerState( struct NineDevice9 *This,
2603                             DWORD Sampler,
2604                             D3DSAMPLERSTATETYPE Type,
2605                             DWORD Value )
2606{
2607    struct nine_state *state = This->update;
2608
2609    DBG("This=%p Sampler=%u Type=%s Value=%08x\n", This,
2610        Sampler, nine_D3DSAMP_to_str(Type), Value);
2611
2612    user_assert(Sampler < This->caps.MaxSimultaneousTextures ||
2613                Sampler == D3DDMAPSAMPLER ||
2614                (Sampler >= D3DVERTEXTEXTURESAMPLER0 &&
2615                 Sampler <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
2616
2617    if (Sampler >= D3DDMAPSAMPLER)
2618        Sampler = Sampler - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
2619
2620    if (unlikely(This->is_recording)) {
2621        state->samp_advertised[Sampler][Type] = Value;
2622        state->changed.group |= NINE_STATE_SAMPLER;
2623        state->changed.sampler[Sampler] |= 1 << Type;
2624        return D3D_OK;
2625    }
2626
2627    if (state->samp_advertised[Sampler][Type] == Value)
2628        return D3D_OK;
2629
2630    state->samp_advertised[Sampler][Type] = Value;
2631    nine_context_set_sampler_state(This, Sampler, Type, Value);
2632
2633    return D3D_OK;
2634}
2635
2636HRESULT NINE_WINAPI
2637NineDevice9_ValidateDevice( struct NineDevice9 *This,
2638                            DWORD *pNumPasses )
2639{
2640    const struct nine_state *state = &This->state;
2641    unsigned i;
2642    unsigned w = 0, h = 0;
2643
2644    DBG("This=%p pNumPasses=%p\n", This, pNumPasses);
2645
2646    for (i = 0; i < ARRAY_SIZE(state->samp_advertised); ++i) {
2647        if (state->samp_advertised[i][D3DSAMP_MINFILTER] == D3DTEXF_NONE ||
2648            state->samp_advertised[i][D3DSAMP_MAGFILTER] == D3DTEXF_NONE)
2649            return D3DERR_UNSUPPORTEDTEXTUREFILTER;
2650    }
2651
2652    for (i = 0; i < This->caps.NumSimultaneousRTs; ++i) {
2653        if (!state->rt[i])
2654            continue;
2655        if (w == 0) {
2656            w = state->rt[i]->desc.Width;
2657            h = state->rt[i]->desc.Height;
2658        } else
2659        if (state->rt[i]->desc.Width != w || state->rt[i]->desc.Height != h) {
2660            return D3DERR_CONFLICTINGRENDERSTATE;
2661        }
2662    }
2663    if (state->ds &&
2664        (state->rs_advertised[D3DRS_ZENABLE] || state->rs_advertised[D3DRS_STENCILENABLE])) {
2665        if (w != 0 &&
2666            (state->ds->desc.Width != w || state->ds->desc.Height != h))
2667            return D3DERR_CONFLICTINGRENDERSTATE;
2668    }
2669
2670    if (pNumPasses)
2671        *pNumPasses = 1;
2672
2673    return D3D_OK;
2674}
2675
2676HRESULT NINE_WINAPI
2677NineDevice9_SetPaletteEntries( struct NineDevice9 *This,
2678                               UINT PaletteNumber,
2679                               const PALETTEENTRY *pEntries )
2680{
2681    STUB(D3D_OK); /* like wine */
2682}
2683
2684HRESULT NINE_WINAPI
2685NineDevice9_GetPaletteEntries( struct NineDevice9 *This,
2686                               UINT PaletteNumber,
2687                               PALETTEENTRY *pEntries )
2688{
2689    STUB(D3DERR_INVALIDCALL);
2690}
2691
2692HRESULT NINE_WINAPI
2693NineDevice9_SetCurrentTexturePalette( struct NineDevice9 *This,
2694                                      UINT PaletteNumber )
2695{
2696    STUB(D3D_OK); /* like wine */
2697}
2698
2699HRESULT NINE_WINAPI
2700NineDevice9_GetCurrentTexturePalette( struct NineDevice9 *This,
2701                                      UINT *PaletteNumber )
2702{
2703    STUB(D3DERR_INVALIDCALL);
2704}
2705
2706HRESULT NINE_WINAPI
2707NineDevice9_SetScissorRect( struct NineDevice9 *This,
2708                            const RECT *pRect )
2709{
2710    struct nine_state *state = This->update;
2711
2712    DBG("x=(%u..%u) y=(%u..%u)\n",
2713        pRect->left, pRect->top, pRect->right, pRect->bottom);
2714
2715    state->scissor.minx = pRect->left;
2716    state->scissor.miny = pRect->top;
2717    state->scissor.maxx = pRect->right;
2718    state->scissor.maxy = pRect->bottom;
2719
2720    state->changed.group |= NINE_STATE_SCISSOR;
2721
2722    return D3D_OK;
2723}
2724
2725HRESULT NINE_WINAPI
2726NineDevice9_GetScissorRect( struct NineDevice9 *This,
2727                            RECT *pRect )
2728{
2729    pRect->left   = This->state.scissor.minx;
2730    pRect->top    = This->state.scissor.miny;
2731    pRect->right  = This->state.scissor.maxx;
2732    pRect->bottom = This->state.scissor.maxy;
2733
2734    return D3D_OK;
2735}
2736
2737HRESULT NINE_WINAPI
2738NineDevice9_SetSoftwareVertexProcessing( struct NineDevice9 *This,
2739                                         BOOL bSoftware )
2740{
2741    if (This->params.BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) {
2742        This->swvp = bSoftware;
2743        This->state.changed.group |= NINE_STATE_SWVP;
2744        return D3D_OK;
2745    } else
2746        return D3DERR_INVALIDCALL; /* msdn. TODO: check in practice */
2747}
2748
2749BOOL NINE_WINAPI
2750NineDevice9_GetSoftwareVertexProcessing( struct NineDevice9 *This )
2751{
2752    return This->swvp;
2753}
2754
2755HRESULT NINE_WINAPI
2756NineDevice9_SetNPatchMode( struct NineDevice9 *This,
2757                           float nSegments )
2758{
2759    return D3D_OK; /* Nothing to do because we don't advertise NPatch support */
2760}
2761
2762float NINE_WINAPI
2763NineDevice9_GetNPatchMode( struct NineDevice9 *This )
2764{
2765    STUB(0);
2766}
2767
2768HRESULT NINE_WINAPI
2769NineDevice9_DrawPrimitive( struct NineDevice9 *This,
2770                           D3DPRIMITIVETYPE PrimitiveType,
2771                           UINT StartVertex,
2772                           UINT PrimitiveCount )
2773{
2774    DBG("iface %p, PrimitiveType %u, StartVertex %u, PrimitiveCount %u\n",
2775        This, PrimitiveType, StartVertex, PrimitiveCount);
2776
2777    nine_context_draw_primitive(This, PrimitiveType, StartVertex, PrimitiveCount);
2778
2779    return D3D_OK;
2780}
2781
2782HRESULT NINE_WINAPI
2783NineDevice9_DrawIndexedPrimitive( struct NineDevice9 *This,
2784                                  D3DPRIMITIVETYPE PrimitiveType,
2785                                  INT BaseVertexIndex,
2786                                  UINT MinVertexIndex,
2787                                  UINT NumVertices,
2788                                  UINT StartIndex,
2789                                  UINT PrimitiveCount )
2790{
2791    DBG("iface %p, PrimitiveType %u, BaseVertexIndex %u, MinVertexIndex %u "
2792        "NumVertices %u, StartIndex %u, PrimitiveCount %u\n",
2793        This, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices,
2794        StartIndex, PrimitiveCount);
2795
2796    user_assert(This->state.idxbuf, D3DERR_INVALIDCALL);
2797    user_assert(This->state.vdecl, D3DERR_INVALIDCALL);
2798
2799    nine_context_draw_indexed_primitive(This, PrimitiveType, BaseVertexIndex,
2800                                        MinVertexIndex, NumVertices, StartIndex,
2801                                        PrimitiveCount);
2802
2803    return D3D_OK;
2804}
2805
2806HRESULT NINE_WINAPI
2807NineDevice9_DrawPrimitiveUP( struct NineDevice9 *This,
2808                             D3DPRIMITIVETYPE PrimitiveType,
2809                             UINT PrimitiveCount,
2810                             const void *pVertexStreamZeroData,
2811                             UINT VertexStreamZeroStride )
2812{
2813    struct pipe_vertex_buffer vtxbuf;
2814
2815    DBG("iface %p, PrimitiveType %u, PrimitiveCount %u, data %p, stride %u\n",
2816        This, PrimitiveType, PrimitiveCount,
2817        pVertexStreamZeroData, VertexStreamZeroStride);
2818
2819    user_assert(pVertexStreamZeroData && VertexStreamZeroStride,
2820                D3DERR_INVALIDCALL);
2821    user_assert(PrimitiveCount, D3D_OK);
2822
2823    vtxbuf.stride = VertexStreamZeroStride;
2824    vtxbuf.buffer_offset = 0;
2825    vtxbuf.buffer = NULL;
2826    vtxbuf.user_buffer = pVertexStreamZeroData;
2827
2828    if (!This->driver_caps.user_vbufs) {
2829        u_upload_data(This->vertex_uploader,
2830                      0,
2831                      (prim_count_to_vertex_count(PrimitiveType, PrimitiveCount)) * VertexStreamZeroStride, /* XXX */
2832                      4,
2833                      vtxbuf.user_buffer,
2834                      &vtxbuf.buffer_offset,
2835                      &vtxbuf.buffer);
2836        u_upload_unmap(This->vertex_uploader);
2837        vtxbuf.user_buffer = NULL;
2838    }
2839
2840    nine_context_draw_primitive_from_vtxbuf(This, PrimitiveType, PrimitiveCount, &vtxbuf);
2841
2842    pipe_resource_reference(&vtxbuf.buffer, NULL);
2843
2844    NineDevice9_PauseRecording(This);
2845    NineDevice9_SetStreamSource(This, 0, NULL, 0, 0);
2846    NineDevice9_ResumeRecording(This);
2847
2848    return D3D_OK;
2849}
2850
2851HRESULT NINE_WINAPI
2852NineDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This,
2853                                    D3DPRIMITIVETYPE PrimitiveType,
2854                                    UINT MinVertexIndex,
2855                                    UINT NumVertices,
2856                                    UINT PrimitiveCount,
2857                                    const void *pIndexData,
2858                                    D3DFORMAT IndexDataFormat,
2859                                    const void *pVertexStreamZeroData,
2860                                    UINT VertexStreamZeroStride )
2861{
2862    struct pipe_vertex_buffer vbuf;
2863    struct pipe_index_buffer ibuf;
2864
2865    DBG("iface %p, PrimitiveType %u, MinVertexIndex %u, NumVertices %u "
2866        "PrimitiveCount %u, pIndexData %p, IndexDataFormat %u "
2867        "pVertexStreamZeroData %p, VertexStreamZeroStride %u\n",
2868        This, PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount,
2869        pIndexData, IndexDataFormat,
2870        pVertexStreamZeroData, VertexStreamZeroStride);
2871
2872    user_assert(pIndexData && pVertexStreamZeroData, D3DERR_INVALIDCALL);
2873    user_assert(VertexStreamZeroStride, D3DERR_INVALIDCALL);
2874    user_assert(IndexDataFormat == D3DFMT_INDEX16 ||
2875                IndexDataFormat == D3DFMT_INDEX32, D3DERR_INVALIDCALL);
2876    user_assert(PrimitiveCount, D3D_OK);
2877
2878    vbuf.stride = VertexStreamZeroStride;
2879    vbuf.buffer_offset = 0;
2880    vbuf.buffer = NULL;
2881    vbuf.user_buffer = pVertexStreamZeroData;
2882
2883    ibuf.index_size = (IndexDataFormat == D3DFMT_INDEX16) ? 2 : 4;
2884    ibuf.offset = 0;
2885    ibuf.buffer = NULL;
2886    ibuf.user_buffer = pIndexData;
2887
2888    if (!This->driver_caps.user_vbufs) {
2889        const unsigned base = MinVertexIndex * VertexStreamZeroStride;
2890        u_upload_data(This->vertex_uploader,
2891                      base,
2892                      NumVertices * VertexStreamZeroStride, /* XXX */
2893                      4,
2894                      (const uint8_t *)vbuf.user_buffer + base,
2895                      &vbuf.buffer_offset,
2896                      &vbuf.buffer);
2897        u_upload_unmap(This->vertex_uploader);
2898        /* Won't be used: */
2899        vbuf.buffer_offset -= base;
2900        vbuf.user_buffer = NULL;
2901    }
2902    if (!This->driver_caps.user_ibufs) {
2903        u_upload_data(This->index_uploader,
2904                      0,
2905                      (prim_count_to_vertex_count(PrimitiveType, PrimitiveCount)) * ibuf.index_size,
2906                      4,
2907                      ibuf.user_buffer,
2908                      &ibuf.offset,
2909                      &ibuf.buffer);
2910        u_upload_unmap(This->index_uploader);
2911        ibuf.user_buffer = NULL;
2912    }
2913
2914    nine_context_draw_indexed_primitive_from_vtxbuf_idxbuf(This, PrimitiveType,
2915                                                           MinVertexIndex,
2916                                                           NumVertices,
2917                                                           PrimitiveCount,
2918                                                           &vbuf,
2919                                                           &ibuf);
2920
2921    pipe_resource_reference(&vbuf.buffer, NULL);
2922    pipe_resource_reference(&ibuf.buffer, NULL);
2923
2924    NineDevice9_PauseRecording(This);
2925    NineDevice9_SetIndices(This, NULL);
2926    NineDevice9_SetStreamSource(This, 0, NULL, 0, 0);
2927    NineDevice9_ResumeRecording(This);
2928
2929    return D3D_OK;
2930}
2931
2932HRESULT NINE_WINAPI
2933NineDevice9_ProcessVertices( struct NineDevice9 *This,
2934                             UINT SrcStartIndex,
2935                             UINT DestIndex,
2936                             UINT VertexCount,
2937                             IDirect3DVertexBuffer9 *pDestBuffer,
2938                             IDirect3DVertexDeclaration9 *pVertexDecl,
2939                             DWORD Flags )
2940{
2941    struct pipe_screen *screen_sw = This->screen_sw;
2942    struct pipe_context *pipe_sw = This->pipe_sw;
2943    struct NineVertexDeclaration9 *vdecl = NineVertexDeclaration9(pVertexDecl);
2944    struct NineVertexBuffer9 *dst = NineVertexBuffer9(pDestBuffer);
2945    struct NineVertexShader9 *vs;
2946    struct pipe_resource *resource;
2947    struct pipe_transfer *transfer = NULL;
2948    struct pipe_stream_output_info so;
2949    struct pipe_stream_output_target *target;
2950    struct pipe_draw_info draw;
2951    struct pipe_box box;
2952    bool programmable_vs = This->state.vs && !(This->state.vdecl && This->state.vdecl->position_t);
2953    unsigned offsets[1] = {0};
2954    HRESULT hr;
2955    unsigned buffer_size;
2956    void *map;
2957
2958    DBG("This=%p SrcStartIndex=%u DestIndex=%u VertexCount=%u "
2959        "pDestBuffer=%p pVertexDecl=%p Flags=%d\n",
2960        This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer,
2961        pVertexDecl, Flags);
2962
2963    if (!screen_sw->get_param(screen_sw, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS)) {
2964        DBG("ProcessVertices not supported\n");
2965        return D3DERR_INVALIDCALL;
2966    }
2967
2968
2969    vs = programmable_vs ? This->state.vs : This->ff.vs;
2970    /* Note: version is 0 for ff */
2971    user_assert(vdecl || (vs->byte_code.version < 0x30 && dst->desc.FVF),
2972                D3DERR_INVALIDCALL);
2973    if (!vdecl) {
2974        DWORD FVF = dst->desc.FVF;
2975        vdecl = util_hash_table_get(This->ff.ht_fvf, &FVF);
2976        if (!vdecl) {
2977            hr = NineVertexDeclaration9_new_from_fvf(This, FVF, &vdecl);
2978            if (FAILED(hr))
2979                return hr;
2980            vdecl->fvf = FVF;
2981            util_hash_table_set(This->ff.ht_fvf, &vdecl->fvf, vdecl);
2982            NineUnknown_ConvertRefToBind(NineUnknown(vdecl));
2983        }
2984    }
2985
2986    /* Flags: Can be 0 or D3DPV_DONOTCOPYDATA, and/or lock flags
2987     * D3DPV_DONOTCOPYDATA -> Has effect only for ff. In particular
2988     * if not set, everything from src will be used, and dst
2989     * must match exactly the ff vs outputs.
2990     * TODO: Handle all the checks, etc for ff */
2991    user_assert(vdecl->position_t || programmable_vs,
2992                D3DERR_INVALIDCALL);
2993
2994    /* TODO: Support vs < 3 and ff */
2995    user_assert(vs->byte_code.version == 0x30,
2996                D3DERR_INVALIDCALL);
2997    /* TODO: Not hardcode the constant buffers for swvp */
2998    user_assert(This->may_swvp,
2999                D3DERR_INVALIDCALL);
3000
3001    nine_state_prepare_draw_sw(This, vdecl, SrcStartIndex, VertexCount, &so);
3002
3003    buffer_size = VertexCount * so.stride[0] * 4;
3004    {
3005        struct pipe_resource templ;
3006
3007        memset(&templ, 0, sizeof(templ));
3008        templ.target = PIPE_BUFFER;
3009        templ.format = PIPE_FORMAT_R8_UNORM;
3010        templ.width0 = buffer_size;
3011        templ.flags = 0;
3012        templ.bind = PIPE_BIND_STREAM_OUTPUT;
3013        templ.usage = PIPE_USAGE_STREAM;
3014        templ.height0 = templ.depth0 = templ.array_size = 1;
3015        templ.last_level = templ.nr_samples = 0;
3016
3017        resource = screen_sw->resource_create(screen_sw, &templ);
3018        if (!resource)
3019            return E_OUTOFMEMORY;
3020    }
3021    target = pipe_sw->create_stream_output_target(pipe_sw, resource,
3022                                                  0, buffer_size);
3023    if (!target) {
3024        pipe_resource_reference(&resource, NULL);
3025        return D3DERR_DRIVERINTERNALERROR;
3026    }
3027
3028    draw.mode = PIPE_PRIM_POINTS;
3029    draw.count = VertexCount;
3030    draw.start_instance = 0;
3031    draw.primitive_restart = FALSE;
3032    draw.restart_index = 0;
3033    draw.count_from_stream_output = NULL;
3034    draw.indirect = NULL;
3035    draw.indirect_params = NULL;
3036    draw.instance_count = 1;
3037    draw.indexed = FALSE;
3038    draw.start = 0;
3039    draw.index_bias = 0;
3040    draw.min_index = 0;
3041    draw.max_index = VertexCount - 1;
3042
3043
3044    pipe_sw->set_stream_output_targets(pipe_sw, 1, &target, offsets);
3045
3046    pipe_sw->draw_vbo(pipe_sw, &draw);
3047
3048    pipe_sw->set_stream_output_targets(pipe_sw, 0, NULL, 0);
3049    pipe_sw->stream_output_target_destroy(pipe_sw, target);
3050
3051    u_box_1d(0, VertexCount * so.stride[0] * 4, &box);
3052    map = pipe_sw->transfer_map(pipe_sw, resource, 0, PIPE_TRANSFER_READ, &box,
3053                                &transfer);
3054    if (!map) {
3055        hr = D3DERR_DRIVERINTERNALERROR;
3056        goto out;
3057    }
3058
3059    hr = NineVertexDeclaration9_ConvertStreamOutput(vdecl,
3060                                                    dst, DestIndex, VertexCount,
3061                                                    map, &so);
3062    if (transfer)
3063        pipe_sw->transfer_unmap(pipe_sw, transfer);
3064
3065out:
3066    nine_state_after_draw_sw(This);
3067    pipe_resource_reference(&resource, NULL);
3068    return hr;
3069}
3070
3071HRESULT NINE_WINAPI
3072NineDevice9_CreateVertexDeclaration( struct NineDevice9 *This,
3073                                     const D3DVERTEXELEMENT9 *pVertexElements,
3074                                     IDirect3DVertexDeclaration9 **ppDecl )
3075{
3076    struct NineVertexDeclaration9 *vdecl;
3077
3078    DBG("This=%p pVertexElements=%p ppDecl=%p\n",
3079        This, pVertexElements, ppDecl);
3080
3081    HRESULT hr = NineVertexDeclaration9_new(This, pVertexElements, &vdecl);
3082    if (SUCCEEDED(hr))
3083        *ppDecl = (IDirect3DVertexDeclaration9 *)vdecl;
3084
3085    return hr;
3086}
3087
3088HRESULT NINE_WINAPI
3089NineDevice9_SetVertexDeclaration( struct NineDevice9 *This,
3090                                  IDirect3DVertexDeclaration9 *pDecl )
3091{
3092    struct nine_state *state = This->update;
3093    struct NineVertexDeclaration9 *vdecl = NineVertexDeclaration9(pDecl);
3094
3095    DBG("This=%p pDecl=%p\n", This, pDecl);
3096
3097    if (unlikely(This->is_recording)) {
3098        nine_bind(&state->vdecl, vdecl);
3099        state->changed.group |= NINE_STATE_VDECL;
3100        return D3D_OK;
3101    }
3102
3103    if (state->vdecl == vdecl)
3104        return D3D_OK;
3105
3106    nine_bind(&state->vdecl, vdecl);
3107
3108    nine_context_set_vertex_declaration(This, vdecl);
3109
3110    return D3D_OK;
3111}
3112
3113HRESULT NINE_WINAPI
3114NineDevice9_GetVertexDeclaration( struct NineDevice9 *This,
3115                                  IDirect3DVertexDeclaration9 **ppDecl )
3116{
3117    user_assert(ppDecl, D3DERR_INVALIDCALL);
3118
3119    *ppDecl = (IDirect3DVertexDeclaration9 *)This->state.vdecl;
3120    if (*ppDecl)
3121        NineUnknown_AddRef(NineUnknown(*ppDecl));
3122    return D3D_OK;
3123}
3124
3125HRESULT NINE_WINAPI
3126NineDevice9_SetFVF( struct NineDevice9 *This,
3127                    DWORD FVF )
3128{
3129    struct NineVertexDeclaration9 *vdecl;
3130    HRESULT hr;
3131
3132    DBG("FVF = %08x\n", FVF);
3133    if (!FVF)
3134        return D3D_OK; /* like wine */
3135
3136    vdecl = util_hash_table_get(This->ff.ht_fvf, &FVF);
3137    if (!vdecl) {
3138        hr = NineVertexDeclaration9_new_from_fvf(This, FVF, &vdecl);
3139        if (FAILED(hr))
3140            return hr;
3141        vdecl->fvf = FVF;
3142        util_hash_table_set(This->ff.ht_fvf, &vdecl->fvf, vdecl);
3143        NineUnknown_ConvertRefToBind(NineUnknown(vdecl));
3144    }
3145    return NineDevice9_SetVertexDeclaration(
3146        This, (IDirect3DVertexDeclaration9 *)vdecl);
3147}
3148
3149HRESULT NINE_WINAPI
3150NineDevice9_GetFVF( struct NineDevice9 *This,
3151                    DWORD *pFVF )
3152{
3153    *pFVF = This->state.vdecl ? This->state.vdecl->fvf : 0;
3154    return D3D_OK;
3155}
3156
3157HRESULT NINE_WINAPI
3158NineDevice9_CreateVertexShader( struct NineDevice9 *This,
3159                                const DWORD *pFunction,
3160                                IDirect3DVertexShader9 **ppShader )
3161{
3162    struct NineVertexShader9 *vs;
3163    HRESULT hr;
3164
3165    DBG("This=%p pFunction=%p ppShader=%p\n", This, pFunction, ppShader);
3166
3167    hr = NineVertexShader9_new(This, &vs, pFunction, NULL);
3168    if (FAILED(hr))
3169        return hr;
3170    *ppShader = (IDirect3DVertexShader9 *)vs;
3171    return D3D_OK;
3172}
3173
3174HRESULT NINE_WINAPI
3175NineDevice9_SetVertexShader( struct NineDevice9 *This,
3176                             IDirect3DVertexShader9 *pShader )
3177{
3178    struct nine_state *state = This->update;
3179    struct NineVertexShader9 *vs_shader = (struct NineVertexShader9*)pShader;
3180
3181    DBG("This=%p pShader=%p\n", This, pShader);
3182
3183    if (unlikely(This->is_recording)) {
3184        nine_bind(&state->vs, vs_shader);
3185        state->changed.group |= NINE_STATE_VS;
3186        return D3D_OK;
3187    }
3188
3189    if (state->vs == vs_shader)
3190      return D3D_OK;
3191
3192    nine_bind(&state->vs, vs_shader);
3193
3194    nine_context_set_vertex_shader(This, vs_shader);
3195
3196    return D3D_OK;
3197}
3198
3199HRESULT NINE_WINAPI
3200NineDevice9_GetVertexShader( struct NineDevice9 *This,
3201                             IDirect3DVertexShader9 **ppShader )
3202{
3203    user_assert(ppShader, D3DERR_INVALIDCALL);
3204    nine_reference_set(ppShader, This->state.vs);
3205    return D3D_OK;
3206}
3207
3208HRESULT NINE_WINAPI
3209NineDevice9_SetVertexShaderConstantF( struct NineDevice9 *This,
3210                                      UINT StartRegister,
3211                                      const float *pConstantData,
3212                                      UINT Vector4fCount )
3213{
3214    struct nine_state *state = This->update;
3215    float *vs_const_f = state->vs_const_f;
3216
3217    DBG("This=%p StartRegister=%u pConstantData=%p Vector4fCount=%u\n",
3218        This, StartRegister, pConstantData, Vector4fCount);
3219
3220    user_assert(StartRegister                  < This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
3221    user_assert(StartRegister + Vector4fCount <= This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
3222
3223    if (!Vector4fCount)
3224       return D3D_OK;
3225    user_assert(pConstantData, D3DERR_INVALIDCALL);
3226
3227    if (unlikely(This->is_recording)) {
3228        memcpy(&vs_const_f[StartRegister * 4],
3229               pConstantData,
3230               Vector4fCount * 4 * sizeof(state->vs_const_f[0]));
3231
3232        nine_ranges_insert(&state->changed.vs_const_f,
3233                           StartRegister, StartRegister + Vector4fCount,
3234                           &This->range_pool);
3235
3236        state->changed.group |= NINE_STATE_VS_CONST;
3237
3238        return D3D_OK;
3239    }
3240
3241    if (!memcmp(&vs_const_f[StartRegister * 4], pConstantData,
3242                Vector4fCount * 4 * sizeof(state->vs_const_f[0])))
3243        return D3D_OK;
3244
3245    memcpy(&vs_const_f[StartRegister * 4],
3246           pConstantData,
3247           Vector4fCount * 4 * sizeof(state->vs_const_f[0]));
3248
3249    nine_context_set_vertex_shader_constant_f(This, StartRegister, pConstantData, Vector4fCount);
3250
3251    return D3D_OK;
3252}
3253
3254HRESULT NINE_WINAPI
3255NineDevice9_GetVertexShaderConstantF( struct NineDevice9 *This,
3256                                      UINT StartRegister,
3257                                      float *pConstantData,
3258                                      UINT Vector4fCount )
3259{
3260    const struct nine_state *state = &This->state;
3261
3262    user_assert(StartRegister                  < This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
3263    user_assert(StartRegister + Vector4fCount <= This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
3264    user_assert(pConstantData, D3DERR_INVALIDCALL);
3265
3266    memcpy(pConstantData,
3267           &state->vs_const_f[StartRegister * 4],
3268           Vector4fCount * 4 * sizeof(state->vs_const_f[0]));
3269
3270    return D3D_OK;
3271}
3272
3273HRESULT NINE_WINAPI
3274NineDevice9_SetVertexShaderConstantI( struct NineDevice9 *This,
3275                                      UINT StartRegister,
3276                                      const int *pConstantData,
3277                                      UINT Vector4iCount )
3278{
3279    struct nine_state *state = This->update;
3280    int i;
3281
3282    DBG("This=%p StartRegister=%u pConstantData=%p Vector4iCount=%u\n",
3283        This, StartRegister, pConstantData, Vector4iCount);
3284
3285    user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I),
3286                D3DERR_INVALIDCALL);
3287    user_assert(StartRegister + Vector4iCount <= (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I),
3288                D3DERR_INVALIDCALL);
3289    user_assert(pConstantData, D3DERR_INVALIDCALL);
3290
3291    if (This->driver_caps.vs_integer) {
3292        if (!This->is_recording) {
3293            if (!memcmp(&state->vs_const_i[4 * StartRegister], pConstantData,
3294                        Vector4iCount * sizeof(int[4])))
3295                return D3D_OK;
3296        }
3297        memcpy(&state->vs_const_i[4 * StartRegister],
3298               pConstantData,
3299               Vector4iCount * sizeof(int[4]));
3300    } else {
3301        for (i = 0; i < Vector4iCount; i++) {
3302            state->vs_const_i[4 * (StartRegister + i)] = fui((float)(pConstantData[4 * i]));
3303            state->vs_const_i[4 * (StartRegister + i) + 1] = fui((float)(pConstantData[4 * i + 1]));
3304            state->vs_const_i[4 * (StartRegister + i) + 2] = fui((float)(pConstantData[4 * i + 2]));
3305            state->vs_const_i[4 * (StartRegister + i) + 3] = fui((float)(pConstantData[4 * i + 3]));
3306        }
3307    }
3308
3309    if (unlikely(This->is_recording)) {
3310        nine_ranges_insert(&state->changed.vs_const_i,
3311                           StartRegister, StartRegister + Vector4iCount,
3312                           &This->range_pool);
3313        state->changed.group |= NINE_STATE_VS_CONST;
3314    } else
3315        nine_context_set_vertex_shader_constant_i(This, StartRegister, pConstantData, Vector4iCount);
3316
3317    return D3D_OK;
3318}
3319
3320HRESULT NINE_WINAPI
3321NineDevice9_GetVertexShaderConstantI( struct NineDevice9 *This,
3322                                      UINT StartRegister,
3323                                      int *pConstantData,
3324                                      UINT Vector4iCount )
3325{
3326    const struct nine_state *state = &This->state;
3327    int i;
3328
3329    user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I),
3330                D3DERR_INVALIDCALL);
3331    user_assert(StartRegister + Vector4iCount <= (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I),
3332                D3DERR_INVALIDCALL);
3333    user_assert(pConstantData, D3DERR_INVALIDCALL);
3334
3335    if (This->driver_caps.vs_integer) {
3336        memcpy(pConstantData,
3337               &state->vs_const_i[4 * StartRegister],
3338               Vector4iCount * sizeof(int[4]));
3339    } else {
3340        for (i = 0; i < Vector4iCount; i++) {
3341            pConstantData[4 * i] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i)]);
3342            pConstantData[4 * i + 1] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i) + 1]);
3343            pConstantData[4 * i + 2] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i) + 2]);
3344            pConstantData[4 * i + 3] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i) + 3]);
3345        }
3346    }
3347
3348    return D3D_OK;
3349}
3350
3351HRESULT NINE_WINAPI
3352NineDevice9_SetVertexShaderConstantB( struct NineDevice9 *This,
3353                                      UINT StartRegister,
3354                                      const BOOL *pConstantData,
3355                                      UINT BoolCount )
3356{
3357    struct nine_state *state = This->update;
3358    int i;
3359    uint32_t bool_true = This->driver_caps.vs_integer ? 0xFFFFFFFF : fui(1.0f);
3360
3361    DBG("This=%p StartRegister=%u pConstantData=%p BoolCount=%u\n",
3362        This, StartRegister, pConstantData, BoolCount);
3363
3364    user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B),
3365                D3DERR_INVALIDCALL);
3366    user_assert(StartRegister + BoolCount <= (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B),
3367                D3DERR_INVALIDCALL);
3368    user_assert(pConstantData, D3DERR_INVALIDCALL);
3369
3370    if (!This->is_recording) {
3371        bool noChange = true;
3372        for (i = 0; i < BoolCount; i++) {
3373            if (!!state->vs_const_b[StartRegister + i] != !!pConstantData[i])
3374              noChange = false;
3375        }
3376        if (noChange)
3377            return D3D_OK;
3378    }
3379
3380    for (i = 0; i < BoolCount; i++)
3381        state->vs_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0;
3382
3383    if (unlikely(This->is_recording)) {
3384        nine_ranges_insert(&state->changed.vs_const_b,
3385                           StartRegister, StartRegister + BoolCount,
3386                           &This->range_pool);
3387        state->changed.group |= NINE_STATE_VS_CONST;
3388    } else
3389        nine_context_set_vertex_shader_constant_b(This, StartRegister, pConstantData, BoolCount);
3390
3391    return D3D_OK;
3392}
3393
3394HRESULT NINE_WINAPI
3395NineDevice9_GetVertexShaderConstantB( struct NineDevice9 *This,
3396                                      UINT StartRegister,
3397                                      BOOL *pConstantData,
3398                                      UINT BoolCount )
3399{
3400    const struct nine_state *state = &This->state;
3401    int i;
3402
3403    user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B),
3404                D3DERR_INVALIDCALL);
3405    user_assert(StartRegister + BoolCount <= (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B),
3406                D3DERR_INVALIDCALL);
3407    user_assert(pConstantData, D3DERR_INVALIDCALL);
3408
3409    for (i = 0; i < BoolCount; i++)
3410        pConstantData[i] = state->vs_const_b[StartRegister + i] != 0 ? TRUE : FALSE;
3411
3412    return D3D_OK;
3413}
3414
3415HRESULT NINE_WINAPI
3416NineDevice9_SetStreamSource( struct NineDevice9 *This,
3417                             UINT StreamNumber,
3418                             IDirect3DVertexBuffer9 *pStreamData,
3419                             UINT OffsetInBytes,
3420                             UINT Stride )
3421{
3422    struct nine_state *state = This->update;
3423    struct NineVertexBuffer9 *pVBuf9 = NineVertexBuffer9(pStreamData);
3424    const unsigned i = StreamNumber;
3425
3426    DBG("This=%p StreamNumber=%u pStreamData=%p OffsetInBytes=%u Stride=%u\n",
3427        This, StreamNumber, pStreamData, OffsetInBytes, Stride);
3428
3429    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
3430    user_assert(Stride <= This->caps.MaxStreamStride, D3DERR_INVALIDCALL);
3431
3432    if (unlikely(This->is_recording)) {
3433        nine_bind(&state->stream[i], pStreamData);
3434        state->changed.vtxbuf |= 1 << StreamNumber;
3435        state->vtxbuf[i].stride = Stride;
3436        state->vtxbuf[i].buffer_offset = OffsetInBytes;
3437        return D3D_OK;
3438    }
3439
3440    if (state->stream[i] == NineVertexBuffer9(pStreamData) &&
3441        state->vtxbuf[i].stride == Stride &&
3442        state->vtxbuf[i].buffer_offset == OffsetInBytes)
3443        return D3D_OK;
3444
3445    state->vtxbuf[i].stride = Stride;
3446    state->vtxbuf[i].buffer_offset = OffsetInBytes;
3447
3448    nine_bind(&state->stream[i], pStreamData);
3449
3450    nine_context_set_stream_source(This,
3451                                   StreamNumber,
3452                                   pVBuf9,
3453                                   OffsetInBytes,
3454                                   Stride);
3455
3456    return D3D_OK;
3457}
3458
3459HRESULT NINE_WINAPI
3460NineDevice9_GetStreamSource( struct NineDevice9 *This,
3461                             UINT StreamNumber,
3462                             IDirect3DVertexBuffer9 **ppStreamData,
3463                             UINT *pOffsetInBytes,
3464                             UINT *pStride )
3465{
3466    const struct nine_state *state = &This->state;
3467    const unsigned i = StreamNumber;
3468
3469    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
3470    user_assert(ppStreamData, D3DERR_INVALIDCALL);
3471
3472    nine_reference_set(ppStreamData, state->stream[i]);
3473    *pStride = state->vtxbuf[i].stride;
3474    *pOffsetInBytes = state->vtxbuf[i].buffer_offset;
3475
3476    return D3D_OK;
3477}
3478
3479HRESULT NINE_WINAPI
3480NineDevice9_SetStreamSourceFreq( struct NineDevice9 *This,
3481                                 UINT StreamNumber,
3482                                 UINT Setting )
3483{
3484    struct nine_state *state = This->update;
3485    /* const UINT freq = Setting & 0x7FFFFF; */
3486
3487    DBG("This=%p StreamNumber=%u FrequencyParameter=0x%x\n", This,
3488        StreamNumber, Setting);
3489
3490    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
3491    user_assert(StreamNumber != 0 || !(Setting & D3DSTREAMSOURCE_INSTANCEDATA),
3492                D3DERR_INVALIDCALL);
3493    user_assert(!((Setting & D3DSTREAMSOURCE_INSTANCEDATA) &&
3494                  (Setting & D3DSTREAMSOURCE_INDEXEDDATA)), D3DERR_INVALIDCALL);
3495    user_assert(Setting, D3DERR_INVALIDCALL);
3496
3497    if (unlikely(This->is_recording)) {
3498        state->stream_freq[StreamNumber] = Setting;
3499        state->changed.stream_freq |= 1 << StreamNumber;
3500        if (StreamNumber != 0)
3501            state->changed.group |= NINE_STATE_STREAMFREQ;
3502        return D3D_OK;
3503    }
3504
3505    if (state->stream_freq[StreamNumber] == Setting)
3506        return D3D_OK;
3507
3508    state->stream_freq[StreamNumber] = Setting;
3509
3510    nine_context_set_stream_source_freq(This, StreamNumber, Setting);
3511    return D3D_OK;
3512}
3513
3514HRESULT NINE_WINAPI
3515NineDevice9_GetStreamSourceFreq( struct NineDevice9 *This,
3516                                 UINT StreamNumber,
3517                                 UINT *pSetting )
3518{
3519    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
3520    *pSetting = This->state.stream_freq[StreamNumber];
3521    return D3D_OK;
3522}
3523
3524HRESULT NINE_WINAPI
3525NineDevice9_SetIndices( struct NineDevice9 *This,
3526                        IDirect3DIndexBuffer9 *pIndexData )
3527{
3528    struct nine_state *state = This->update;
3529
3530    DBG("This=%p pIndexData=%p\n", This, pIndexData);
3531
3532    if (likely(!This->is_recording))
3533        if (state->idxbuf == NineIndexBuffer9(pIndexData))
3534            return D3D_OK;
3535    nine_bind(&state->idxbuf, pIndexData);
3536
3537    state->changed.group |= NINE_STATE_IDXBUF;
3538
3539    return D3D_OK;
3540}
3541
3542/* XXX: wine/d3d9 doesn't have pBaseVertexIndex, and it doesn't make sense
3543 * here because it's an argument passed to the Draw calls.
3544 */
3545HRESULT NINE_WINAPI
3546NineDevice9_GetIndices( struct NineDevice9 *This,
3547                        IDirect3DIndexBuffer9 **ppIndexData)
3548{
3549    user_assert(ppIndexData, D3DERR_INVALIDCALL);
3550    nine_reference_set(ppIndexData, This->state.idxbuf);
3551    return D3D_OK;
3552}
3553
3554HRESULT NINE_WINAPI
3555NineDevice9_CreatePixelShader( struct NineDevice9 *This,
3556                               const DWORD *pFunction,
3557                               IDirect3DPixelShader9 **ppShader )
3558{
3559    struct NinePixelShader9 *ps;
3560    HRESULT hr;
3561
3562    DBG("This=%p pFunction=%p ppShader=%p\n", This, pFunction, ppShader);
3563
3564    hr = NinePixelShader9_new(This, &ps, pFunction, NULL);
3565    if (FAILED(hr))
3566        return hr;
3567    *ppShader = (IDirect3DPixelShader9 *)ps;
3568    return D3D_OK;
3569}
3570
3571HRESULT NINE_WINAPI
3572NineDevice9_SetPixelShader( struct NineDevice9 *This,
3573                            IDirect3DPixelShader9 *pShader )
3574{
3575    struct nine_state *state = This->update;
3576    struct nine_context *context = &This->context;
3577    unsigned old_mask = state->ps ? state->ps->rt_mask : 1;
3578    unsigned mask;
3579
3580    DBG("This=%p pShader=%p\n", This, pShader);
3581
3582    if (!This->is_recording && state->ps == (struct NinePixelShader9*)pShader)
3583      return D3D_OK;
3584
3585    /* ff -> non-ff: commit back non-ff constants */
3586    if (!state->ps && pShader)
3587        context->commit |= NINE_STATE_COMMIT_CONST_PS;
3588
3589    nine_bind(&state->ps, pShader);
3590
3591    state->changed.group |= NINE_STATE_PS;
3592
3593    mask = state->ps ? state->ps->rt_mask : 1;
3594    /* We need to update cbufs if the pixel shader would
3595     * write to different render targets */
3596    if (mask != old_mask)
3597        state->changed.group |= NINE_STATE_FB;
3598
3599    return D3D_OK;
3600}
3601
3602HRESULT NINE_WINAPI
3603NineDevice9_GetPixelShader( struct NineDevice9 *This,
3604                            IDirect3DPixelShader9 **ppShader )
3605{
3606    user_assert(ppShader, D3DERR_INVALIDCALL);
3607    nine_reference_set(ppShader, This->state.ps);
3608    return D3D_OK;
3609}
3610
3611HRESULT NINE_WINAPI
3612NineDevice9_SetPixelShaderConstantF( struct NineDevice9 *This,
3613                                     UINT StartRegister,
3614                                     const float *pConstantData,
3615                                     UINT Vector4fCount )
3616{
3617    struct nine_state *state = This->update;
3618
3619    DBG("This=%p StartRegister=%u pConstantData=%p Vector4fCount=%u\n",
3620        This, StartRegister, pConstantData, Vector4fCount);
3621
3622    user_assert(StartRegister                  < NINE_MAX_CONST_F_PS3, D3DERR_INVALIDCALL);
3623    user_assert(StartRegister + Vector4fCount <= NINE_MAX_CONST_F_PS3, D3DERR_INVALIDCALL);
3624
3625    if (!Vector4fCount)
3626       return D3D_OK;
3627    user_assert(pConstantData, D3DERR_INVALIDCALL);
3628
3629    if (unlikely(This->is_recording)) {
3630        memcpy(&state->ps_const_f[StartRegister * 4],
3631               pConstantData,
3632               Vector4fCount * 4 * sizeof(state->ps_const_f[0]));
3633
3634        nine_ranges_insert(&state->changed.ps_const_f,
3635                           StartRegister, StartRegister + Vector4fCount,
3636                           &This->range_pool);
3637
3638        state->changed.group |= NINE_STATE_PS_CONST;
3639        return D3D_OK;
3640    }
3641
3642    if (!memcmp(&state->ps_const_f[StartRegister * 4], pConstantData,
3643                Vector4fCount * 4 * sizeof(state->ps_const_f[0])))
3644        return D3D_OK;
3645
3646    memcpy(&state->ps_const_f[StartRegister * 4],
3647           pConstantData,
3648           Vector4fCount * 4 * sizeof(state->ps_const_f[0]));
3649
3650    nine_context_set_pixel_shader_constant_f(This, StartRegister, pConstantData, Vector4fCount);
3651
3652    return D3D_OK;
3653}
3654
3655HRESULT NINE_WINAPI
3656NineDevice9_GetPixelShaderConstantF( struct NineDevice9 *This,
3657                                     UINT StartRegister,
3658                                     float *pConstantData,
3659                                     UINT Vector4fCount )
3660{
3661    const struct nine_state *state = &This->state;
3662
3663    user_assert(StartRegister                  < NINE_MAX_CONST_F_PS3, D3DERR_INVALIDCALL);
3664    user_assert(StartRegister + Vector4fCount <= NINE_MAX_CONST_F_PS3, D3DERR_INVALIDCALL);
3665    user_assert(pConstantData, D3DERR_INVALIDCALL);
3666
3667    memcpy(pConstantData,
3668           &state->ps_const_f[StartRegister * 4],
3669           Vector4fCount * 4 * sizeof(state->ps_const_f[0]));
3670
3671    return D3D_OK;
3672}
3673
3674HRESULT NINE_WINAPI
3675NineDevice9_SetPixelShaderConstantI( struct NineDevice9 *This,
3676                                     UINT StartRegister,
3677                                     const int *pConstantData,
3678                                     UINT Vector4iCount )
3679{
3680    struct nine_state *state = This->update;
3681    int i;
3682
3683    DBG("This=%p StartRegister=%u pConstantData=%p Vector4iCount=%u\n",
3684        This, StartRegister, pConstantData, Vector4iCount);
3685
3686    user_assert(StartRegister                  < NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
3687    user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
3688    user_assert(pConstantData, D3DERR_INVALIDCALL);
3689
3690    if (This->driver_caps.ps_integer) {
3691        if (!This->is_recording) {
3692            if (!memcmp(&state->ps_const_i[StartRegister][0], pConstantData,
3693                        Vector4iCount * sizeof(state->ps_const_i[0])))
3694                return D3D_OK;
3695        }
3696        memcpy(&state->ps_const_i[StartRegister][0],
3697               pConstantData,
3698               Vector4iCount * sizeof(state->ps_const_i[0]));
3699    } else {
3700        for (i = 0; i < Vector4iCount; i++) {
3701            state->ps_const_i[StartRegister+i][0] = fui((float)(pConstantData[4*i]));
3702            state->ps_const_i[StartRegister+i][1] = fui((float)(pConstantData[4*i+1]));
3703            state->ps_const_i[StartRegister+i][2] = fui((float)(pConstantData[4*i+2]));
3704            state->ps_const_i[StartRegister+i][3] = fui((float)(pConstantData[4*i+3]));
3705        }
3706    }
3707
3708    if (unlikely(This->is_recording)) {
3709        state->changed.ps_const_i |= ((1 << Vector4iCount) - 1) << StartRegister;
3710        state->changed.group |= NINE_STATE_PS_CONST;
3711    } else
3712        nine_context_set_pixel_shader_constant_i(This, StartRegister, pConstantData, Vector4iCount);
3713
3714    return D3D_OK;
3715}
3716
3717HRESULT NINE_WINAPI
3718NineDevice9_GetPixelShaderConstantI( struct NineDevice9 *This,
3719                                     UINT StartRegister,
3720                                     int *pConstantData,
3721                                     UINT Vector4iCount )
3722{
3723    const struct nine_state *state = &This->state;
3724    int i;
3725
3726    user_assert(StartRegister                  < NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
3727    user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
3728    user_assert(pConstantData, D3DERR_INVALIDCALL);
3729
3730    if (This->driver_caps.ps_integer) {
3731        memcpy(pConstantData,
3732               &state->ps_const_i[StartRegister][0],
3733               Vector4iCount * sizeof(state->ps_const_i[0]));
3734    } else {
3735        for (i = 0; i < Vector4iCount; i++) {
3736            pConstantData[4*i] = (int32_t) uif(state->ps_const_i[StartRegister+i][0]);
3737            pConstantData[4*i+1] = (int32_t) uif(state->ps_const_i[StartRegister+i][1]);
3738            pConstantData[4*i+2] = (int32_t) uif(state->ps_const_i[StartRegister+i][2]);
3739            pConstantData[4*i+3] = (int32_t) uif(state->ps_const_i[StartRegister+i][3]);
3740        }
3741    }
3742
3743    return D3D_OK;
3744}
3745
3746HRESULT NINE_WINAPI
3747NineDevice9_SetPixelShaderConstantB( struct NineDevice9 *This,
3748                                     UINT StartRegister,
3749                                     const BOOL *pConstantData,
3750                                     UINT BoolCount )
3751{
3752    struct nine_state *state = This->update;
3753    int i;
3754    uint32_t bool_true = This->driver_caps.ps_integer ? 0xFFFFFFFF : fui(1.0f);
3755
3756    DBG("This=%p StartRegister=%u pConstantData=%p BoolCount=%u\n",
3757        This, StartRegister, pConstantData, BoolCount);
3758
3759    user_assert(StartRegister              < NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
3760    user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
3761    user_assert(pConstantData, D3DERR_INVALIDCALL);
3762
3763    if (!This->is_recording) {
3764        bool noChange = true;
3765        for (i = 0; i < BoolCount; i++) {
3766            if (!!state->ps_const_b[StartRegister + i] != !!pConstantData[i])
3767              noChange = false;
3768        }
3769        if (noChange)
3770            return D3D_OK;
3771    }
3772
3773    for (i = 0; i < BoolCount; i++)
3774        state->ps_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0;
3775
3776    if (unlikely(This->is_recording)) {
3777        state->changed.ps_const_b |= ((1 << BoolCount) - 1) << StartRegister;
3778        state->changed.group |= NINE_STATE_PS_CONST;
3779    } else
3780        nine_context_set_pixel_shader_constant_b(This, StartRegister, pConstantData, BoolCount);
3781
3782    return D3D_OK;
3783}
3784
3785HRESULT NINE_WINAPI
3786NineDevice9_GetPixelShaderConstantB( struct NineDevice9 *This,
3787                                     UINT StartRegister,
3788                                     BOOL *pConstantData,
3789                                     UINT BoolCount )
3790{
3791    const struct nine_state *state = &This->state;
3792    int i;
3793
3794    user_assert(StartRegister              < NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
3795    user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
3796    user_assert(pConstantData, D3DERR_INVALIDCALL);
3797
3798    for (i = 0; i < BoolCount; i++)
3799        pConstantData[i] = state->ps_const_b[StartRegister + i] ? TRUE : FALSE;
3800
3801    return D3D_OK;
3802}
3803
3804HRESULT NINE_WINAPI
3805NineDevice9_DrawRectPatch( struct NineDevice9 *This,
3806                           UINT Handle,
3807                           const float *pNumSegs,
3808                           const D3DRECTPATCH_INFO *pRectPatchInfo )
3809{
3810    STUB(D3DERR_INVALIDCALL);
3811}
3812
3813HRESULT NINE_WINAPI
3814NineDevice9_DrawTriPatch( struct NineDevice9 *This,
3815                          UINT Handle,
3816                          const float *pNumSegs,
3817                          const D3DTRIPATCH_INFO *pTriPatchInfo )
3818{
3819    STUB(D3DERR_INVALIDCALL);
3820}
3821
3822HRESULT NINE_WINAPI
3823NineDevice9_DeletePatch( struct NineDevice9 *This,
3824                         UINT Handle )
3825{
3826    STUB(D3DERR_INVALIDCALL);
3827}
3828
3829HRESULT NINE_WINAPI
3830NineDevice9_CreateQuery( struct NineDevice9 *This,
3831                         D3DQUERYTYPE Type,
3832                         IDirect3DQuery9 **ppQuery )
3833{
3834    struct NineQuery9 *query;
3835    HRESULT hr;
3836
3837    DBG("This=%p Type=%d ppQuery=%p\n", This, Type, ppQuery);
3838
3839    hr = nine_is_query_supported(This->screen, Type);
3840    if (!ppQuery || hr != D3D_OK)
3841        return hr;
3842
3843    hr = NineQuery9_new(This, &query, Type);
3844    if (FAILED(hr))
3845        return hr;
3846    *ppQuery = (IDirect3DQuery9 *)query;
3847    return D3D_OK;
3848}
3849
3850IDirect3DDevice9Vtbl NineDevice9_vtable = {
3851    (void *)NineUnknown_QueryInterface,
3852    (void *)NineUnknown_AddRef,
3853    (void *)NineUnknown_Release,
3854    (void *)NineDevice9_TestCooperativeLevel,
3855    (void *)NineDevice9_GetAvailableTextureMem,
3856    (void *)NineDevice9_EvictManagedResources,
3857    (void *)NineDevice9_GetDirect3D,
3858    (void *)NineDevice9_GetDeviceCaps,
3859    (void *)NineDevice9_GetDisplayMode,
3860    (void *)NineDevice9_GetCreationParameters,
3861    (void *)NineDevice9_SetCursorProperties,
3862    (void *)NineDevice9_SetCursorPosition,
3863    (void *)NineDevice9_ShowCursor,
3864    (void *)NineDevice9_CreateAdditionalSwapChain,
3865    (void *)NineDevice9_GetSwapChain,
3866    (void *)NineDevice9_GetNumberOfSwapChains,
3867    (void *)NineDevice9_Reset,
3868    (void *)NineDevice9_Present,
3869    (void *)NineDevice9_GetBackBuffer,
3870    (void *)NineDevice9_GetRasterStatus,
3871    (void *)NineDevice9_SetDialogBoxMode,
3872    (void *)NineDevice9_SetGammaRamp,
3873    (void *)NineDevice9_GetGammaRamp,
3874    (void *)NineDevice9_CreateTexture,
3875    (void *)NineDevice9_CreateVolumeTexture,
3876    (void *)NineDevice9_CreateCubeTexture,
3877    (void *)NineDevice9_CreateVertexBuffer,
3878    (void *)NineDevice9_CreateIndexBuffer,
3879    (void *)NineDevice9_CreateRenderTarget,
3880    (void *)NineDevice9_CreateDepthStencilSurface,
3881    (void *)NineDevice9_UpdateSurface,
3882    (void *)NineDevice9_UpdateTexture,
3883    (void *)NineDevice9_GetRenderTargetData,
3884    (void *)NineDevice9_GetFrontBufferData,
3885    (void *)NineDevice9_StretchRect,
3886    (void *)NineDevice9_ColorFill,
3887    (void *)NineDevice9_CreateOffscreenPlainSurface,
3888    (void *)NineDevice9_SetRenderTarget,
3889    (void *)NineDevice9_GetRenderTarget,
3890    (void *)NineDevice9_SetDepthStencilSurface,
3891    (void *)NineDevice9_GetDepthStencilSurface,
3892    (void *)NineDevice9_BeginScene,
3893    (void *)NineDevice9_EndScene,
3894    (void *)NineDevice9_Clear,
3895    (void *)NineDevice9_SetTransform,
3896    (void *)NineDevice9_GetTransform,
3897    (void *)NineDevice9_MultiplyTransform,
3898    (void *)NineDevice9_SetViewport,
3899    (void *)NineDevice9_GetViewport,
3900    (void *)NineDevice9_SetMaterial,
3901    (void *)NineDevice9_GetMaterial,
3902    (void *)NineDevice9_SetLight,
3903    (void *)NineDevice9_GetLight,
3904    (void *)NineDevice9_LightEnable,
3905    (void *)NineDevice9_GetLightEnable,
3906    (void *)NineDevice9_SetClipPlane,
3907    (void *)NineDevice9_GetClipPlane,
3908    (void *)NineDevice9_SetRenderState,
3909    (void *)NineDevice9_GetRenderState,
3910    (void *)NineDevice9_CreateStateBlock,
3911    (void *)NineDevice9_BeginStateBlock,
3912    (void *)NineDevice9_EndStateBlock,
3913    (void *)NineDevice9_SetClipStatus,
3914    (void *)NineDevice9_GetClipStatus,
3915    (void *)NineDevice9_GetTexture,
3916    (void *)NineDevice9_SetTexture,
3917    (void *)NineDevice9_GetTextureStageState,
3918    (void *)NineDevice9_SetTextureStageState,
3919    (void *)NineDevice9_GetSamplerState,
3920    (void *)NineDevice9_SetSamplerState,
3921    (void *)NineDevice9_ValidateDevice,
3922    (void *)NineDevice9_SetPaletteEntries,
3923    (void *)NineDevice9_GetPaletteEntries,
3924    (void *)NineDevice9_SetCurrentTexturePalette,
3925    (void *)NineDevice9_GetCurrentTexturePalette,
3926    (void *)NineDevice9_SetScissorRect,
3927    (void *)NineDevice9_GetScissorRect,
3928    (void *)NineDevice9_SetSoftwareVertexProcessing,
3929    (void *)NineDevice9_GetSoftwareVertexProcessing,
3930    (void *)NineDevice9_SetNPatchMode,
3931    (void *)NineDevice9_GetNPatchMode,
3932    (void *)NineDevice9_DrawPrimitive,
3933    (void *)NineDevice9_DrawIndexedPrimitive,
3934    (void *)NineDevice9_DrawPrimitiveUP,
3935    (void *)NineDevice9_DrawIndexedPrimitiveUP,
3936    (void *)NineDevice9_ProcessVertices,
3937    (void *)NineDevice9_CreateVertexDeclaration,
3938    (void *)NineDevice9_SetVertexDeclaration,
3939    (void *)NineDevice9_GetVertexDeclaration,
3940    (void *)NineDevice9_SetFVF,
3941    (void *)NineDevice9_GetFVF,
3942    (void *)NineDevice9_CreateVertexShader,
3943    (void *)NineDevice9_SetVertexShader,
3944    (void *)NineDevice9_GetVertexShader,
3945    (void *)NineDevice9_SetVertexShaderConstantF,
3946    (void *)NineDevice9_GetVertexShaderConstantF,
3947    (void *)NineDevice9_SetVertexShaderConstantI,
3948    (void *)NineDevice9_GetVertexShaderConstantI,
3949    (void *)NineDevice9_SetVertexShaderConstantB,
3950    (void *)NineDevice9_GetVertexShaderConstantB,
3951    (void *)NineDevice9_SetStreamSource,
3952    (void *)NineDevice9_GetStreamSource,
3953    (void *)NineDevice9_SetStreamSourceFreq,
3954    (void *)NineDevice9_GetStreamSourceFreq,
3955    (void *)NineDevice9_SetIndices,
3956    (void *)NineDevice9_GetIndices,
3957    (void *)NineDevice9_CreatePixelShader,
3958    (void *)NineDevice9_SetPixelShader,
3959    (void *)NineDevice9_GetPixelShader,
3960    (void *)NineDevice9_SetPixelShaderConstantF,
3961    (void *)NineDevice9_GetPixelShaderConstantF,
3962    (void *)NineDevice9_SetPixelShaderConstantI,
3963    (void *)NineDevice9_GetPixelShaderConstantI,
3964    (void *)NineDevice9_SetPixelShaderConstantB,
3965    (void *)NineDevice9_GetPixelShaderConstantB,
3966    (void *)NineDevice9_DrawRectPatch,
3967    (void *)NineDevice9_DrawTriPatch,
3968    (void *)NineDevice9_DeletePatch,
3969    (void *)NineDevice9_CreateQuery
3970};
3971
3972static const GUID *NineDevice9_IIDs[] = {
3973    &IID_IDirect3DDevice9,
3974    &IID_IUnknown,
3975    NULL
3976};
3977
3978HRESULT
3979NineDevice9_new( struct pipe_screen *pScreen,
3980                 D3DDEVICE_CREATION_PARAMETERS *pCreationParameters,
3981                 D3DCAPS9 *pCaps,
3982                 D3DPRESENT_PARAMETERS *pPresentationParameters,
3983                 IDirect3D9 *pD3D9,
3984                 ID3DPresentGroup *pPresentationGroup,
3985                 struct d3dadapter9_context *pCTX,
3986                 boolean ex,
3987                 D3DDISPLAYMODEEX *pFullscreenDisplayMode,
3988                 struct NineDevice9 **ppOut,
3989                 int minorVersionNum )
3990{
3991    BOOL lock;
3992    lock = !!(pCreationParameters->BehaviorFlags & D3DCREATE_MULTITHREADED);
3993
3994    NINE_NEW(Device9, ppOut, lock, /* args */
3995             pScreen, pCreationParameters, pCaps,
3996             pPresentationParameters, pD3D9, pPresentationGroup, pCTX,
3997             ex, pFullscreenDisplayMode, minorVersionNum );
3998}
3999