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