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