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