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