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