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