17ec681f3Smrg/*
27ec681f3Smrg * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub
87ec681f3Smrg * license, and/or sell copies of the Software, and to permit persons to whom
97ec681f3Smrg * the Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
197ec681f3Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
207ec681f3Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
217ec681f3Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */
227ec681f3Smrg
237ec681f3Smrg#include "device9.h"
247ec681f3Smrg#include "stateblock9.h"
257ec681f3Smrg#include "surface9.h"
267ec681f3Smrg#include "swapchain9.h"
277ec681f3Smrg#include "swapchain9ex.h"
287ec681f3Smrg#include "indexbuffer9.h"
297ec681f3Smrg#include "vertexbuffer9.h"
307ec681f3Smrg#include "vertexdeclaration9.h"
317ec681f3Smrg#include "vertexshader9.h"
327ec681f3Smrg#include "pixelshader9.h"
337ec681f3Smrg#include "query9.h"
347ec681f3Smrg#include "texture9.h"
357ec681f3Smrg#include "cubetexture9.h"
367ec681f3Smrg#include "volumetexture9.h"
377ec681f3Smrg#include "nine_buffer_upload.h"
387ec681f3Smrg#include "nine_helpers.h"
397ec681f3Smrg#include "nine_memory_helper.h"
407ec681f3Smrg#include "nine_pipe.h"
417ec681f3Smrg#include "nine_ff.h"
427ec681f3Smrg#include "nine_dump.h"
437ec681f3Smrg#include "nine_limits.h"
447ec681f3Smrg
457ec681f3Smrg#include "pipe/p_screen.h"
467ec681f3Smrg#include "pipe/p_context.h"
477ec681f3Smrg#include "pipe/p_config.h"
487ec681f3Smrg#include "util/macros.h"
497ec681f3Smrg#include "util/u_math.h"
507ec681f3Smrg#include "util/u_inlines.h"
517ec681f3Smrg#include "util/u_hash_table.h"
527ec681f3Smrg#include "util/format/u_format.h"
537ec681f3Smrg#include "util/u_surface.h"
547ec681f3Smrg#include "util/u_upload_mgr.h"
557ec681f3Smrg#include "hud/hud_context.h"
567ec681f3Smrg#include "compiler/glsl_types.h"
577ec681f3Smrg
587ec681f3Smrg#include "cso_cache/cso_context.h"
597ec681f3Smrg
607ec681f3Smrg#define DBG_CHANNEL DBG_DEVICE
617ec681f3Smrg
627ec681f3Smrg#if defined(PIPE_CC_GCC) && (defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64))
637ec681f3Smrg
647ec681f3Smrgstatic void nine_setup_fpu()
657ec681f3Smrg{
667ec681f3Smrg    uint16_t c;
677ec681f3Smrg
687ec681f3Smrg    __asm__ __volatile__ ("fnstcw %0" : "=m" (*&c));
697ec681f3Smrg
707ec681f3Smrg    /* clear the control word */
717ec681f3Smrg    c &= 0xF0C0;
727ec681f3Smrg    /* d3d9 doc/wine tests: mask all exceptions, use single-precision
737ec681f3Smrg     * and round to nearest */
747ec681f3Smrg    c |= 0x003F;
757ec681f3Smrg
767ec681f3Smrg    __asm__ __volatile__ ("fldcw %0" : : "m" (*&c));
777ec681f3Smrg}
787ec681f3Smrg
797ec681f3Smrgstatic void nine_setup_set_fpu(uint16_t val)
807ec681f3Smrg{
817ec681f3Smrg    __asm__ __volatile__ ("fldcw %0" : : "m" (*&val));
827ec681f3Smrg}
837ec681f3Smrg
847ec681f3Smrgstatic uint16_t nine_setup_get_fpu()
857ec681f3Smrg{
867ec681f3Smrg    uint16_t c;
877ec681f3Smrg
887ec681f3Smrg    __asm__ __volatile__ ("fnstcw %0" : "=m" (*&c));
897ec681f3Smrg    return c;
907ec681f3Smrg}
917ec681f3Smrg
927ec681f3Smrg#else
937ec681f3Smrg
947ec681f3Smrgstatic void nine_setup_fpu(void)
957ec681f3Smrg{
967ec681f3Smrg    WARN_ONCE("FPU setup not supported on non-x86 platforms\n");
977ec681f3Smrg}
987ec681f3Smrg
997ec681f3Smrgstatic void nine_setup_set_fpu(UNUSED uint16_t val)
1007ec681f3Smrg{
1017ec681f3Smrg    WARN_ONCE("FPU setup not supported on non-x86 platforms\n");
1027ec681f3Smrg}
1037ec681f3Smrg
1047ec681f3Smrgstatic uint16_t nine_setup_get_fpu()
1057ec681f3Smrg{
1067ec681f3Smrg    WARN_ONCE("FPU setup not supported on non-x86 platforms\n");
1077ec681f3Smrg    return 0;
1087ec681f3Smrg}
1097ec681f3Smrg
1107ec681f3Smrg#endif
1117ec681f3Smrg
1127ec681f3Smrgstruct pipe_resource *
1137ec681f3Smrgnine_resource_create_with_retry( struct NineDevice9 *This,
1147ec681f3Smrg                                 struct pipe_screen *screen,
1157ec681f3Smrg                                 const struct pipe_resource *templat )
1167ec681f3Smrg{
1177ec681f3Smrg    struct pipe_resource *res;
1187ec681f3Smrg    res = screen->resource_create(screen, templat);
1197ec681f3Smrg    if (res)
1207ec681f3Smrg        return res;
1217ec681f3Smrg    /* Allocation failed, retry after freeing some resources
1227ec681f3Smrg     * Note: Shouldn't be called from the worker thread */
1237ec681f3Smrg    if (!This)
1247ec681f3Smrg        return NULL;
1257ec681f3Smrg    /* Evict resources we can evict */
1267ec681f3Smrg    NineDevice9_EvictManagedResourcesInternal(This);
1277ec681f3Smrg    /* Execute anything pending, such that some
1287ec681f3Smrg     * deleted resources can be actually freed */
1297ec681f3Smrg    nine_csmt_process(This);
1307ec681f3Smrg    /* We could also finish the context, if needed */
1317ec681f3Smrg    return screen->resource_create(screen, templat);
1327ec681f3Smrg}
1337ec681f3Smrg
1347ec681f3Smrgvoid
1357ec681f3SmrgNineDevice9_SetDefaultState( struct NineDevice9 *This, boolean is_reset )
1367ec681f3Smrg{
1377ec681f3Smrg    struct NineSurface9 *refSurf = NULL;
1387ec681f3Smrg
1397ec681f3Smrg    DBG("This=%p is_reset=%d\n", This, (int) is_reset);
1407ec681f3Smrg
1417ec681f3Smrg    assert(!This->is_recording);
1427ec681f3Smrg
1437ec681f3Smrg    nine_state_set_defaults(This, &This->caps, is_reset);
1447ec681f3Smrg
1457ec681f3Smrg    refSurf = This->swapchains[0]->buffers[0];
1467ec681f3Smrg    assert(refSurf);
1477ec681f3Smrg
1487ec681f3Smrg    This->state.viewport.X = 0;
1497ec681f3Smrg    This->state.viewport.Y = 0;
1507ec681f3Smrg    This->state.viewport.Width = refSurf->desc.Width;
1517ec681f3Smrg    This->state.viewport.Height = refSurf->desc.Height;
1527ec681f3Smrg
1537ec681f3Smrg    nine_context_set_viewport(This, &This->state.viewport);
1547ec681f3Smrg
1557ec681f3Smrg    This->state.scissor.minx = 0;
1567ec681f3Smrg    This->state.scissor.miny = 0;
1577ec681f3Smrg    This->state.scissor.maxx = refSurf->desc.Width;
1587ec681f3Smrg    This->state.scissor.maxy = refSurf->desc.Height;
1597ec681f3Smrg
1607ec681f3Smrg    nine_context_set_scissor(This, &This->state.scissor);
1617ec681f3Smrg
1627ec681f3Smrg    if (This->nswapchains && This->swapchains[0]->params.EnableAutoDepthStencil) {
1637ec681f3Smrg        nine_context_set_render_state(This, D3DRS_ZENABLE, TRUE);
1647ec681f3Smrg        This->state.rs_advertised[D3DRS_ZENABLE] = TRUE;
1657ec681f3Smrg    }
1667ec681f3Smrg    if (This->state.rs_advertised[D3DRS_ZENABLE])
1677ec681f3Smrg        NineDevice9_SetDepthStencilSurface(
1687ec681f3Smrg            This, (IDirect3DSurface9 *)This->swapchains[0]->zsbuf);
1697ec681f3Smrg}
1707ec681f3Smrg
1717ec681f3Smrg#define GET_PCAP(n) pScreen->get_param(pScreen, PIPE_CAP_##n)
1727ec681f3SmrgHRESULT
1737ec681f3SmrgNineDevice9_ctor( struct NineDevice9 *This,
1747ec681f3Smrg                  struct NineUnknownParams *pParams,
1757ec681f3Smrg                  struct pipe_screen *pScreen,
1767ec681f3Smrg                  D3DDEVICE_CREATION_PARAMETERS *pCreationParameters,
1777ec681f3Smrg                  D3DCAPS9 *pCaps,
1787ec681f3Smrg                  D3DPRESENT_PARAMETERS *pPresentationParameters,
1797ec681f3Smrg                  IDirect3D9 *pD3D9,
1807ec681f3Smrg                  ID3DPresentGroup *pPresentationGroup,
1817ec681f3Smrg                  struct d3dadapter9_context *pCTX,
1827ec681f3Smrg                  boolean ex,
1837ec681f3Smrg                  D3DDISPLAYMODEEX *pFullscreenDisplayMode,
1847ec681f3Smrg                  int minorVersionNum )
1857ec681f3Smrg{
1867ec681f3Smrg    unsigned i;
1877ec681f3Smrg    uint16_t fpu_cw = 0;
1887ec681f3Smrg    HRESULT hr = NineUnknown_ctor(&This->base, pParams);
1897ec681f3Smrg
1907ec681f3Smrg    DBG("This=%p pParams=%p pScreen=%p pCreationParameters=%p pCaps=%p pPresentationParameters=%p "
1917ec681f3Smrg        "pD3D9=%p pPresentationGroup=%p pCTX=%p ex=%d pFullscreenDisplayMode=%p\n",
1927ec681f3Smrg        This, pParams, pScreen, pCreationParameters, pCaps, pPresentationParameters, pD3D9,
1937ec681f3Smrg        pPresentationGroup, pCTX, (int) ex, pFullscreenDisplayMode);
1947ec681f3Smrg
1957ec681f3Smrg    if (FAILED(hr)) { return hr; }
1967ec681f3Smrg
1977ec681f3Smrg    /* NIR shaders need to use GLSL types so let's initialize them here */
1987ec681f3Smrg    glsl_type_singleton_init_or_ref();
1997ec681f3Smrg
2007ec681f3Smrg    list_inithead(&This->update_buffers);
2017ec681f3Smrg    list_inithead(&This->update_textures);
2027ec681f3Smrg    list_inithead(&This->managed_buffers);
2037ec681f3Smrg    list_inithead(&This->managed_textures);
2047ec681f3Smrg
2057ec681f3Smrg    This->screen = pScreen;
2067ec681f3Smrg    This->screen_sw = pCTX->ref;
2077ec681f3Smrg    This->caps = *pCaps;
2087ec681f3Smrg    This->d3d9 = pD3D9;
2097ec681f3Smrg    This->params = *pCreationParameters;
2107ec681f3Smrg    This->ex = ex;
2117ec681f3Smrg    This->present = pPresentationGroup;
2127ec681f3Smrg    This->minor_version_num = minorVersionNum;
2137ec681f3Smrg
2147ec681f3Smrg    /* Ex */
2157ec681f3Smrg    This->gpu_priority = 0;
2167ec681f3Smrg    This->max_frame_latency = 3;
2177ec681f3Smrg
2187ec681f3Smrg    IDirect3D9_AddRef(This->d3d9);
2197ec681f3Smrg    ID3DPresentGroup_AddRef(This->present);
2207ec681f3Smrg
2217ec681f3Smrg    if (!(This->params.BehaviorFlags & D3DCREATE_FPU_PRESERVE)) {
2227ec681f3Smrg        nine_setup_fpu();
2237ec681f3Smrg    } else {
2247ec681f3Smrg        /* Software renderer initialization needs exceptions masked */
2257ec681f3Smrg        fpu_cw = nine_setup_get_fpu();
2267ec681f3Smrg        nine_setup_set_fpu(fpu_cw | 0x007f);
2277ec681f3Smrg    }
2287ec681f3Smrg
2297ec681f3Smrg    if (This->params.BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) {
2307ec681f3Smrg        DBG("Application asked full Software Vertex Processing.\n");
2317ec681f3Smrg        This->swvp = true;
2327ec681f3Smrg        This->may_swvp = true;
2337ec681f3Smrg    } else
2347ec681f3Smrg        This->swvp = false;
2357ec681f3Smrg    if (This->params.BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) {
2367ec681f3Smrg        DBG("Application asked mixed Software Vertex Processing.\n");
2377ec681f3Smrg        This->may_swvp = true;
2387ec681f3Smrg    }
2397ec681f3Smrg    This->context.swvp = This->swvp;
2407ec681f3Smrg    /* TODO: check if swvp is resetted by device Resets */
2417ec681f3Smrg
2427ec681f3Smrg    if (This->may_swvp &&
2437ec681f3Smrg        (This->screen->get_shader_param(This->screen, PIPE_SHADER_VERTEX,
2447ec681f3Smrg                                        PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE)
2457ec681f3Smrg                                     < (NINE_MAX_CONST_F_SWVP/2) * sizeof(float[4]) ||
2467ec681f3Smrg         This->screen->get_shader_param(This->screen, PIPE_SHADER_VERTEX,
2477ec681f3Smrg                                        PIPE_SHADER_CAP_MAX_CONST_BUFFERS) < 5)) {
2487ec681f3Smrg        /* Note: We just go on, some apps never use the abilities of
2497ec681f3Smrg         * swvp, and just set more constants than allowed at init.
2507ec681f3Smrg         * Only cards we support that are affected are the r500 */
2517ec681f3Smrg        WARN("Card unable to handle Software Vertex Processing. Game may fail\n");
2527ec681f3Smrg    }
2537ec681f3Smrg
2547ec681f3Smrg    /* When may_swvp, SetConstant* limits are different */
2557ec681f3Smrg    if (This->may_swvp)
2567ec681f3Smrg        This->caps.MaxVertexShaderConst = NINE_MAX_CONST_F_SWVP;
2577ec681f3Smrg
2587ec681f3Smrg    This->pure = !!(This->params.BehaviorFlags & D3DCREATE_PUREDEVICE);
2597ec681f3Smrg
2607ec681f3Smrg    This->context.pipe = This->screen->context_create(This->screen, NULL, PIPE_CONTEXT_PREFER_THREADED);
2617ec681f3Smrg    This->pipe_secondary = This->screen->context_create(This->screen, NULL, 0);
2627ec681f3Smrg    if (!This->context.pipe || !This->pipe_secondary) { return E_OUTOFMEMORY; } /* guess */
2637ec681f3Smrg    This->pipe_sw = This->screen_sw->context_create(This->screen_sw, NULL, PIPE_CONTEXT_PREFER_THREADED);
2647ec681f3Smrg    if (!This->pipe_sw) { return E_OUTOFMEMORY; }
2657ec681f3Smrg
2667ec681f3Smrg    This->context.cso = cso_create_context(This->context.pipe, CSO_NO_USER_VERTEX_BUFFERS);
2677ec681f3Smrg    if (!This->context.cso) { return E_OUTOFMEMORY; } /* also a guess */
2687ec681f3Smrg    This->cso_sw = cso_create_context(This->pipe_sw, 0);
2697ec681f3Smrg    if (!This->cso_sw) { return E_OUTOFMEMORY; }
2707ec681f3Smrg
2717ec681f3Smrg    /* Create first, it messes up our state. */
2727ec681f3Smrg    This->hud = hud_create(This->context.cso, NULL, NULL); /* NULL result is fine */
2737ec681f3Smrg
2747ec681f3Smrg    This->allocator = nine_allocator_create(This, pCTX->memfd_virtualsizelimit);
2757ec681f3Smrg
2767ec681f3Smrg    /* Available memory counter. Updated only for allocations with this device
2777ec681f3Smrg     * instance. This is the Win 7 behavior.
2787ec681f3Smrg     * Win XP shares this counter across multiple devices. */
2797ec681f3Smrg    This->available_texture_mem = This->screen->get_param(This->screen, PIPE_CAP_VIDEO_MEMORY);
2807ec681f3Smrg    This->available_texture_mem =  (pCTX->override_vram_size >= 0) ?
2817ec681f3Smrg        (long long)pCTX->override_vram_size : This->available_texture_mem;
2827ec681f3Smrg    This->available_texture_mem <<= 20;
2837ec681f3Smrg
2847ec681f3Smrg    /* We cap texture memory usage to 95% of what is reported free initially
2857ec681f3Smrg     * This helps get closer Win behaviour. For example VertexBuffer allocation
2867ec681f3Smrg     * still succeeds when texture allocation fails. */
2877ec681f3Smrg    This->available_texture_limit = This->available_texture_mem * 5LL / 100LL;
2887ec681f3Smrg
2897ec681f3Smrg    This->frame_count = 0; /* Used to check if events occur the same frame */
2907ec681f3Smrg
2917ec681f3Smrg    /* create implicit swapchains */
2927ec681f3Smrg    This->nswapchains = ID3DPresentGroup_GetMultiheadCount(This->present);
2937ec681f3Smrg    This->swapchains = CALLOC(This->nswapchains,
2947ec681f3Smrg                              sizeof(struct NineSwapChain9 *));
2957ec681f3Smrg    if (!This->swapchains) { return E_OUTOFMEMORY; }
2967ec681f3Smrg
2977ec681f3Smrg    for (i = 0; i < This->nswapchains; ++i) {
2987ec681f3Smrg        ID3DPresent *present;
2997ec681f3Smrg
3007ec681f3Smrg        hr = ID3DPresentGroup_GetPresent(This->present, i, &present);
3017ec681f3Smrg        if (FAILED(hr))
3027ec681f3Smrg            return hr;
3037ec681f3Smrg
3047ec681f3Smrg        if (ex) {
3057ec681f3Smrg            D3DDISPLAYMODEEX *mode = NULL;
3067ec681f3Smrg            struct NineSwapChain9Ex **ret =
3077ec681f3Smrg                (struct NineSwapChain9Ex **)&This->swapchains[i];
3087ec681f3Smrg
3097ec681f3Smrg            if (pFullscreenDisplayMode) mode = &(pFullscreenDisplayMode[i]);
3107ec681f3Smrg            /* when this is a Device9Ex, it should create SwapChain9Exs */
3117ec681f3Smrg            hr = NineSwapChain9Ex_new(This, TRUE, present,
3127ec681f3Smrg                                      &pPresentationParameters[i], pCTX,
3137ec681f3Smrg                                      This->params.hFocusWindow, mode, ret);
3147ec681f3Smrg        } else {
3157ec681f3Smrg            hr = NineSwapChain9_new(This, TRUE, present,
3167ec681f3Smrg                                    &pPresentationParameters[i], pCTX,
3177ec681f3Smrg                                    This->params.hFocusWindow,
3187ec681f3Smrg                                    &This->swapchains[i]);
3197ec681f3Smrg        }
3207ec681f3Smrg
3217ec681f3Smrg        ID3DPresent_Release(present);
3227ec681f3Smrg        if (FAILED(hr))
3237ec681f3Smrg            return hr;
3247ec681f3Smrg        NineUnknown_ConvertRefToBind(NineUnknown(This->swapchains[i]));
3257ec681f3Smrg
3267ec681f3Smrg        hr = NineSwapChain9_GetBackBuffer(This->swapchains[i], 0,
3277ec681f3Smrg                                          D3DBACKBUFFER_TYPE_MONO,
3287ec681f3Smrg                                          (IDirect3DSurface9 **)
3297ec681f3Smrg                                          &This->state.rt[i]);
3307ec681f3Smrg        if (FAILED(hr))
3317ec681f3Smrg            return hr;
3327ec681f3Smrg        NineUnknown_ConvertRefToBind(NineUnknown(This->state.rt[i]));
3337ec681f3Smrg        nine_bind(&This->context.rt[i], This->state.rt[i]);
3347ec681f3Smrg    }
3357ec681f3Smrg
3367ec681f3Smrg    /* Initialize CSMT */
3377ec681f3Smrg    /* r600, radeonsi and iris are thread safe. */
3387ec681f3Smrg    if (pCTX->csmt_force == 1)
3397ec681f3Smrg        This->csmt_active = true;
3407ec681f3Smrg    else if (pCTX->csmt_force == 0)
3417ec681f3Smrg        This->csmt_active = false;
3427ec681f3Smrg    else if (strstr(pScreen->get_name(pScreen), "AMD") != NULL)
3437ec681f3Smrg        This->csmt_active = true;
3447ec681f3Smrg    else if (strstr(pScreen->get_name(pScreen), "Intel") != NULL)
3457ec681f3Smrg        This->csmt_active = true;
3467ec681f3Smrg
3477ec681f3Smrg    /* We rely on u_upload_mgr using persistent coherent buffers (which don't
3487ec681f3Smrg     * require flush to work in multi-pipe_context scenario) for vertex and
3497ec681f3Smrg     * index buffers */
3507ec681f3Smrg    if (!GET_PCAP(BUFFER_MAP_PERSISTENT_COHERENT))
3517ec681f3Smrg        This->csmt_active = false;
3527ec681f3Smrg
3537ec681f3Smrg    if (This->csmt_active) {
3547ec681f3Smrg        This->csmt_ctx = nine_csmt_create(This);
3557ec681f3Smrg        if (!This->csmt_ctx)
3567ec681f3Smrg            return E_OUTOFMEMORY;
3577ec681f3Smrg    }
3587ec681f3Smrg
3597ec681f3Smrg    if (This->csmt_active)
3607ec681f3Smrg        DBG("\033[1;32mCSMT is active\033[0m\n");
3617ec681f3Smrg
3627ec681f3Smrg    This->workarounds.dynamic_texture_workaround = pCTX->dynamic_texture_workaround;
3637ec681f3Smrg
3647ec681f3Smrg    /* Due to the pb_cache, in some cases the buffer_upload path can increase GTT usage/virtual memory.
3657ec681f3Smrg     * As the performance gain is negligible when csmt is off, disable it in this case.
3667ec681f3Smrg     * That way csmt_force=0 can be used as a workaround to reduce GTT usage/virtual memory. */
3677ec681f3Smrg    This->buffer_upload = This->csmt_active ? nine_upload_create(This->pipe_secondary, 4 * 1024 * 1024, 4) : NULL;
3687ec681f3Smrg
3697ec681f3Smrg    /* Initialize a dummy VBO to be used when a vertex declaration does not
3707ec681f3Smrg     * specify all the inputs needed by vertex shader, on win default behavior
3717ec681f3Smrg     * is to pass 0,0,0,0 to the shader */
3727ec681f3Smrg    {
3737ec681f3Smrg        struct pipe_transfer *transfer;
3747ec681f3Smrg        struct pipe_resource tmpl;
3757ec681f3Smrg        struct pipe_box box;
3767ec681f3Smrg        unsigned char *data;
3777ec681f3Smrg
3787ec681f3Smrg        memset(&tmpl, 0, sizeof(tmpl));
3797ec681f3Smrg        tmpl.target = PIPE_BUFFER;
3807ec681f3Smrg        tmpl.format = PIPE_FORMAT_R8_UNORM;
3817ec681f3Smrg        tmpl.width0 = 16; /* 4 floats */
3827ec681f3Smrg        tmpl.height0 = 1;
3837ec681f3Smrg        tmpl.depth0 = 1;
3847ec681f3Smrg        tmpl.array_size = 1;
3857ec681f3Smrg        tmpl.last_level = 0;
3867ec681f3Smrg        tmpl.nr_samples = 0;
3877ec681f3Smrg        tmpl.usage = PIPE_USAGE_DEFAULT;
3887ec681f3Smrg        tmpl.bind = PIPE_BIND_VERTEX_BUFFER;
3897ec681f3Smrg        tmpl.flags = 0;
3907ec681f3Smrg        This->dummy_vbo = pScreen->resource_create(pScreen, &tmpl);
3917ec681f3Smrg
3927ec681f3Smrg        if (!This->dummy_vbo)
3937ec681f3Smrg            return D3DERR_OUTOFVIDEOMEMORY;
3947ec681f3Smrg
3957ec681f3Smrg        u_box_1d(0, 16, &box);
3967ec681f3Smrg        data = This->context.pipe->buffer_map(This->context.pipe, This->dummy_vbo, 0,
3977ec681f3Smrg                                        PIPE_MAP_WRITE |
3987ec681f3Smrg                                        PIPE_MAP_DISCARD_WHOLE_RESOURCE,
3997ec681f3Smrg                                        &box, &transfer);
4007ec681f3Smrg        assert(data);
4017ec681f3Smrg        assert(transfer);
4027ec681f3Smrg        memset(data, 0, 16);
4037ec681f3Smrg        This->context.pipe->buffer_unmap(This->context.pipe, transfer);
4047ec681f3Smrg    }
4057ec681f3Smrg
4067ec681f3Smrg    This->cursor.software = FALSE;
4077ec681f3Smrg    This->cursor.hotspot.x = -1;
4087ec681f3Smrg    This->cursor.hotspot.y = -1;
4097ec681f3Smrg    This->cursor.w = This->cursor.h = 0;
4107ec681f3Smrg    This->cursor.visible = FALSE;
4117ec681f3Smrg    if (ID3DPresent_GetCursorPos(This->swapchains[0]->present, &This->cursor.pos) != S_OK) {
4127ec681f3Smrg        This->cursor.pos.x = 0;
4137ec681f3Smrg        This->cursor.pos.y = 0;
4147ec681f3Smrg    }
4157ec681f3Smrg
4167ec681f3Smrg    {
4177ec681f3Smrg        struct pipe_resource tmpl;
4187ec681f3Smrg        memset(&tmpl, 0, sizeof(tmpl));
4197ec681f3Smrg        tmpl.target = PIPE_TEXTURE_2D;
4207ec681f3Smrg        tmpl.format = PIPE_FORMAT_R8G8B8A8_UNORM;
4217ec681f3Smrg        tmpl.width0 = 64;
4227ec681f3Smrg        tmpl.height0 = 64;
4237ec681f3Smrg        tmpl.depth0 = 1;
4247ec681f3Smrg        tmpl.array_size = 1;
4257ec681f3Smrg        tmpl.last_level = 0;
4267ec681f3Smrg        tmpl.nr_samples = 0;
4277ec681f3Smrg        tmpl.usage = PIPE_USAGE_DEFAULT;
4287ec681f3Smrg        tmpl.bind = PIPE_BIND_CURSOR | PIPE_BIND_SAMPLER_VIEW;
4297ec681f3Smrg        tmpl.flags = 0;
4307ec681f3Smrg
4317ec681f3Smrg        This->cursor.image = pScreen->resource_create(pScreen, &tmpl);
4327ec681f3Smrg        if (!This->cursor.image)
4337ec681f3Smrg            return D3DERR_OUTOFVIDEOMEMORY;
4347ec681f3Smrg
4357ec681f3Smrg        /* For uploading 32x32 (argb) cursor */
4367ec681f3Smrg        This->cursor.hw_upload_temp = MALLOC(32 * 4 * 32);
4377ec681f3Smrg        if (!This->cursor.hw_upload_temp)
4387ec681f3Smrg            return D3DERR_OUTOFVIDEOMEMORY;
4397ec681f3Smrg    }
4407ec681f3Smrg
4417ec681f3Smrg    /* Create constant buffers. */
4427ec681f3Smrg    {
4437ec681f3Smrg        unsigned max_const_vs, max_const_ps;
4447ec681f3Smrg
4457ec681f3Smrg        /* vs 3.0: >= 256 float constants, but for cards with exactly 256 slots,
4467ec681f3Smrg         * we have to take in some more slots for int and bool*/
4477ec681f3Smrg        max_const_vs = _min(pScreen->get_shader_param(pScreen, PIPE_SHADER_VERTEX,
4487ec681f3Smrg                                PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE) /
4497ec681f3Smrg                                sizeof(float[4]),
4507ec681f3Smrg                            NINE_MAX_CONST_ALL);
4517ec681f3Smrg        /* ps 3.0: 224 float constants. All cards supported support at least
4527ec681f3Smrg         * 256 constants for ps */
4537ec681f3Smrg        max_const_ps = NINE_MAX_CONST_F_PS3 + (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4);
4547ec681f3Smrg
4557ec681f3Smrg        This->max_vs_const_f = max_const_vs -
4567ec681f3Smrg                               (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4);
4577ec681f3Smrg        This->max_ps_const_f = max_const_ps -
4587ec681f3Smrg                               (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4);
4597ec681f3Smrg
4607ec681f3Smrg        This->vs_const_size = max_const_vs * sizeof(float[4]);
4617ec681f3Smrg        This->ps_const_size = max_const_ps * sizeof(float[4]);
4627ec681f3Smrg        /* Include space for I,B constants for user constbuf. */
4637ec681f3Smrg        if (This->may_swvp) {
4647ec681f3Smrg            This->state.vs_const_f = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1);
4657ec681f3Smrg            This->context.vs_const_f_swvp = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1);
4667ec681f3Smrg            if (!This->context.vs_const_f_swvp)
4677ec681f3Smrg                return E_OUTOFMEMORY;
4687ec681f3Smrg            This->state.vs_lconstf_temp = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1);
4697ec681f3Smrg            This->context.vs_lconstf_temp = CALLOC(NINE_MAX_CONST_F_SWVP * sizeof(float[4]),1);
4707ec681f3Smrg            This->state.vs_const_i = CALLOC(NINE_MAX_CONST_I_SWVP * sizeof(int[4]), 1);
4717ec681f3Smrg            This->context.vs_const_i = CALLOC(NINE_MAX_CONST_I_SWVP * sizeof(int[4]), 1);
4727ec681f3Smrg            This->state.vs_const_b = CALLOC(NINE_MAX_CONST_B_SWVP * sizeof(BOOL), 1);
4737ec681f3Smrg            This->context.vs_const_b = CALLOC(NINE_MAX_CONST_B_SWVP * sizeof(BOOL), 1);
4747ec681f3Smrg        } else {
4757ec681f3Smrg            This->state.vs_const_f = CALLOC(NINE_MAX_CONST_F * sizeof(float[4]), 1);
4767ec681f3Smrg            This->context.vs_const_f_swvp = NULL;
4777ec681f3Smrg            This->state.vs_lconstf_temp = CALLOC(This->vs_const_size,1);
4787ec681f3Smrg            This->context.vs_lconstf_temp = CALLOC(This->vs_const_size,1);
4797ec681f3Smrg            This->state.vs_const_i = CALLOC(NINE_MAX_CONST_I * sizeof(int[4]), 1);
4807ec681f3Smrg            This->context.vs_const_i = CALLOC(NINE_MAX_CONST_I * sizeof(int[4]), 1);
4817ec681f3Smrg            This->state.vs_const_b = CALLOC(NINE_MAX_CONST_B * sizeof(BOOL), 1);
4827ec681f3Smrg            This->context.vs_const_b = CALLOC(NINE_MAX_CONST_B * sizeof(BOOL), 1);
4837ec681f3Smrg        }
4847ec681f3Smrg        This->context.vs_const_f = CALLOC(This->vs_const_size, 1);
4857ec681f3Smrg        This->state.ps_const_f = CALLOC(This->ps_const_size, 1);
4867ec681f3Smrg        This->context.ps_const_f = CALLOC(This->ps_const_size, 1);
4877ec681f3Smrg        This->context.ps_lconstf_temp = CALLOC(This->ps_const_size,1);
4887ec681f3Smrg        if (!This->state.vs_const_f || !This->context.vs_const_f ||
4897ec681f3Smrg            !This->state.ps_const_f || !This->context.ps_const_f ||
4907ec681f3Smrg            !This->state.vs_lconstf_temp || !This->context.vs_lconstf_temp ||
4917ec681f3Smrg            !This->context.ps_lconstf_temp ||
4927ec681f3Smrg            !This->state.vs_const_i || !This->context.vs_const_i ||
4937ec681f3Smrg            !This->state.vs_const_b || !This->context.vs_const_b)
4947ec681f3Smrg            return E_OUTOFMEMORY;
4957ec681f3Smrg
4967ec681f3Smrg        if (strstr(pScreen->get_name(pScreen), "AMD") ||
4977ec681f3Smrg            strstr(pScreen->get_name(pScreen), "ATI")) {
4987ec681f3Smrg            This->driver_bugs.buggy_barycentrics = TRUE;
4997ec681f3Smrg        }
5007ec681f3Smrg    }
5017ec681f3Smrg
5027ec681f3Smrg    /* allocate dummy texture/sampler for when there are missing ones bound */
5037ec681f3Smrg    {
5047ec681f3Smrg        struct pipe_resource tmplt;
5057ec681f3Smrg        struct pipe_sampler_view templ;
5067ec681f3Smrg        struct pipe_sampler_state samp;
5077ec681f3Smrg        memset(&tmplt, 0, sizeof(tmplt));
5087ec681f3Smrg        memset(&samp, 0, sizeof(samp));
5097ec681f3Smrg
5107ec681f3Smrg        tmplt.target = PIPE_TEXTURE_2D;
5117ec681f3Smrg        tmplt.width0 = 1;
5127ec681f3Smrg        tmplt.height0 = 1;
5137ec681f3Smrg        tmplt.depth0 = 1;
5147ec681f3Smrg        tmplt.last_level = 0;
5157ec681f3Smrg        tmplt.array_size = 1;
5167ec681f3Smrg        tmplt.usage = PIPE_USAGE_DEFAULT;
5177ec681f3Smrg        tmplt.flags = 0;
5187ec681f3Smrg        tmplt.format = PIPE_FORMAT_B8G8R8A8_UNORM;
5197ec681f3Smrg        tmplt.bind = PIPE_BIND_SAMPLER_VIEW;
5207ec681f3Smrg        tmplt.nr_samples = 0;
5217ec681f3Smrg
5227ec681f3Smrg        This->dummy_texture = This->screen->resource_create(This->screen, &tmplt);
5237ec681f3Smrg        if (!This->dummy_texture)
5247ec681f3Smrg            return D3DERR_DRIVERINTERNALERROR;
5257ec681f3Smrg
5267ec681f3Smrg        templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
5277ec681f3Smrg        templ.u.tex.first_layer = 0;
5287ec681f3Smrg        templ.u.tex.last_layer = 0;
5297ec681f3Smrg        templ.u.tex.first_level = 0;
5307ec681f3Smrg        templ.u.tex.last_level = 0;
5317ec681f3Smrg        templ.swizzle_r = PIPE_SWIZZLE_0;
5327ec681f3Smrg        templ.swizzle_g = PIPE_SWIZZLE_0;
5337ec681f3Smrg        templ.swizzle_b = PIPE_SWIZZLE_0;
5347ec681f3Smrg        templ.swizzle_a = PIPE_SWIZZLE_1;
5357ec681f3Smrg        templ.target = This->dummy_texture->target;
5367ec681f3Smrg
5377ec681f3Smrg        This->dummy_sampler_view = This->context.pipe->create_sampler_view(This->context.pipe, This->dummy_texture, &templ);
5387ec681f3Smrg        if (!This->dummy_sampler_view)
5397ec681f3Smrg            return D3DERR_DRIVERINTERNALERROR;
5407ec681f3Smrg
5417ec681f3Smrg        samp.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
5427ec681f3Smrg        samp.max_lod = 15.0f;
5437ec681f3Smrg        samp.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
5447ec681f3Smrg        samp.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
5457ec681f3Smrg        samp.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
5467ec681f3Smrg        samp.min_img_filter = PIPE_TEX_FILTER_NEAREST;
5477ec681f3Smrg        samp.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
5487ec681f3Smrg        samp.compare_mode = PIPE_TEX_COMPARE_NONE;
5497ec681f3Smrg        samp.compare_func = PIPE_FUNC_LEQUAL;
5507ec681f3Smrg        samp.normalized_coords = 1;
5517ec681f3Smrg        samp.seamless_cube_map = 0;
5527ec681f3Smrg        This->dummy_sampler_state = samp;
5537ec681f3Smrg    }
5547ec681f3Smrg
5557ec681f3Smrg    /* Allocate upload helper for drivers that suck (from st pov ;). */
5567ec681f3Smrg
5577ec681f3Smrg    This->driver_caps.user_sw_vbufs = This->screen_sw->get_param(This->screen_sw, PIPE_CAP_USER_VERTEX_BUFFERS);
5587ec681f3Smrg    This->vertex_uploader = This->csmt_active ? This->pipe_secondary->stream_uploader : This->context.pipe->stream_uploader;
5597ec681f3Smrg    This->driver_caps.window_space_position_support = GET_PCAP(TGSI_VS_WINDOW_SPACE_POSITION);
5607ec681f3Smrg    This->driver_caps.vs_integer = pScreen->get_shader_param(pScreen, PIPE_SHADER_VERTEX, PIPE_SHADER_CAP_INTEGERS);
5617ec681f3Smrg    This->driver_caps.ps_integer = pScreen->get_shader_param(pScreen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_INTEGERS);
5627ec681f3Smrg    This->driver_caps.offset_units_unscaled = GET_PCAP(POLYGON_OFFSET_UNITS_UNSCALED);
5637ec681f3Smrg
5647ec681f3Smrg    This->context.inline_constants = pCTX->shader_inline_constants;
5657ec681f3Smrg    /* Code would be needed when integers are not available to correctly
5667ec681f3Smrg     * handle the conversion of integer constants */
5677ec681f3Smrg    This->context.inline_constants &= This->driver_caps.vs_integer && This->driver_caps.ps_integer;
5687ec681f3Smrg
5697ec681f3Smrg    nine_ff_init(This); /* initialize fixed function code */
5707ec681f3Smrg
5717ec681f3Smrg    NineDevice9_SetDefaultState(This, FALSE);
5727ec681f3Smrg
5737ec681f3Smrg    {
5747ec681f3Smrg        struct pipe_poly_stipple stipple;
5757ec681f3Smrg        memset(&stipple, ~0, sizeof(stipple));
5767ec681f3Smrg        This->context.pipe->set_polygon_stipple(This->context.pipe, &stipple);
5777ec681f3Smrg    }
5787ec681f3Smrg
5797ec681f3Smrg    This->update = &This->state;
5807ec681f3Smrg
5817ec681f3Smrg    nine_state_init_sw(This);
5827ec681f3Smrg
5837ec681f3Smrg    ID3DPresentGroup_Release(This->present);
5847ec681f3Smrg    nine_context_update_state(This); /* Some drivers needs states to be initialized */
5857ec681f3Smrg    nine_csmt_process(This);
5867ec681f3Smrg
5877ec681f3Smrg    if (This->params.BehaviorFlags & D3DCREATE_FPU_PRESERVE)
5887ec681f3Smrg        nine_setup_set_fpu(fpu_cw);
5897ec681f3Smrg
5907ec681f3Smrg    return D3D_OK;
5917ec681f3Smrg}
5927ec681f3Smrg#undef GET_PCAP
5937ec681f3Smrg
5947ec681f3Smrgvoid
5957ec681f3SmrgNineDevice9_dtor( struct NineDevice9 *This )
5967ec681f3Smrg{
5977ec681f3Smrg    unsigned i;
5987ec681f3Smrg
5997ec681f3Smrg    DBG("This=%p\n", This);
6007ec681f3Smrg
6017ec681f3Smrg    /* Flush all pending commands to get refcount right,
6027ec681f3Smrg     * and properly release bound objects. It is ok to still
6037ec681f3Smrg     * execute commands while we are in device dtor, because
6047ec681f3Smrg     * we haven't released anything yet. Note that no pending
6057ec681f3Smrg     * command can increase the device refcount. */
6067ec681f3Smrg    if (This->csmt_active && This->csmt_ctx) {
6077ec681f3Smrg        nine_csmt_process(This);
6087ec681f3Smrg        nine_csmt_destroy(This, This->csmt_ctx);
6097ec681f3Smrg        This->csmt_active = FALSE;
6107ec681f3Smrg        This->csmt_ctx = NULL;
6117ec681f3Smrg    }
6127ec681f3Smrg
6137ec681f3Smrg    nine_ff_fini(This);
6147ec681f3Smrg    nine_state_destroy_sw(This);
6157ec681f3Smrg    nine_device_state_clear(This);
6167ec681f3Smrg    nine_context_clear(This);
6177ec681f3Smrg
6187ec681f3Smrg    nine_bind(&This->record, NULL);
6197ec681f3Smrg
6207ec681f3Smrg    pipe_sampler_view_reference(&This->dummy_sampler_view, NULL);
6217ec681f3Smrg    pipe_resource_reference(&This->dummy_texture, NULL);
6227ec681f3Smrg    pipe_resource_reference(&This->dummy_vbo, NULL);
6237ec681f3Smrg    FREE(This->state.vs_const_f);
6247ec681f3Smrg    FREE(This->context.vs_const_f);
6257ec681f3Smrg    FREE(This->state.ps_const_f);
6267ec681f3Smrg    FREE(This->context.ps_const_f);
6277ec681f3Smrg    FREE(This->state.vs_lconstf_temp);
6287ec681f3Smrg    FREE(This->context.vs_lconstf_temp);
6297ec681f3Smrg    FREE(This->context.ps_lconstf_temp);
6307ec681f3Smrg    FREE(This->state.vs_const_i);
6317ec681f3Smrg    FREE(This->context.vs_const_i);
6327ec681f3Smrg    FREE(This->state.vs_const_b);
6337ec681f3Smrg    FREE(This->context.vs_const_b);
6347ec681f3Smrg    FREE(This->context.vs_const_f_swvp);
6357ec681f3Smrg
6367ec681f3Smrg    pipe_resource_reference(&This->cursor.image, NULL);
6377ec681f3Smrg    FREE(This->cursor.hw_upload_temp);
6387ec681f3Smrg
6397ec681f3Smrg    if (This->swapchains) {
6407ec681f3Smrg        for (i = 0; i < This->nswapchains; ++i)
6417ec681f3Smrg            if (This->swapchains[i])
6427ec681f3Smrg                NineUnknown_Unbind(NineUnknown(This->swapchains[i]));
6437ec681f3Smrg        FREE(This->swapchains);
6447ec681f3Smrg    }
6457ec681f3Smrg
6467ec681f3Smrg    if (This->buffer_upload)
6477ec681f3Smrg        nine_upload_destroy(This->buffer_upload);
6487ec681f3Smrg
6497ec681f3Smrg    if (This->allocator)
6507ec681f3Smrg        nine_allocator_destroy(This->allocator);
6517ec681f3Smrg
6527ec681f3Smrg    /* Destroy cso first */
6537ec681f3Smrg    if (This->context.cso) { cso_destroy_context(This->context.cso); }
6547ec681f3Smrg    if (This->cso_sw) { cso_destroy_context(This->cso_sw); }
6557ec681f3Smrg    if (This->context.pipe && This->context.pipe->destroy) { This->context.pipe->destroy(This->context.pipe); }
6567ec681f3Smrg    if (This->pipe_secondary && This->pipe_secondary->destroy) { This->pipe_secondary->destroy(This->pipe_secondary); }
6577ec681f3Smrg    if (This->pipe_sw && This->pipe_sw->destroy) { This->pipe_sw->destroy(This->pipe_sw); }
6587ec681f3Smrg
6597ec681f3Smrg    if (This->present) { ID3DPresentGroup_Release(This->present); }
6607ec681f3Smrg    if (This->d3d9) { IDirect3D9_Release(This->d3d9); }
6617ec681f3Smrg
6627ec681f3Smrg    NineUnknown_dtor(&This->base);
6637ec681f3Smrg    glsl_type_singleton_decref();
6647ec681f3Smrg}
6657ec681f3Smrg
6667ec681f3Smrgstruct pipe_screen *
6677ec681f3SmrgNineDevice9_GetScreen( struct NineDevice9 *This )
6687ec681f3Smrg{
6697ec681f3Smrg    return This->screen;
6707ec681f3Smrg}
6717ec681f3Smrg
6727ec681f3Smrgstruct pipe_context *
6737ec681f3SmrgNineDevice9_GetPipe( struct NineDevice9 *This )
6747ec681f3Smrg{
6757ec681f3Smrg    return nine_context_get_pipe(This);
6767ec681f3Smrg}
6777ec681f3Smrg
6787ec681f3Smrgconst D3DCAPS9 *
6797ec681f3SmrgNineDevice9_GetCaps( struct NineDevice9 *This )
6807ec681f3Smrg{
6817ec681f3Smrg    return &This->caps;
6827ec681f3Smrg}
6837ec681f3Smrg
6847ec681f3Smrgstatic inline void
6857ec681f3SmrgNineDevice9_PauseRecording( struct NineDevice9 *This )
6867ec681f3Smrg{
6877ec681f3Smrg    if (This->record) {
6887ec681f3Smrg        This->update = &This->state;
6897ec681f3Smrg        This->is_recording = FALSE;
6907ec681f3Smrg    }
6917ec681f3Smrg}
6927ec681f3Smrg
6937ec681f3Smrgstatic inline void
6947ec681f3SmrgNineDevice9_ResumeRecording( struct NineDevice9 *This )
6957ec681f3Smrg{
6967ec681f3Smrg    if (This->record) {
6977ec681f3Smrg        This->update = &This->record->state;
6987ec681f3Smrg        This->is_recording = TRUE;
6997ec681f3Smrg    }
7007ec681f3Smrg}
7017ec681f3Smrg
7027ec681f3SmrgHRESULT NINE_WINAPI
7037ec681f3SmrgNineDevice9_TestCooperativeLevel( struct NineDevice9 *This )
7047ec681f3Smrg{
7057ec681f3Smrg    if (NineSwapChain9_GetOccluded(This->swapchains[0])) {
7067ec681f3Smrg        This->device_needs_reset = TRUE;
7077ec681f3Smrg        return D3DERR_DEVICELOST;
7087ec681f3Smrg    } else if (NineSwapChain9_ResolutionMismatch(This->swapchains[0])) {
7097ec681f3Smrg        This->device_needs_reset = TRUE;
7107ec681f3Smrg        return D3DERR_DEVICENOTRESET;
7117ec681f3Smrg    } else if (This->device_needs_reset) {
7127ec681f3Smrg        return D3DERR_DEVICENOTRESET;
7137ec681f3Smrg    }
7147ec681f3Smrg
7157ec681f3Smrg    return D3D_OK;
7167ec681f3Smrg}
7177ec681f3Smrg
7187ec681f3SmrgUINT NINE_WINAPI
7197ec681f3SmrgNineDevice9_GetAvailableTextureMem( struct NineDevice9 *This )
7207ec681f3Smrg{
7217ec681f3Smrg    /* To prevent overflows - Not sure how this should be handled */
7227ec681f3Smrg    return (UINT)MIN2(This->available_texture_mem, (long long)(UINT_MAX - (64 << 20))); /* 64 MB margin */
7237ec681f3Smrg}
7247ec681f3Smrg
7257ec681f3Smrgvoid
7267ec681f3SmrgNineDevice9_EvictManagedResourcesInternal( struct NineDevice9 *This )
7277ec681f3Smrg{
7287ec681f3Smrg    struct NineBaseTexture9 *tex;
7297ec681f3Smrg
7307ec681f3Smrg    DBG("This=%p\n", This);
7317ec681f3Smrg
7327ec681f3Smrg    /* This function is called internally when an allocation fails.
7337ec681f3Smrg     * We are supposed to release old unused managed textures/buffers,
7347ec681f3Smrg     * until we have enough space for the allocation.
7357ec681f3Smrg     * For now just release everything, except the bound textures,
7367ec681f3Smrg     * as this function can be called when uploading bound textures.
7377ec681f3Smrg     */
7387ec681f3Smrg    LIST_FOR_EACH_ENTRY(tex, &This->managed_textures, list2) {
7397ec681f3Smrg        if (!tex->bind_count)
7407ec681f3Smrg            NineBaseTexture9_UnLoad(tex);
7417ec681f3Smrg    }
7427ec681f3Smrg}
7437ec681f3Smrg
7447ec681f3SmrgHRESULT NINE_WINAPI
7457ec681f3SmrgNineDevice9_EvictManagedResources( struct NineDevice9 *This )
7467ec681f3Smrg{
7477ec681f3Smrg    struct NineBaseTexture9 *tex;
7487ec681f3Smrg    struct NineBuffer9 *buf;
7497ec681f3Smrg
7507ec681f3Smrg    DBG("This=%p\n", This);
7517ec681f3Smrg    LIST_FOR_EACH_ENTRY(tex, &This->managed_textures, list2) {
7527ec681f3Smrg        NineBaseTexture9_UnLoad(tex);
7537ec681f3Smrg    }
7547ec681f3Smrg    /* Vertex/index buffers don't take a lot of space and aren't accounted
7557ec681f3Smrg     * for d3d memory usage. Instead of actually freeing from memory,
7567ec681f3Smrg     * just mark the buffer dirty to trigger a re-upload later. We
7577ec681f3Smrg     * could just ignore, but some bad behaving apps could rely on it (if
7587ec681f3Smrg     * they write outside the locked regions typically). */
7597ec681f3Smrg    LIST_FOR_EACH_ENTRY(buf, &This->managed_buffers, managed.list2) {
7607ec681f3Smrg        NineBuffer9_SetDirty(buf);
7617ec681f3Smrg    }
7627ec681f3Smrg
7637ec681f3Smrg    return D3D_OK;
7647ec681f3Smrg}
7657ec681f3Smrg
7667ec681f3SmrgHRESULT NINE_WINAPI
7677ec681f3SmrgNineDevice9_GetDirect3D( struct NineDevice9 *This,
7687ec681f3Smrg                         IDirect3D9 **ppD3D9 )
7697ec681f3Smrg{
7707ec681f3Smrg    user_assert(ppD3D9 != NULL, E_POINTER);
7717ec681f3Smrg    IDirect3D9_AddRef(This->d3d9);
7727ec681f3Smrg    *ppD3D9 = This->d3d9;
7737ec681f3Smrg    return D3D_OK;
7747ec681f3Smrg}
7757ec681f3Smrg
7767ec681f3SmrgHRESULT NINE_WINAPI
7777ec681f3SmrgNineDevice9_GetDeviceCaps( struct NineDevice9 *This,
7787ec681f3Smrg                           D3DCAPS9 *pCaps )
7797ec681f3Smrg{
7807ec681f3Smrg    user_assert(pCaps != NULL, D3DERR_INVALIDCALL);
7817ec681f3Smrg    *pCaps = This->caps;
7827ec681f3Smrg    return D3D_OK;
7837ec681f3Smrg}
7847ec681f3Smrg
7857ec681f3SmrgHRESULT NINE_WINAPI
7867ec681f3SmrgNineDevice9_GetDisplayMode( struct NineDevice9 *This,
7877ec681f3Smrg                            UINT iSwapChain,
7887ec681f3Smrg                            D3DDISPLAYMODE *pMode )
7897ec681f3Smrg{
7907ec681f3Smrg    DBG("This=%p iSwapChain=%u pMode=%p\n", This, iSwapChain, pMode);
7917ec681f3Smrg
7927ec681f3Smrg    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
7937ec681f3Smrg
7947ec681f3Smrg    return NineSwapChain9_GetDisplayMode(This->swapchains[iSwapChain], pMode);
7957ec681f3Smrg}
7967ec681f3Smrg
7977ec681f3SmrgHRESULT NINE_WINAPI
7987ec681f3SmrgNineDevice9_GetCreationParameters( struct NineDevice9 *This,
7997ec681f3Smrg                                   D3DDEVICE_CREATION_PARAMETERS *pParameters )
8007ec681f3Smrg{
8017ec681f3Smrg    user_assert(pParameters != NULL, D3DERR_INVALIDCALL);
8027ec681f3Smrg    *pParameters = This->params;
8037ec681f3Smrg    return D3D_OK;
8047ec681f3Smrg}
8057ec681f3Smrg
8067ec681f3SmrgHRESULT NINE_WINAPI
8077ec681f3SmrgNineDevice9_SetCursorProperties( struct NineDevice9 *This,
8087ec681f3Smrg                                 UINT XHotSpot,
8097ec681f3Smrg                                 UINT YHotSpot,
8107ec681f3Smrg                                 IDirect3DSurface9 *pCursorBitmap )
8117ec681f3Smrg{
8127ec681f3Smrg    struct NineSurface9 *surf = NineSurface9(pCursorBitmap);
8137ec681f3Smrg    struct pipe_context *pipe = NineDevice9_GetPipe(This);
8147ec681f3Smrg    struct pipe_box box;
8157ec681f3Smrg    struct pipe_transfer *transfer;
8167ec681f3Smrg    BOOL hw_cursor;
8177ec681f3Smrg    void *ptr;
8187ec681f3Smrg
8197ec681f3Smrg    DBG_FLAG(DBG_SWAPCHAIN, "This=%p XHotSpot=%u YHotSpot=%u "
8207ec681f3Smrg             "pCursorBitmap=%p\n", This, XHotSpot, YHotSpot, pCursorBitmap);
8217ec681f3Smrg
8227ec681f3Smrg    user_assert(pCursorBitmap, D3DERR_INVALIDCALL);
8237ec681f3Smrg    user_assert(surf->desc.Format == D3DFMT_A8R8G8B8, D3DERR_INVALIDCALL);
8247ec681f3Smrg
8257ec681f3Smrg    if (This->swapchains[0]->params.Windowed) {
8267ec681f3Smrg        This->cursor.w = MIN2(surf->desc.Width, 32);
8277ec681f3Smrg        This->cursor.h = MIN2(surf->desc.Height, 32);
8287ec681f3Smrg        hw_cursor = 1; /* always use hw cursor for windowed mode */
8297ec681f3Smrg    } else {
8307ec681f3Smrg        This->cursor.w = MIN2(surf->desc.Width, This->cursor.image->width0);
8317ec681f3Smrg        This->cursor.h = MIN2(surf->desc.Height, This->cursor.image->height0);
8327ec681f3Smrg        hw_cursor = This->cursor.w == 32 && This->cursor.h == 32;
8337ec681f3Smrg    }
8347ec681f3Smrg
8357ec681f3Smrg    u_box_origin_2d(This->cursor.w, This->cursor.h, &box);
8367ec681f3Smrg
8377ec681f3Smrg    ptr = pipe->texture_map(pipe, This->cursor.image, 0,
8387ec681f3Smrg                             PIPE_MAP_WRITE |
8397ec681f3Smrg                             PIPE_MAP_DISCARD_WHOLE_RESOURCE,
8407ec681f3Smrg                             &box, &transfer);
8417ec681f3Smrg    if (!ptr)
8427ec681f3Smrg        ret_err("Failed to update cursor image.\n", D3DERR_DRIVERINTERNALERROR);
8437ec681f3Smrg
8447ec681f3Smrg    This->cursor.hotspot.x = XHotSpot;
8457ec681f3Smrg    This->cursor.hotspot.y = YHotSpot;
8467ec681f3Smrg
8477ec681f3Smrg    /* Copy cursor image to internal storage. */
8487ec681f3Smrg    {
8497ec681f3Smrg        D3DLOCKED_RECT lock;
8507ec681f3Smrg        HRESULT hr;
8517ec681f3Smrg
8527ec681f3Smrg        hr = NineSurface9_LockRect(surf, &lock, NULL, D3DLOCK_READONLY);
8537ec681f3Smrg        if (FAILED(hr))
8547ec681f3Smrg            ret_err("Failed to map cursor source image.\n",
8557ec681f3Smrg                    D3DERR_DRIVERINTERNALERROR);
8567ec681f3Smrg
8577ec681f3Smrg        util_format_unpack_rgba_8unorm_rect(surf->base.info.format, ptr, transfer->stride,
8587ec681f3Smrg                                   lock.pBits, lock.Pitch,
8597ec681f3Smrg                                   This->cursor.w, This->cursor.h);
8607ec681f3Smrg
8617ec681f3Smrg        if (hw_cursor) {
8627ec681f3Smrg            void *data = lock.pBits;
8637ec681f3Smrg            /* SetCursor assumes 32x32 argb with pitch 128 */
8647ec681f3Smrg            if (lock.Pitch != 128) {
8657ec681f3Smrg                util_format_unpack_rgba_8unorm_rect(surf->base.info.format,
8667ec681f3Smrg                                           This->cursor.hw_upload_temp, 128,
8677ec681f3Smrg                                           lock.pBits, lock.Pitch,
8687ec681f3Smrg                                           32, 32);
8697ec681f3Smrg                data = This->cursor.hw_upload_temp;
8707ec681f3Smrg            }
8717ec681f3Smrg            hw_cursor = ID3DPresent_SetCursor(This->swapchains[0]->present,
8727ec681f3Smrg                                              data,
8737ec681f3Smrg                                              &This->cursor.hotspot,
8747ec681f3Smrg                                              This->cursor.visible) == D3D_OK;
8757ec681f3Smrg        }
8767ec681f3Smrg
8777ec681f3Smrg        NineSurface9_UnlockRect(surf);
8787ec681f3Smrg    }
8797ec681f3Smrg    pipe->texture_unmap(pipe, transfer);
8807ec681f3Smrg
8817ec681f3Smrg    /* hide cursor if we emulate it */
8827ec681f3Smrg    if (!hw_cursor)
8837ec681f3Smrg        ID3DPresent_SetCursor(This->swapchains[0]->present, NULL, NULL, FALSE);
8847ec681f3Smrg    This->cursor.software = !hw_cursor;
8857ec681f3Smrg
8867ec681f3Smrg    return D3D_OK;
8877ec681f3Smrg}
8887ec681f3Smrg
8897ec681f3Smrgvoid NINE_WINAPI
8907ec681f3SmrgNineDevice9_SetCursorPosition( struct NineDevice9 *This,
8917ec681f3Smrg                               int X,
8927ec681f3Smrg                               int Y,
8937ec681f3Smrg                               DWORD Flags )
8947ec681f3Smrg{
8957ec681f3Smrg    struct NineSwapChain9 *swap = This->swapchains[0];
8967ec681f3Smrg
8977ec681f3Smrg    DBG("This=%p X=%d Y=%d Flags=%d\n", This, X, Y, Flags);
8987ec681f3Smrg
8997ec681f3Smrg    /* present >= v1.4 handles this itself */
9007ec681f3Smrg    if (This->minor_version_num < 4) {
9017ec681f3Smrg        if (This->cursor.pos.x == X && This->cursor.pos.y == Y)
9027ec681f3Smrg            return;
9037ec681f3Smrg    }
9047ec681f3Smrg
9057ec681f3Smrg    This->cursor.pos.x = X;
9067ec681f3Smrg    This->cursor.pos.y = Y;
9077ec681f3Smrg
9087ec681f3Smrg    if (!This->cursor.software)
9097ec681f3Smrg        This->cursor.software = ID3DPresent_SetCursorPos(swap->present, &This->cursor.pos) != D3D_OK;
9107ec681f3Smrg}
9117ec681f3Smrg
9127ec681f3SmrgBOOL NINE_WINAPI
9137ec681f3SmrgNineDevice9_ShowCursor( struct NineDevice9 *This,
9147ec681f3Smrg                        BOOL bShow )
9157ec681f3Smrg{
9167ec681f3Smrg    BOOL old = This->cursor.visible;
9177ec681f3Smrg
9187ec681f3Smrg    DBG("This=%p bShow=%d\n", This, (int) bShow);
9197ec681f3Smrg
9207ec681f3Smrg    /* No-op until a cursor is set in d3d */
9217ec681f3Smrg    if (This->cursor.hotspot.x == -1)
9227ec681f3Smrg        return old;
9237ec681f3Smrg
9247ec681f3Smrg    This->cursor.visible = bShow;
9257ec681f3Smrg    /* Note: Don't optimize by avoiding the call if This->cursor.visible
9267ec681f3Smrg     * hasn't changed. One has to keep in mind the app may do SetCursor
9277ec681f3Smrg     * calls outside d3d, thus such an optimization affects behaviour. */
9287ec681f3Smrg    if (!This->cursor.software)
9297ec681f3Smrg        This->cursor.software = ID3DPresent_SetCursor(This->swapchains[0]->present, NULL, NULL, bShow) != D3D_OK;
9307ec681f3Smrg
9317ec681f3Smrg    return old;
9327ec681f3Smrg}
9337ec681f3Smrg
9347ec681f3SmrgHRESULT NINE_WINAPI
9357ec681f3SmrgNineDevice9_CreateAdditionalSwapChain( struct NineDevice9 *This,
9367ec681f3Smrg                                       D3DPRESENT_PARAMETERS *pPresentationParameters,
9377ec681f3Smrg                                       IDirect3DSwapChain9 **pSwapChain )
9387ec681f3Smrg{
9397ec681f3Smrg    struct NineSwapChain9 *swapchain, *tmplt = This->swapchains[0];
9407ec681f3Smrg    ID3DPresent *present;
9417ec681f3Smrg    HRESULT hr;
9427ec681f3Smrg
9437ec681f3Smrg    DBG("This=%p pPresentationParameters=%p pSwapChain=%p\n",
9447ec681f3Smrg        This, pPresentationParameters, pSwapChain);
9457ec681f3Smrg
9467ec681f3Smrg    user_assert(pPresentationParameters, D3DERR_INVALIDCALL);
9477ec681f3Smrg    user_assert(pSwapChain != NULL, D3DERR_INVALIDCALL);
9487ec681f3Smrg    user_assert(tmplt->params.Windowed && pPresentationParameters->Windowed, D3DERR_INVALIDCALL);
9497ec681f3Smrg
9507ec681f3Smrg    /* TODO: this deserves more tests */
9517ec681f3Smrg    if (!pPresentationParameters->hDeviceWindow)
9527ec681f3Smrg        pPresentationParameters->hDeviceWindow = This->params.hFocusWindow;
9537ec681f3Smrg
9547ec681f3Smrg    hr = ID3DPresentGroup_CreateAdditionalPresent(This->present, pPresentationParameters, &present);
9557ec681f3Smrg
9567ec681f3Smrg    if (FAILED(hr))
9577ec681f3Smrg        return hr;
9587ec681f3Smrg
9597ec681f3Smrg    hr = NineSwapChain9_new(This, FALSE, present, pPresentationParameters,
9607ec681f3Smrg                            tmplt->actx,
9617ec681f3Smrg                            tmplt->params.hDeviceWindow,
9627ec681f3Smrg                            &swapchain);
9637ec681f3Smrg    if (FAILED(hr))
9647ec681f3Smrg        return hr;
9657ec681f3Smrg
9667ec681f3Smrg    *pSwapChain = (IDirect3DSwapChain9 *)swapchain;
9677ec681f3Smrg    return D3D_OK;
9687ec681f3Smrg}
9697ec681f3Smrg
9707ec681f3SmrgHRESULT NINE_WINAPI
9717ec681f3SmrgNineDevice9_GetSwapChain( struct NineDevice9 *This,
9727ec681f3Smrg                          UINT iSwapChain,
9737ec681f3Smrg                          IDirect3DSwapChain9 **pSwapChain )
9747ec681f3Smrg{
9757ec681f3Smrg    user_assert(pSwapChain != NULL, D3DERR_INVALIDCALL);
9767ec681f3Smrg
9777ec681f3Smrg    *pSwapChain = NULL;
9787ec681f3Smrg    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
9797ec681f3Smrg
9807ec681f3Smrg    NineUnknown_AddRef(NineUnknown(This->swapchains[iSwapChain]));
9817ec681f3Smrg    *pSwapChain = (IDirect3DSwapChain9 *)This->swapchains[iSwapChain];
9827ec681f3Smrg
9837ec681f3Smrg    return D3D_OK;
9847ec681f3Smrg}
9857ec681f3Smrg
9867ec681f3SmrgUINT NINE_WINAPI
9877ec681f3SmrgNineDevice9_GetNumberOfSwapChains( struct NineDevice9 *This )
9887ec681f3Smrg{
9897ec681f3Smrg    return This->nswapchains;
9907ec681f3Smrg}
9917ec681f3Smrg
9927ec681f3SmrgHRESULT NINE_WINAPI
9937ec681f3SmrgNineDevice9_Reset( struct NineDevice9 *This,
9947ec681f3Smrg                   D3DPRESENT_PARAMETERS *pPresentationParameters )
9957ec681f3Smrg{
9967ec681f3Smrg    HRESULT hr = D3D_OK;
9977ec681f3Smrg    unsigned i;
9987ec681f3Smrg
9997ec681f3Smrg    DBG("This=%p pPresentationParameters=%p\n", This, pPresentationParameters);
10007ec681f3Smrg
10017ec681f3Smrg    user_assert(pPresentationParameters != NULL, D3DERR_INVALIDCALL);
10027ec681f3Smrg
10037ec681f3Smrg    if (NineSwapChain9_GetOccluded(This->swapchains[0])) {
10047ec681f3Smrg        This->device_needs_reset = TRUE;
10057ec681f3Smrg        return D3DERR_DEVICELOST;
10067ec681f3Smrg    }
10077ec681f3Smrg
10087ec681f3Smrg    for (i = 0; i < This->nswapchains; ++i) {
10097ec681f3Smrg        D3DPRESENT_PARAMETERS *params = &pPresentationParameters[i];
10107ec681f3Smrg        hr = NineSwapChain9_Resize(This->swapchains[i], params, NULL);
10117ec681f3Smrg        if (hr != D3D_OK)
10127ec681f3Smrg            break;
10137ec681f3Smrg    }
10147ec681f3Smrg
10157ec681f3Smrg    nine_csmt_process(This);
10167ec681f3Smrg    nine_device_state_clear(This);
10177ec681f3Smrg    nine_context_clear(This);
10187ec681f3Smrg
10197ec681f3Smrg    NineDevice9_SetDefaultState(This, TRUE);
10207ec681f3Smrg    NineDevice9_SetRenderTarget(
10217ec681f3Smrg        This, 0, (IDirect3DSurface9 *)This->swapchains[0]->buffers[0]);
10227ec681f3Smrg    /* XXX: better use GetBackBuffer here ? */
10237ec681f3Smrg
10247ec681f3Smrg    This->device_needs_reset = (hr != D3D_OK);
10257ec681f3Smrg    return hr;
10267ec681f3Smrg}
10277ec681f3Smrg
10287ec681f3SmrgHRESULT NINE_WINAPI
10297ec681f3SmrgNineDevice9_Present( struct NineDevice9 *This,
10307ec681f3Smrg                     const RECT *pSourceRect,
10317ec681f3Smrg                     const RECT *pDestRect,
10327ec681f3Smrg                     HWND hDestWindowOverride,
10337ec681f3Smrg                     const RGNDATA *pDirtyRegion )
10347ec681f3Smrg{
10357ec681f3Smrg    unsigned i;
10367ec681f3Smrg    HRESULT hr;
10377ec681f3Smrg
10387ec681f3Smrg    DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p pDirtyRegion=%p\n",
10397ec681f3Smrg        This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
10407ec681f3Smrg
10417ec681f3Smrg    /* XXX is this right? */
10427ec681f3Smrg    for (i = 0; i < This->nswapchains; ++i) {
10437ec681f3Smrg        hr = NineSwapChain9_Present(This->swapchains[i], pSourceRect, pDestRect,
10447ec681f3Smrg                                    hDestWindowOverride, pDirtyRegion, 0);
10457ec681f3Smrg        if (FAILED(hr)) { return hr; }
10467ec681f3Smrg    }
10477ec681f3Smrg
10487ec681f3Smrg    return D3D_OK;
10497ec681f3Smrg}
10507ec681f3Smrg
10517ec681f3SmrgHRESULT NINE_WINAPI
10527ec681f3SmrgNineDevice9_GetBackBuffer( struct NineDevice9 *This,
10537ec681f3Smrg                           UINT iSwapChain,
10547ec681f3Smrg                           UINT iBackBuffer,
10557ec681f3Smrg                           D3DBACKBUFFER_TYPE Type,
10567ec681f3Smrg                           IDirect3DSurface9 **ppBackBuffer )
10577ec681f3Smrg{
10587ec681f3Smrg    user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL);
10597ec681f3Smrg    /* return NULL on error */
10607ec681f3Smrg    *ppBackBuffer = NULL;
10617ec681f3Smrg    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
10627ec681f3Smrg
10637ec681f3Smrg    return NineSwapChain9_GetBackBuffer(This->swapchains[iSwapChain],
10647ec681f3Smrg                                        iBackBuffer, Type, ppBackBuffer);
10657ec681f3Smrg}
10667ec681f3Smrg
10677ec681f3SmrgHRESULT NINE_WINAPI
10687ec681f3SmrgNineDevice9_GetRasterStatus( struct NineDevice9 *This,
10697ec681f3Smrg                             UINT iSwapChain,
10707ec681f3Smrg                             D3DRASTER_STATUS *pRasterStatus )
10717ec681f3Smrg{
10727ec681f3Smrg    user_assert(pRasterStatus != NULL, D3DERR_INVALIDCALL);
10737ec681f3Smrg    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
10747ec681f3Smrg
10757ec681f3Smrg    return NineSwapChain9_GetRasterStatus(This->swapchains[iSwapChain],
10767ec681f3Smrg                                          pRasterStatus);
10777ec681f3Smrg}
10787ec681f3Smrg
10797ec681f3SmrgHRESULT NINE_WINAPI
10807ec681f3SmrgNineDevice9_SetDialogBoxMode( struct NineDevice9 *This,
10817ec681f3Smrg                              BOOL bEnableDialogs )
10827ec681f3Smrg{
10837ec681f3Smrg    STUB(D3DERR_INVALIDCALL);
10847ec681f3Smrg}
10857ec681f3Smrg
10867ec681f3Smrgvoid NINE_WINAPI
10877ec681f3SmrgNineDevice9_SetGammaRamp( struct NineDevice9 *This,
10887ec681f3Smrg                          UINT iSwapChain,
10897ec681f3Smrg                          DWORD Flags,
10907ec681f3Smrg                          const D3DGAMMARAMP *pRamp )
10917ec681f3Smrg{
10927ec681f3Smrg    DBG("This=%p iSwapChain=%u Flags=%x pRamp=%p\n", This,
10937ec681f3Smrg        iSwapChain, Flags, pRamp);
10947ec681f3Smrg
10957ec681f3Smrg    user_warn(iSwapChain >= This->nswapchains);
10967ec681f3Smrg    user_warn(!pRamp);
10977ec681f3Smrg
10987ec681f3Smrg    if (pRamp && (iSwapChain < This->nswapchains)) {
10997ec681f3Smrg        struct NineSwapChain9 *swap = This->swapchains[iSwapChain];
11007ec681f3Smrg        swap->gamma = *pRamp;
11017ec681f3Smrg        ID3DPresent_SetGammaRamp(swap->present, pRamp, swap->params.hDeviceWindow);
11027ec681f3Smrg    }
11037ec681f3Smrg}
11047ec681f3Smrg
11057ec681f3Smrgvoid NINE_WINAPI
11067ec681f3SmrgNineDevice9_GetGammaRamp( struct NineDevice9 *This,
11077ec681f3Smrg                          UINT iSwapChain,
11087ec681f3Smrg                          D3DGAMMARAMP *pRamp )
11097ec681f3Smrg{
11107ec681f3Smrg    DBG("This=%p iSwapChain=%u pRamp=%p\n", This, iSwapChain, pRamp);
11117ec681f3Smrg
11127ec681f3Smrg    user_warn(iSwapChain >= This->nswapchains);
11137ec681f3Smrg    user_warn(!pRamp);
11147ec681f3Smrg
11157ec681f3Smrg    if (pRamp && (iSwapChain < This->nswapchains))
11167ec681f3Smrg        *pRamp = This->swapchains[iSwapChain]->gamma;
11177ec681f3Smrg}
11187ec681f3Smrg
11197ec681f3SmrgHRESULT NINE_WINAPI
11207ec681f3SmrgNineDevice9_CreateTexture( struct NineDevice9 *This,
11217ec681f3Smrg                           UINT Width,
11227ec681f3Smrg                           UINT Height,
11237ec681f3Smrg                           UINT Levels,
11247ec681f3Smrg                           DWORD Usage,
11257ec681f3Smrg                           D3DFORMAT Format,
11267ec681f3Smrg                           D3DPOOL Pool,
11277ec681f3Smrg                           IDirect3DTexture9 **ppTexture,
11287ec681f3Smrg                           HANDLE *pSharedHandle )
11297ec681f3Smrg{
11307ec681f3Smrg    struct NineTexture9 *tex;
11317ec681f3Smrg    HRESULT hr;
11327ec681f3Smrg
11337ec681f3Smrg    DBG("This=%p Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s "
11347ec681f3Smrg        "ppOut=%p pSharedHandle=%p\n", This, Width, Height, Levels,
11357ec681f3Smrg        nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format),
11367ec681f3Smrg        nine_D3DPOOL_to_str(Pool), ppTexture, pSharedHandle);
11377ec681f3Smrg
11387ec681f3Smrg    user_assert(ppTexture != NULL, D3DERR_INVALIDCALL);
11397ec681f3Smrg
11407ec681f3Smrg    Usage &= D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DMAP |
11417ec681f3Smrg             D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE | D3DUSAGE_RENDERTARGET |
11427ec681f3Smrg             D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_TEXTAPI;
11437ec681f3Smrg
11447ec681f3Smrg    *ppTexture = NULL;
11457ec681f3Smrg
11467ec681f3Smrg    hr = NineTexture9_new(This, Width, Height, Levels, Usage, Format, Pool,
11477ec681f3Smrg                          &tex, pSharedHandle);
11487ec681f3Smrg    if (SUCCEEDED(hr))
11497ec681f3Smrg        *ppTexture = (IDirect3DTexture9 *)tex;
11507ec681f3Smrg
11517ec681f3Smrg    return hr;
11527ec681f3Smrg}
11537ec681f3Smrg
11547ec681f3SmrgHRESULT NINE_WINAPI
11557ec681f3SmrgNineDevice9_CreateVolumeTexture( struct NineDevice9 *This,
11567ec681f3Smrg                                 UINT Width,
11577ec681f3Smrg                                 UINT Height,
11587ec681f3Smrg                                 UINT Depth,
11597ec681f3Smrg                                 UINT Levels,
11607ec681f3Smrg                                 DWORD Usage,
11617ec681f3Smrg                                 D3DFORMAT Format,
11627ec681f3Smrg                                 D3DPOOL Pool,
11637ec681f3Smrg                                 IDirect3DVolumeTexture9 **ppVolumeTexture,
11647ec681f3Smrg                                 HANDLE *pSharedHandle )
11657ec681f3Smrg{
11667ec681f3Smrg    struct NineVolumeTexture9 *tex;
11677ec681f3Smrg    HRESULT hr;
11687ec681f3Smrg
11697ec681f3Smrg    DBG("This=%p Width=%u Height=%u Depth=%u Levels=%u Usage=%s Format=%s Pool=%s "
11707ec681f3Smrg        "ppOut=%p pSharedHandle=%p\n", This, Width, Height, Depth, Levels,
11717ec681f3Smrg        nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format),
11727ec681f3Smrg        nine_D3DPOOL_to_str(Pool), ppVolumeTexture, pSharedHandle);
11737ec681f3Smrg
11747ec681f3Smrg    user_assert(ppVolumeTexture != NULL, D3DERR_INVALIDCALL);
11757ec681f3Smrg
11767ec681f3Smrg    Usage &= D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE |
11777ec681f3Smrg             D3DUSAGE_SOFTWAREPROCESSING;
11787ec681f3Smrg
11797ec681f3Smrg    *ppVolumeTexture = NULL;
11807ec681f3Smrg
11817ec681f3Smrg    hr = NineVolumeTexture9_new(This, Width, Height, Depth, Levels,
11827ec681f3Smrg                                Usage, Format, Pool, &tex, pSharedHandle);
11837ec681f3Smrg    if (SUCCEEDED(hr))
11847ec681f3Smrg        *ppVolumeTexture = (IDirect3DVolumeTexture9 *)tex;
11857ec681f3Smrg
11867ec681f3Smrg    return hr;
11877ec681f3Smrg}
11887ec681f3Smrg
11897ec681f3SmrgHRESULT NINE_WINAPI
11907ec681f3SmrgNineDevice9_CreateCubeTexture( struct NineDevice9 *This,
11917ec681f3Smrg                               UINT EdgeLength,
11927ec681f3Smrg                               UINT Levels,
11937ec681f3Smrg                               DWORD Usage,
11947ec681f3Smrg                               D3DFORMAT Format,
11957ec681f3Smrg                               D3DPOOL Pool,
11967ec681f3Smrg                               IDirect3DCubeTexture9 **ppCubeTexture,
11977ec681f3Smrg                               HANDLE *pSharedHandle )
11987ec681f3Smrg{
11997ec681f3Smrg    struct NineCubeTexture9 *tex;
12007ec681f3Smrg    HRESULT hr;
12017ec681f3Smrg
12027ec681f3Smrg    DBG("This=%p EdgeLength=%u Levels=%u Usage=%s Format=%s Pool=%s ppOut=%p "
12037ec681f3Smrg        "pSharedHandle=%p\n", This, EdgeLength, Levels,
12047ec681f3Smrg        nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format),
12057ec681f3Smrg        nine_D3DPOOL_to_str(Pool), ppCubeTexture, pSharedHandle);
12067ec681f3Smrg
12077ec681f3Smrg    user_assert(ppCubeTexture != NULL, D3DERR_INVALIDCALL);
12087ec681f3Smrg
12097ec681f3Smrg    Usage &= D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DYNAMIC |
12107ec681f3Smrg             D3DUSAGE_NONSECURE | D3DUSAGE_RENDERTARGET |
12117ec681f3Smrg             D3DUSAGE_SOFTWAREPROCESSING;
12127ec681f3Smrg
12137ec681f3Smrg    *ppCubeTexture = NULL;
12147ec681f3Smrg
12157ec681f3Smrg    hr = NineCubeTexture9_new(This, EdgeLength, Levels, Usage, Format, Pool,
12167ec681f3Smrg                              &tex, pSharedHandle);
12177ec681f3Smrg    if (SUCCEEDED(hr))
12187ec681f3Smrg        *ppCubeTexture = (IDirect3DCubeTexture9 *)tex;
12197ec681f3Smrg
12207ec681f3Smrg    return hr;
12217ec681f3Smrg}
12227ec681f3Smrg
12237ec681f3SmrgHRESULT NINE_WINAPI
12247ec681f3SmrgNineDevice9_CreateVertexBuffer( struct NineDevice9 *This,
12257ec681f3Smrg                                UINT Length,
12267ec681f3Smrg                                DWORD Usage,
12277ec681f3Smrg                                DWORD FVF,
12287ec681f3Smrg                                D3DPOOL Pool,
12297ec681f3Smrg                                IDirect3DVertexBuffer9 **ppVertexBuffer,
12307ec681f3Smrg                                HANDLE *pSharedHandle )
12317ec681f3Smrg{
12327ec681f3Smrg    struct NineVertexBuffer9 *buf;
12337ec681f3Smrg    HRESULT hr;
12347ec681f3Smrg    D3DVERTEXBUFFER_DESC desc;
12357ec681f3Smrg
12367ec681f3Smrg    DBG("This=%p Length=%u Usage=%x FVF=%x Pool=%u ppOut=%p pSharedHandle=%p\n",
12377ec681f3Smrg        This, Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
12387ec681f3Smrg
12397ec681f3Smrg    user_assert(ppVertexBuffer != NULL, D3DERR_INVALIDCALL);
12407ec681f3Smrg    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_NOTAVAILABLE);
12417ec681f3Smrg
12427ec681f3Smrg    desc.Format = D3DFMT_VERTEXDATA;
12437ec681f3Smrg    desc.Type = D3DRTYPE_VERTEXBUFFER;
12447ec681f3Smrg    desc.Usage = Usage &
12457ec681f3Smrg        (D3DUSAGE_DONOTCLIP | D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE |
12467ec681f3Smrg         D3DUSAGE_NPATCHES | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES |
12477ec681f3Smrg         D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_TEXTAPI |
12487ec681f3Smrg         D3DUSAGE_WRITEONLY);
12497ec681f3Smrg    desc.Pool = Pool;
12507ec681f3Smrg    desc.Size = Length;
12517ec681f3Smrg    desc.FVF = FVF;
12527ec681f3Smrg
12537ec681f3Smrg    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
12547ec681f3Smrg    user_assert(desc.Usage == Usage, D3DERR_INVALIDCALL);
12557ec681f3Smrg
12567ec681f3Smrg    hr = NineVertexBuffer9_new(This, &desc, &buf);
12577ec681f3Smrg    if (SUCCEEDED(hr))
12587ec681f3Smrg        *ppVertexBuffer = (IDirect3DVertexBuffer9 *)buf;
12597ec681f3Smrg    return hr;
12607ec681f3Smrg}
12617ec681f3Smrg
12627ec681f3SmrgHRESULT NINE_WINAPI
12637ec681f3SmrgNineDevice9_CreateIndexBuffer( struct NineDevice9 *This,
12647ec681f3Smrg                               UINT Length,
12657ec681f3Smrg                               DWORD Usage,
12667ec681f3Smrg                               D3DFORMAT Format,
12677ec681f3Smrg                               D3DPOOL Pool,
12687ec681f3Smrg                               IDirect3DIndexBuffer9 **ppIndexBuffer,
12697ec681f3Smrg                               HANDLE *pSharedHandle )
12707ec681f3Smrg{
12717ec681f3Smrg    struct NineIndexBuffer9 *buf;
12727ec681f3Smrg    HRESULT hr;
12737ec681f3Smrg    D3DINDEXBUFFER_DESC desc;
12747ec681f3Smrg
12757ec681f3Smrg    DBG("This=%p Length=%u Usage=%x Format=%s Pool=%u ppOut=%p "
12767ec681f3Smrg        "pSharedHandle=%p\n", This, Length, Usage,
12777ec681f3Smrg        d3dformat_to_string(Format), Pool, ppIndexBuffer, pSharedHandle);
12787ec681f3Smrg
12797ec681f3Smrg    user_assert(ppIndexBuffer != NULL, D3DERR_INVALIDCALL);
12807ec681f3Smrg    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_NOTAVAILABLE);
12817ec681f3Smrg
12827ec681f3Smrg    desc.Format = Format;
12837ec681f3Smrg    desc.Type = D3DRTYPE_INDEXBUFFER;
12847ec681f3Smrg    desc.Usage = Usage &
12857ec681f3Smrg        (D3DUSAGE_DONOTCLIP | D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE |
12867ec681f3Smrg         D3DUSAGE_NPATCHES | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES |
12877ec681f3Smrg         D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_WRITEONLY);
12887ec681f3Smrg    desc.Pool = Pool;
12897ec681f3Smrg    desc.Size = Length;
12907ec681f3Smrg
12917ec681f3Smrg    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
12927ec681f3Smrg    user_assert(desc.Usage == Usage, D3DERR_INVALIDCALL);
12937ec681f3Smrg
12947ec681f3Smrg    hr = NineIndexBuffer9_new(This, &desc, &buf);
12957ec681f3Smrg    if (SUCCEEDED(hr))
12967ec681f3Smrg        *ppIndexBuffer = (IDirect3DIndexBuffer9 *)buf;
12977ec681f3Smrg    return hr;
12987ec681f3Smrg}
12997ec681f3Smrg
13007ec681f3Smrgstatic HRESULT
13017ec681f3Smrgcreate_zs_or_rt_surface(struct NineDevice9 *This,
13027ec681f3Smrg                        unsigned type, /* 0 = RT, 1 = ZS, 2 = plain */
13037ec681f3Smrg                        D3DPOOL Pool,
13047ec681f3Smrg                        UINT Width, UINT Height,
13057ec681f3Smrg                        D3DFORMAT Format,
13067ec681f3Smrg                        D3DMULTISAMPLE_TYPE MultiSample,
13077ec681f3Smrg                        DWORD MultisampleQuality,
13087ec681f3Smrg                        BOOL Discard_or_Lockable,
13097ec681f3Smrg                        IDirect3DSurface9 **ppSurface,
13107ec681f3Smrg                        HANDLE *pSharedHandle)
13117ec681f3Smrg{
13127ec681f3Smrg    struct NineSurface9 *surface;
13137ec681f3Smrg    HRESULT hr;
13147ec681f3Smrg    D3DSURFACE_DESC desc;
13157ec681f3Smrg
13167ec681f3Smrg    DBG("This=%p type=%u Pool=%s Width=%u Height=%u Format=%s MS=%u Quality=%u "
13177ec681f3Smrg        "Discard_or_Lockable=%i ppSurface=%p pSharedHandle=%p\n",
13187ec681f3Smrg        This, type, nine_D3DPOOL_to_str(Pool), Width, Height,
13197ec681f3Smrg        d3dformat_to_string(Format), MultiSample, MultisampleQuality,
13207ec681f3Smrg        Discard_or_Lockable, ppSurface, pSharedHandle);
13217ec681f3Smrg
13227ec681f3Smrg    if (pSharedHandle)
13237ec681f3Smrg      DBG("FIXME Used shared handle! This option isn't probably handled correctly!\n");
13247ec681f3Smrg
13257ec681f3Smrg    user_assert(Width && Height, D3DERR_INVALIDCALL);
13267ec681f3Smrg    user_assert(Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL);
13277ec681f3Smrg
13287ec681f3Smrg    desc.Format = Format;
13297ec681f3Smrg    desc.Type = D3DRTYPE_SURFACE;
13307ec681f3Smrg    desc.Usage = 0;
13317ec681f3Smrg    desc.Pool = Pool;
13327ec681f3Smrg    desc.MultiSampleType = MultiSample;
13337ec681f3Smrg    desc.MultiSampleQuality = MultisampleQuality;
13347ec681f3Smrg    desc.Width = Width;
13357ec681f3Smrg    desc.Height = Height;
13367ec681f3Smrg    switch (type) {
13377ec681f3Smrg    case 0: desc.Usage = D3DUSAGE_RENDERTARGET; break;
13387ec681f3Smrg    case 1: desc.Usage = D3DUSAGE_DEPTHSTENCIL; break;
13397ec681f3Smrg    default: assert(type == 2); break;
13407ec681f3Smrg    }
13417ec681f3Smrg
13427ec681f3Smrg    hr = NineSurface9_new(This, NULL, NULL, NULL, 0, 0, 0, &desc, &surface);
13437ec681f3Smrg    if (SUCCEEDED(hr)) {
13447ec681f3Smrg        *ppSurface = (IDirect3DSurface9 *)surface;
13457ec681f3Smrg
13467ec681f3Smrg        if (surface->base.resource && Discard_or_Lockable && (type != 1))
13477ec681f3Smrg            surface->base.resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
13487ec681f3Smrg    }
13497ec681f3Smrg
13507ec681f3Smrg    return hr;
13517ec681f3Smrg}
13527ec681f3Smrg
13537ec681f3SmrgHRESULT NINE_WINAPI
13547ec681f3SmrgNineDevice9_CreateRenderTarget( struct NineDevice9 *This,
13557ec681f3Smrg                                UINT Width,
13567ec681f3Smrg                                UINT Height,
13577ec681f3Smrg                                D3DFORMAT Format,
13587ec681f3Smrg                                D3DMULTISAMPLE_TYPE MultiSample,
13597ec681f3Smrg                                DWORD MultisampleQuality,
13607ec681f3Smrg                                BOOL Lockable,
13617ec681f3Smrg                                IDirect3DSurface9 **ppSurface,
13627ec681f3Smrg                                HANDLE *pSharedHandle )
13637ec681f3Smrg{
13647ec681f3Smrg    user_assert(ppSurface != NULL, D3DERR_INVALIDCALL);
13657ec681f3Smrg    *ppSurface = NULL;
13667ec681f3Smrg    return create_zs_or_rt_surface(This, 0, D3DPOOL_DEFAULT,
13677ec681f3Smrg                                   Width, Height, Format,
13687ec681f3Smrg                                   MultiSample, MultisampleQuality,
13697ec681f3Smrg                                   Lockable, ppSurface, pSharedHandle);
13707ec681f3Smrg}
13717ec681f3Smrg
13727ec681f3SmrgHRESULT NINE_WINAPI
13737ec681f3SmrgNineDevice9_CreateDepthStencilSurface( struct NineDevice9 *This,
13747ec681f3Smrg                                       UINT Width,
13757ec681f3Smrg                                       UINT Height,
13767ec681f3Smrg                                       D3DFORMAT Format,
13777ec681f3Smrg                                       D3DMULTISAMPLE_TYPE MultiSample,
13787ec681f3Smrg                                       DWORD MultisampleQuality,
13797ec681f3Smrg                                       BOOL Discard,
13807ec681f3Smrg                                       IDirect3DSurface9 **ppSurface,
13817ec681f3Smrg                                       HANDLE *pSharedHandle )
13827ec681f3Smrg{
13837ec681f3Smrg    user_assert(ppSurface != NULL, D3DERR_INVALIDCALL);
13847ec681f3Smrg    *ppSurface = NULL;
13857ec681f3Smrg    if (!depth_stencil_format(Format))
13867ec681f3Smrg        return D3DERR_NOTAVAILABLE;
13877ec681f3Smrg    return create_zs_or_rt_surface(This, 1, D3DPOOL_DEFAULT,
13887ec681f3Smrg                                   Width, Height, Format,
13897ec681f3Smrg                                   MultiSample, MultisampleQuality,
13907ec681f3Smrg                                   Discard, ppSurface, pSharedHandle);
13917ec681f3Smrg}
13927ec681f3Smrg
13937ec681f3SmrgHRESULT NINE_WINAPI
13947ec681f3SmrgNineDevice9_UpdateSurface( struct NineDevice9 *This,
13957ec681f3Smrg                           IDirect3DSurface9 *pSourceSurface,
13967ec681f3Smrg                           const RECT *pSourceRect,
13977ec681f3Smrg                           IDirect3DSurface9 *pDestinationSurface,
13987ec681f3Smrg                           const POINT *pDestPoint )
13997ec681f3Smrg{
14007ec681f3Smrg    struct NineSurface9 *dst = NineSurface9(pDestinationSurface);
14017ec681f3Smrg    struct NineSurface9 *src = NineSurface9(pSourceSurface);
14027ec681f3Smrg    int copy_width, copy_height;
14037ec681f3Smrg    RECT destRect;
14047ec681f3Smrg
14057ec681f3Smrg    DBG("This=%p pSourceSurface=%p pDestinationSurface=%p "
14067ec681f3Smrg        "pSourceRect=%p pDestPoint=%p\n", This,
14077ec681f3Smrg        pSourceSurface, pDestinationSurface, pSourceRect, pDestPoint);
14087ec681f3Smrg    if (pSourceRect)
14097ec681f3Smrg        DBG("pSourceRect = (%u,%u)-(%u,%u)\n",
14107ec681f3Smrg            pSourceRect->left, pSourceRect->top,
14117ec681f3Smrg            pSourceRect->right, pSourceRect->bottom);
14127ec681f3Smrg    if (pDestPoint)
14137ec681f3Smrg        DBG("pDestPoint = (%u,%u)\n", pDestPoint->x, pDestPoint->y);
14147ec681f3Smrg
14157ec681f3Smrg    user_assert(dst && src, D3DERR_INVALIDCALL);
14167ec681f3Smrg
14177ec681f3Smrg    user_assert(dst->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
14187ec681f3Smrg    user_assert(src->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
14197ec681f3Smrg
14207ec681f3Smrg    user_assert(dst->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL);
14217ec681f3Smrg    user_assert(src->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL);
14227ec681f3Smrg
14237ec681f3Smrg    user_assert(!src->lock_count, D3DERR_INVALIDCALL);
14247ec681f3Smrg    user_assert(!dst->lock_count, D3DERR_INVALIDCALL);
14257ec681f3Smrg
14267ec681f3Smrg    user_assert(dst->desc.Format == src->desc.Format, D3DERR_INVALIDCALL);
14277ec681f3Smrg    user_assert(!depth_stencil_format(dst->desc.Format), D3DERR_INVALIDCALL);
14287ec681f3Smrg
14297ec681f3Smrg    if (pSourceRect) {
14307ec681f3Smrg        copy_width = pSourceRect->right - pSourceRect->left;
14317ec681f3Smrg        copy_height = pSourceRect->bottom - pSourceRect->top;
14327ec681f3Smrg
14337ec681f3Smrg        user_assert(pSourceRect->left >= 0 &&
14347ec681f3Smrg                    copy_width > 0 &&
14357ec681f3Smrg                    pSourceRect->right <= src->desc.Width &&
14367ec681f3Smrg                    pSourceRect->top >= 0 &&
14377ec681f3Smrg                    copy_height > 0 &&
14387ec681f3Smrg                    pSourceRect->bottom <= src->desc.Height,
14397ec681f3Smrg                    D3DERR_INVALIDCALL);
14407ec681f3Smrg    } else {
14417ec681f3Smrg        copy_width = src->desc.Width;
14427ec681f3Smrg        copy_height = src->desc.Height;
14437ec681f3Smrg    }
14447ec681f3Smrg
14457ec681f3Smrg    destRect.right = copy_width;
14467ec681f3Smrg    destRect.bottom = copy_height;
14477ec681f3Smrg
14487ec681f3Smrg    if (pDestPoint) {
14497ec681f3Smrg        user_assert(pDestPoint->x >= 0 && pDestPoint->y >= 0,
14507ec681f3Smrg                    D3DERR_INVALIDCALL);
14517ec681f3Smrg        destRect.right += pDestPoint->x;
14527ec681f3Smrg        destRect.bottom += pDestPoint->y;
14537ec681f3Smrg    }
14547ec681f3Smrg
14557ec681f3Smrg    user_assert(destRect.right <= dst->desc.Width &&
14567ec681f3Smrg                destRect.bottom <= dst->desc.Height,
14577ec681f3Smrg                D3DERR_INVALIDCALL);
14587ec681f3Smrg
14597ec681f3Smrg    if (compressed_format(dst->desc.Format)) {
14607ec681f3Smrg        const unsigned w = util_format_get_blockwidth(dst->base.info.format);
14617ec681f3Smrg        const unsigned h = util_format_get_blockheight(dst->base.info.format);
14627ec681f3Smrg
14637ec681f3Smrg        if (pDestPoint) {
14647ec681f3Smrg            user_assert(!(pDestPoint->x % w) && !(pDestPoint->y % h),
14657ec681f3Smrg                        D3DERR_INVALIDCALL);
14667ec681f3Smrg        }
14677ec681f3Smrg
14687ec681f3Smrg        if (pSourceRect) {
14697ec681f3Smrg            user_assert(!(pSourceRect->left % w) && !(pSourceRect->top % h),
14707ec681f3Smrg                        D3DERR_INVALIDCALL);
14717ec681f3Smrg        }
14727ec681f3Smrg        if (!(copy_width == src->desc.Width &&
14737ec681f3Smrg              copy_width == dst->desc.Width &&
14747ec681f3Smrg              copy_height == src->desc.Height &&
14757ec681f3Smrg              copy_height == dst->desc.Height)) {
14767ec681f3Smrg            user_assert(!(copy_width  % w) && !(copy_height % h),
14777ec681f3Smrg                        D3DERR_INVALIDCALL);
14787ec681f3Smrg        }
14797ec681f3Smrg    }
14807ec681f3Smrg
14817ec681f3Smrg    NineSurface9_CopyMemToDefault(dst, src, pDestPoint, pSourceRect);
14827ec681f3Smrg
14837ec681f3Smrg    return D3D_OK;
14847ec681f3Smrg}
14857ec681f3Smrg
14867ec681f3SmrgHRESULT NINE_WINAPI
14877ec681f3SmrgNineDevice9_UpdateTexture( struct NineDevice9 *This,
14887ec681f3Smrg                           IDirect3DBaseTexture9 *pSourceTexture,
14897ec681f3Smrg                           IDirect3DBaseTexture9 *pDestinationTexture )
14907ec681f3Smrg{
14917ec681f3Smrg    struct NineBaseTexture9 *dstb = NineBaseTexture9(pDestinationTexture);
14927ec681f3Smrg    struct NineBaseTexture9 *srcb = NineBaseTexture9(pSourceTexture);
14937ec681f3Smrg    unsigned l, m;
14947ec681f3Smrg    unsigned last_src_level, last_dst_level;
14957ec681f3Smrg    RECT rect;
14967ec681f3Smrg
14977ec681f3Smrg    DBG("This=%p pSourceTexture=%p pDestinationTexture=%p\n", This,
14987ec681f3Smrg        pSourceTexture, pDestinationTexture);
14997ec681f3Smrg
15007ec681f3Smrg    user_assert(pSourceTexture && pDestinationTexture, D3DERR_INVALIDCALL);
15017ec681f3Smrg    user_assert(pSourceTexture != pDestinationTexture, D3DERR_INVALIDCALL);
15027ec681f3Smrg
15037ec681f3Smrg    user_assert(dstb->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
15047ec681f3Smrg    user_assert(srcb->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
15057ec681f3Smrg    user_assert(dstb->base.type == srcb->base.type, D3DERR_INVALIDCALL);
15067ec681f3Smrg    user_assert(!(srcb->base.usage & D3DUSAGE_AUTOGENMIPMAP) ||
15077ec681f3Smrg                dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP, D3DERR_INVALIDCALL);
15087ec681f3Smrg
15097ec681f3Smrg    /* Spec: Failure if
15107ec681f3Smrg     * . Different formats
15117ec681f3Smrg     * . Fewer src levels than dst levels (if the opposite, only matching levels
15127ec681f3Smrg     *   are supposed to be copied)
15137ec681f3Smrg     * . Levels do not match
15147ec681f3Smrg     * DDI: Actually the above should pass because of legacy applications
15157ec681f3Smrg     * Do what you want about these, but you shouldn't crash.
15167ec681f3Smrg     * However driver can expect that the top dimension is greater for src than dst.
15177ec681f3Smrg     * Wine tests: Every combination that passes the initial checks should pass.
15187ec681f3Smrg     * . Different formats => conversion driver and format dependent.
15197ec681f3Smrg     * . 1 level, but size not matching => copy is done (and even crash if src bigger
15207ec681f3Smrg     * than dst. For the case where dst bigger, wine doesn't test if a stretch is applied
15217ec681f3Smrg     * or if a subrect is copied).
15227ec681f3Smrg     * . 8x8 4 sublevels -> 7x7 2 sublevels => driver dependent, On NV seems to be 4x4 subrect
15237ec681f3Smrg     * copied to 7x7.
15247ec681f3Smrg     *
15257ec681f3Smrg     * From these, the proposal is:
15267ec681f3Smrg     * . Different formats -> use util_format_translate to translate if possible for surfaces.
15277ec681f3Smrg     * Accept ARGB/XRGB for Volumes. Do nothing for the other combinations
15287ec681f3Smrg     * . First level copied -> the first level such that src is smaller or equal to dst first level
15297ec681f3Smrg     * . number of levels copied -> as long as it fits and textures have levels
15307ec681f3Smrg     * That should satisfy the constraints (and instead of crashing for some cases we return D3D_OK)
15317ec681f3Smrg     */
15327ec681f3Smrg
15337ec681f3Smrg    last_src_level = srcb->level_count-1;
15347ec681f3Smrg    last_dst_level = dstb->level_count-1;
15357ec681f3Smrg
15367ec681f3Smrg    for (m = 0; m <= last_src_level; ++m) {
15377ec681f3Smrg        unsigned w = u_minify(srcb->base.info.width0, m);
15387ec681f3Smrg        unsigned h = u_minify(srcb->base.info.height0, m);
15397ec681f3Smrg        unsigned d = u_minify(srcb->base.info.depth0, m);
15407ec681f3Smrg
15417ec681f3Smrg        if (w <= dstb->base.info.width0 &&
15427ec681f3Smrg            h <= dstb->base.info.height0 &&
15437ec681f3Smrg            d <= dstb->base.info.depth0)
15447ec681f3Smrg            break;
15457ec681f3Smrg    }
15467ec681f3Smrg    user_assert(m <= last_src_level, D3D_OK);
15477ec681f3Smrg
15487ec681f3Smrg    last_dst_level = MIN2(srcb->base.info.last_level - m, last_dst_level);
15497ec681f3Smrg
15507ec681f3Smrg    if (dstb->base.type == D3DRTYPE_TEXTURE) {
15517ec681f3Smrg        struct NineTexture9 *dst = NineTexture9(dstb);
15527ec681f3Smrg        struct NineTexture9 *src = NineTexture9(srcb);
15537ec681f3Smrg
15547ec681f3Smrg        if (src->dirty_rect.width == 0)
15557ec681f3Smrg            return D3D_OK;
15567ec681f3Smrg
15577ec681f3Smrg        pipe_box_to_rect(&rect, &src->dirty_rect);
15587ec681f3Smrg        for (l = 0; l < m; ++l)
15597ec681f3Smrg            rect_minify_inclusive(&rect);
15607ec681f3Smrg
15617ec681f3Smrg        for (l = 0; l <= last_dst_level; ++l, ++m) {
15627ec681f3Smrg            fit_rect_format_inclusive(dst->base.base.info.format,
15637ec681f3Smrg                                      &rect,
15647ec681f3Smrg                                      dst->surfaces[l]->desc.Width,
15657ec681f3Smrg                                      dst->surfaces[l]->desc.Height);
15667ec681f3Smrg            NineSurface9_CopyMemToDefault(dst->surfaces[l],
15677ec681f3Smrg                                          src->surfaces[m],
15687ec681f3Smrg                                          (POINT *)&rect,
15697ec681f3Smrg                                          &rect);
15707ec681f3Smrg            rect_minify_inclusive(&rect);
15717ec681f3Smrg        }
15727ec681f3Smrg        u_box_origin_2d(0, 0, &src->dirty_rect);
15737ec681f3Smrg    } else
15747ec681f3Smrg    if (dstb->base.type == D3DRTYPE_CUBETEXTURE) {
15757ec681f3Smrg        struct NineCubeTexture9 *dst = NineCubeTexture9(dstb);
15767ec681f3Smrg        struct NineCubeTexture9 *src = NineCubeTexture9(srcb);
15777ec681f3Smrg        unsigned z;
15787ec681f3Smrg
15797ec681f3Smrg        /* GPUs usually have them stored as arrays of mip-mapped 2D textures. */
15807ec681f3Smrg        for (z = 0; z < 6; ++z) {
15817ec681f3Smrg            if (src->dirty_rect[z].width == 0)
15827ec681f3Smrg                continue;
15837ec681f3Smrg
15847ec681f3Smrg            pipe_box_to_rect(&rect, &src->dirty_rect[z]);
15857ec681f3Smrg            for (l = 0; l < m; ++l)
15867ec681f3Smrg                rect_minify_inclusive(&rect);
15877ec681f3Smrg
15887ec681f3Smrg            for (l = 0; l <= last_dst_level; ++l, ++m) {
15897ec681f3Smrg                fit_rect_format_inclusive(dst->base.base.info.format,
15907ec681f3Smrg                                          &rect,
15917ec681f3Smrg                                          dst->surfaces[l * 6 + z]->desc.Width,
15927ec681f3Smrg                                          dst->surfaces[l * 6 + z]->desc.Height);
15937ec681f3Smrg                NineSurface9_CopyMemToDefault(dst->surfaces[l * 6 + z],
15947ec681f3Smrg                                              src->surfaces[m * 6 + z],
15957ec681f3Smrg                                              (POINT *)&rect,
15967ec681f3Smrg                                              &rect);
15977ec681f3Smrg                rect_minify_inclusive(&rect);
15987ec681f3Smrg            }
15997ec681f3Smrg            u_box_origin_2d(0, 0, &src->dirty_rect[z]);
16007ec681f3Smrg            m -= l;
16017ec681f3Smrg        }
16027ec681f3Smrg    } else
16037ec681f3Smrg    if (dstb->base.type == D3DRTYPE_VOLUMETEXTURE) {
16047ec681f3Smrg        struct NineVolumeTexture9 *dst = NineVolumeTexture9(dstb);
16057ec681f3Smrg        struct NineVolumeTexture9 *src = NineVolumeTexture9(srcb);
16067ec681f3Smrg
16077ec681f3Smrg        if (src->dirty_box.width == 0)
16087ec681f3Smrg            return D3D_OK;
16097ec681f3Smrg        for (l = 0; l <= last_dst_level; ++l, ++m)
16107ec681f3Smrg            NineVolume9_CopyMemToDefault(dst->volumes[l],
16117ec681f3Smrg                                         src->volumes[m], 0, 0, 0, NULL);
16127ec681f3Smrg        u_box_3d(0, 0, 0, 0, 0, 0, &src->dirty_box);
16137ec681f3Smrg    } else{
16147ec681f3Smrg        assert(!"invalid texture type");
16157ec681f3Smrg    }
16167ec681f3Smrg
16177ec681f3Smrg    if (dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP) {
16187ec681f3Smrg        dstb->dirty_mip = TRUE;
16197ec681f3Smrg        NineBaseTexture9_GenerateMipSubLevels(dstb);
16207ec681f3Smrg    }
16217ec681f3Smrg
16227ec681f3Smrg    return D3D_OK;
16237ec681f3Smrg}
16247ec681f3Smrg
16257ec681f3SmrgHRESULT NINE_WINAPI
16267ec681f3SmrgNineDevice9_GetRenderTargetData( struct NineDevice9 *This,
16277ec681f3Smrg                                 IDirect3DSurface9 *pRenderTarget,
16287ec681f3Smrg                                 IDirect3DSurface9 *pDestSurface )
16297ec681f3Smrg{
16307ec681f3Smrg    struct NineSurface9 *dst = NineSurface9(pDestSurface);
16317ec681f3Smrg    struct NineSurface9 *src = NineSurface9(pRenderTarget);
16327ec681f3Smrg
16337ec681f3Smrg    DBG("This=%p pRenderTarget=%p pDestSurface=%p\n",
16347ec681f3Smrg        This, pRenderTarget, pDestSurface);
16357ec681f3Smrg
16367ec681f3Smrg    user_assert(pRenderTarget && pDestSurface, D3DERR_INVALIDCALL);
16377ec681f3Smrg
16387ec681f3Smrg    user_assert(dst->desc.Pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
16397ec681f3Smrg    user_assert(src->desc.Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
16407ec681f3Smrg
16417ec681f3Smrg    user_assert(dst->desc.MultiSampleType < 2, D3DERR_INVALIDCALL);
16427ec681f3Smrg    user_assert(src->desc.MultiSampleType < 2, D3DERR_INVALIDCALL);
16437ec681f3Smrg
16447ec681f3Smrg    user_assert(src->desc.Width == dst->desc.Width, D3DERR_INVALIDCALL);
16457ec681f3Smrg    user_assert(src->desc.Height == dst->desc.Height, D3DERR_INVALIDCALL);
16467ec681f3Smrg
16477ec681f3Smrg    user_assert(src->desc.Format != D3DFMT_NULL, D3DERR_INVALIDCALL);
16487ec681f3Smrg
16497ec681f3Smrg    NineSurface9_CopyDefaultToMem(dst, src);
16507ec681f3Smrg
16517ec681f3Smrg    return D3D_OK;
16527ec681f3Smrg}
16537ec681f3Smrg
16547ec681f3SmrgHRESULT NINE_WINAPI
16557ec681f3SmrgNineDevice9_GetFrontBufferData( struct NineDevice9 *This,
16567ec681f3Smrg                                UINT iSwapChain,
16577ec681f3Smrg                                IDirect3DSurface9 *pDestSurface )
16587ec681f3Smrg{
16597ec681f3Smrg    DBG("This=%p iSwapChain=%u pDestSurface=%p\n", This,
16607ec681f3Smrg        iSwapChain, pDestSurface);
16617ec681f3Smrg
16627ec681f3Smrg    user_assert(pDestSurface != NULL, D3DERR_INVALIDCALL);
16637ec681f3Smrg    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
16647ec681f3Smrg
16657ec681f3Smrg    return NineSwapChain9_GetFrontBufferData(This->swapchains[iSwapChain],
16667ec681f3Smrg                                             pDestSurface);
16677ec681f3Smrg}
16687ec681f3Smrg
16697ec681f3SmrgHRESULT NINE_WINAPI
16707ec681f3SmrgNineDevice9_StretchRect( struct NineDevice9 *This,
16717ec681f3Smrg                         IDirect3DSurface9 *pSourceSurface,
16727ec681f3Smrg                         const RECT *pSourceRect,
16737ec681f3Smrg                         IDirect3DSurface9 *pDestSurface,
16747ec681f3Smrg                         const RECT *pDestRect,
16757ec681f3Smrg                         D3DTEXTUREFILTERTYPE Filter )
16767ec681f3Smrg{
16777ec681f3Smrg    struct pipe_screen *screen = This->screen;
16787ec681f3Smrg    struct NineSurface9 *dst = NineSurface9(pDestSurface);
16797ec681f3Smrg    struct NineSurface9 *src = NineSurface9(pSourceSurface);
16807ec681f3Smrg    struct pipe_resource *dst_res, *src_res;
16817ec681f3Smrg    boolean zs;
16827ec681f3Smrg    struct pipe_blit_info blit;
16837ec681f3Smrg    boolean scaled, clamped, ms, flip_x = FALSE, flip_y = FALSE;
16847ec681f3Smrg
16857ec681f3Smrg    DBG("This=%p pSourceSurface=%p pSourceRect=%p pDestSurface=%p "
16867ec681f3Smrg        "pDestRect=%p Filter=%u\n",
16877ec681f3Smrg        This, pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter);
16887ec681f3Smrg    if (pSourceRect)
16897ec681f3Smrg        DBG("pSourceRect=(%u,%u)-(%u,%u)\n",
16907ec681f3Smrg            pSourceRect->left, pSourceRect->top,
16917ec681f3Smrg            pSourceRect->right, pSourceRect->bottom);
16927ec681f3Smrg    if (pDestRect)
16937ec681f3Smrg        DBG("pDestRect=(%u,%u)-(%u,%u)\n", pDestRect->left, pDestRect->top,
16947ec681f3Smrg            pDestRect->right, pDestRect->bottom);
16957ec681f3Smrg
16967ec681f3Smrg    user_assert(pSourceSurface && pDestSurface, D3DERR_INVALIDCALL);
16977ec681f3Smrg    user_assert(dst->base.pool == D3DPOOL_DEFAULT &&
16987ec681f3Smrg                src->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
16997ec681f3Smrg
17007ec681f3Smrg    dst_res = NineSurface9_GetResource(dst);
17017ec681f3Smrg    src_res = NineSurface9_GetResource(src);
17027ec681f3Smrg    zs = util_format_is_depth_or_stencil(dst_res->format);
17037ec681f3Smrg    user_assert(!zs || !This->in_scene, D3DERR_INVALIDCALL);
17047ec681f3Smrg    user_assert(!zs || !pSourceRect ||
17057ec681f3Smrg                (pSourceRect->left == 0 &&
17067ec681f3Smrg                 pSourceRect->top == 0 &&
17077ec681f3Smrg                 pSourceRect->right == src->desc.Width &&
17087ec681f3Smrg                 pSourceRect->bottom == src->desc.Height), D3DERR_INVALIDCALL);
17097ec681f3Smrg    user_assert(!zs || !pDestRect ||
17107ec681f3Smrg                (pDestRect->left == 0 &&
17117ec681f3Smrg                 pDestRect->top == 0 &&
17127ec681f3Smrg                 pDestRect->right == dst->desc.Width &&
17137ec681f3Smrg                 pDestRect->bottom == dst->desc.Height), D3DERR_INVALIDCALL);
17147ec681f3Smrg    user_assert(!zs ||
17157ec681f3Smrg                (dst->desc.Width == src->desc.Width &&
17167ec681f3Smrg                 dst->desc.Height == src->desc.Height), D3DERR_INVALIDCALL);
17177ec681f3Smrg    user_assert(zs || !util_format_is_depth_or_stencil(src_res->format),
17187ec681f3Smrg                D3DERR_INVALIDCALL);
17197ec681f3Smrg    user_assert(!zs || dst->desc.Format == src->desc.Format,
17207ec681f3Smrg                D3DERR_INVALIDCALL);
17217ec681f3Smrg    user_assert(screen->is_format_supported(screen, src_res->format,
17227ec681f3Smrg                                            src_res->target,
17237ec681f3Smrg                                            src_res->nr_samples,
17247ec681f3Smrg                                            src_res->nr_storage_samples,
17257ec681f3Smrg                                            PIPE_BIND_SAMPLER_VIEW),
17267ec681f3Smrg                D3DERR_INVALIDCALL);
17277ec681f3Smrg
17287ec681f3Smrg    /* We might want to permit these, but wine thinks we shouldn't. */
17297ec681f3Smrg    user_assert(!pDestRect ||
17307ec681f3Smrg                (pDestRect->left <= pDestRect->right &&
17317ec681f3Smrg                 pDestRect->top <= pDestRect->bottom), D3DERR_INVALIDCALL);
17327ec681f3Smrg    user_assert(!pSourceRect ||
17337ec681f3Smrg                (pSourceRect->left <= pSourceRect->right &&
17347ec681f3Smrg                 pSourceRect->top <= pSourceRect->bottom), D3DERR_INVALIDCALL);
17357ec681f3Smrg
17367ec681f3Smrg    memset(&blit, 0, sizeof(blit));
17377ec681f3Smrg    blit.dst.resource = dst_res;
17387ec681f3Smrg    blit.dst.level = dst->level;
17397ec681f3Smrg    blit.dst.box.z = dst->layer;
17407ec681f3Smrg    blit.dst.box.depth = 1;
17417ec681f3Smrg    blit.dst.format = dst_res->format;
17427ec681f3Smrg    if (pDestRect) {
17437ec681f3Smrg        flip_x = pDestRect->left > pDestRect->right;
17447ec681f3Smrg        if (flip_x) {
17457ec681f3Smrg            blit.dst.box.x = pDestRect->right;
17467ec681f3Smrg            blit.dst.box.width = pDestRect->left - pDestRect->right;
17477ec681f3Smrg        } else {
17487ec681f3Smrg            blit.dst.box.x = pDestRect->left;
17497ec681f3Smrg            blit.dst.box.width = pDestRect->right - pDestRect->left;
17507ec681f3Smrg        }
17517ec681f3Smrg        flip_y = pDestRect->top > pDestRect->bottom;
17527ec681f3Smrg        if (flip_y) {
17537ec681f3Smrg            blit.dst.box.y = pDestRect->bottom;
17547ec681f3Smrg            blit.dst.box.height = pDestRect->top - pDestRect->bottom;
17557ec681f3Smrg        } else {
17567ec681f3Smrg            blit.dst.box.y = pDestRect->top;
17577ec681f3Smrg            blit.dst.box.height = pDestRect->bottom - pDestRect->top;
17587ec681f3Smrg        }
17597ec681f3Smrg    } else {
17607ec681f3Smrg        blit.dst.box.x = 0;
17617ec681f3Smrg        blit.dst.box.y = 0;
17627ec681f3Smrg        blit.dst.box.width = dst->desc.Width;
17637ec681f3Smrg        blit.dst.box.height = dst->desc.Height;
17647ec681f3Smrg    }
17657ec681f3Smrg    blit.src.resource = src_res;
17667ec681f3Smrg    blit.src.level = src->level;
17677ec681f3Smrg    blit.src.box.z = src->layer;
17687ec681f3Smrg    blit.src.box.depth = 1;
17697ec681f3Smrg    blit.src.format = src_res->format;
17707ec681f3Smrg    if (pSourceRect) {
17717ec681f3Smrg        if (flip_x ^ (pSourceRect->left > pSourceRect->right)) {
17727ec681f3Smrg            blit.src.box.x = pSourceRect->right;
17737ec681f3Smrg            blit.src.box.width = pSourceRect->left - pSourceRect->right;
17747ec681f3Smrg        } else {
17757ec681f3Smrg            blit.src.box.x = pSourceRect->left;
17767ec681f3Smrg            blit.src.box.width = pSourceRect->right - pSourceRect->left;
17777ec681f3Smrg        }
17787ec681f3Smrg        if (flip_y ^ (pSourceRect->top > pSourceRect->bottom)) {
17797ec681f3Smrg            blit.src.box.y = pSourceRect->bottom;
17807ec681f3Smrg            blit.src.box.height = pSourceRect->top - pSourceRect->bottom;
17817ec681f3Smrg        } else {
17827ec681f3Smrg            blit.src.box.y = pSourceRect->top;
17837ec681f3Smrg            blit.src.box.height = pSourceRect->bottom - pSourceRect->top;
17847ec681f3Smrg        }
17857ec681f3Smrg    } else {
17867ec681f3Smrg        blit.src.box.x = flip_x ? src->desc.Width : 0;
17877ec681f3Smrg        blit.src.box.y = flip_y ? src->desc.Height : 0;
17887ec681f3Smrg        blit.src.box.width = flip_x ? -src->desc.Width : src->desc.Width;
17897ec681f3Smrg        blit.src.box.height = flip_y ? -src->desc.Height : src->desc.Height;
17907ec681f3Smrg    }
17917ec681f3Smrg    blit.mask = zs ? PIPE_MASK_ZS : PIPE_MASK_RGBA;
17927ec681f3Smrg    blit.filter = Filter == D3DTEXF_LINEAR ?
17937ec681f3Smrg       PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST;
17947ec681f3Smrg    blit.scissor_enable = FALSE;
17957ec681f3Smrg    blit.alpha_blend = FALSE;
17967ec681f3Smrg
17977ec681f3Smrg    /* If both of a src and dst dimension are negative, flip them. */
17987ec681f3Smrg    if (blit.dst.box.width < 0 && blit.src.box.width < 0) {
17997ec681f3Smrg        blit.dst.box.width = -blit.dst.box.width;
18007ec681f3Smrg        blit.src.box.width = -blit.src.box.width;
18017ec681f3Smrg    }
18027ec681f3Smrg    if (blit.dst.box.height < 0 && blit.src.box.height < 0) {
18037ec681f3Smrg        blit.dst.box.height = -blit.dst.box.height;
18047ec681f3Smrg        blit.src.box.height = -blit.src.box.height;
18057ec681f3Smrg    }
18067ec681f3Smrg    scaled =
18077ec681f3Smrg        blit.dst.box.width != blit.src.box.width ||
18087ec681f3Smrg        blit.dst.box.height != blit.src.box.height;
18097ec681f3Smrg
18107ec681f3Smrg    user_assert(!scaled || dst != src, D3DERR_INVALIDCALL);
18117ec681f3Smrg    user_assert(!scaled ||
18127ec681f3Smrg                !NineSurface9_IsOffscreenPlain(dst), D3DERR_INVALIDCALL);
18137ec681f3Smrg    user_assert(!NineSurface9_IsOffscreenPlain(dst) ||
18147ec681f3Smrg                NineSurface9_IsOffscreenPlain(src), D3DERR_INVALIDCALL);
18157ec681f3Smrg    user_assert(NineSurface9_IsOffscreenPlain(dst) ||
18167ec681f3Smrg                dst->desc.Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL),
18177ec681f3Smrg                D3DERR_INVALIDCALL);
18187ec681f3Smrg    user_assert(!scaled ||
18197ec681f3Smrg                (!util_format_is_compressed(dst->base.info.format) &&
18207ec681f3Smrg                 !util_format_is_compressed(src->base.info.format)),
18217ec681f3Smrg                D3DERR_INVALIDCALL);
18227ec681f3Smrg
18237ec681f3Smrg    user_warn(src == dst &&
18247ec681f3Smrg              u_box_test_intersection_2d(&blit.src.box, &blit.dst.box));
18257ec681f3Smrg
18267ec681f3Smrg    /* Check for clipping/clamping: */
18277ec681f3Smrg    {
18287ec681f3Smrg        struct pipe_box box;
18297ec681f3Smrg        int xy;
18307ec681f3Smrg
18317ec681f3Smrg        xy = u_box_clip_2d(&box, &blit.dst.box,
18327ec681f3Smrg                           dst->desc.Width, dst->desc.Height);
18337ec681f3Smrg        if (xy < 0)
18347ec681f3Smrg            return D3D_OK;
18357ec681f3Smrg        if (xy == 0)
18367ec681f3Smrg            xy = u_box_clip_2d(&box, &blit.src.box,
18377ec681f3Smrg                               src->desc.Width, src->desc.Height);
18387ec681f3Smrg        clamped = !!xy;
18397ec681f3Smrg    }
18407ec681f3Smrg
18417ec681f3Smrg    ms = (dst->desc.MultiSampleType != src->desc.MultiSampleType) ||
18427ec681f3Smrg         (dst->desc.MultiSampleQuality != src->desc.MultiSampleQuality);
18437ec681f3Smrg
18447ec681f3Smrg    if (clamped || scaled || (blit.dst.format != blit.src.format) || ms) {
18457ec681f3Smrg        DBG("using pipe->blit()\n");
18467ec681f3Smrg        /* TODO: software scaling */
18477ec681f3Smrg        user_assert(screen->is_format_supported(screen, dst_res->format,
18487ec681f3Smrg                                                dst_res->target,
18497ec681f3Smrg                                                dst_res->nr_samples,
18507ec681f3Smrg                                                dst_res->nr_storage_samples,
18517ec681f3Smrg                                                zs ? PIPE_BIND_DEPTH_STENCIL :
18527ec681f3Smrg                                                PIPE_BIND_RENDER_TARGET),
18537ec681f3Smrg                    D3DERR_INVALIDCALL);
18547ec681f3Smrg
18557ec681f3Smrg        nine_context_blit(This, (struct NineUnknown *)dst,
18567ec681f3Smrg                          (struct NineUnknown *)src, &blit);
18577ec681f3Smrg    } else {
18587ec681f3Smrg        assert(blit.dst.box.x >= 0 && blit.dst.box.y >= 0 &&
18597ec681f3Smrg               blit.src.box.x >= 0 && blit.src.box.y >= 0 &&
18607ec681f3Smrg               blit.dst.box.x + blit.dst.box.width <= dst->desc.Width &&
18617ec681f3Smrg               blit.src.box.x + blit.src.box.width <= src->desc.Width &&
18627ec681f3Smrg               blit.dst.box.y + blit.dst.box.height <= dst->desc.Height &&
18637ec681f3Smrg               blit.src.box.y + blit.src.box.height <= src->desc.Height);
18647ec681f3Smrg        /* Or drivers might crash ... */
18657ec681f3Smrg        DBG("Using resource_copy_region.\n");
18667ec681f3Smrg        nine_context_resource_copy_region(This, (struct NineUnknown *)dst,
18677ec681f3Smrg                                          (struct NineUnknown *)src,
18687ec681f3Smrg                                          blit.dst.resource, blit.dst.level,
18697ec681f3Smrg                                          &blit.dst.box,
18707ec681f3Smrg                                          blit.src.resource, blit.src.level,
18717ec681f3Smrg                                          &blit.src.box);
18727ec681f3Smrg    }
18737ec681f3Smrg
18747ec681f3Smrg    /* Communicate the container it needs to update sublevels - if apply */
18757ec681f3Smrg    NineSurface9_MarkContainerDirty(dst);
18767ec681f3Smrg
18777ec681f3Smrg    return D3D_OK;
18787ec681f3Smrg}
18797ec681f3Smrg
18807ec681f3SmrgHRESULT NINE_WINAPI
18817ec681f3SmrgNineDevice9_ColorFill( struct NineDevice9 *This,
18827ec681f3Smrg                       IDirect3DSurface9 *pSurface,
18837ec681f3Smrg                       const RECT *pRect,
18847ec681f3Smrg                       D3DCOLOR color )
18857ec681f3Smrg{
18867ec681f3Smrg    struct NineSurface9 *surf = NineSurface9(pSurface);
18877ec681f3Smrg    unsigned x, y, w, h;
18887ec681f3Smrg
18897ec681f3Smrg    DBG("This=%p pSurface=%p pRect=%p color=%08x\n", This,
18907ec681f3Smrg        pSurface, pRect, color);
18917ec681f3Smrg    if (pRect)
18927ec681f3Smrg        DBG("pRect=(%u,%u)-(%u,%u)\n", pRect->left, pRect->top,
18937ec681f3Smrg            pRect->right, pRect->bottom);
18947ec681f3Smrg
18957ec681f3Smrg    user_assert(pSurface != NULL, D3DERR_INVALIDCALL);
18967ec681f3Smrg
18977ec681f3Smrg    user_assert(surf->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
18987ec681f3Smrg
18997ec681f3Smrg    user_assert((surf->base.usage & D3DUSAGE_RENDERTARGET) ||
19007ec681f3Smrg                NineSurface9_IsOffscreenPlain(surf), D3DERR_INVALIDCALL);
19017ec681f3Smrg
19027ec681f3Smrg    user_assert(surf->desc.Format != D3DFMT_NULL, D3D_OK);
19037ec681f3Smrg
19047ec681f3Smrg    if (pRect) {
19057ec681f3Smrg        x = pRect->left;
19067ec681f3Smrg        y = pRect->top;
19077ec681f3Smrg        w = pRect->right - pRect->left;
19087ec681f3Smrg        h = pRect->bottom - pRect->top;
19097ec681f3Smrg        /* Wine tests: */
19107ec681f3Smrg        if (compressed_format(surf->desc.Format)) {
19117ec681f3Smrg           const unsigned bw = util_format_get_blockwidth(surf->base.info.format);
19127ec681f3Smrg           const unsigned bh = util_format_get_blockheight(surf->base.info.format);
19137ec681f3Smrg
19147ec681f3Smrg           user_assert(!(x % bw) && !(y % bh) && !(w % bw) && !(h % bh),
19157ec681f3Smrg                       D3DERR_INVALIDCALL);
19167ec681f3Smrg        }
19177ec681f3Smrg    } else{
19187ec681f3Smrg        x = 0;
19197ec681f3Smrg        y = 0;
19207ec681f3Smrg        w = surf->desc.Width;
19217ec681f3Smrg        h = surf->desc.Height;
19227ec681f3Smrg    }
19237ec681f3Smrg
19247ec681f3Smrg    if (surf->base.info.bind & PIPE_BIND_RENDER_TARGET) {
19257ec681f3Smrg        nine_context_clear_render_target(This, surf, color, x, y, w, h);
19267ec681f3Smrg    } else {
19277ec681f3Smrg        D3DLOCKED_RECT lock;
19287ec681f3Smrg        union util_color uc;
19297ec681f3Smrg        HRESULT hr;
19307ec681f3Smrg        /* XXX: lock pRect and fix util_fill_rect */
19317ec681f3Smrg        hr = NineSurface9_LockRect(surf, &lock, NULL, pRect ? 0 : D3DLOCK_DISCARD);
19327ec681f3Smrg        if (FAILED(hr))
19337ec681f3Smrg            return hr;
19347ec681f3Smrg        util_pack_color_ub(color >> 16, color >> 8, color >> 0, color >> 24,
19357ec681f3Smrg                           surf->base.info.format, &uc);
19367ec681f3Smrg        util_fill_rect(lock.pBits, surf->base.info.format,lock.Pitch,
19377ec681f3Smrg                       x, y, w, h, &uc);
19387ec681f3Smrg        NineSurface9_UnlockRect(surf);
19397ec681f3Smrg    }
19407ec681f3Smrg
19417ec681f3Smrg    return D3D_OK;
19427ec681f3Smrg}
19437ec681f3Smrg
19447ec681f3SmrgHRESULT NINE_WINAPI
19457ec681f3SmrgNineDevice9_CreateOffscreenPlainSurface( struct NineDevice9 *This,
19467ec681f3Smrg                                         UINT Width,
19477ec681f3Smrg                                         UINT Height,
19487ec681f3Smrg                                         D3DFORMAT Format,
19497ec681f3Smrg                                         D3DPOOL Pool,
19507ec681f3Smrg                                         IDirect3DSurface9 **ppSurface,
19517ec681f3Smrg                                         HANDLE *pSharedHandle )
19527ec681f3Smrg{
19537ec681f3Smrg    HRESULT hr;
19547ec681f3Smrg
19557ec681f3Smrg    DBG("This=%p Width=%u Height=%u Format=%s(0x%x) Pool=%u "
19567ec681f3Smrg        "ppSurface=%p pSharedHandle=%p\n", This,
19577ec681f3Smrg        Width, Height, d3dformat_to_string(Format), Format, Pool,
19587ec681f3Smrg        ppSurface, pSharedHandle);
19597ec681f3Smrg
19607ec681f3Smrg    user_assert(ppSurface != NULL, D3DERR_INVALIDCALL);
19617ec681f3Smrg    *ppSurface = NULL;
19627ec681f3Smrg    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT
19637ec681f3Smrg                               || Pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
19647ec681f3Smrg    user_assert(Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL);
19657ec681f3Smrg
19667ec681f3Smrg    /* Can be used with StretchRect and ColorFill. It's also always lockable.
19677ec681f3Smrg     */
19687ec681f3Smrg    hr = create_zs_or_rt_surface(This, 2, Pool, Width, Height,
19697ec681f3Smrg                                 Format,
19707ec681f3Smrg                                 D3DMULTISAMPLE_NONE, 0,
19717ec681f3Smrg                                 TRUE,
19727ec681f3Smrg                                 ppSurface, pSharedHandle);
19737ec681f3Smrg    if (FAILED(hr))
19747ec681f3Smrg        DBG("Failed to create surface.\n");
19757ec681f3Smrg    return hr;
19767ec681f3Smrg}
19777ec681f3Smrg
19787ec681f3SmrgHRESULT NINE_WINAPI
19797ec681f3SmrgNineDevice9_SetRenderTarget( struct NineDevice9 *This,
19807ec681f3Smrg                             DWORD RenderTargetIndex,
19817ec681f3Smrg                             IDirect3DSurface9 *pRenderTarget )
19827ec681f3Smrg{
19837ec681f3Smrg    struct NineSurface9 *rt = NineSurface9(pRenderTarget);
19847ec681f3Smrg    const unsigned i = RenderTargetIndex;
19857ec681f3Smrg
19867ec681f3Smrg    DBG("This=%p RenderTargetIndex=%u pRenderTarget=%p\n", This,
19877ec681f3Smrg        RenderTargetIndex, pRenderTarget);
19887ec681f3Smrg
19897ec681f3Smrg    user_assert(i < This->caps.NumSimultaneousRTs, D3DERR_INVALIDCALL);
19907ec681f3Smrg    user_assert(i != 0 || pRenderTarget, D3DERR_INVALIDCALL);
19917ec681f3Smrg    user_assert(!pRenderTarget ||
19927ec681f3Smrg                rt->desc.Usage & D3DUSAGE_RENDERTARGET, D3DERR_INVALIDCALL);
19937ec681f3Smrg
19947ec681f3Smrg    if (i == 0) {
19957ec681f3Smrg        This->state.viewport.X = 0;
19967ec681f3Smrg        This->state.viewport.Y = 0;
19977ec681f3Smrg        This->state.viewport.Width = rt->desc.Width;
19987ec681f3Smrg        This->state.viewport.Height = rt->desc.Height;
19997ec681f3Smrg        This->state.viewport.MinZ = 0.0f;
20007ec681f3Smrg        This->state.viewport.MaxZ = 1.0f;
20017ec681f3Smrg
20027ec681f3Smrg        This->state.scissor.minx = 0;
20037ec681f3Smrg        This->state.scissor.miny = 0;
20047ec681f3Smrg        This->state.scissor.maxx = rt->desc.Width;
20057ec681f3Smrg        This->state.scissor.maxy = rt->desc.Height;
20067ec681f3Smrg        nine_context_set_viewport(This, &This->state.viewport);
20077ec681f3Smrg        nine_context_set_scissor(This, &This->state.scissor);
20087ec681f3Smrg    }
20097ec681f3Smrg
20107ec681f3Smrg    if (This->state.rt[i] != NineSurface9(pRenderTarget))
20117ec681f3Smrg        nine_bind(&This->state.rt[i], pRenderTarget);
20127ec681f3Smrg
20137ec681f3Smrg    nine_context_set_render_target(This, i, rt);
20147ec681f3Smrg    return D3D_OK;
20157ec681f3Smrg}
20167ec681f3Smrg
20177ec681f3SmrgHRESULT NINE_WINAPI
20187ec681f3SmrgNineDevice9_GetRenderTarget( struct NineDevice9 *This,
20197ec681f3Smrg                             DWORD RenderTargetIndex,
20207ec681f3Smrg                             IDirect3DSurface9 **ppRenderTarget )
20217ec681f3Smrg{
20227ec681f3Smrg    const unsigned i = RenderTargetIndex;
20237ec681f3Smrg
20247ec681f3Smrg    user_assert(i < This->caps.NumSimultaneousRTs, D3DERR_INVALIDCALL);
20257ec681f3Smrg    user_assert(ppRenderTarget, D3DERR_INVALIDCALL);
20267ec681f3Smrg
20277ec681f3Smrg    *ppRenderTarget = (IDirect3DSurface9 *)This->state.rt[i];
20287ec681f3Smrg    if (!This->state.rt[i])
20297ec681f3Smrg        return D3DERR_NOTFOUND;
20307ec681f3Smrg
20317ec681f3Smrg    NineUnknown_AddRef(NineUnknown(This->state.rt[i]));
20327ec681f3Smrg    return D3D_OK;
20337ec681f3Smrg}
20347ec681f3Smrg
20357ec681f3SmrgHRESULT NINE_WINAPI
20367ec681f3SmrgNineDevice9_SetDepthStencilSurface( struct NineDevice9 *This,
20377ec681f3Smrg                                    IDirect3DSurface9 *pNewZStencil )
20387ec681f3Smrg{
20397ec681f3Smrg    struct NineSurface9 *ds = NineSurface9(pNewZStencil);
20407ec681f3Smrg    DBG("This=%p pNewZStencil=%p\n", This, pNewZStencil);
20417ec681f3Smrg
20427ec681f3Smrg    user_assert(!ds || util_format_is_depth_or_stencil(ds->base.info.format),
20437ec681f3Smrg                D3DERR_INVALIDCALL);
20447ec681f3Smrg
20457ec681f3Smrg    if (This->state.ds != ds) {
20467ec681f3Smrg        nine_bind(&This->state.ds, ds);
20477ec681f3Smrg        nine_context_set_depth_stencil(This, ds);
20487ec681f3Smrg    }
20497ec681f3Smrg    return D3D_OK;
20507ec681f3Smrg}
20517ec681f3Smrg
20527ec681f3SmrgHRESULT NINE_WINAPI
20537ec681f3SmrgNineDevice9_GetDepthStencilSurface( struct NineDevice9 *This,
20547ec681f3Smrg                                    IDirect3DSurface9 **ppZStencilSurface )
20557ec681f3Smrg{
20567ec681f3Smrg    user_assert(ppZStencilSurface, D3DERR_INVALIDCALL);
20577ec681f3Smrg
20587ec681f3Smrg    *ppZStencilSurface = (IDirect3DSurface9 *)This->state.ds;
20597ec681f3Smrg    if (!This->state.ds)
20607ec681f3Smrg        return D3DERR_NOTFOUND;
20617ec681f3Smrg
20627ec681f3Smrg    NineUnknown_AddRef(NineUnknown(This->state.ds));
20637ec681f3Smrg    return D3D_OK;
20647ec681f3Smrg}
20657ec681f3Smrg
20667ec681f3SmrgHRESULT NINE_WINAPI
20677ec681f3SmrgNineDevice9_BeginScene( struct NineDevice9 *This )
20687ec681f3Smrg{
20697ec681f3Smrg    DBG("This=%p\n", This);
20707ec681f3Smrg    user_assert(!This->in_scene, D3DERR_INVALIDCALL);
20717ec681f3Smrg    This->in_scene = TRUE;
20727ec681f3Smrg    /* Do we want to do anything else here ? */
20737ec681f3Smrg    return D3D_OK;
20747ec681f3Smrg}
20757ec681f3Smrg
20767ec681f3SmrgHRESULT NINE_WINAPI
20777ec681f3SmrgNineDevice9_EndScene( struct NineDevice9 *This )
20787ec681f3Smrg{
20797ec681f3Smrg    DBG("This=%p\n", This);
20807ec681f3Smrg    user_assert(This->in_scene, D3DERR_INVALIDCALL);
20817ec681f3Smrg    This->in_scene = FALSE;
20827ec681f3Smrg    This->end_scene_since_present++;
20837ec681f3Smrg    /* EndScene() is supposed to flush the GPU commands.
20847ec681f3Smrg     * The idea is to flush ahead of the Present() call.
20857ec681f3Smrg     * (Apps could take advantage of this by inserting CPU
20867ec681f3Smrg     * work between EndScene() and Present()).
20877ec681f3Smrg     * Most apps will have one EndScene per frame.
20887ec681f3Smrg     * Some will have 2 or 3.
20897ec681f3Smrg     * Some bad behaving apps do a lot of them.
20907ec681f3Smrg     * As flushing has a cost, do it only once. */
20917ec681f3Smrg    if (This->end_scene_since_present <= 1) {
20927ec681f3Smrg        nine_context_pipe_flush(This);
20937ec681f3Smrg        nine_csmt_flush(This);
20947ec681f3Smrg    }
20957ec681f3Smrg    return D3D_OK;
20967ec681f3Smrg}
20977ec681f3Smrg
20987ec681f3SmrgHRESULT NINE_WINAPI
20997ec681f3SmrgNineDevice9_Clear( struct NineDevice9 *This,
21007ec681f3Smrg                   DWORD Count,
21017ec681f3Smrg                   const D3DRECT *pRects,
21027ec681f3Smrg                   DWORD Flags,
21037ec681f3Smrg                   D3DCOLOR Color,
21047ec681f3Smrg                   float Z,
21057ec681f3Smrg                   DWORD Stencil )
21067ec681f3Smrg{
21077ec681f3Smrg    struct NineSurface9 *zsbuf_surf = This->state.ds;
21087ec681f3Smrg
21097ec681f3Smrg    DBG("This=%p Count=%u pRects=%p Flags=%x Color=%08x Z=%f Stencil=%x\n",
21107ec681f3Smrg        This, Count, pRects, Flags, Color, Z, Stencil);
21117ec681f3Smrg
21127ec681f3Smrg    user_assert(This->state.ds || !(Flags & NINED3DCLEAR_DEPTHSTENCIL),
21137ec681f3Smrg                D3DERR_INVALIDCALL);
21147ec681f3Smrg    user_assert(!(Flags & D3DCLEAR_STENCIL) ||
21157ec681f3Smrg                (zsbuf_surf &&
21167ec681f3Smrg                 util_format_is_depth_and_stencil(zsbuf_surf->base.info.format)),
21177ec681f3Smrg                D3DERR_INVALIDCALL);
21187ec681f3Smrg#ifdef NINE_STRICT
21197ec681f3Smrg    user_assert((Count && pRects) || (!Count && !pRects), D3DERR_INVALIDCALL);
21207ec681f3Smrg#else
21217ec681f3Smrg    user_warn((pRects && !Count) || (!pRects && Count));
21227ec681f3Smrg    if (pRects && !Count)
21237ec681f3Smrg        return D3D_OK;
21247ec681f3Smrg    if (!pRects)
21257ec681f3Smrg        Count = 0;
21267ec681f3Smrg#endif
21277ec681f3Smrg
21287ec681f3Smrg    nine_context_clear_fb(This, Count, pRects, Flags, Color, Z, Stencil);
21297ec681f3Smrg    return D3D_OK;
21307ec681f3Smrg}
21317ec681f3Smrg
21327ec681f3Smrgstatic void
21337ec681f3Smrgnine_D3DMATRIX_print(const D3DMATRIX *M)
21347ec681f3Smrg{
21357ec681f3Smrg    DBG("\n(%f %f %f %f)\n"
21367ec681f3Smrg        "(%f %f %f %f)\n"
21377ec681f3Smrg        "(%f %f %f %f)\n"
21387ec681f3Smrg        "(%f %f %f %f)\n",
21397ec681f3Smrg        M->m[0][0], M->m[0][1], M->m[0][2], M->m[0][3],
21407ec681f3Smrg        M->m[1][0], M->m[1][1], M->m[1][2], M->m[1][3],
21417ec681f3Smrg        M->m[2][0], M->m[2][1], M->m[2][2], M->m[2][3],
21427ec681f3Smrg        M->m[3][0], M->m[3][1], M->m[3][2], M->m[3][3]);
21437ec681f3Smrg}
21447ec681f3Smrg
21457ec681f3SmrgHRESULT NINE_WINAPI
21467ec681f3SmrgNineDevice9_SetTransform( struct NineDevice9 *This,
21477ec681f3Smrg                          D3DTRANSFORMSTATETYPE State,
21487ec681f3Smrg                          const D3DMATRIX *pMatrix )
21497ec681f3Smrg{
21507ec681f3Smrg    struct nine_state *state = This->update;
21517ec681f3Smrg    D3DMATRIX *M = nine_state_access_transform(&state->ff, State, TRUE);
21527ec681f3Smrg
21537ec681f3Smrg    DBG("This=%p State=%d pMatrix=%p\n", This, State, pMatrix);
21547ec681f3Smrg
21557ec681f3Smrg    user_assert(pMatrix, D3DERR_INVALIDCALL);
21567ec681f3Smrg    user_assert(M, D3DERR_INVALIDCALL);
21577ec681f3Smrg    nine_D3DMATRIX_print(pMatrix);
21587ec681f3Smrg
21597ec681f3Smrg    *M = *pMatrix;
21607ec681f3Smrg    if (unlikely(This->is_recording)) {
21617ec681f3Smrg        state->ff.changed.transform[State / 32] |= 1 << (State % 32);
21627ec681f3Smrg        state->changed.group |= NINE_STATE_FF_VSTRANSF;
21637ec681f3Smrg    } else
21647ec681f3Smrg        nine_context_set_transform(This, State, pMatrix);
21657ec681f3Smrg
21667ec681f3Smrg    return D3D_OK;
21677ec681f3Smrg}
21687ec681f3Smrg
21697ec681f3SmrgHRESULT NINE_WINAPI
21707ec681f3SmrgNineDevice9_GetTransform( struct NineDevice9 *This,
21717ec681f3Smrg                          D3DTRANSFORMSTATETYPE State,
21727ec681f3Smrg                          D3DMATRIX *pMatrix )
21737ec681f3Smrg{
21747ec681f3Smrg    D3DMATRIX *M;
21757ec681f3Smrg
21767ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
21777ec681f3Smrg    M = nine_state_access_transform(&This->state.ff, State, FALSE);
21787ec681f3Smrg    user_assert(pMatrix, D3DERR_INVALIDCALL);
21797ec681f3Smrg    user_assert(M, D3DERR_INVALIDCALL);
21807ec681f3Smrg    *pMatrix = *M;
21817ec681f3Smrg    return D3D_OK;
21827ec681f3Smrg}
21837ec681f3Smrg
21847ec681f3SmrgHRESULT NINE_WINAPI
21857ec681f3SmrgNineDevice9_MultiplyTransform( struct NineDevice9 *This,
21867ec681f3Smrg                               D3DTRANSFORMSTATETYPE State,
21877ec681f3Smrg                               const D3DMATRIX *pMatrix )
21887ec681f3Smrg{
21897ec681f3Smrg    struct nine_state *state = This->update;
21907ec681f3Smrg    D3DMATRIX T;
21917ec681f3Smrg    D3DMATRIX *M = nine_state_access_transform(&state->ff, State, TRUE);
21927ec681f3Smrg
21937ec681f3Smrg    DBG("This=%p State=%d pMatrix=%p\n", This, State, pMatrix);
21947ec681f3Smrg
21957ec681f3Smrg    user_assert(pMatrix, D3DERR_INVALIDCALL);
21967ec681f3Smrg    user_assert(M, D3DERR_INVALIDCALL);
21977ec681f3Smrg
21987ec681f3Smrg    nine_d3d_matrix_matrix_mul(&T, pMatrix, M);
21997ec681f3Smrg    return NineDevice9_SetTransform(This, State, &T);
22007ec681f3Smrg}
22017ec681f3Smrg
22027ec681f3SmrgHRESULT NINE_WINAPI
22037ec681f3SmrgNineDevice9_SetViewport( struct NineDevice9 *This,
22047ec681f3Smrg                         const D3DVIEWPORT9 *pViewport )
22057ec681f3Smrg{
22067ec681f3Smrg    struct nine_state *state = This->update;
22077ec681f3Smrg
22087ec681f3Smrg    DBG("X=%u Y=%u W=%u H=%u MinZ=%f MaxZ=%f\n",
22097ec681f3Smrg        pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height,
22107ec681f3Smrg        pViewport->MinZ, pViewport->MaxZ);
22117ec681f3Smrg
22127ec681f3Smrg    user_assert(pViewport != NULL, D3DERR_INVALIDCALL);
22137ec681f3Smrg    state->viewport = *pViewport;
22147ec681f3Smrg    nine_context_set_viewport(This, pViewport);
22157ec681f3Smrg
22167ec681f3Smrg    return D3D_OK;
22177ec681f3Smrg}
22187ec681f3Smrg
22197ec681f3SmrgHRESULT NINE_WINAPI
22207ec681f3SmrgNineDevice9_GetViewport( struct NineDevice9 *This,
22217ec681f3Smrg                         D3DVIEWPORT9 *pViewport )
22227ec681f3Smrg{
22237ec681f3Smrg    user_assert(pViewport != NULL, D3DERR_INVALIDCALL);
22247ec681f3Smrg    *pViewport = This->state.viewport;
22257ec681f3Smrg    return D3D_OK;
22267ec681f3Smrg}
22277ec681f3Smrg
22287ec681f3SmrgHRESULT NINE_WINAPI
22297ec681f3SmrgNineDevice9_SetMaterial( struct NineDevice9 *This,
22307ec681f3Smrg                         const D3DMATERIAL9 *pMaterial )
22317ec681f3Smrg{
22327ec681f3Smrg    struct nine_state *state = This->update;
22337ec681f3Smrg
22347ec681f3Smrg    DBG("This=%p pMaterial=%p\n", This, pMaterial);
22357ec681f3Smrg    if (pMaterial)
22367ec681f3Smrg        nine_dump_D3DMATERIAL9(DBG_FF, pMaterial);
22377ec681f3Smrg
22387ec681f3Smrg    user_assert(pMaterial, E_POINTER);
22397ec681f3Smrg
22407ec681f3Smrg    state->ff.material = *pMaterial;
22417ec681f3Smrg    if (unlikely(This->is_recording))
22427ec681f3Smrg        state->changed.group |= NINE_STATE_FF_MATERIAL;
22437ec681f3Smrg    else
22447ec681f3Smrg        nine_context_set_material(This, pMaterial);
22457ec681f3Smrg
22467ec681f3Smrg    return D3D_OK;
22477ec681f3Smrg}
22487ec681f3Smrg
22497ec681f3SmrgHRESULT NINE_WINAPI
22507ec681f3SmrgNineDevice9_GetMaterial( struct NineDevice9 *This,
22517ec681f3Smrg                         D3DMATERIAL9 *pMaterial )
22527ec681f3Smrg{
22537ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
22547ec681f3Smrg    user_assert(pMaterial, E_POINTER);
22557ec681f3Smrg    *pMaterial = This->state.ff.material;
22567ec681f3Smrg    return D3D_OK;
22577ec681f3Smrg}
22587ec681f3Smrg
22597ec681f3SmrgHRESULT NINE_WINAPI
22607ec681f3SmrgNineDevice9_SetLight( struct NineDevice9 *This,
22617ec681f3Smrg                      DWORD Index,
22627ec681f3Smrg                      const D3DLIGHT9 *pLight )
22637ec681f3Smrg{
22647ec681f3Smrg    struct nine_state *state = This->update;
22657ec681f3Smrg    HRESULT hr;
22667ec681f3Smrg
22677ec681f3Smrg    DBG("This=%p Index=%u pLight=%p\n", This, Index, pLight);
22687ec681f3Smrg    if (pLight)
22697ec681f3Smrg        nine_dump_D3DLIGHT9(DBG_FF, pLight);
22707ec681f3Smrg
22717ec681f3Smrg    user_assert(pLight, D3DERR_INVALIDCALL);
22727ec681f3Smrg    user_assert(pLight->Type < NINED3DLIGHT_INVALID, D3DERR_INVALIDCALL);
22737ec681f3Smrg
22747ec681f3Smrg    user_assert(Index < NINE_MAX_LIGHTS, D3DERR_INVALIDCALL); /* sanity */
22757ec681f3Smrg
22767ec681f3Smrg    hr = nine_state_set_light(&state->ff, Index, pLight);
22777ec681f3Smrg    if (hr != D3D_OK)
22787ec681f3Smrg        return hr;
22797ec681f3Smrg
22807ec681f3Smrg    if (pLight->Type != D3DLIGHT_DIRECTIONAL &&
22817ec681f3Smrg        pLight->Attenuation0 == 0.0f &&
22827ec681f3Smrg        pLight->Attenuation1 == 0.0f &&
22837ec681f3Smrg        pLight->Attenuation2 == 0.0f) {
22847ec681f3Smrg        DBG("Warning: all D3DLIGHT9.Attenuation[i] are 0\n");
22857ec681f3Smrg    }
22867ec681f3Smrg
22877ec681f3Smrg    if (unlikely(This->is_recording))
22887ec681f3Smrg        state->changed.group |= NINE_STATE_FF_LIGHTING;
22897ec681f3Smrg    else
22907ec681f3Smrg        nine_context_set_light(This, Index, pLight);
22917ec681f3Smrg
22927ec681f3Smrg    return D3D_OK;
22937ec681f3Smrg}
22947ec681f3Smrg
22957ec681f3SmrgHRESULT NINE_WINAPI
22967ec681f3SmrgNineDevice9_GetLight( struct NineDevice9 *This,
22977ec681f3Smrg                      DWORD Index,
22987ec681f3Smrg                      D3DLIGHT9 *pLight )
22997ec681f3Smrg{
23007ec681f3Smrg    const struct nine_state *state = &This->state;
23017ec681f3Smrg
23027ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
23037ec681f3Smrg    user_assert(pLight, D3DERR_INVALIDCALL);
23047ec681f3Smrg    user_assert(Index < state->ff.num_lights, D3DERR_INVALIDCALL);
23057ec681f3Smrg    user_assert(state->ff.light[Index].Type < NINED3DLIGHT_INVALID,
23067ec681f3Smrg                D3DERR_INVALIDCALL);
23077ec681f3Smrg
23087ec681f3Smrg    *pLight = state->ff.light[Index];
23097ec681f3Smrg
23107ec681f3Smrg    return D3D_OK;
23117ec681f3Smrg}
23127ec681f3Smrg
23137ec681f3SmrgHRESULT NINE_WINAPI
23147ec681f3SmrgNineDevice9_LightEnable( struct NineDevice9 *This,
23157ec681f3Smrg                         DWORD Index,
23167ec681f3Smrg                         BOOL Enable )
23177ec681f3Smrg{
23187ec681f3Smrg    struct nine_state *state = This->update;
23197ec681f3Smrg
23207ec681f3Smrg    DBG("This=%p Index=%u Enable=%i\n", This, Index, Enable);
23217ec681f3Smrg
23227ec681f3Smrg    if (Index >= state->ff.num_lights ||
23237ec681f3Smrg        state->ff.light[Index].Type == NINED3DLIGHT_INVALID) {
23247ec681f3Smrg        /* This should create a default light. */
23257ec681f3Smrg        D3DLIGHT9 light;
23267ec681f3Smrg        memset(&light, 0, sizeof(light));
23277ec681f3Smrg        light.Type = D3DLIGHT_DIRECTIONAL;
23287ec681f3Smrg        light.Diffuse.r = 1.0f;
23297ec681f3Smrg        light.Diffuse.g = 1.0f;
23307ec681f3Smrg        light.Diffuse.b = 1.0f;
23317ec681f3Smrg        light.Direction.z = 1.0f;
23327ec681f3Smrg        NineDevice9_SetLight(This, Index, &light);
23337ec681f3Smrg    }
23347ec681f3Smrg
23357ec681f3Smrg    nine_state_light_enable(&state->ff, Index, Enable);
23367ec681f3Smrg    if (likely(!This->is_recording))
23377ec681f3Smrg        nine_context_light_enable(This, Index, Enable);
23387ec681f3Smrg    else
23397ec681f3Smrg        state->changed.group |= NINE_STATE_FF_LIGHTING;
23407ec681f3Smrg
23417ec681f3Smrg    return D3D_OK;
23427ec681f3Smrg}
23437ec681f3Smrg
23447ec681f3SmrgHRESULT NINE_WINAPI
23457ec681f3SmrgNineDevice9_GetLightEnable( struct NineDevice9 *This,
23467ec681f3Smrg                            DWORD Index,
23477ec681f3Smrg                            BOOL *pEnable )
23487ec681f3Smrg{
23497ec681f3Smrg    const struct nine_state *state = &This->state;
23507ec681f3Smrg    unsigned i;
23517ec681f3Smrg
23527ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
23537ec681f3Smrg    user_assert(pEnable != NULL, D3DERR_INVALIDCALL);
23547ec681f3Smrg    user_assert(Index < state->ff.num_lights, D3DERR_INVALIDCALL);
23557ec681f3Smrg    user_assert(state->ff.light[Index].Type < NINED3DLIGHT_INVALID,
23567ec681f3Smrg                D3DERR_INVALIDCALL);
23577ec681f3Smrg
23587ec681f3Smrg    for (i = 0; i < state->ff.num_lights_active; ++i)
23597ec681f3Smrg        if (state->ff.active_light[i] == Index)
23607ec681f3Smrg            break;
23617ec681f3Smrg
23627ec681f3Smrg    *pEnable = i != state->ff.num_lights_active ? 128 : 0; // Taken from wine
23637ec681f3Smrg
23647ec681f3Smrg    return D3D_OK;
23657ec681f3Smrg}
23667ec681f3Smrg
23677ec681f3SmrgHRESULT NINE_WINAPI
23687ec681f3SmrgNineDevice9_SetClipPlane( struct NineDevice9 *This,
23697ec681f3Smrg                          DWORD Index,
23707ec681f3Smrg                          const float *pPlane )
23717ec681f3Smrg{
23727ec681f3Smrg    struct nine_state *state = This->update;
23737ec681f3Smrg
23747ec681f3Smrg    user_assert(pPlane, D3DERR_INVALIDCALL);
23757ec681f3Smrg
23767ec681f3Smrg    DBG("This=%p Index=%u pPlane=%f %f %f %f\n", This, Index,
23777ec681f3Smrg        pPlane[0], pPlane[1],
23787ec681f3Smrg        pPlane[2], pPlane[3]);
23797ec681f3Smrg
23807ec681f3Smrg    user_assert(Index < PIPE_MAX_CLIP_PLANES, D3DERR_INVALIDCALL);
23817ec681f3Smrg
23827ec681f3Smrg    memcpy(&state->clip.ucp[Index][0], pPlane, sizeof(state->clip.ucp[0]));
23837ec681f3Smrg    if (unlikely(This->is_recording))
23847ec681f3Smrg        state->changed.ucp |= 1 << Index;
23857ec681f3Smrg    else
23867ec681f3Smrg        nine_context_set_clip_plane(This, Index, (struct nine_clipplane *)pPlane);
23877ec681f3Smrg
23887ec681f3Smrg    return D3D_OK;
23897ec681f3Smrg}
23907ec681f3Smrg
23917ec681f3SmrgHRESULT NINE_WINAPI
23927ec681f3SmrgNineDevice9_GetClipPlane( struct NineDevice9 *This,
23937ec681f3Smrg                          DWORD Index,
23947ec681f3Smrg                          float *pPlane )
23957ec681f3Smrg{
23967ec681f3Smrg    const struct nine_state *state = &This->state;
23977ec681f3Smrg
23987ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
23997ec681f3Smrg    user_assert(pPlane != NULL, D3DERR_INVALIDCALL);
24007ec681f3Smrg    user_assert(Index < PIPE_MAX_CLIP_PLANES, D3DERR_INVALIDCALL);
24017ec681f3Smrg
24027ec681f3Smrg    memcpy(pPlane, &state->clip.ucp[Index][0], sizeof(state->clip.ucp[0]));
24037ec681f3Smrg    return D3D_OK;
24047ec681f3Smrg}
24057ec681f3Smrg
24067ec681f3SmrgHRESULT NINE_WINAPI
24077ec681f3SmrgNineDevice9_SetRenderState( struct NineDevice9 *This,
24087ec681f3Smrg                            D3DRENDERSTATETYPE State,
24097ec681f3Smrg                            DWORD Value )
24107ec681f3Smrg{
24117ec681f3Smrg    struct nine_state *state = This->update;
24127ec681f3Smrg
24137ec681f3Smrg    DBG("This=%p State=%u(%s) Value=%08x\n", This,
24147ec681f3Smrg        State, nine_d3drs_to_string(State), Value);
24157ec681f3Smrg
24167ec681f3Smrg    user_assert(State < D3DRS_COUNT, D3D_OK);
24177ec681f3Smrg
24187ec681f3Smrg    if (unlikely(This->is_recording)) {
24197ec681f3Smrg        state->rs_advertised[State] = Value;
24207ec681f3Smrg        /* only need to record changed render states for stateblocks */
24217ec681f3Smrg        state->changed.rs[State / 32] |= 1 << (State % 32);
24227ec681f3Smrg        return D3D_OK;
24237ec681f3Smrg    }
24247ec681f3Smrg
24257ec681f3Smrg    if (state->rs_advertised[State] == Value)
24267ec681f3Smrg        return D3D_OK;
24277ec681f3Smrg
24287ec681f3Smrg    state->rs_advertised[State] = Value;
24297ec681f3Smrg    nine_context_set_render_state(This, State, Value);
24307ec681f3Smrg
24317ec681f3Smrg    return D3D_OK;
24327ec681f3Smrg}
24337ec681f3Smrg
24347ec681f3SmrgHRESULT NINE_WINAPI
24357ec681f3SmrgNineDevice9_GetRenderState( struct NineDevice9 *This,
24367ec681f3Smrg                            D3DRENDERSTATETYPE State,
24377ec681f3Smrg                            DWORD *pValue )
24387ec681f3Smrg{
24397ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
24407ec681f3Smrg    user_assert(pValue != NULL, D3DERR_INVALIDCALL);
24417ec681f3Smrg    /* TODO: This needs tests */
24427ec681f3Smrg    if (State >= D3DRS_COUNT) {
24437ec681f3Smrg        *pValue = 0;
24447ec681f3Smrg        return D3D_OK;
24457ec681f3Smrg    }
24467ec681f3Smrg
24477ec681f3Smrg    *pValue = This->state.rs_advertised[State];
24487ec681f3Smrg    return D3D_OK;
24497ec681f3Smrg}
24507ec681f3Smrg
24517ec681f3SmrgHRESULT NINE_WINAPI
24527ec681f3SmrgNineDevice9_CreateStateBlock( struct NineDevice9 *This,
24537ec681f3Smrg                              D3DSTATEBLOCKTYPE Type,
24547ec681f3Smrg                              IDirect3DStateBlock9 **ppSB )
24557ec681f3Smrg{
24567ec681f3Smrg    struct NineStateBlock9 *nsb;
24577ec681f3Smrg    struct nine_state *dst;
24587ec681f3Smrg    HRESULT hr;
24597ec681f3Smrg    enum nine_stateblock_type type;
24607ec681f3Smrg    unsigned s;
24617ec681f3Smrg
24627ec681f3Smrg    DBG("This=%p Type=%u ppSB=%p\n", This, Type, ppSB);
24637ec681f3Smrg
24647ec681f3Smrg    user_assert(ppSB != NULL, D3DERR_INVALIDCALL);
24657ec681f3Smrg    user_assert(Type == D3DSBT_ALL ||
24667ec681f3Smrg                Type == D3DSBT_VERTEXSTATE ||
24677ec681f3Smrg                Type == D3DSBT_PIXELSTATE, D3DERR_INVALIDCALL);
24687ec681f3Smrg
24697ec681f3Smrg    switch (Type) {
24707ec681f3Smrg    case D3DSBT_VERTEXSTATE: type = NINESBT_VERTEXSTATE; break;
24717ec681f3Smrg    case D3DSBT_PIXELSTATE:  type = NINESBT_PIXELSTATE; break;
24727ec681f3Smrg    default:
24737ec681f3Smrg       type = NINESBT_ALL;
24747ec681f3Smrg       break;
24757ec681f3Smrg    }
24767ec681f3Smrg
24777ec681f3Smrg    hr = NineStateBlock9_new(This, &nsb, type);
24787ec681f3Smrg    if (FAILED(hr))
24797ec681f3Smrg       return hr;
24807ec681f3Smrg    *ppSB = (IDirect3DStateBlock9 *)nsb;
24817ec681f3Smrg    dst = &nsb->state;
24827ec681f3Smrg
24837ec681f3Smrg    dst->changed.group = NINE_STATE_SAMPLER;
24847ec681f3Smrg
24857ec681f3Smrg    if (Type == D3DSBT_ALL || Type == D3DSBT_VERTEXSTATE) {
24867ec681f3Smrg       dst->changed.group |=
24877ec681f3Smrg           NINE_STATE_FF_LIGHTING |
24887ec681f3Smrg           NINE_STATE_VS | NINE_STATE_VS_CONST |
24897ec681f3Smrg           NINE_STATE_VDECL;
24907ec681f3Smrg       /* TODO: texture/sampler state */
24917ec681f3Smrg       memcpy(dst->changed.rs,
24927ec681f3Smrg              nine_render_states_vertex, sizeof(dst->changed.rs));
24937ec681f3Smrg       nine_ranges_insert(&dst->changed.vs_const_f, 0, This->may_swvp ? NINE_MAX_CONST_F_SWVP : This->max_vs_const_f,
24947ec681f3Smrg                          &This->range_pool);
24957ec681f3Smrg       nine_ranges_insert(&dst->changed.vs_const_i, 0, This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I,
24967ec681f3Smrg                          &This->range_pool);
24977ec681f3Smrg       nine_ranges_insert(&dst->changed.vs_const_b, 0, This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B,
24987ec681f3Smrg                          &This->range_pool);
24997ec681f3Smrg       for (s = 0; s < NINE_MAX_SAMPLERS; ++s)
25007ec681f3Smrg           dst->changed.sampler[s] |= 1 << D3DSAMP_DMAPOFFSET;
25017ec681f3Smrg       if (This->state.ff.num_lights) {
25027ec681f3Smrg           dst->ff.num_lights = This->state.ff.num_lights;
25037ec681f3Smrg           /* zero'd -> light type won't be NINED3DLIGHT_INVALID, so
25047ec681f3Smrg            * all currently existing lights will be captured
25057ec681f3Smrg            */
25067ec681f3Smrg           dst->ff.light = CALLOC(This->state.ff.num_lights,
25077ec681f3Smrg                                  sizeof(D3DLIGHT9));
25087ec681f3Smrg           if (!dst->ff.light) {
25097ec681f3Smrg               nine_bind(ppSB, NULL);
25107ec681f3Smrg               return E_OUTOFMEMORY;
25117ec681f3Smrg           }
25127ec681f3Smrg       }
25137ec681f3Smrg    }
25147ec681f3Smrg    if (Type == D3DSBT_ALL || Type == D3DSBT_PIXELSTATE) {
25157ec681f3Smrg       dst->changed.group |=
25167ec681f3Smrg          NINE_STATE_PS | NINE_STATE_PS_CONST | NINE_STATE_FF_PS_CONSTS;
25177ec681f3Smrg       memcpy(dst->changed.rs,
25187ec681f3Smrg              nine_render_states_pixel, sizeof(dst->changed.rs));
25197ec681f3Smrg       nine_ranges_insert(&dst->changed.ps_const_f, 0, This->max_ps_const_f,
25207ec681f3Smrg                          &This->range_pool);
25217ec681f3Smrg       dst->changed.ps_const_i = 0xffff;
25227ec681f3Smrg       dst->changed.ps_const_b = 0xffff;
25237ec681f3Smrg       for (s = 0; s < NINE_MAX_SAMPLERS; ++s)
25247ec681f3Smrg           dst->changed.sampler[s] |= 0x1ffe;
25257ec681f3Smrg       for (s = 0; s < NINE_MAX_TEXTURE_STAGES; ++s) {
25267ec681f3Smrg           dst->ff.changed.tex_stage[s][0] |= 0xffffffff;
25277ec681f3Smrg           dst->ff.changed.tex_stage[s][1] |= 0xffffffff;
25287ec681f3Smrg       }
25297ec681f3Smrg    }
25307ec681f3Smrg    if (Type == D3DSBT_ALL) {
25317ec681f3Smrg       dst->changed.group |=
25327ec681f3Smrg          NINE_STATE_VIEWPORT |
25337ec681f3Smrg          NINE_STATE_SCISSOR |
25347ec681f3Smrg          NINE_STATE_IDXBUF |
25357ec681f3Smrg          NINE_STATE_FF_MATERIAL |
25367ec681f3Smrg          NINE_STATE_FF_VSTRANSF;
25377ec681f3Smrg       memset(dst->changed.rs, ~0, (D3DRS_COUNT / 32) * sizeof(uint32_t));
25387ec681f3Smrg       dst->changed.rs[D3DRS_LAST / 32] |= (1 << (D3DRS_COUNT % 32)) - 1;
25397ec681f3Smrg       dst->changed.vtxbuf = (1ULL << This->caps.MaxStreams) - 1;
25407ec681f3Smrg       dst->changed.stream_freq = dst->changed.vtxbuf;
25417ec681f3Smrg       dst->changed.ucp = (1 << PIPE_MAX_CLIP_PLANES) - 1;
25427ec681f3Smrg       dst->changed.texture = (1 << NINE_MAX_SAMPLERS) - 1;
25437ec681f3Smrg       /* The doc says the projection, world, view and texture matrices
25447ec681f3Smrg        * are saved, which would translate to:
25457ec681f3Smrg        * dst->ff.changed.transform[0] = 0x00FF000C;
25467ec681f3Smrg        * dst->ff.changed.transform[D3DTS_WORLD / 32] |= 1 << (D3DTS_WORLD % 32);
25477ec681f3Smrg        * However we assume they meant save everything (which is basically just the
25487ec681f3Smrg        * above plus the other world matrices).
25497ec681f3Smrg        */
25507ec681f3Smrg       dst->ff.changed.transform[0] = 0x00FF000C;
25517ec681f3Smrg       for (s = 0; s < 8; s++)
25527ec681f3Smrg           dst->ff.changed.transform[8+s] = ~0;
25537ec681f3Smrg    }
25547ec681f3Smrg    NineStateBlock9_Capture(NineStateBlock9(*ppSB));
25557ec681f3Smrg
25567ec681f3Smrg    /* TODO: fixed function state */
25577ec681f3Smrg
25587ec681f3Smrg    return D3D_OK;
25597ec681f3Smrg}
25607ec681f3Smrg
25617ec681f3SmrgHRESULT NINE_WINAPI
25627ec681f3SmrgNineDevice9_BeginStateBlock( struct NineDevice9 *This )
25637ec681f3Smrg{
25647ec681f3Smrg    HRESULT hr;
25657ec681f3Smrg
25667ec681f3Smrg    DBG("This=%p\n", This);
25677ec681f3Smrg
25687ec681f3Smrg    user_assert(!This->record, D3DERR_INVALIDCALL);
25697ec681f3Smrg
25707ec681f3Smrg    hr = NineStateBlock9_new(This, &This->record, NINESBT_CUSTOM);
25717ec681f3Smrg    if (FAILED(hr))
25727ec681f3Smrg        return hr;
25737ec681f3Smrg    NineUnknown_ConvertRefToBind(NineUnknown(This->record));
25747ec681f3Smrg
25757ec681f3Smrg    This->update = &This->record->state;
25767ec681f3Smrg    This->is_recording = TRUE;
25777ec681f3Smrg
25787ec681f3Smrg    return D3D_OK;
25797ec681f3Smrg}
25807ec681f3Smrg
25817ec681f3SmrgHRESULT NINE_WINAPI
25827ec681f3SmrgNineDevice9_EndStateBlock( struct NineDevice9 *This,
25837ec681f3Smrg                           IDirect3DStateBlock9 **ppSB )
25847ec681f3Smrg{
25857ec681f3Smrg    DBG("This=%p ppSB=%p\n", This, ppSB);
25867ec681f3Smrg
25877ec681f3Smrg    user_assert(This->record, D3DERR_INVALIDCALL);
25887ec681f3Smrg    user_assert(ppSB != NULL, D3DERR_INVALIDCALL);
25897ec681f3Smrg
25907ec681f3Smrg    This->update = &This->state;
25917ec681f3Smrg    This->is_recording = FALSE;
25927ec681f3Smrg
25937ec681f3Smrg    NineUnknown_AddRef(NineUnknown(This->record));
25947ec681f3Smrg    *ppSB = (IDirect3DStateBlock9 *)This->record;
25957ec681f3Smrg    NineUnknown_Unbind(NineUnknown(This->record));
25967ec681f3Smrg    This->record = NULL;
25977ec681f3Smrg
25987ec681f3Smrg    return D3D_OK;
25997ec681f3Smrg}
26007ec681f3Smrg
26017ec681f3SmrgHRESULT NINE_WINAPI
26027ec681f3SmrgNineDevice9_SetClipStatus( struct NineDevice9 *This,
26037ec681f3Smrg                           const D3DCLIPSTATUS9 *pClipStatus )
26047ec681f3Smrg{
26057ec681f3Smrg    user_assert(pClipStatus, D3DERR_INVALIDCALL);
26067ec681f3Smrg    return D3D_OK;
26077ec681f3Smrg}
26087ec681f3Smrg
26097ec681f3SmrgHRESULT NINE_WINAPI
26107ec681f3SmrgNineDevice9_GetClipStatus( struct NineDevice9 *This,
26117ec681f3Smrg                           D3DCLIPSTATUS9 *pClipStatus )
26127ec681f3Smrg{
26137ec681f3Smrg    user_assert(pClipStatus, D3DERR_INVALIDCALL);
26147ec681f3Smrg    /* Set/GetClipStatus is supposed to get the app some infos
26157ec681f3Smrg     * about vertices being clipped if it is using the software
26167ec681f3Smrg     * vertex rendering. It would be too complicated to implement.
26177ec681f3Smrg     * Probably the info is for developpers when working on their
26187ec681f3Smrg     * applications. Else it could be for apps to know if it is worth
26197ec681f3Smrg     * drawing some elements. In that case it makes sense to send
26207ec681f3Smrg     * 0 for ClipUnion and 0xFFFFFFFF for ClipIntersection (basically
26217ec681f3Smrg     * means not all vertices are clipped). Those values are known to
26227ec681f3Smrg     * be the default if SetClipStatus is not set. Else we could return
26237ec681f3Smrg     * what was set with SetClipStatus unchanged. */
26247ec681f3Smrg    pClipStatus->ClipUnion = 0;
26257ec681f3Smrg    pClipStatus->ClipIntersection = 0xFFFFFFFF;
26267ec681f3Smrg    return D3D_OK;
26277ec681f3Smrg}
26287ec681f3Smrg
26297ec681f3SmrgHRESULT NINE_WINAPI
26307ec681f3SmrgNineDevice9_GetTexture( struct NineDevice9 *This,
26317ec681f3Smrg                        DWORD Stage,
26327ec681f3Smrg                        IDirect3DBaseTexture9 **ppTexture )
26337ec681f3Smrg{
26347ec681f3Smrg    user_assert(Stage < NINE_MAX_SAMPLERS_PS ||
26357ec681f3Smrg                Stage == D3DDMAPSAMPLER ||
26367ec681f3Smrg                (Stage >= D3DVERTEXTEXTURESAMPLER0 &&
26377ec681f3Smrg                 Stage <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
26387ec681f3Smrg    user_assert(ppTexture, D3DERR_INVALIDCALL);
26397ec681f3Smrg
26407ec681f3Smrg    if (Stage >= D3DDMAPSAMPLER)
26417ec681f3Smrg        Stage = Stage - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
26427ec681f3Smrg
26437ec681f3Smrg    *ppTexture = (IDirect3DBaseTexture9 *)This->state.texture[Stage];
26447ec681f3Smrg
26457ec681f3Smrg    if (This->state.texture[Stage])
26467ec681f3Smrg        NineUnknown_AddRef(NineUnknown(This->state.texture[Stage]));
26477ec681f3Smrg    return D3D_OK;
26487ec681f3Smrg}
26497ec681f3Smrg
26507ec681f3SmrgHRESULT NINE_WINAPI
26517ec681f3SmrgNineDevice9_SetTexture( struct NineDevice9 *This,
26527ec681f3Smrg                        DWORD Stage,
26537ec681f3Smrg                        IDirect3DBaseTexture9 *pTexture )
26547ec681f3Smrg{
26557ec681f3Smrg    struct nine_state *state = This->update;
26567ec681f3Smrg    struct NineBaseTexture9 *tex = NineBaseTexture9(pTexture);
26577ec681f3Smrg    struct NineBaseTexture9 *old;
26587ec681f3Smrg
26597ec681f3Smrg    DBG("This=%p Stage=%u pTexture=%p\n", This, Stage, pTexture);
26607ec681f3Smrg
26617ec681f3Smrg    user_assert(Stage < NINE_MAX_SAMPLERS_PS ||
26627ec681f3Smrg                Stage == D3DDMAPSAMPLER ||
26637ec681f3Smrg                (Stage >= D3DVERTEXTEXTURESAMPLER0 &&
26647ec681f3Smrg                 Stage <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
26657ec681f3Smrg    user_assert(!tex || (tex->base.pool != D3DPOOL_SCRATCH &&
26667ec681f3Smrg                tex->base.pool != D3DPOOL_SYSTEMMEM), D3DERR_INVALIDCALL);
26677ec681f3Smrg
26687ec681f3Smrg    if (Stage >= D3DDMAPSAMPLER)
26697ec681f3Smrg        Stage = Stage - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
26707ec681f3Smrg
26717ec681f3Smrg    if (This->is_recording) {
26727ec681f3Smrg        state->changed.texture |= 1 << Stage;
26737ec681f3Smrg        nine_bind(&state->texture[Stage], pTexture);
26747ec681f3Smrg        return D3D_OK;
26757ec681f3Smrg    }
26767ec681f3Smrg
26777ec681f3Smrg    old = state->texture[Stage];
26787ec681f3Smrg    if (old == tex)
26797ec681f3Smrg        return D3D_OK;
26807ec681f3Smrg
26817ec681f3Smrg    NineBindTextureToDevice(This, &state->texture[Stage], tex);
26827ec681f3Smrg
26837ec681f3Smrg    nine_context_set_texture(This, Stage, tex);
26847ec681f3Smrg
26857ec681f3Smrg    return D3D_OK;
26867ec681f3Smrg}
26877ec681f3Smrg
26887ec681f3SmrgHRESULT NINE_WINAPI
26897ec681f3SmrgNineDevice9_GetTextureStageState( struct NineDevice9 *This,
26907ec681f3Smrg                                  DWORD Stage,
26917ec681f3Smrg                                  D3DTEXTURESTAGESTATETYPE Type,
26927ec681f3Smrg                                  DWORD *pValue )
26937ec681f3Smrg{
26947ec681f3Smrg    const struct nine_state *state = &This->state;
26957ec681f3Smrg
26967ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
26977ec681f3Smrg    user_assert(pValue != NULL, D3DERR_INVALIDCALL);
26987ec681f3Smrg    user_assert(Stage < ARRAY_SIZE(state->ff.tex_stage), D3DERR_INVALIDCALL);
26997ec681f3Smrg    user_assert(Type < ARRAY_SIZE(state->ff.tex_stage[0]), D3DERR_INVALIDCALL);
27007ec681f3Smrg
27017ec681f3Smrg    *pValue = state->ff.tex_stage[Stage][Type];
27027ec681f3Smrg
27037ec681f3Smrg    return D3D_OK;
27047ec681f3Smrg}
27057ec681f3Smrg
27067ec681f3SmrgHRESULT NINE_WINAPI
27077ec681f3SmrgNineDevice9_SetTextureStageState( struct NineDevice9 *This,
27087ec681f3Smrg                                  DWORD Stage,
27097ec681f3Smrg                                  D3DTEXTURESTAGESTATETYPE Type,
27107ec681f3Smrg                                  DWORD Value )
27117ec681f3Smrg{
27127ec681f3Smrg    struct nine_state *state = This->update;
27137ec681f3Smrg
27147ec681f3Smrg    DBG("Stage=%u Type=%u Value=%08x\n", Stage, Type, Value);
27157ec681f3Smrg    nine_dump_D3DTSS_value(DBG_FF, Type, Value);
27167ec681f3Smrg
27177ec681f3Smrg    user_assert(Stage < ARRAY_SIZE(state->ff.tex_stage), D3DERR_INVALIDCALL);
27187ec681f3Smrg    user_assert(Type < ARRAY_SIZE(state->ff.tex_stage[0]), D3DERR_INVALIDCALL);
27197ec681f3Smrg
27207ec681f3Smrg    state->ff.tex_stage[Stage][Type] = Value;
27217ec681f3Smrg
27227ec681f3Smrg    if (unlikely(This->is_recording)) {
27237ec681f3Smrg        state->changed.group |= NINE_STATE_FF_PS_CONSTS;
27247ec681f3Smrg        state->ff.changed.tex_stage[Stage][Type / 32] |= 1 << (Type % 32);
27257ec681f3Smrg    } else
27267ec681f3Smrg        nine_context_set_texture_stage_state(This, Stage, Type, Value);
27277ec681f3Smrg
27287ec681f3Smrg    return D3D_OK;
27297ec681f3Smrg}
27307ec681f3Smrg
27317ec681f3SmrgHRESULT NINE_WINAPI
27327ec681f3SmrgNineDevice9_GetSamplerState( struct NineDevice9 *This,
27337ec681f3Smrg                             DWORD Sampler,
27347ec681f3Smrg                             D3DSAMPLERSTATETYPE Type,
27357ec681f3Smrg                             DWORD *pValue )
27367ec681f3Smrg{
27377ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
27387ec681f3Smrg    user_assert(pValue != NULL, D3DERR_INVALIDCALL);
27397ec681f3Smrg    user_assert(Sampler < NINE_MAX_SAMPLERS_PS ||
27407ec681f3Smrg                Sampler == D3DDMAPSAMPLER ||
27417ec681f3Smrg                (Sampler >= D3DVERTEXTEXTURESAMPLER0 &&
27427ec681f3Smrg                 Sampler <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
27437ec681f3Smrg
27447ec681f3Smrg    if (Sampler >= D3DDMAPSAMPLER)
27457ec681f3Smrg        Sampler = Sampler - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
27467ec681f3Smrg
27477ec681f3Smrg    *pValue = This->state.samp_advertised[Sampler][Type];
27487ec681f3Smrg    return D3D_OK;
27497ec681f3Smrg}
27507ec681f3Smrg
27517ec681f3SmrgHRESULT NINE_WINAPI
27527ec681f3SmrgNineDevice9_SetSamplerState( struct NineDevice9 *This,
27537ec681f3Smrg                             DWORD Sampler,
27547ec681f3Smrg                             D3DSAMPLERSTATETYPE Type,
27557ec681f3Smrg                             DWORD Value )
27567ec681f3Smrg{
27577ec681f3Smrg    struct nine_state *state = This->update;
27587ec681f3Smrg
27597ec681f3Smrg    DBG("This=%p Sampler=%u Type=%s Value=%08x\n", This,
27607ec681f3Smrg        Sampler, nine_D3DSAMP_to_str(Type), Value);
27617ec681f3Smrg
27627ec681f3Smrg    user_assert(Sampler < NINE_MAX_SAMPLERS_PS ||
27637ec681f3Smrg                Sampler == D3DDMAPSAMPLER ||
27647ec681f3Smrg                (Sampler >= D3DVERTEXTEXTURESAMPLER0 &&
27657ec681f3Smrg                 Sampler <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
27667ec681f3Smrg
27677ec681f3Smrg    if (Sampler >= D3DDMAPSAMPLER)
27687ec681f3Smrg        Sampler = Sampler - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
27697ec681f3Smrg
27707ec681f3Smrg    if (unlikely(This->is_recording)) {
27717ec681f3Smrg        state->samp_advertised[Sampler][Type] = Value;
27727ec681f3Smrg        state->changed.group |= NINE_STATE_SAMPLER;
27737ec681f3Smrg        state->changed.sampler[Sampler] |= 1 << Type;
27747ec681f3Smrg        return D3D_OK;
27757ec681f3Smrg    }
27767ec681f3Smrg
27777ec681f3Smrg    if (state->samp_advertised[Sampler][Type] == Value)
27787ec681f3Smrg        return D3D_OK;
27797ec681f3Smrg
27807ec681f3Smrg    state->samp_advertised[Sampler][Type] = Value;
27817ec681f3Smrg    nine_context_set_sampler_state(This, Sampler, Type, Value);
27827ec681f3Smrg
27837ec681f3Smrg    return D3D_OK;
27847ec681f3Smrg}
27857ec681f3Smrg
27867ec681f3SmrgHRESULT NINE_WINAPI
27877ec681f3SmrgNineDevice9_ValidateDevice( struct NineDevice9 *This,
27887ec681f3Smrg                            DWORD *pNumPasses )
27897ec681f3Smrg{
27907ec681f3Smrg    const struct nine_state *state = &This->state;
27917ec681f3Smrg    unsigned i;
27927ec681f3Smrg    unsigned w = 0, h = 0;
27937ec681f3Smrg
27947ec681f3Smrg    DBG("This=%p pNumPasses=%p\n", This, pNumPasses);
27957ec681f3Smrg
27967ec681f3Smrg    for (i = 0; i < ARRAY_SIZE(state->samp_advertised); ++i) {
27977ec681f3Smrg        if (state->samp_advertised[i][D3DSAMP_MINFILTER] == D3DTEXF_NONE ||
27987ec681f3Smrg            state->samp_advertised[i][D3DSAMP_MAGFILTER] == D3DTEXF_NONE)
27997ec681f3Smrg            return D3DERR_UNSUPPORTEDTEXTUREFILTER;
28007ec681f3Smrg    }
28017ec681f3Smrg
28027ec681f3Smrg    for (i = 0; i < This->caps.NumSimultaneousRTs; ++i) {
28037ec681f3Smrg        if (!state->rt[i])
28047ec681f3Smrg            continue;
28057ec681f3Smrg        if (w == 0) {
28067ec681f3Smrg            w = state->rt[i]->desc.Width;
28077ec681f3Smrg            h = state->rt[i]->desc.Height;
28087ec681f3Smrg        } else
28097ec681f3Smrg        if (state->rt[i]->desc.Width != w || state->rt[i]->desc.Height != h) {
28107ec681f3Smrg            return D3DERR_CONFLICTINGRENDERSTATE;
28117ec681f3Smrg        }
28127ec681f3Smrg    }
28137ec681f3Smrg    if (state->ds &&
28147ec681f3Smrg        (state->rs_advertised[D3DRS_ZENABLE] || state->rs_advertised[D3DRS_STENCILENABLE])) {
28157ec681f3Smrg        if (w != 0 &&
28167ec681f3Smrg            (state->ds->desc.Width != w || state->ds->desc.Height != h))
28177ec681f3Smrg            return D3DERR_CONFLICTINGRENDERSTATE;
28187ec681f3Smrg    }
28197ec681f3Smrg
28207ec681f3Smrg    if (pNumPasses)
28217ec681f3Smrg        *pNumPasses = 1;
28227ec681f3Smrg
28237ec681f3Smrg    return D3D_OK;
28247ec681f3Smrg}
28257ec681f3Smrg
28267ec681f3SmrgHRESULT NINE_WINAPI
28277ec681f3SmrgNineDevice9_SetPaletteEntries( struct NineDevice9 *This,
28287ec681f3Smrg                               UINT PaletteNumber,
28297ec681f3Smrg                               const PALETTEENTRY *pEntries )
28307ec681f3Smrg{
28317ec681f3Smrg    STUB(D3D_OK); /* like wine */
28327ec681f3Smrg}
28337ec681f3Smrg
28347ec681f3SmrgHRESULT NINE_WINAPI
28357ec681f3SmrgNineDevice9_GetPaletteEntries( struct NineDevice9 *This,
28367ec681f3Smrg                               UINT PaletteNumber,
28377ec681f3Smrg                               PALETTEENTRY *pEntries )
28387ec681f3Smrg{
28397ec681f3Smrg    STUB(D3DERR_INVALIDCALL);
28407ec681f3Smrg}
28417ec681f3Smrg
28427ec681f3SmrgHRESULT NINE_WINAPI
28437ec681f3SmrgNineDevice9_SetCurrentTexturePalette( struct NineDevice9 *This,
28447ec681f3Smrg                                      UINT PaletteNumber )
28457ec681f3Smrg{
28467ec681f3Smrg    STUB(D3D_OK); /* like wine */
28477ec681f3Smrg}
28487ec681f3Smrg
28497ec681f3SmrgHRESULT NINE_WINAPI
28507ec681f3SmrgNineDevice9_GetCurrentTexturePalette( struct NineDevice9 *This,
28517ec681f3Smrg                                      UINT *PaletteNumber )
28527ec681f3Smrg{
28537ec681f3Smrg    STUB(D3DERR_INVALIDCALL);
28547ec681f3Smrg}
28557ec681f3Smrg
28567ec681f3SmrgHRESULT NINE_WINAPI
28577ec681f3SmrgNineDevice9_SetScissorRect( struct NineDevice9 *This,
28587ec681f3Smrg                            const RECT *pRect )
28597ec681f3Smrg{
28607ec681f3Smrg    struct nine_state *state = This->update;
28617ec681f3Smrg
28627ec681f3Smrg    user_assert(pRect != NULL, D3DERR_INVALIDCALL);
28637ec681f3Smrg
28647ec681f3Smrg    DBG("x=(%u..%u) y=(%u..%u)\n",
28657ec681f3Smrg        pRect->left, pRect->top, pRect->right, pRect->bottom);
28667ec681f3Smrg
28677ec681f3Smrg    state->scissor.minx = pRect->left;
28687ec681f3Smrg    state->scissor.miny = pRect->top;
28697ec681f3Smrg    state->scissor.maxx = pRect->right;
28707ec681f3Smrg    state->scissor.maxy = pRect->bottom;
28717ec681f3Smrg
28727ec681f3Smrg    if (unlikely(This->is_recording))
28737ec681f3Smrg        state->changed.group |= NINE_STATE_SCISSOR;
28747ec681f3Smrg    else
28757ec681f3Smrg        nine_context_set_scissor(This, &state->scissor);
28767ec681f3Smrg
28777ec681f3Smrg    return D3D_OK;
28787ec681f3Smrg}
28797ec681f3Smrg
28807ec681f3SmrgHRESULT NINE_WINAPI
28817ec681f3SmrgNineDevice9_GetScissorRect( struct NineDevice9 *This,
28827ec681f3Smrg                            RECT *pRect )
28837ec681f3Smrg{
28847ec681f3Smrg    user_assert(pRect != NULL, D3DERR_INVALIDCALL);
28857ec681f3Smrg
28867ec681f3Smrg    pRect->left   = This->state.scissor.minx;
28877ec681f3Smrg    pRect->top    = This->state.scissor.miny;
28887ec681f3Smrg    pRect->right  = This->state.scissor.maxx;
28897ec681f3Smrg    pRect->bottom = This->state.scissor.maxy;
28907ec681f3Smrg
28917ec681f3Smrg    return D3D_OK;
28927ec681f3Smrg}
28937ec681f3Smrg
28947ec681f3SmrgHRESULT NINE_WINAPI
28957ec681f3SmrgNineDevice9_SetSoftwareVertexProcessing( struct NineDevice9 *This,
28967ec681f3Smrg                                         BOOL bSoftware )
28977ec681f3Smrg{
28987ec681f3Smrg    if (This->params.BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) {
28997ec681f3Smrg        This->swvp = bSoftware;
29007ec681f3Smrg        nine_context_set_swvp(This, bSoftware);
29017ec681f3Smrg        return D3D_OK;
29027ec681f3Smrg    } else
29037ec681f3Smrg        return D3D_OK; /* msdn seems to indicate INVALIDCALL, but at least Halo expects OK */
29047ec681f3Smrg}
29057ec681f3Smrg
29067ec681f3SmrgBOOL NINE_WINAPI
29077ec681f3SmrgNineDevice9_GetSoftwareVertexProcessing( struct NineDevice9 *This )
29087ec681f3Smrg{
29097ec681f3Smrg    return This->swvp;
29107ec681f3Smrg}
29117ec681f3Smrg
29127ec681f3SmrgHRESULT NINE_WINAPI
29137ec681f3SmrgNineDevice9_SetNPatchMode( struct NineDevice9 *This,
29147ec681f3Smrg                           float nSegments )
29157ec681f3Smrg{
29167ec681f3Smrg    return D3D_OK; /* Nothing to do because we don't advertise NPatch support */
29177ec681f3Smrg}
29187ec681f3Smrg
29197ec681f3Smrgfloat NINE_WINAPI
29207ec681f3SmrgNineDevice9_GetNPatchMode( struct NineDevice9 *This )
29217ec681f3Smrg{
29227ec681f3Smrg    STUB(0);
29237ec681f3Smrg}
29247ec681f3Smrg
29257ec681f3Smrg/* TODO: only go through dirty textures */
29267ec681f3Smrgstatic void
29277ec681f3Smrgvalidate_textures(struct NineDevice9 *device)
29287ec681f3Smrg{
29297ec681f3Smrg    struct NineBaseTexture9 *tex, *ptr;
29307ec681f3Smrg    LIST_FOR_EACH_ENTRY_SAFE(tex, ptr, &device->update_textures, list) {
29317ec681f3Smrg        list_delinit(&tex->list);
29327ec681f3Smrg        NineBaseTexture9_Validate(tex);
29337ec681f3Smrg    }
29347ec681f3Smrg}
29357ec681f3Smrg
29367ec681f3Smrgstatic void
29377ec681f3Smrgupdate_managed_buffers(struct NineDevice9 *device)
29387ec681f3Smrg{
29397ec681f3Smrg    struct NineBuffer9 *buf, *ptr;
29407ec681f3Smrg    LIST_FOR_EACH_ENTRY_SAFE(buf, ptr, &device->update_buffers, managed.list) {
29417ec681f3Smrg        list_delinit(&buf->managed.list);
29427ec681f3Smrg        NineBuffer9_Upload(buf);
29437ec681f3Smrg    }
29447ec681f3Smrg}
29457ec681f3Smrg
29467ec681f3Smrgstatic void
29477ec681f3SmrgNineBeforeDraw( struct NineDevice9 *This )
29487ec681f3Smrg{
29497ec681f3Smrg    /* Upload Managed dirty content */
29507ec681f3Smrg    validate_textures(This); /* may clobber state */
29517ec681f3Smrg    update_managed_buffers(This);
29527ec681f3Smrg}
29537ec681f3Smrg
29547ec681f3Smrgstatic void
29557ec681f3SmrgNineAfterDraw( struct NineDevice9 *This )
29567ec681f3Smrg{
29577ec681f3Smrg    unsigned i;
29587ec681f3Smrg    struct nine_state *state = &This->state;
29597ec681f3Smrg    unsigned ps_mask = state->ps ? state->ps->rt_mask : 1;
29607ec681f3Smrg
29617ec681f3Smrg    /* Flag render-targets with autogenmipmap for mipmap regeneration */
29627ec681f3Smrg    for (i = 0; i < This->caps.NumSimultaneousRTs; ++i) {
29637ec681f3Smrg        struct NineSurface9 *rt = state->rt[i];
29647ec681f3Smrg
29657ec681f3Smrg        if (rt && rt->desc.Format != D3DFMT_NULL && (ps_mask & (1 << i)) &&
29667ec681f3Smrg            rt->desc.Usage & D3DUSAGE_AUTOGENMIPMAP) {
29677ec681f3Smrg            assert(rt->texture == D3DRTYPE_TEXTURE ||
29687ec681f3Smrg                   rt->texture == D3DRTYPE_CUBETEXTURE);
29697ec681f3Smrg            NineBaseTexture9(rt->base.base.container)->dirty_mip = TRUE;
29707ec681f3Smrg        }
29717ec681f3Smrg    }
29727ec681f3Smrg}
29737ec681f3Smrg
29747ec681f3Smrg#define IS_SYSTEMMEM_DYNAMIC(t) ((t) && (t)->base.pool == D3DPOOL_SYSTEMMEM && (t)->base.usage & D3DUSAGE_DYNAMIC)
29757ec681f3Smrg
29767ec681f3Smrg/* Indicates the region needed right now for these buffers and add them to the list
29777ec681f3Smrg * of buffers to process in NineBeforeDraw.
29787ec681f3Smrg * The reason we don't call the upload right now is to generate smaller code (no
29797ec681f3Smrg * duplication of the NineBuffer9_Upload inline) and to have one upload (of the correct size)
29807ec681f3Smrg * if a vertex buffer is twice input of the draw call. */
29817ec681f3Smrgstatic void
29827ec681f3SmrgNineTrackSystemmemDynamic( struct NineBuffer9 *This, unsigned start, unsigned width )
29837ec681f3Smrg{
29847ec681f3Smrg    struct pipe_box box;
29857ec681f3Smrg
29867ec681f3Smrg    u_box_1d(start, width, &box);
29877ec681f3Smrg    u_box_union_1d(&This->managed.required_valid_region,
29887ec681f3Smrg                   &This->managed.required_valid_region,
29897ec681f3Smrg                   &box);
29907ec681f3Smrg    This->managed.dirty = TRUE;
29917ec681f3Smrg    BASEBUF_REGISTER_UPDATE(This);
29927ec681f3Smrg}
29937ec681f3Smrg
29947ec681f3SmrgHRESULT NINE_WINAPI
29957ec681f3SmrgNineDevice9_DrawPrimitive( struct NineDevice9 *This,
29967ec681f3Smrg                           D3DPRIMITIVETYPE PrimitiveType,
29977ec681f3Smrg                           UINT StartVertex,
29987ec681f3Smrg                           UINT PrimitiveCount )
29997ec681f3Smrg{
30007ec681f3Smrg    unsigned i;
30017ec681f3Smrg    DBG("iface %p, PrimitiveType %u, StartVertex %u, PrimitiveCount %u\n",
30027ec681f3Smrg        This, PrimitiveType, StartVertex, PrimitiveCount);
30037ec681f3Smrg
30047ec681f3Smrg    /* Tracking for dynamic SYSTEMMEM */
30057ec681f3Smrg    for (i = 0; i < This->caps.MaxStreams; i++) {
30067ec681f3Smrg        unsigned stride = This->state.vtxbuf[i].stride;
30077ec681f3Smrg        if (IS_SYSTEMMEM_DYNAMIC((struct NineBuffer9*)This->state.stream[i])) {
30087ec681f3Smrg            unsigned start = This->state.vtxbuf[i].buffer_offset + StartVertex * stride;
30097ec681f3Smrg            unsigned full_size = This->state.stream[i]->base.size;
30107ec681f3Smrg            unsigned num_vertices = prim_count_to_vertex_count(PrimitiveType, PrimitiveCount);
30117ec681f3Smrg            unsigned size = MIN2(full_size-start, num_vertices * stride);
30127ec681f3Smrg            if (!stride) /* Instancing. Not sure what to do. Require all */
30137ec681f3Smrg                size = full_size;
30147ec681f3Smrg            NineTrackSystemmemDynamic(&This->state.stream[i]->base, start, size);
30157ec681f3Smrg        }
30167ec681f3Smrg    }
30177ec681f3Smrg
30187ec681f3Smrg    NineBeforeDraw(This);
30197ec681f3Smrg    nine_context_draw_primitive(This, PrimitiveType, StartVertex, PrimitiveCount);
30207ec681f3Smrg    NineAfterDraw(This);
30217ec681f3Smrg
30227ec681f3Smrg    return D3D_OK;
30237ec681f3Smrg}
30247ec681f3Smrg
30257ec681f3SmrgHRESULT NINE_WINAPI
30267ec681f3SmrgNineDevice9_DrawIndexedPrimitive( struct NineDevice9 *This,
30277ec681f3Smrg                                  D3DPRIMITIVETYPE PrimitiveType,
30287ec681f3Smrg                                  INT BaseVertexIndex,
30297ec681f3Smrg                                  UINT MinVertexIndex,
30307ec681f3Smrg                                  UINT NumVertices,
30317ec681f3Smrg                                  UINT StartIndex,
30327ec681f3Smrg                                  UINT PrimitiveCount )
30337ec681f3Smrg{
30347ec681f3Smrg    unsigned i, num_indices;
30357ec681f3Smrg    DBG("iface %p, PrimitiveType %u, BaseVertexIndex %u, MinVertexIndex %u "
30367ec681f3Smrg        "NumVertices %u, StartIndex %u, PrimitiveCount %u\n",
30377ec681f3Smrg        This, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices,
30387ec681f3Smrg        StartIndex, PrimitiveCount);
30397ec681f3Smrg
30407ec681f3Smrg    user_assert(This->state.idxbuf, D3DERR_INVALIDCALL);
30417ec681f3Smrg    user_assert(This->state.vdecl, D3DERR_INVALIDCALL);
30427ec681f3Smrg
30437ec681f3Smrg    num_indices = prim_count_to_vertex_count(PrimitiveType, PrimitiveCount);
30447ec681f3Smrg
30457ec681f3Smrg    /* Tracking for dynamic SYSTEMMEM */
30467ec681f3Smrg    if (IS_SYSTEMMEM_DYNAMIC(&This->state.idxbuf->base))
30477ec681f3Smrg        NineTrackSystemmemDynamic(&This->state.idxbuf->base,
30487ec681f3Smrg                                  StartIndex * This->state.idxbuf->index_size,
30497ec681f3Smrg                                  num_indices * This->state.idxbuf->index_size);
30507ec681f3Smrg
30517ec681f3Smrg    for (i = 0; i < This->caps.MaxStreams; i++) {
30527ec681f3Smrg        if (IS_SYSTEMMEM_DYNAMIC((struct NineBuffer9*)This->state.stream[i])) {
30537ec681f3Smrg            uint32_t stride = This->state.vtxbuf[i].stride;
30547ec681f3Smrg            uint32_t full_size = This->state.stream[i]->base.size;
30557ec681f3Smrg            uint32_t start, stop;
30567ec681f3Smrg
30577ec681f3Smrg            start = MAX2(0, This->state.vtxbuf[i].buffer_offset+(MinVertexIndex+BaseVertexIndex)*stride);
30587ec681f3Smrg            stop = This->state.vtxbuf[i].buffer_offset+(MinVertexIndex+NumVertices+BaseVertexIndex)*stride;
30597ec681f3Smrg            stop = MIN2(stop, full_size);
30607ec681f3Smrg            NineTrackSystemmemDynamic(&This->state.stream[i]->base,
30617ec681f3Smrg                                      start, stop-start);
30627ec681f3Smrg        }
30637ec681f3Smrg    }
30647ec681f3Smrg
30657ec681f3Smrg    NineBeforeDraw(This);
30667ec681f3Smrg    nine_context_draw_indexed_primitive(This, PrimitiveType, BaseVertexIndex,
30677ec681f3Smrg                                        MinVertexIndex, NumVertices, StartIndex,
30687ec681f3Smrg                                        PrimitiveCount);
30697ec681f3Smrg    NineAfterDraw(This);
30707ec681f3Smrg
30717ec681f3Smrg    return D3D_OK;
30727ec681f3Smrg}
30737ec681f3Smrg
30747ec681f3Smrgstatic void
30757ec681f3SmrgNineDevice9_SetStreamSourceNULL( struct NineDevice9 *This );
30767ec681f3Smrg
30777ec681f3SmrgHRESULT NINE_WINAPI
30787ec681f3SmrgNineDevice9_DrawPrimitiveUP( struct NineDevice9 *This,
30797ec681f3Smrg                             D3DPRIMITIVETYPE PrimitiveType,
30807ec681f3Smrg                             UINT PrimitiveCount,
30817ec681f3Smrg                             const void *pVertexStreamZeroData,
30827ec681f3Smrg                             UINT VertexStreamZeroStride )
30837ec681f3Smrg{
30847ec681f3Smrg    struct pipe_resource *resource = NULL;
30857ec681f3Smrg    unsigned buffer_offset;
30867ec681f3Smrg    unsigned StartVertex = 0;
30877ec681f3Smrg
30887ec681f3Smrg    DBG("iface %p, PrimitiveType %u, PrimitiveCount %u, data %p, stride %u\n",
30897ec681f3Smrg        This, PrimitiveType, PrimitiveCount,
30907ec681f3Smrg        pVertexStreamZeroData, VertexStreamZeroStride);
30917ec681f3Smrg
30927ec681f3Smrg    user_assert(pVertexStreamZeroData && VertexStreamZeroStride,
30937ec681f3Smrg                D3DERR_INVALIDCALL);
30947ec681f3Smrg    user_assert(PrimitiveCount, D3D_OK);
30957ec681f3Smrg
30967ec681f3Smrg    u_upload_data(This->vertex_uploader,
30977ec681f3Smrg                  0,
30987ec681f3Smrg                  (prim_count_to_vertex_count(PrimitiveType, PrimitiveCount)) * VertexStreamZeroStride,
30997ec681f3Smrg                  1,
31007ec681f3Smrg                  pVertexStreamZeroData,
31017ec681f3Smrg                  &buffer_offset,
31027ec681f3Smrg                  &resource);
31037ec681f3Smrg    u_upload_unmap(This->vertex_uploader);
31047ec681f3Smrg
31057ec681f3Smrg    /* Optimization to skip changing the bound vertex buffer data
31067ec681f3Smrg     * for consecutive DrawPrimitiveUp with identical VertexStreamZeroStride */
31077ec681f3Smrg    if (VertexStreamZeroStride > 0) {
31087ec681f3Smrg        StartVertex = buffer_offset / VertexStreamZeroStride;
31097ec681f3Smrg        buffer_offset -= StartVertex * VertexStreamZeroStride;
31107ec681f3Smrg    }
31117ec681f3Smrg
31127ec681f3Smrg    nine_context_set_stream_source_apply(This, 0, resource,
31137ec681f3Smrg                                         buffer_offset, VertexStreamZeroStride);
31147ec681f3Smrg    pipe_resource_reference(&resource, NULL);
31157ec681f3Smrg
31167ec681f3Smrg    NineBeforeDraw(This);
31177ec681f3Smrg    nine_context_draw_primitive(This, PrimitiveType, StartVertex, PrimitiveCount);
31187ec681f3Smrg    NineAfterDraw(This);
31197ec681f3Smrg
31207ec681f3Smrg    NineDevice9_PauseRecording(This);
31217ec681f3Smrg    NineDevice9_SetStreamSourceNULL(This);
31227ec681f3Smrg    NineDevice9_ResumeRecording(This);
31237ec681f3Smrg
31247ec681f3Smrg    return D3D_OK;
31257ec681f3Smrg}
31267ec681f3Smrg
31277ec681f3SmrgHRESULT NINE_WINAPI
31287ec681f3SmrgNineDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This,
31297ec681f3Smrg                                    D3DPRIMITIVETYPE PrimitiveType,
31307ec681f3Smrg                                    UINT MinVertexIndex,
31317ec681f3Smrg                                    UINT NumVertices,
31327ec681f3Smrg                                    UINT PrimitiveCount,
31337ec681f3Smrg                                    const void *pIndexData,
31347ec681f3Smrg                                    D3DFORMAT IndexDataFormat,
31357ec681f3Smrg                                    const void *pVertexStreamZeroData,
31367ec681f3Smrg                                    UINT VertexStreamZeroStride )
31377ec681f3Smrg{
31387ec681f3Smrg    struct pipe_vertex_buffer vbuf;
31397ec681f3Smrg    unsigned index_size = (IndexDataFormat == D3DFMT_INDEX16) ? 2 : 4;
31407ec681f3Smrg    struct pipe_resource *ibuf = NULL;
31417ec681f3Smrg    unsigned base;
31427ec681f3Smrg
31437ec681f3Smrg    DBG("iface %p, PrimitiveType %u, MinVertexIndex %u, NumVertices %u "
31447ec681f3Smrg        "PrimitiveCount %u, pIndexData %p, IndexDataFormat %u "
31457ec681f3Smrg        "pVertexStreamZeroData %p, VertexStreamZeroStride %u\n",
31467ec681f3Smrg        This, PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount,
31477ec681f3Smrg        pIndexData, IndexDataFormat,
31487ec681f3Smrg        pVertexStreamZeroData, VertexStreamZeroStride);
31497ec681f3Smrg
31507ec681f3Smrg    user_assert(pIndexData && pVertexStreamZeroData, D3DERR_INVALIDCALL);
31517ec681f3Smrg    user_assert(VertexStreamZeroStride, D3DERR_INVALIDCALL);
31527ec681f3Smrg    user_assert(IndexDataFormat == D3DFMT_INDEX16 ||
31537ec681f3Smrg                IndexDataFormat == D3DFMT_INDEX32, D3DERR_INVALIDCALL);
31547ec681f3Smrg    user_assert(PrimitiveCount, D3D_OK);
31557ec681f3Smrg
31567ec681f3Smrg    base = MinVertexIndex * VertexStreamZeroStride;
31577ec681f3Smrg    vbuf.is_user_buffer = false;
31587ec681f3Smrg    vbuf.buffer.resource = NULL;
31597ec681f3Smrg    vbuf.stride = VertexStreamZeroStride;
31607ec681f3Smrg    u_upload_data(This->vertex_uploader,
31617ec681f3Smrg                  base,
31627ec681f3Smrg                  NumVertices * VertexStreamZeroStride, /* XXX */
31637ec681f3Smrg                  64,
31647ec681f3Smrg                  (const uint8_t *)pVertexStreamZeroData + base,
31657ec681f3Smrg                  &vbuf.buffer_offset,
31667ec681f3Smrg                  &vbuf.buffer.resource);
31677ec681f3Smrg    u_upload_unmap(This->vertex_uploader);
31687ec681f3Smrg    /* Won't be used: */
31697ec681f3Smrg    vbuf.buffer_offset -= base;
31707ec681f3Smrg
31717ec681f3Smrg    unsigned index_offset = 0;
31727ec681f3Smrg    u_upload_data(This->pipe_secondary->stream_uploader,
31737ec681f3Smrg                  0,
31747ec681f3Smrg                  (prim_count_to_vertex_count(PrimitiveType, PrimitiveCount)) * index_size,
31757ec681f3Smrg                  64,
31767ec681f3Smrg                  pIndexData,
31777ec681f3Smrg                  &index_offset,
31787ec681f3Smrg                  &ibuf);
31797ec681f3Smrg    u_upload_unmap(This->pipe_secondary->stream_uploader);
31807ec681f3Smrg
31817ec681f3Smrg    NineBeforeDraw(This);
31827ec681f3Smrg    nine_context_draw_indexed_primitive_from_vtxbuf_idxbuf(This, PrimitiveType,
31837ec681f3Smrg                                                           MinVertexIndex,
31847ec681f3Smrg                                                           NumVertices,
31857ec681f3Smrg                                                           PrimitiveCount,
31867ec681f3Smrg                                                           &vbuf,
31877ec681f3Smrg                                                           ibuf,
31887ec681f3Smrg                                                           ibuf ? NULL : (void*)pIndexData,
31897ec681f3Smrg                                                           index_offset,
31907ec681f3Smrg                                                           index_size);
31917ec681f3Smrg    NineAfterDraw(This);
31927ec681f3Smrg
31937ec681f3Smrg    pipe_vertex_buffer_unreference(&vbuf);
31947ec681f3Smrg    pipe_resource_reference(&ibuf, NULL);
31957ec681f3Smrg
31967ec681f3Smrg    NineDevice9_PauseRecording(This);
31977ec681f3Smrg    NineDevice9_SetIndices(This, NULL);
31987ec681f3Smrg    NineDevice9_SetStreamSourceNULL(This);
31997ec681f3Smrg    NineDevice9_ResumeRecording(This);
32007ec681f3Smrg
32017ec681f3Smrg    return D3D_OK;
32027ec681f3Smrg}
32037ec681f3Smrg
32047ec681f3SmrgHRESULT NINE_WINAPI
32057ec681f3SmrgNineDevice9_ProcessVertices( struct NineDevice9 *This,
32067ec681f3Smrg                             UINT SrcStartIndex,
32077ec681f3Smrg                             UINT DestIndex,
32087ec681f3Smrg                             UINT VertexCount,
32097ec681f3Smrg                             IDirect3DVertexBuffer9 *pDestBuffer,
32107ec681f3Smrg                             IDirect3DVertexDeclaration9 *pVertexDecl,
32117ec681f3Smrg                             DWORD Flags )
32127ec681f3Smrg{
32137ec681f3Smrg    struct pipe_screen *screen_sw = This->screen_sw;
32147ec681f3Smrg    struct pipe_context *pipe_sw = This->pipe_sw;
32157ec681f3Smrg    struct NineVertexDeclaration9 *vdecl = NineVertexDeclaration9(pVertexDecl);
32167ec681f3Smrg    struct NineVertexBuffer9 *dst = NineVertexBuffer9(pDestBuffer);
32177ec681f3Smrg    struct NineVertexShader9 *vs;
32187ec681f3Smrg    struct pipe_resource *resource;
32197ec681f3Smrg    struct pipe_transfer *transfer = NULL;
32207ec681f3Smrg    struct pipe_stream_output_info so;
32217ec681f3Smrg    struct pipe_stream_output_target *target;
32227ec681f3Smrg    struct pipe_draw_info draw;
32237ec681f3Smrg    struct pipe_draw_start_count_bias sc;
32247ec681f3Smrg    struct pipe_box box;
32257ec681f3Smrg    bool programmable_vs = This->state.vs && !(This->state.vdecl && This->state.vdecl->position_t);
32267ec681f3Smrg    unsigned offsets[1] = {0};
32277ec681f3Smrg    HRESULT hr;
32287ec681f3Smrg    unsigned buffer_size;
32297ec681f3Smrg    void *map;
32307ec681f3Smrg
32317ec681f3Smrg    DBG("This=%p SrcStartIndex=%u DestIndex=%u VertexCount=%u "
32327ec681f3Smrg        "pDestBuffer=%p pVertexDecl=%p Flags=%d\n",
32337ec681f3Smrg        This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer,
32347ec681f3Smrg        pVertexDecl, Flags);
32357ec681f3Smrg
32367ec681f3Smrg    user_assert(pDestBuffer && pVertexDecl, D3DERR_INVALIDCALL);
32377ec681f3Smrg
32387ec681f3Smrg    if (!screen_sw->get_param(screen_sw, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS)) {
32397ec681f3Smrg        DBG("ProcessVertices not supported\n");
32407ec681f3Smrg        return D3DERR_INVALIDCALL;
32417ec681f3Smrg    }
32427ec681f3Smrg
32437ec681f3Smrg
32447ec681f3Smrg    vs = programmable_vs ? This->state.vs : This->ff.vs;
32457ec681f3Smrg    /* Note: version is 0 for ff */
32467ec681f3Smrg    user_assert(vdecl || (vs->byte_code.version < 0x30 && dst->desc.FVF),
32477ec681f3Smrg                D3DERR_INVALIDCALL);
32487ec681f3Smrg    if (!vdecl) {
32497ec681f3Smrg        DWORD FVF = dst->desc.FVF;
32507ec681f3Smrg        vdecl = util_hash_table_get(This->ff.ht_fvf, &FVF);
32517ec681f3Smrg        if (!vdecl) {
32527ec681f3Smrg            hr = NineVertexDeclaration9_new_from_fvf(This, FVF, &vdecl);
32537ec681f3Smrg            if (FAILED(hr))
32547ec681f3Smrg                return hr;
32557ec681f3Smrg            vdecl->fvf = FVF;
32567ec681f3Smrg            _mesa_hash_table_insert(This->ff.ht_fvf, &vdecl->fvf, vdecl);
32577ec681f3Smrg            NineUnknown_ConvertRefToBind(NineUnknown(vdecl));
32587ec681f3Smrg        }
32597ec681f3Smrg    }
32607ec681f3Smrg
32617ec681f3Smrg    /* Flags: Can be 0 or D3DPV_DONOTCOPYDATA, and/or lock flags
32627ec681f3Smrg     * D3DPV_DONOTCOPYDATA -> Has effect only for ff. In particular
32637ec681f3Smrg     * if not set, everything from src will be used, and dst
32647ec681f3Smrg     * must match exactly the ff vs outputs.
32657ec681f3Smrg     * TODO: Handle all the checks, etc for ff */
32667ec681f3Smrg    user_assert(vdecl->position_t || programmable_vs,
32677ec681f3Smrg                D3DERR_INVALIDCALL);
32687ec681f3Smrg
32697ec681f3Smrg    /* TODO: Support vs < 3 and ff */
32707ec681f3Smrg    user_assert(vs->byte_code.version == 0x30,
32717ec681f3Smrg                D3DERR_INVALIDCALL);
32727ec681f3Smrg    /* TODO: Not hardcode the constant buffers for swvp */
32737ec681f3Smrg    user_assert(This->may_swvp,
32747ec681f3Smrg                D3DERR_INVALIDCALL);
32757ec681f3Smrg
32767ec681f3Smrg    nine_state_prepare_draw_sw(This, vdecl, SrcStartIndex, VertexCount, &so);
32777ec681f3Smrg
32787ec681f3Smrg    buffer_size = VertexCount * so.stride[0] * 4;
32797ec681f3Smrg    {
32807ec681f3Smrg        struct pipe_resource templ;
32817ec681f3Smrg
32827ec681f3Smrg        memset(&templ, 0, sizeof(templ));
32837ec681f3Smrg        templ.target = PIPE_BUFFER;
32847ec681f3Smrg        templ.format = PIPE_FORMAT_R8_UNORM;
32857ec681f3Smrg        templ.width0 = buffer_size;
32867ec681f3Smrg        templ.flags = 0;
32877ec681f3Smrg        templ.bind = PIPE_BIND_STREAM_OUTPUT;
32887ec681f3Smrg        templ.usage = PIPE_USAGE_STREAM;
32897ec681f3Smrg        templ.height0 = templ.depth0 = templ.array_size = 1;
32907ec681f3Smrg        templ.last_level = templ.nr_samples = templ.nr_storage_samples = 0;
32917ec681f3Smrg
32927ec681f3Smrg        resource = screen_sw->resource_create(screen_sw, &templ);
32937ec681f3Smrg        if (!resource)
32947ec681f3Smrg            return E_OUTOFMEMORY;
32957ec681f3Smrg    }
32967ec681f3Smrg    target = pipe_sw->create_stream_output_target(pipe_sw, resource,
32977ec681f3Smrg                                                  0, buffer_size);
32987ec681f3Smrg    if (!target) {
32997ec681f3Smrg        pipe_resource_reference(&resource, NULL);
33007ec681f3Smrg        return D3DERR_DRIVERINTERNALERROR;
33017ec681f3Smrg    }
33027ec681f3Smrg
33037ec681f3Smrg    draw.mode = PIPE_PRIM_POINTS;
33047ec681f3Smrg    sc.count = VertexCount;
33057ec681f3Smrg    draw.start_instance = 0;
33067ec681f3Smrg    draw.primitive_restart = FALSE;
33077ec681f3Smrg    draw.restart_index = 0;
33087ec681f3Smrg    draw.instance_count = 1;
33097ec681f3Smrg    draw.index_size = 0;
33107ec681f3Smrg    sc.start = 0;
33117ec681f3Smrg    sc.index_bias = 0;
33127ec681f3Smrg    draw.min_index = 0;
33137ec681f3Smrg    draw.max_index = VertexCount - 1;
33147ec681f3Smrg
33157ec681f3Smrg
33167ec681f3Smrg    pipe_sw->set_stream_output_targets(pipe_sw, 1, &target, offsets);
33177ec681f3Smrg
33187ec681f3Smrg    pipe_sw->draw_vbo(pipe_sw, &draw, 0, NULL, &sc, 1);
33197ec681f3Smrg
33207ec681f3Smrg    pipe_sw->set_stream_output_targets(pipe_sw, 0, NULL, 0);
33217ec681f3Smrg    pipe_sw->stream_output_target_destroy(pipe_sw, target);
33227ec681f3Smrg
33237ec681f3Smrg    u_box_1d(0, VertexCount * so.stride[0] * 4, &box);
33247ec681f3Smrg    map = pipe_sw->buffer_map(pipe_sw, resource, 0, PIPE_MAP_READ, &box,
33257ec681f3Smrg                                &transfer);
33267ec681f3Smrg    if (!map) {
33277ec681f3Smrg        hr = D3DERR_DRIVERINTERNALERROR;
33287ec681f3Smrg        goto out;
33297ec681f3Smrg    }
33307ec681f3Smrg
33317ec681f3Smrg    hr = NineVertexDeclaration9_ConvertStreamOutput(vdecl,
33327ec681f3Smrg                                                    dst, DestIndex, VertexCount,
33337ec681f3Smrg                                                    map, &so);
33347ec681f3Smrg    if (transfer)
33357ec681f3Smrg        pipe_sw->buffer_unmap(pipe_sw, transfer);
33367ec681f3Smrg
33377ec681f3Smrgout:
33387ec681f3Smrg    nine_state_after_draw_sw(This);
33397ec681f3Smrg    pipe_resource_reference(&resource, NULL);
33407ec681f3Smrg    return hr;
33417ec681f3Smrg}
33427ec681f3Smrg
33437ec681f3SmrgHRESULT NINE_WINAPI
33447ec681f3SmrgNineDevice9_CreateVertexDeclaration( struct NineDevice9 *This,
33457ec681f3Smrg                                     const D3DVERTEXELEMENT9 *pVertexElements,
33467ec681f3Smrg                                     IDirect3DVertexDeclaration9 **ppDecl )
33477ec681f3Smrg{
33487ec681f3Smrg    struct NineVertexDeclaration9 *vdecl;
33497ec681f3Smrg
33507ec681f3Smrg    DBG("This=%p pVertexElements=%p ppDecl=%p\n",
33517ec681f3Smrg        This, pVertexElements, ppDecl);
33527ec681f3Smrg
33537ec681f3Smrg    user_assert(pVertexElements && ppDecl, D3DERR_INVALIDCALL);
33547ec681f3Smrg
33557ec681f3Smrg    HRESULT hr = NineVertexDeclaration9_new(This, pVertexElements, &vdecl);
33567ec681f3Smrg    if (SUCCEEDED(hr))
33577ec681f3Smrg        *ppDecl = (IDirect3DVertexDeclaration9 *)vdecl;
33587ec681f3Smrg
33597ec681f3Smrg    return hr;
33607ec681f3Smrg}
33617ec681f3Smrg
33627ec681f3SmrgHRESULT NINE_WINAPI
33637ec681f3SmrgNineDevice9_SetVertexDeclaration( struct NineDevice9 *This,
33647ec681f3Smrg                                  IDirect3DVertexDeclaration9 *pDecl )
33657ec681f3Smrg{
33667ec681f3Smrg    struct nine_state *state = This->update;
33677ec681f3Smrg    struct NineVertexDeclaration9 *vdecl = NineVertexDeclaration9(pDecl);
33687ec681f3Smrg
33697ec681f3Smrg    DBG("This=%p pDecl=%p\n", This, pDecl);
33707ec681f3Smrg
33717ec681f3Smrg    if (unlikely(This->is_recording)) {
33727ec681f3Smrg        nine_bind(&state->vdecl, vdecl);
33737ec681f3Smrg        state->changed.group |= NINE_STATE_VDECL;
33747ec681f3Smrg        return D3D_OK;
33757ec681f3Smrg    }
33767ec681f3Smrg
33777ec681f3Smrg    if (state->vdecl == vdecl)
33787ec681f3Smrg        return D3D_OK;
33797ec681f3Smrg
33807ec681f3Smrg    nine_bind(&state->vdecl, vdecl);
33817ec681f3Smrg
33827ec681f3Smrg    nine_context_set_vertex_declaration(This, vdecl);
33837ec681f3Smrg
33847ec681f3Smrg    return D3D_OK;
33857ec681f3Smrg}
33867ec681f3Smrg
33877ec681f3SmrgHRESULT NINE_WINAPI
33887ec681f3SmrgNineDevice9_GetVertexDeclaration( struct NineDevice9 *This,
33897ec681f3Smrg                                  IDirect3DVertexDeclaration9 **ppDecl )
33907ec681f3Smrg{
33917ec681f3Smrg    user_assert(ppDecl, D3DERR_INVALIDCALL);
33927ec681f3Smrg
33937ec681f3Smrg    *ppDecl = (IDirect3DVertexDeclaration9 *)This->state.vdecl;
33947ec681f3Smrg    if (*ppDecl)
33957ec681f3Smrg        NineUnknown_AddRef(NineUnknown(*ppDecl));
33967ec681f3Smrg    return D3D_OK;
33977ec681f3Smrg}
33987ec681f3Smrg
33997ec681f3SmrgHRESULT NINE_WINAPI
34007ec681f3SmrgNineDevice9_SetFVF( struct NineDevice9 *This,
34017ec681f3Smrg                    DWORD FVF )
34027ec681f3Smrg{
34037ec681f3Smrg    struct NineVertexDeclaration9 *vdecl;
34047ec681f3Smrg    HRESULT hr;
34057ec681f3Smrg
34067ec681f3Smrg    DBG("FVF = %08x\n", FVF);
34077ec681f3Smrg    if (!FVF)
34087ec681f3Smrg        return D3D_OK; /* like wine */
34097ec681f3Smrg
34107ec681f3Smrg    vdecl = util_hash_table_get(This->ff.ht_fvf, &FVF);
34117ec681f3Smrg    if (!vdecl) {
34127ec681f3Smrg        hr = NineVertexDeclaration9_new_from_fvf(This, FVF, &vdecl);
34137ec681f3Smrg        if (FAILED(hr))
34147ec681f3Smrg            return hr;
34157ec681f3Smrg        vdecl->fvf = FVF;
34167ec681f3Smrg        _mesa_hash_table_insert(This->ff.ht_fvf, &vdecl->fvf, vdecl);
34177ec681f3Smrg        NineUnknown_ConvertRefToBind(NineUnknown(vdecl));
34187ec681f3Smrg    }
34197ec681f3Smrg    return NineDevice9_SetVertexDeclaration(
34207ec681f3Smrg        This, (IDirect3DVertexDeclaration9 *)vdecl);
34217ec681f3Smrg}
34227ec681f3Smrg
34237ec681f3SmrgHRESULT NINE_WINAPI
34247ec681f3SmrgNineDevice9_GetFVF( struct NineDevice9 *This,
34257ec681f3Smrg                    DWORD *pFVF )
34267ec681f3Smrg{
34277ec681f3Smrg    user_assert(pFVF != NULL, D3DERR_INVALIDCALL);
34287ec681f3Smrg    *pFVF = This->state.vdecl ? This->state.vdecl->fvf : 0;
34297ec681f3Smrg    return D3D_OK;
34307ec681f3Smrg}
34317ec681f3Smrg
34327ec681f3SmrgHRESULT NINE_WINAPI
34337ec681f3SmrgNineDevice9_CreateVertexShader( struct NineDevice9 *This,
34347ec681f3Smrg                                const DWORD *pFunction,
34357ec681f3Smrg                                IDirect3DVertexShader9 **ppShader )
34367ec681f3Smrg{
34377ec681f3Smrg    struct NineVertexShader9 *vs;
34387ec681f3Smrg    HRESULT hr;
34397ec681f3Smrg
34407ec681f3Smrg    DBG("This=%p pFunction=%p ppShader=%p\n", This, pFunction, ppShader);
34417ec681f3Smrg
34427ec681f3Smrg    user_assert(pFunction && ppShader, D3DERR_INVALIDCALL);
34437ec681f3Smrg
34447ec681f3Smrg    hr = NineVertexShader9_new(This, &vs, pFunction, NULL);
34457ec681f3Smrg    if (FAILED(hr))
34467ec681f3Smrg        return hr;
34477ec681f3Smrg    *ppShader = (IDirect3DVertexShader9 *)vs;
34487ec681f3Smrg    return D3D_OK;
34497ec681f3Smrg}
34507ec681f3Smrg
34517ec681f3SmrgHRESULT NINE_WINAPI
34527ec681f3SmrgNineDevice9_SetVertexShader( struct NineDevice9 *This,
34537ec681f3Smrg                             IDirect3DVertexShader9 *pShader )
34547ec681f3Smrg{
34557ec681f3Smrg    struct nine_state *state = This->update;
34567ec681f3Smrg    struct NineVertexShader9 *vs_shader = (struct NineVertexShader9*)pShader;
34577ec681f3Smrg
34587ec681f3Smrg    DBG("This=%p pShader=%p\n", This, pShader);
34597ec681f3Smrg
34607ec681f3Smrg    if (unlikely(This->is_recording)) {
34617ec681f3Smrg        nine_bind(&state->vs, vs_shader);
34627ec681f3Smrg        state->changed.group |= NINE_STATE_VS;
34637ec681f3Smrg        return D3D_OK;
34647ec681f3Smrg    }
34657ec681f3Smrg
34667ec681f3Smrg    if (state->vs == vs_shader)
34677ec681f3Smrg      return D3D_OK;
34687ec681f3Smrg
34697ec681f3Smrg    nine_bind(&state->vs, vs_shader);
34707ec681f3Smrg
34717ec681f3Smrg    nine_context_set_vertex_shader(This, vs_shader);
34727ec681f3Smrg
34737ec681f3Smrg    return D3D_OK;
34747ec681f3Smrg}
34757ec681f3Smrg
34767ec681f3SmrgHRESULT NINE_WINAPI
34777ec681f3SmrgNineDevice9_GetVertexShader( struct NineDevice9 *This,
34787ec681f3Smrg                             IDirect3DVertexShader9 **ppShader )
34797ec681f3Smrg{
34807ec681f3Smrg    user_assert(ppShader, D3DERR_INVALIDCALL);
34817ec681f3Smrg    nine_reference_set(ppShader, This->state.vs);
34827ec681f3Smrg    return D3D_OK;
34837ec681f3Smrg}
34847ec681f3Smrg
34857ec681f3SmrgHRESULT NINE_WINAPI
34867ec681f3SmrgNineDevice9_SetVertexShaderConstantF( struct NineDevice9 *This,
34877ec681f3Smrg                                      UINT StartRegister,
34887ec681f3Smrg                                      const float *pConstantData,
34897ec681f3Smrg                                      UINT Vector4fCount )
34907ec681f3Smrg{
34917ec681f3Smrg    struct nine_state *state = This->update;
34927ec681f3Smrg    float *vs_const_f = state->vs_const_f;
34937ec681f3Smrg
34947ec681f3Smrg    DBG("This=%p StartRegister=%u pConstantData=%p Vector4fCount=%u\n",
34957ec681f3Smrg        This, StartRegister, pConstantData, Vector4fCount);
34967ec681f3Smrg
34977ec681f3Smrg    user_assert(StartRegister                  < This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
34987ec681f3Smrg    user_assert(StartRegister + Vector4fCount <= This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
34997ec681f3Smrg
35007ec681f3Smrg    if (!Vector4fCount)
35017ec681f3Smrg       return D3D_OK;
35027ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
35037ec681f3Smrg
35047ec681f3Smrg    if (unlikely(This->is_recording)) {
35057ec681f3Smrg        memcpy(&vs_const_f[StartRegister * 4],
35067ec681f3Smrg               pConstantData,
35077ec681f3Smrg               Vector4fCount * 4 * sizeof(state->vs_const_f[0]));
35087ec681f3Smrg
35097ec681f3Smrg        nine_ranges_insert(&state->changed.vs_const_f,
35107ec681f3Smrg                           StartRegister, StartRegister + Vector4fCount,
35117ec681f3Smrg                           &This->range_pool);
35127ec681f3Smrg
35137ec681f3Smrg        state->changed.group |= NINE_STATE_VS_CONST;
35147ec681f3Smrg
35157ec681f3Smrg        return D3D_OK;
35167ec681f3Smrg    }
35177ec681f3Smrg
35187ec681f3Smrg    if (!memcmp(&vs_const_f[StartRegister * 4], pConstantData,
35197ec681f3Smrg                Vector4fCount * 4 * sizeof(state->vs_const_f[0])))
35207ec681f3Smrg        return D3D_OK;
35217ec681f3Smrg
35227ec681f3Smrg    memcpy(&vs_const_f[StartRegister * 4],
35237ec681f3Smrg           pConstantData,
35247ec681f3Smrg           Vector4fCount * 4 * sizeof(state->vs_const_f[0]));
35257ec681f3Smrg
35267ec681f3Smrg    nine_context_set_vertex_shader_constant_f(This, StartRegister, pConstantData,
35277ec681f3Smrg                                              Vector4fCount * 4 * sizeof(state->vs_const_f[0]),
35287ec681f3Smrg                                              Vector4fCount);
35297ec681f3Smrg
35307ec681f3Smrg    return D3D_OK;
35317ec681f3Smrg}
35327ec681f3Smrg
35337ec681f3SmrgHRESULT NINE_WINAPI
35347ec681f3SmrgNineDevice9_GetVertexShaderConstantF( struct NineDevice9 *This,
35357ec681f3Smrg                                      UINT StartRegister,
35367ec681f3Smrg                                      float *pConstantData,
35377ec681f3Smrg                                      UINT Vector4fCount )
35387ec681f3Smrg{
35397ec681f3Smrg    const struct nine_state *state = &This->state;
35407ec681f3Smrg
35417ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
35427ec681f3Smrg    user_assert(StartRegister                  < This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
35437ec681f3Smrg    user_assert(StartRegister + Vector4fCount <= This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
35447ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
35457ec681f3Smrg
35467ec681f3Smrg    memcpy(pConstantData,
35477ec681f3Smrg           &state->vs_const_f[StartRegister * 4],
35487ec681f3Smrg           Vector4fCount * 4 * sizeof(state->vs_const_f[0]));
35497ec681f3Smrg
35507ec681f3Smrg    return D3D_OK;
35517ec681f3Smrg}
35527ec681f3Smrg
35537ec681f3SmrgHRESULT NINE_WINAPI
35547ec681f3SmrgNineDevice9_SetVertexShaderConstantI( struct NineDevice9 *This,
35557ec681f3Smrg                                      UINT StartRegister,
35567ec681f3Smrg                                      const int *pConstantData,
35577ec681f3Smrg                                      UINT Vector4iCount )
35587ec681f3Smrg{
35597ec681f3Smrg    struct nine_state *state = This->update;
35607ec681f3Smrg    int i;
35617ec681f3Smrg
35627ec681f3Smrg    DBG("This=%p StartRegister=%u pConstantData=%p Vector4iCount=%u\n",
35637ec681f3Smrg        This, StartRegister, pConstantData, Vector4iCount);
35647ec681f3Smrg
35657ec681f3Smrg    user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I),
35667ec681f3Smrg                D3DERR_INVALIDCALL);
35677ec681f3Smrg    user_assert(StartRegister + Vector4iCount <= (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I),
35687ec681f3Smrg                D3DERR_INVALIDCALL);
35697ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
35707ec681f3Smrg
35717ec681f3Smrg    if (This->driver_caps.vs_integer) {
35727ec681f3Smrg        if (!This->is_recording) {
35737ec681f3Smrg            if (!memcmp(&state->vs_const_i[4 * StartRegister], pConstantData,
35747ec681f3Smrg                        Vector4iCount * sizeof(int[4])))
35757ec681f3Smrg                return D3D_OK;
35767ec681f3Smrg        }
35777ec681f3Smrg        memcpy(&state->vs_const_i[4 * StartRegister],
35787ec681f3Smrg               pConstantData,
35797ec681f3Smrg               Vector4iCount * sizeof(int[4]));
35807ec681f3Smrg    } else {
35817ec681f3Smrg        for (i = 0; i < Vector4iCount; i++) {
35827ec681f3Smrg            state->vs_const_i[4 * (StartRegister + i)] = fui((float)(pConstantData[4 * i]));
35837ec681f3Smrg            state->vs_const_i[4 * (StartRegister + i) + 1] = fui((float)(pConstantData[4 * i + 1]));
35847ec681f3Smrg            state->vs_const_i[4 * (StartRegister + i) + 2] = fui((float)(pConstantData[4 * i + 2]));
35857ec681f3Smrg            state->vs_const_i[4 * (StartRegister + i) + 3] = fui((float)(pConstantData[4 * i + 3]));
35867ec681f3Smrg        }
35877ec681f3Smrg    }
35887ec681f3Smrg
35897ec681f3Smrg    if (unlikely(This->is_recording)) {
35907ec681f3Smrg        nine_ranges_insert(&state->changed.vs_const_i,
35917ec681f3Smrg                           StartRegister, StartRegister + Vector4iCount,
35927ec681f3Smrg                           &This->range_pool);
35937ec681f3Smrg        state->changed.group |= NINE_STATE_VS_CONST;
35947ec681f3Smrg    } else
35957ec681f3Smrg        nine_context_set_vertex_shader_constant_i(This, StartRegister, pConstantData,
35967ec681f3Smrg                                                  Vector4iCount * sizeof(int[4]), Vector4iCount);
35977ec681f3Smrg
35987ec681f3Smrg    return D3D_OK;
35997ec681f3Smrg}
36007ec681f3Smrg
36017ec681f3SmrgHRESULT NINE_WINAPI
36027ec681f3SmrgNineDevice9_GetVertexShaderConstantI( struct NineDevice9 *This,
36037ec681f3Smrg                                      UINT StartRegister,
36047ec681f3Smrg                                      int *pConstantData,
36057ec681f3Smrg                                      UINT Vector4iCount )
36067ec681f3Smrg{
36077ec681f3Smrg    const struct nine_state *state = &This->state;
36087ec681f3Smrg    int i;
36097ec681f3Smrg
36107ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
36117ec681f3Smrg    user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I),
36127ec681f3Smrg                D3DERR_INVALIDCALL);
36137ec681f3Smrg    user_assert(StartRegister + Vector4iCount <= (This->may_swvp ? NINE_MAX_CONST_I_SWVP : NINE_MAX_CONST_I),
36147ec681f3Smrg                D3DERR_INVALIDCALL);
36157ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
36167ec681f3Smrg
36177ec681f3Smrg    if (This->driver_caps.vs_integer) {
36187ec681f3Smrg        memcpy(pConstantData,
36197ec681f3Smrg               &state->vs_const_i[4 * StartRegister],
36207ec681f3Smrg               Vector4iCount * sizeof(int[4]));
36217ec681f3Smrg    } else {
36227ec681f3Smrg        for (i = 0; i < Vector4iCount; i++) {
36237ec681f3Smrg            pConstantData[4 * i] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i)]);
36247ec681f3Smrg            pConstantData[4 * i + 1] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i) + 1]);
36257ec681f3Smrg            pConstantData[4 * i + 2] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i) + 2]);
36267ec681f3Smrg            pConstantData[4 * i + 3] = (int32_t) uif(state->vs_const_i[4 * (StartRegister + i) + 3]);
36277ec681f3Smrg        }
36287ec681f3Smrg    }
36297ec681f3Smrg
36307ec681f3Smrg    return D3D_OK;
36317ec681f3Smrg}
36327ec681f3Smrg
36337ec681f3SmrgHRESULT NINE_WINAPI
36347ec681f3SmrgNineDevice9_SetVertexShaderConstantB( struct NineDevice9 *This,
36357ec681f3Smrg                                      UINT StartRegister,
36367ec681f3Smrg                                      const BOOL *pConstantData,
36377ec681f3Smrg                                      UINT BoolCount )
36387ec681f3Smrg{
36397ec681f3Smrg    struct nine_state *state = This->update;
36407ec681f3Smrg    int i;
36417ec681f3Smrg    uint32_t bool_true = This->driver_caps.vs_integer ? 0xFFFFFFFF : fui(1.0f);
36427ec681f3Smrg
36437ec681f3Smrg    DBG("This=%p StartRegister=%u pConstantData=%p BoolCount=%u\n",
36447ec681f3Smrg        This, StartRegister, pConstantData, BoolCount);
36457ec681f3Smrg
36467ec681f3Smrg    user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B),
36477ec681f3Smrg                D3DERR_INVALIDCALL);
36487ec681f3Smrg    user_assert(StartRegister + BoolCount <= (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B),
36497ec681f3Smrg                D3DERR_INVALIDCALL);
36507ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
36517ec681f3Smrg
36527ec681f3Smrg    if (!This->is_recording) {
36537ec681f3Smrg        bool noChange = true;
36547ec681f3Smrg        for (i = 0; i < BoolCount; i++) {
36557ec681f3Smrg            if (!!state->vs_const_b[StartRegister + i] != !!pConstantData[i])
36567ec681f3Smrg              noChange = false;
36577ec681f3Smrg        }
36587ec681f3Smrg        if (noChange)
36597ec681f3Smrg            return D3D_OK;
36607ec681f3Smrg    }
36617ec681f3Smrg
36627ec681f3Smrg    for (i = 0; i < BoolCount; i++)
36637ec681f3Smrg        state->vs_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0;
36647ec681f3Smrg
36657ec681f3Smrg    if (unlikely(This->is_recording)) {
36667ec681f3Smrg        nine_ranges_insert(&state->changed.vs_const_b,
36677ec681f3Smrg                           StartRegister, StartRegister + BoolCount,
36687ec681f3Smrg                           &This->range_pool);
36697ec681f3Smrg        state->changed.group |= NINE_STATE_VS_CONST;
36707ec681f3Smrg    } else
36717ec681f3Smrg        nine_context_set_vertex_shader_constant_b(This, StartRegister, pConstantData,
36727ec681f3Smrg                                                  sizeof(BOOL) * BoolCount, BoolCount);
36737ec681f3Smrg
36747ec681f3Smrg    return D3D_OK;
36757ec681f3Smrg}
36767ec681f3Smrg
36777ec681f3SmrgHRESULT NINE_WINAPI
36787ec681f3SmrgNineDevice9_GetVertexShaderConstantB( struct NineDevice9 *This,
36797ec681f3Smrg                                      UINT StartRegister,
36807ec681f3Smrg                                      BOOL *pConstantData,
36817ec681f3Smrg                                      UINT BoolCount )
36827ec681f3Smrg{
36837ec681f3Smrg    const struct nine_state *state = &This->state;
36847ec681f3Smrg    int i;
36857ec681f3Smrg
36867ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
36877ec681f3Smrg    user_assert(StartRegister < (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B),
36887ec681f3Smrg                D3DERR_INVALIDCALL);
36897ec681f3Smrg    user_assert(StartRegister + BoolCount <= (This->may_swvp ? NINE_MAX_CONST_B_SWVP : NINE_MAX_CONST_B),
36907ec681f3Smrg                D3DERR_INVALIDCALL);
36917ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
36927ec681f3Smrg
36937ec681f3Smrg    for (i = 0; i < BoolCount; i++)
36947ec681f3Smrg        pConstantData[i] = state->vs_const_b[StartRegister + i] != 0 ? TRUE : FALSE;
36957ec681f3Smrg
36967ec681f3Smrg    return D3D_OK;
36977ec681f3Smrg}
36987ec681f3Smrg
36997ec681f3SmrgHRESULT NINE_WINAPI
37007ec681f3SmrgNineDevice9_SetStreamSource( struct NineDevice9 *This,
37017ec681f3Smrg                             UINT StreamNumber,
37027ec681f3Smrg                             IDirect3DVertexBuffer9 *pStreamData,
37037ec681f3Smrg                             UINT OffsetInBytes,
37047ec681f3Smrg                             UINT Stride )
37057ec681f3Smrg{
37067ec681f3Smrg    struct nine_state *state = This->update;
37077ec681f3Smrg    struct NineVertexBuffer9 *pVBuf9 = NineVertexBuffer9(pStreamData);
37087ec681f3Smrg    const unsigned i = StreamNumber;
37097ec681f3Smrg
37107ec681f3Smrg    DBG("This=%p StreamNumber=%u pStreamData=%p OffsetInBytes=%u Stride=%u\n",
37117ec681f3Smrg        This, StreamNumber, pStreamData, OffsetInBytes, Stride);
37127ec681f3Smrg
37137ec681f3Smrg    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
37147ec681f3Smrg    user_assert(Stride <= This->caps.MaxStreamStride, D3DERR_INVALIDCALL);
37157ec681f3Smrg
37167ec681f3Smrg    if (unlikely(This->is_recording)) {
37177ec681f3Smrg        nine_bind(&state->stream[i], pStreamData);
37187ec681f3Smrg        state->changed.vtxbuf |= 1 << StreamNumber;
37197ec681f3Smrg        state->vtxbuf[i].stride = Stride;
37207ec681f3Smrg        state->vtxbuf[i].buffer_offset = OffsetInBytes;
37217ec681f3Smrg        return D3D_OK;
37227ec681f3Smrg    }
37237ec681f3Smrg
37247ec681f3Smrg    if (state->stream[i] == NineVertexBuffer9(pStreamData) &&
37257ec681f3Smrg        state->vtxbuf[i].stride == Stride &&
37267ec681f3Smrg        state->vtxbuf[i].buffer_offset == OffsetInBytes)
37277ec681f3Smrg        return D3D_OK;
37287ec681f3Smrg
37297ec681f3Smrg    state->vtxbuf[i].stride = Stride;
37307ec681f3Smrg    state->vtxbuf[i].buffer_offset = OffsetInBytes;
37317ec681f3Smrg
37327ec681f3Smrg    NineBindBufferToDevice(This,
37337ec681f3Smrg                           (struct NineBuffer9 **)&state->stream[i],
37347ec681f3Smrg                           (struct NineBuffer9 *)pVBuf9);
37357ec681f3Smrg
37367ec681f3Smrg    nine_context_set_stream_source(This,
37377ec681f3Smrg                                   StreamNumber,
37387ec681f3Smrg                                   pVBuf9,
37397ec681f3Smrg                                   OffsetInBytes,
37407ec681f3Smrg                                   Stride);
37417ec681f3Smrg
37427ec681f3Smrg    return D3D_OK;
37437ec681f3Smrg}
37447ec681f3Smrg
37457ec681f3Smrgstatic void
37467ec681f3SmrgNineDevice9_SetStreamSourceNULL( struct NineDevice9 *This )
37477ec681f3Smrg{
37487ec681f3Smrg    struct nine_state *state = This->update;
37497ec681f3Smrg
37507ec681f3Smrg    DBG("This=%p\n", This);
37517ec681f3Smrg
37527ec681f3Smrg    state->vtxbuf[0].stride = 0;
37537ec681f3Smrg    state->vtxbuf[0].buffer_offset = 0;
37547ec681f3Smrg
37557ec681f3Smrg    if (!state->stream[0])
37567ec681f3Smrg        return;
37577ec681f3Smrg
37587ec681f3Smrg    NineBindBufferToDevice(This,
37597ec681f3Smrg                           (struct NineBuffer9 **)&state->stream[0],
37607ec681f3Smrg                           NULL);
37617ec681f3Smrg}
37627ec681f3Smrg
37637ec681f3SmrgHRESULT NINE_WINAPI
37647ec681f3SmrgNineDevice9_GetStreamSource( struct NineDevice9 *This,
37657ec681f3Smrg                             UINT StreamNumber,
37667ec681f3Smrg                             IDirect3DVertexBuffer9 **ppStreamData,
37677ec681f3Smrg                             UINT *pOffsetInBytes,
37687ec681f3Smrg                             UINT *pStride )
37697ec681f3Smrg{
37707ec681f3Smrg    const struct nine_state *state = &This->state;
37717ec681f3Smrg    const unsigned i = StreamNumber;
37727ec681f3Smrg
37737ec681f3Smrg    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
37747ec681f3Smrg    user_assert(ppStreamData && pOffsetInBytes && pStride, D3DERR_INVALIDCALL);
37757ec681f3Smrg
37767ec681f3Smrg    nine_reference_set(ppStreamData, state->stream[i]);
37777ec681f3Smrg    *pStride = state->vtxbuf[i].stride;
37787ec681f3Smrg    *pOffsetInBytes = state->vtxbuf[i].buffer_offset;
37797ec681f3Smrg
37807ec681f3Smrg    return D3D_OK;
37817ec681f3Smrg}
37827ec681f3Smrg
37837ec681f3SmrgHRESULT NINE_WINAPI
37847ec681f3SmrgNineDevice9_SetStreamSourceFreq( struct NineDevice9 *This,
37857ec681f3Smrg                                 UINT StreamNumber,
37867ec681f3Smrg                                 UINT Setting )
37877ec681f3Smrg{
37887ec681f3Smrg    struct nine_state *state = This->update;
37897ec681f3Smrg    /* const UINT freq = Setting & 0x7FFFFF; */
37907ec681f3Smrg
37917ec681f3Smrg    DBG("This=%p StreamNumber=%u FrequencyParameter=0x%x\n", This,
37927ec681f3Smrg        StreamNumber, Setting);
37937ec681f3Smrg
37947ec681f3Smrg    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
37957ec681f3Smrg    user_assert(StreamNumber != 0 || !(Setting & D3DSTREAMSOURCE_INSTANCEDATA),
37967ec681f3Smrg                D3DERR_INVALIDCALL);
37977ec681f3Smrg    user_assert(!((Setting & D3DSTREAMSOURCE_INSTANCEDATA) &&
37987ec681f3Smrg                  (Setting & D3DSTREAMSOURCE_INDEXEDDATA)), D3DERR_INVALIDCALL);
37997ec681f3Smrg    user_assert(Setting, D3DERR_INVALIDCALL);
38007ec681f3Smrg
38017ec681f3Smrg    if (unlikely(This->is_recording)) {
38027ec681f3Smrg        state->stream_freq[StreamNumber] = Setting;
38037ec681f3Smrg        state->changed.stream_freq |= 1 << StreamNumber;
38047ec681f3Smrg        return D3D_OK;
38057ec681f3Smrg    }
38067ec681f3Smrg
38077ec681f3Smrg    if (state->stream_freq[StreamNumber] == Setting)
38087ec681f3Smrg        return D3D_OK;
38097ec681f3Smrg
38107ec681f3Smrg    state->stream_freq[StreamNumber] = Setting;
38117ec681f3Smrg
38127ec681f3Smrg    nine_context_set_stream_source_freq(This, StreamNumber, Setting);
38137ec681f3Smrg    return D3D_OK;
38147ec681f3Smrg}
38157ec681f3Smrg
38167ec681f3SmrgHRESULT NINE_WINAPI
38177ec681f3SmrgNineDevice9_GetStreamSourceFreq( struct NineDevice9 *This,
38187ec681f3Smrg                                 UINT StreamNumber,
38197ec681f3Smrg                                 UINT *pSetting )
38207ec681f3Smrg{
38217ec681f3Smrg    user_assert(pSetting != NULL, D3DERR_INVALIDCALL);
38227ec681f3Smrg    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
38237ec681f3Smrg    *pSetting = This->state.stream_freq[StreamNumber];
38247ec681f3Smrg    return D3D_OK;
38257ec681f3Smrg}
38267ec681f3Smrg
38277ec681f3SmrgHRESULT NINE_WINAPI
38287ec681f3SmrgNineDevice9_SetIndices( struct NineDevice9 *This,
38297ec681f3Smrg                        IDirect3DIndexBuffer9 *pIndexData )
38307ec681f3Smrg{
38317ec681f3Smrg    struct nine_state *state = This->update;
38327ec681f3Smrg    struct NineIndexBuffer9 *idxbuf = NineIndexBuffer9(pIndexData);
38337ec681f3Smrg
38347ec681f3Smrg    DBG("This=%p pIndexData=%p\n", This, pIndexData);
38357ec681f3Smrg
38367ec681f3Smrg    if (unlikely(This->is_recording)) {
38377ec681f3Smrg        nine_bind(&state->idxbuf, idxbuf);
38387ec681f3Smrg        state->changed.group |= NINE_STATE_IDXBUF;
38397ec681f3Smrg        return D3D_OK;
38407ec681f3Smrg    }
38417ec681f3Smrg
38427ec681f3Smrg    if (state->idxbuf == idxbuf)
38437ec681f3Smrg        return D3D_OK;
38447ec681f3Smrg
38457ec681f3Smrg    NineBindBufferToDevice(This,
38467ec681f3Smrg                           (struct NineBuffer9 **)&state->idxbuf,
38477ec681f3Smrg                           (struct NineBuffer9 *)idxbuf);
38487ec681f3Smrg
38497ec681f3Smrg    nine_context_set_indices(This, idxbuf);
38507ec681f3Smrg
38517ec681f3Smrg    return D3D_OK;
38527ec681f3Smrg}
38537ec681f3Smrg
38547ec681f3Smrg/* XXX: wine/d3d9 doesn't have pBaseVertexIndex, and it doesn't make sense
38557ec681f3Smrg * here because it's an argument passed to the Draw calls.
38567ec681f3Smrg */
38577ec681f3SmrgHRESULT NINE_WINAPI
38587ec681f3SmrgNineDevice9_GetIndices( struct NineDevice9 *This,
38597ec681f3Smrg                        IDirect3DIndexBuffer9 **ppIndexData)
38607ec681f3Smrg{
38617ec681f3Smrg    user_assert(ppIndexData, D3DERR_INVALIDCALL);
38627ec681f3Smrg    nine_reference_set(ppIndexData, This->state.idxbuf);
38637ec681f3Smrg    return D3D_OK;
38647ec681f3Smrg}
38657ec681f3Smrg
38667ec681f3SmrgHRESULT NINE_WINAPI
38677ec681f3SmrgNineDevice9_CreatePixelShader( struct NineDevice9 *This,
38687ec681f3Smrg                               const DWORD *pFunction,
38697ec681f3Smrg                               IDirect3DPixelShader9 **ppShader )
38707ec681f3Smrg{
38717ec681f3Smrg    struct NinePixelShader9 *ps;
38727ec681f3Smrg    HRESULT hr;
38737ec681f3Smrg
38747ec681f3Smrg    DBG("This=%p pFunction=%p ppShader=%p\n", This, pFunction, ppShader);
38757ec681f3Smrg
38767ec681f3Smrg    user_assert(pFunction && ppShader, D3DERR_INVALIDCALL);
38777ec681f3Smrg
38787ec681f3Smrg    hr = NinePixelShader9_new(This, &ps, pFunction, NULL);
38797ec681f3Smrg    if (FAILED(hr))
38807ec681f3Smrg        return hr;
38817ec681f3Smrg    *ppShader = (IDirect3DPixelShader9 *)ps;
38827ec681f3Smrg    return D3D_OK;
38837ec681f3Smrg}
38847ec681f3Smrg
38857ec681f3SmrgHRESULT NINE_WINAPI
38867ec681f3SmrgNineDevice9_SetPixelShader( struct NineDevice9 *This,
38877ec681f3Smrg                            IDirect3DPixelShader9 *pShader )
38887ec681f3Smrg{
38897ec681f3Smrg    struct nine_state *state = This->update;
38907ec681f3Smrg    struct NinePixelShader9 *ps = (struct NinePixelShader9*)pShader;
38917ec681f3Smrg
38927ec681f3Smrg    DBG("This=%p pShader=%p\n", This, pShader);
38937ec681f3Smrg
38947ec681f3Smrg    if (unlikely(This->is_recording)) {
38957ec681f3Smrg        nine_bind(&state->ps, pShader);
38967ec681f3Smrg        state->changed.group |= NINE_STATE_PS;
38977ec681f3Smrg        return D3D_OK;
38987ec681f3Smrg    }
38997ec681f3Smrg
39007ec681f3Smrg    if (state->ps == ps)
39017ec681f3Smrg        return D3D_OK;
39027ec681f3Smrg
39037ec681f3Smrg    nine_bind(&state->ps, ps);
39047ec681f3Smrg
39057ec681f3Smrg    nine_context_set_pixel_shader(This, ps);
39067ec681f3Smrg
39077ec681f3Smrg    return D3D_OK;
39087ec681f3Smrg}
39097ec681f3Smrg
39107ec681f3SmrgHRESULT NINE_WINAPI
39117ec681f3SmrgNineDevice9_GetPixelShader( struct NineDevice9 *This,
39127ec681f3Smrg                            IDirect3DPixelShader9 **ppShader )
39137ec681f3Smrg{
39147ec681f3Smrg    user_assert(ppShader, D3DERR_INVALIDCALL);
39157ec681f3Smrg    nine_reference_set(ppShader, This->state.ps);
39167ec681f3Smrg    return D3D_OK;
39177ec681f3Smrg}
39187ec681f3Smrg
39197ec681f3SmrgHRESULT NINE_WINAPI
39207ec681f3SmrgNineDevice9_SetPixelShaderConstantF( struct NineDevice9 *This,
39217ec681f3Smrg                                     UINT StartRegister,
39227ec681f3Smrg                                     const float *pConstantData,
39237ec681f3Smrg                                     UINT Vector4fCount )
39247ec681f3Smrg{
39257ec681f3Smrg    struct nine_state *state = This->update;
39267ec681f3Smrg
39277ec681f3Smrg    DBG("This=%p StartRegister=%u pConstantData=%p Vector4fCount=%u\n",
39287ec681f3Smrg        This, StartRegister, pConstantData, Vector4fCount);
39297ec681f3Smrg
39307ec681f3Smrg    user_assert(StartRegister                  < NINE_MAX_CONST_F_PS3, D3DERR_INVALIDCALL);
39317ec681f3Smrg    user_assert(StartRegister + Vector4fCount <= NINE_MAX_CONST_F_PS3, D3DERR_INVALIDCALL);
39327ec681f3Smrg
39337ec681f3Smrg    if (!Vector4fCount)
39347ec681f3Smrg       return D3D_OK;
39357ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
39367ec681f3Smrg
39377ec681f3Smrg    if (unlikely(This->is_recording)) {
39387ec681f3Smrg        memcpy(&state->ps_const_f[StartRegister * 4],
39397ec681f3Smrg               pConstantData,
39407ec681f3Smrg               Vector4fCount * 4 * sizeof(state->ps_const_f[0]));
39417ec681f3Smrg
39427ec681f3Smrg        nine_ranges_insert(&state->changed.ps_const_f,
39437ec681f3Smrg                           StartRegister, StartRegister + Vector4fCount,
39447ec681f3Smrg                           &This->range_pool);
39457ec681f3Smrg
39467ec681f3Smrg        state->changed.group |= NINE_STATE_PS_CONST;
39477ec681f3Smrg        return D3D_OK;
39487ec681f3Smrg    }
39497ec681f3Smrg
39507ec681f3Smrg    if (!memcmp(&state->ps_const_f[StartRegister * 4], pConstantData,
39517ec681f3Smrg                Vector4fCount * 4 * sizeof(state->ps_const_f[0])))
39527ec681f3Smrg        return D3D_OK;
39537ec681f3Smrg
39547ec681f3Smrg    memcpy(&state->ps_const_f[StartRegister * 4],
39557ec681f3Smrg           pConstantData,
39567ec681f3Smrg           Vector4fCount * 4 * sizeof(state->ps_const_f[0]));
39577ec681f3Smrg
39587ec681f3Smrg    nine_context_set_pixel_shader_constant_f(This, StartRegister, pConstantData,
39597ec681f3Smrg                                             Vector4fCount * 4 * sizeof(state->ps_const_f[0]),
39607ec681f3Smrg                                             Vector4fCount);
39617ec681f3Smrg
39627ec681f3Smrg    return D3D_OK;
39637ec681f3Smrg}
39647ec681f3Smrg
39657ec681f3SmrgHRESULT NINE_WINAPI
39667ec681f3SmrgNineDevice9_GetPixelShaderConstantF( struct NineDevice9 *This,
39677ec681f3Smrg                                     UINT StartRegister,
39687ec681f3Smrg                                     float *pConstantData,
39697ec681f3Smrg                                     UINT Vector4fCount )
39707ec681f3Smrg{
39717ec681f3Smrg    const struct nine_state *state = &This->state;
39727ec681f3Smrg
39737ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
39747ec681f3Smrg    user_assert(StartRegister                  < NINE_MAX_CONST_F_PS3, D3DERR_INVALIDCALL);
39757ec681f3Smrg    user_assert(StartRegister + Vector4fCount <= NINE_MAX_CONST_F_PS3, D3DERR_INVALIDCALL);
39767ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
39777ec681f3Smrg
39787ec681f3Smrg    memcpy(pConstantData,
39797ec681f3Smrg           &state->ps_const_f[StartRegister * 4],
39807ec681f3Smrg           Vector4fCount * 4 * sizeof(state->ps_const_f[0]));
39817ec681f3Smrg
39827ec681f3Smrg    return D3D_OK;
39837ec681f3Smrg}
39847ec681f3Smrg
39857ec681f3SmrgHRESULT NINE_WINAPI
39867ec681f3SmrgNineDevice9_SetPixelShaderConstantI( struct NineDevice9 *This,
39877ec681f3Smrg                                     UINT StartRegister,
39887ec681f3Smrg                                     const int *pConstantData,
39897ec681f3Smrg                                     UINT Vector4iCount )
39907ec681f3Smrg{
39917ec681f3Smrg    struct nine_state *state = This->update;
39927ec681f3Smrg    int i;
39937ec681f3Smrg
39947ec681f3Smrg    DBG("This=%p StartRegister=%u pConstantData=%p Vector4iCount=%u\n",
39957ec681f3Smrg        This, StartRegister, pConstantData, Vector4iCount);
39967ec681f3Smrg
39977ec681f3Smrg    user_assert(StartRegister                  < NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
39987ec681f3Smrg    user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
39997ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
40007ec681f3Smrg
40017ec681f3Smrg    if (This->driver_caps.ps_integer) {
40027ec681f3Smrg        if (!This->is_recording) {
40037ec681f3Smrg            if (!memcmp(&state->ps_const_i[StartRegister][0], pConstantData,
40047ec681f3Smrg                        Vector4iCount * sizeof(state->ps_const_i[0])))
40057ec681f3Smrg                return D3D_OK;
40067ec681f3Smrg        }
40077ec681f3Smrg        memcpy(&state->ps_const_i[StartRegister][0],
40087ec681f3Smrg               pConstantData,
40097ec681f3Smrg               Vector4iCount * sizeof(state->ps_const_i[0]));
40107ec681f3Smrg    } else {
40117ec681f3Smrg        for (i = 0; i < Vector4iCount; i++) {
40127ec681f3Smrg            state->ps_const_i[StartRegister+i][0] = fui((float)(pConstantData[4*i]));
40137ec681f3Smrg            state->ps_const_i[StartRegister+i][1] = fui((float)(pConstantData[4*i+1]));
40147ec681f3Smrg            state->ps_const_i[StartRegister+i][2] = fui((float)(pConstantData[4*i+2]));
40157ec681f3Smrg            state->ps_const_i[StartRegister+i][3] = fui((float)(pConstantData[4*i+3]));
40167ec681f3Smrg        }
40177ec681f3Smrg    }
40187ec681f3Smrg
40197ec681f3Smrg    if (unlikely(This->is_recording)) {
40207ec681f3Smrg        state->changed.ps_const_i |= ((1 << Vector4iCount) - 1) << StartRegister;
40217ec681f3Smrg        state->changed.group |= NINE_STATE_PS_CONST;
40227ec681f3Smrg    } else
40237ec681f3Smrg        nine_context_set_pixel_shader_constant_i(This, StartRegister, pConstantData,
40247ec681f3Smrg                                                 sizeof(state->ps_const_i[0]) * Vector4iCount, Vector4iCount);
40257ec681f3Smrg
40267ec681f3Smrg    return D3D_OK;
40277ec681f3Smrg}
40287ec681f3Smrg
40297ec681f3SmrgHRESULT NINE_WINAPI
40307ec681f3SmrgNineDevice9_GetPixelShaderConstantI( struct NineDevice9 *This,
40317ec681f3Smrg                                     UINT StartRegister,
40327ec681f3Smrg                                     int *pConstantData,
40337ec681f3Smrg                                     UINT Vector4iCount )
40347ec681f3Smrg{
40357ec681f3Smrg    const struct nine_state *state = &This->state;
40367ec681f3Smrg    int i;
40377ec681f3Smrg
40387ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
40397ec681f3Smrg    user_assert(StartRegister                  < NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
40407ec681f3Smrg    user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
40417ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
40427ec681f3Smrg
40437ec681f3Smrg    if (This->driver_caps.ps_integer) {
40447ec681f3Smrg        memcpy(pConstantData,
40457ec681f3Smrg               &state->ps_const_i[StartRegister][0],
40467ec681f3Smrg               Vector4iCount * sizeof(state->ps_const_i[0]));
40477ec681f3Smrg    } else {
40487ec681f3Smrg        for (i = 0; i < Vector4iCount; i++) {
40497ec681f3Smrg            pConstantData[4*i] = (int32_t) uif(state->ps_const_i[StartRegister+i][0]);
40507ec681f3Smrg            pConstantData[4*i+1] = (int32_t) uif(state->ps_const_i[StartRegister+i][1]);
40517ec681f3Smrg            pConstantData[4*i+2] = (int32_t) uif(state->ps_const_i[StartRegister+i][2]);
40527ec681f3Smrg            pConstantData[4*i+3] = (int32_t) uif(state->ps_const_i[StartRegister+i][3]);
40537ec681f3Smrg        }
40547ec681f3Smrg    }
40557ec681f3Smrg
40567ec681f3Smrg    return D3D_OK;
40577ec681f3Smrg}
40587ec681f3Smrg
40597ec681f3SmrgHRESULT NINE_WINAPI
40607ec681f3SmrgNineDevice9_SetPixelShaderConstantB( struct NineDevice9 *This,
40617ec681f3Smrg                                     UINT StartRegister,
40627ec681f3Smrg                                     const BOOL *pConstantData,
40637ec681f3Smrg                                     UINT BoolCount )
40647ec681f3Smrg{
40657ec681f3Smrg    struct nine_state *state = This->update;
40667ec681f3Smrg    int i;
40677ec681f3Smrg    uint32_t bool_true = This->driver_caps.ps_integer ? 0xFFFFFFFF : fui(1.0f);
40687ec681f3Smrg
40697ec681f3Smrg    DBG("This=%p StartRegister=%u pConstantData=%p BoolCount=%u\n",
40707ec681f3Smrg        This, StartRegister, pConstantData, BoolCount);
40717ec681f3Smrg
40727ec681f3Smrg    user_assert(StartRegister              < NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
40737ec681f3Smrg    user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
40747ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
40757ec681f3Smrg
40767ec681f3Smrg    if (!This->is_recording) {
40777ec681f3Smrg        bool noChange = true;
40787ec681f3Smrg        for (i = 0; i < BoolCount; i++) {
40797ec681f3Smrg            if (!!state->ps_const_b[StartRegister + i] != !!pConstantData[i])
40807ec681f3Smrg              noChange = false;
40817ec681f3Smrg        }
40827ec681f3Smrg        if (noChange)
40837ec681f3Smrg            return D3D_OK;
40847ec681f3Smrg    }
40857ec681f3Smrg
40867ec681f3Smrg    for (i = 0; i < BoolCount; i++)
40877ec681f3Smrg        state->ps_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0;
40887ec681f3Smrg
40897ec681f3Smrg    if (unlikely(This->is_recording)) {
40907ec681f3Smrg        state->changed.ps_const_b |= ((1 << BoolCount) - 1) << StartRegister;
40917ec681f3Smrg        state->changed.group |= NINE_STATE_PS_CONST;
40927ec681f3Smrg    } else
40937ec681f3Smrg        nine_context_set_pixel_shader_constant_b(This, StartRegister, pConstantData,
40947ec681f3Smrg                                                 sizeof(BOOL) * BoolCount, BoolCount);
40957ec681f3Smrg
40967ec681f3Smrg    return D3D_OK;
40977ec681f3Smrg}
40987ec681f3Smrg
40997ec681f3SmrgHRESULT NINE_WINAPI
41007ec681f3SmrgNineDevice9_GetPixelShaderConstantB( struct NineDevice9 *This,
41017ec681f3Smrg                                     UINT StartRegister,
41027ec681f3Smrg                                     BOOL *pConstantData,
41037ec681f3Smrg                                     UINT BoolCount )
41047ec681f3Smrg{
41057ec681f3Smrg    const struct nine_state *state = &This->state;
41067ec681f3Smrg    int i;
41077ec681f3Smrg
41087ec681f3Smrg    user_assert(!This->pure, D3DERR_INVALIDCALL);
41097ec681f3Smrg    user_assert(StartRegister              < NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
41107ec681f3Smrg    user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
41117ec681f3Smrg    user_assert(pConstantData, D3DERR_INVALIDCALL);
41127ec681f3Smrg
41137ec681f3Smrg    for (i = 0; i < BoolCount; i++)
41147ec681f3Smrg        pConstantData[i] = state->ps_const_b[StartRegister + i] ? TRUE : FALSE;
41157ec681f3Smrg
41167ec681f3Smrg    return D3D_OK;
41177ec681f3Smrg}
41187ec681f3Smrg
41197ec681f3SmrgHRESULT NINE_WINAPI
41207ec681f3SmrgNineDevice9_DrawRectPatch( struct NineDevice9 *This,
41217ec681f3Smrg                           UINT Handle,
41227ec681f3Smrg                           const float *pNumSegs,
41237ec681f3Smrg                           const D3DRECTPATCH_INFO *pRectPatchInfo )
41247ec681f3Smrg{
41257ec681f3Smrg    STUB(D3DERR_INVALIDCALL);
41267ec681f3Smrg}
41277ec681f3Smrg
41287ec681f3SmrgHRESULT NINE_WINAPI
41297ec681f3SmrgNineDevice9_DrawTriPatch( struct NineDevice9 *This,
41307ec681f3Smrg                          UINT Handle,
41317ec681f3Smrg                          const float *pNumSegs,
41327ec681f3Smrg                          const D3DTRIPATCH_INFO *pTriPatchInfo )
41337ec681f3Smrg{
41347ec681f3Smrg    STUB(D3DERR_INVALIDCALL);
41357ec681f3Smrg}
41367ec681f3Smrg
41377ec681f3SmrgHRESULT NINE_WINAPI
41387ec681f3SmrgNineDevice9_DeletePatch( struct NineDevice9 *This,
41397ec681f3Smrg                         UINT Handle )
41407ec681f3Smrg{
41417ec681f3Smrg    STUB(D3DERR_INVALIDCALL);
41427ec681f3Smrg}
41437ec681f3Smrg
41447ec681f3SmrgHRESULT NINE_WINAPI
41457ec681f3SmrgNineDevice9_CreateQuery( struct NineDevice9 *This,
41467ec681f3Smrg                         D3DQUERYTYPE Type,
41477ec681f3Smrg                         IDirect3DQuery9 **ppQuery )
41487ec681f3Smrg{
41497ec681f3Smrg    struct NineQuery9 *query;
41507ec681f3Smrg    HRESULT hr;
41517ec681f3Smrg
41527ec681f3Smrg    DBG("This=%p Type=%d ppQuery=%p\n", This, Type, ppQuery);
41537ec681f3Smrg
41547ec681f3Smrg    hr = nine_is_query_supported(This->screen, Type);
41557ec681f3Smrg    if (!ppQuery || hr != D3D_OK)
41567ec681f3Smrg        return hr;
41577ec681f3Smrg
41587ec681f3Smrg    hr = NineQuery9_new(This, &query, Type);
41597ec681f3Smrg    if (FAILED(hr))
41607ec681f3Smrg        return hr;
41617ec681f3Smrg    *ppQuery = (IDirect3DQuery9 *)query;
41627ec681f3Smrg    return D3D_OK;
41637ec681f3Smrg}
41647ec681f3Smrg
41657ec681f3SmrgIDirect3DDevice9Vtbl NineDevice9_vtable = {
41667ec681f3Smrg    (void *)NineUnknown_QueryInterface,
41677ec681f3Smrg    (void *)NineUnknown_AddRef,
41687ec681f3Smrg    (void *)NineUnknown_Release,
41697ec681f3Smrg    (void *)NineDevice9_TestCooperativeLevel,
41707ec681f3Smrg    (void *)NineDevice9_GetAvailableTextureMem,
41717ec681f3Smrg    (void *)NineDevice9_EvictManagedResources,
41727ec681f3Smrg    (void *)NineDevice9_GetDirect3D,
41737ec681f3Smrg    (void *)NineDevice9_GetDeviceCaps,
41747ec681f3Smrg    (void *)NineDevice9_GetDisplayMode,
41757ec681f3Smrg    (void *)NineDevice9_GetCreationParameters,
41767ec681f3Smrg    (void *)NineDevice9_SetCursorProperties,
41777ec681f3Smrg    (void *)NineDevice9_SetCursorPosition,
41787ec681f3Smrg    (void *)NineDevice9_ShowCursor,
41797ec681f3Smrg    (void *)NineDevice9_CreateAdditionalSwapChain,
41807ec681f3Smrg    (void *)NineDevice9_GetSwapChain,
41817ec681f3Smrg    (void *)NineDevice9_GetNumberOfSwapChains,
41827ec681f3Smrg    (void *)NineDevice9_Reset,
41837ec681f3Smrg    (void *)NineDevice9_Present,
41847ec681f3Smrg    (void *)NineDevice9_GetBackBuffer,
41857ec681f3Smrg    (void *)NineDevice9_GetRasterStatus,
41867ec681f3Smrg    (void *)NineDevice9_SetDialogBoxMode,
41877ec681f3Smrg    (void *)NineDevice9_SetGammaRamp,
41887ec681f3Smrg    (void *)NineDevice9_GetGammaRamp,
41897ec681f3Smrg    (void *)NineDevice9_CreateTexture,
41907ec681f3Smrg    (void *)NineDevice9_CreateVolumeTexture,
41917ec681f3Smrg    (void *)NineDevice9_CreateCubeTexture,
41927ec681f3Smrg    (void *)NineDevice9_CreateVertexBuffer,
41937ec681f3Smrg    (void *)NineDevice9_CreateIndexBuffer,
41947ec681f3Smrg    (void *)NineDevice9_CreateRenderTarget,
41957ec681f3Smrg    (void *)NineDevice9_CreateDepthStencilSurface,
41967ec681f3Smrg    (void *)NineDevice9_UpdateSurface,
41977ec681f3Smrg    (void *)NineDevice9_UpdateTexture,
41987ec681f3Smrg    (void *)NineDevice9_GetRenderTargetData,
41997ec681f3Smrg    (void *)NineDevice9_GetFrontBufferData,
42007ec681f3Smrg    (void *)NineDevice9_StretchRect,
42017ec681f3Smrg    (void *)NineDevice9_ColorFill,
42027ec681f3Smrg    (void *)NineDevice9_CreateOffscreenPlainSurface,
42037ec681f3Smrg    (void *)NineDevice9_SetRenderTarget,
42047ec681f3Smrg    (void *)NineDevice9_GetRenderTarget,
42057ec681f3Smrg    (void *)NineDevice9_SetDepthStencilSurface,
42067ec681f3Smrg    (void *)NineDevice9_GetDepthStencilSurface,
42077ec681f3Smrg    (void *)NineDevice9_BeginScene,
42087ec681f3Smrg    (void *)NineDevice9_EndScene,
42097ec681f3Smrg    (void *)NineDevice9_Clear,
42107ec681f3Smrg    (void *)NineDevice9_SetTransform,
42117ec681f3Smrg    (void *)NineDevice9_GetTransform,
42127ec681f3Smrg    (void *)NineDevice9_MultiplyTransform,
42137ec681f3Smrg    (void *)NineDevice9_SetViewport,
42147ec681f3Smrg    (void *)NineDevice9_GetViewport,
42157ec681f3Smrg    (void *)NineDevice9_SetMaterial,
42167ec681f3Smrg    (void *)NineDevice9_GetMaterial,
42177ec681f3Smrg    (void *)NineDevice9_SetLight,
42187ec681f3Smrg    (void *)NineDevice9_GetLight,
42197ec681f3Smrg    (void *)NineDevice9_LightEnable,
42207ec681f3Smrg    (void *)NineDevice9_GetLightEnable,
42217ec681f3Smrg    (void *)NineDevice9_SetClipPlane,
42227ec681f3Smrg    (void *)NineDevice9_GetClipPlane,
42237ec681f3Smrg    (void *)NineDevice9_SetRenderState,
42247ec681f3Smrg    (void *)NineDevice9_GetRenderState,
42257ec681f3Smrg    (void *)NineDevice9_CreateStateBlock,
42267ec681f3Smrg    (void *)NineDevice9_BeginStateBlock,
42277ec681f3Smrg    (void *)NineDevice9_EndStateBlock,
42287ec681f3Smrg    (void *)NineDevice9_SetClipStatus,
42297ec681f3Smrg    (void *)NineDevice9_GetClipStatus,
42307ec681f3Smrg    (void *)NineDevice9_GetTexture,
42317ec681f3Smrg    (void *)NineDevice9_SetTexture,
42327ec681f3Smrg    (void *)NineDevice9_GetTextureStageState,
42337ec681f3Smrg    (void *)NineDevice9_SetTextureStageState,
42347ec681f3Smrg    (void *)NineDevice9_GetSamplerState,
42357ec681f3Smrg    (void *)NineDevice9_SetSamplerState,
42367ec681f3Smrg    (void *)NineDevice9_ValidateDevice,
42377ec681f3Smrg    (void *)NineDevice9_SetPaletteEntries,
42387ec681f3Smrg    (void *)NineDevice9_GetPaletteEntries,
42397ec681f3Smrg    (void *)NineDevice9_SetCurrentTexturePalette,
42407ec681f3Smrg    (void *)NineDevice9_GetCurrentTexturePalette,
42417ec681f3Smrg    (void *)NineDevice9_SetScissorRect,
42427ec681f3Smrg    (void *)NineDevice9_GetScissorRect,
42437ec681f3Smrg    (void *)NineDevice9_SetSoftwareVertexProcessing,
42447ec681f3Smrg    (void *)NineDevice9_GetSoftwareVertexProcessing,
42457ec681f3Smrg    (void *)NineDevice9_SetNPatchMode,
42467ec681f3Smrg    (void *)NineDevice9_GetNPatchMode,
42477ec681f3Smrg    (void *)NineDevice9_DrawPrimitive,
42487ec681f3Smrg    (void *)NineDevice9_DrawIndexedPrimitive,
42497ec681f3Smrg    (void *)NineDevice9_DrawPrimitiveUP,
42507ec681f3Smrg    (void *)NineDevice9_DrawIndexedPrimitiveUP,
42517ec681f3Smrg    (void *)NineDevice9_ProcessVertices,
42527ec681f3Smrg    (void *)NineDevice9_CreateVertexDeclaration,
42537ec681f3Smrg    (void *)NineDevice9_SetVertexDeclaration,
42547ec681f3Smrg    (void *)NineDevice9_GetVertexDeclaration,
42557ec681f3Smrg    (void *)NineDevice9_SetFVF,
42567ec681f3Smrg    (void *)NineDevice9_GetFVF,
42577ec681f3Smrg    (void *)NineDevice9_CreateVertexShader,
42587ec681f3Smrg    (void *)NineDevice9_SetVertexShader,
42597ec681f3Smrg    (void *)NineDevice9_GetVertexShader,
42607ec681f3Smrg    (void *)NineDevice9_SetVertexShaderConstantF,
42617ec681f3Smrg    (void *)NineDevice9_GetVertexShaderConstantF,
42627ec681f3Smrg    (void *)NineDevice9_SetVertexShaderConstantI,
42637ec681f3Smrg    (void *)NineDevice9_GetVertexShaderConstantI,
42647ec681f3Smrg    (void *)NineDevice9_SetVertexShaderConstantB,
42657ec681f3Smrg    (void *)NineDevice9_GetVertexShaderConstantB,
42667ec681f3Smrg    (void *)NineDevice9_SetStreamSource,
42677ec681f3Smrg    (void *)NineDevice9_GetStreamSource,
42687ec681f3Smrg    (void *)NineDevice9_SetStreamSourceFreq,
42697ec681f3Smrg    (void *)NineDevice9_GetStreamSourceFreq,
42707ec681f3Smrg    (void *)NineDevice9_SetIndices,
42717ec681f3Smrg    (void *)NineDevice9_GetIndices,
42727ec681f3Smrg    (void *)NineDevice9_CreatePixelShader,
42737ec681f3Smrg    (void *)NineDevice9_SetPixelShader,
42747ec681f3Smrg    (void *)NineDevice9_GetPixelShader,
42757ec681f3Smrg    (void *)NineDevice9_SetPixelShaderConstantF,
42767ec681f3Smrg    (void *)NineDevice9_GetPixelShaderConstantF,
42777ec681f3Smrg    (void *)NineDevice9_SetPixelShaderConstantI,
42787ec681f3Smrg    (void *)NineDevice9_GetPixelShaderConstantI,
42797ec681f3Smrg    (void *)NineDevice9_SetPixelShaderConstantB,
42807ec681f3Smrg    (void *)NineDevice9_GetPixelShaderConstantB,
42817ec681f3Smrg    (void *)NineDevice9_DrawRectPatch,
42827ec681f3Smrg    (void *)NineDevice9_DrawTriPatch,
42837ec681f3Smrg    (void *)NineDevice9_DeletePatch,
42847ec681f3Smrg    (void *)NineDevice9_CreateQuery
42857ec681f3Smrg};
42867ec681f3Smrg
42877ec681f3Smrgstatic const GUID *NineDevice9_IIDs[] = {
42887ec681f3Smrg    &IID_IDirect3DDevice9,
42897ec681f3Smrg    &IID_IUnknown,
42907ec681f3Smrg    NULL
42917ec681f3Smrg};
42927ec681f3Smrg
42937ec681f3SmrgHRESULT
42947ec681f3SmrgNineDevice9_new( struct pipe_screen *pScreen,
42957ec681f3Smrg                 D3DDEVICE_CREATION_PARAMETERS *pCreationParameters,
42967ec681f3Smrg                 D3DCAPS9 *pCaps,
42977ec681f3Smrg                 D3DPRESENT_PARAMETERS *pPresentationParameters,
42987ec681f3Smrg                 IDirect3D9 *pD3D9,
42997ec681f3Smrg                 ID3DPresentGroup *pPresentationGroup,
43007ec681f3Smrg                 struct d3dadapter9_context *pCTX,
43017ec681f3Smrg                 boolean ex,
43027ec681f3Smrg                 D3DDISPLAYMODEEX *pFullscreenDisplayMode,
43037ec681f3Smrg                 struct NineDevice9 **ppOut,
43047ec681f3Smrg                 int minorVersionNum )
43057ec681f3Smrg{
43067ec681f3Smrg    BOOL lock;
43077ec681f3Smrg    lock = !!(pCreationParameters->BehaviorFlags & D3DCREATE_MULTITHREADED);
43087ec681f3Smrg
43097ec681f3Smrg    NINE_NEW(Device9, ppOut, lock, /* args */
43107ec681f3Smrg             pScreen, pCreationParameters, pCaps,
43117ec681f3Smrg             pPresentationParameters, pD3D9, pPresentationGroup, pCTX,
43127ec681f3Smrg             ex, pFullscreenDisplayMode, minorVersionNum );
43137ec681f3Smrg}
4314