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