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