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