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