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