2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 #include "stateblock9.h"
25 #include "basetexture9.h"
26 #include "nine_helpers.h"
27 #include "vertexdeclaration9.h"
28 #include "vertexbuffer9.h"
29 #include "indexbuffer9.h"
31 #define DBG_CHANNEL DBG_STATEBLOCK
33 /* XXX TODO: handling of lights is broken */
36 NineStateBlock9_ctor( struct NineStateBlock9
*This
,
37 struct NineUnknownParams
*pParams
,
38 enum nine_stateblock_type type
)
40 HRESULT hr
= NineUnknown_ctor(&This
->base
, pParams
);
42 DBG("This=%p pParams=%p type=%d\n", This
, pParams
, type
);
49 This
->state
.vs_const_f
= MALLOC(VS_CONST_F_SIZE(This
->base
.device
));
50 This
->state
.ps_const_f
= MALLOC(This
->base
.device
->ps_const_size
);
51 This
->state
.vs_const_i
= MALLOC(VS_CONST_I_SIZE(This
->base
.device
));
52 This
->state
.vs_const_b
= MALLOC(VS_CONST_B_SIZE(This
->base
.device
));
53 if (!This
->state
.vs_const_f
|| !This
->state
.ps_const_f
||
54 !This
->state
.vs_const_i
|| !This
->state
.vs_const_b
)
61 NineStateBlock9_dtor( struct NineStateBlock9
*This
)
63 struct nine_state
*state
= &This
->state
;
65 struct nine_range_pool
*pool
= &This
->base
.device
->range_pool
;
67 nine_state_clear(state
, false);
69 FREE(state
->vs_const_f
);
70 FREE(state
->ps_const_f
);
71 FREE(state
->vs_const_i
);
72 FREE(state
->vs_const_b
);
74 FREE(state
->ff
.light
);
76 FREE(state
->ff
.transform
);
78 if (This
->state
.changed
.ps_const_f
) {
79 for (r
= This
->state
.changed
.ps_const_f
; r
->next
; r
= r
->next
);
80 nine_range_pool_put_chain(pool
, This
->state
.changed
.ps_const_f
, r
);
82 if (This
->state
.changed
.vs_const_f
) {
83 for (r
= This
->state
.changed
.vs_const_f
; r
->next
; r
= r
->next
);
84 nine_range_pool_put_chain(pool
, This
->state
.changed
.vs_const_f
, r
);
86 if (This
->state
.changed
.vs_const_i
) {
87 for (r
= This
->state
.changed
.vs_const_i
; r
->next
; r
= r
->next
);
88 nine_range_pool_put_chain(pool
, This
->state
.changed
.vs_const_i
, r
);
90 if (This
->state
.changed
.vs_const_b
) {
91 for (r
= This
->state
.changed
.vs_const_b
; r
->next
; r
= r
->next
);
92 nine_range_pool_put_chain(pool
, This
->state
.changed
.vs_const_b
, r
);
95 NineUnknown_dtor(&This
->base
);
99 NineStateBlock9_BindBuffer( struct NineDevice9
*device
,
100 boolean applyToDevice
,
101 struct NineBuffer9
**slot
,
102 struct NineBuffer9
*buf
)
105 NineBindBufferToDevice(device
, slot
, buf
);
107 nine_bind(slot
, buf
);
111 NineStateBlock9_BindTexture( struct NineDevice9
*device
,
112 boolean applyToDevice
,
113 struct NineBaseTexture9
**slot
,
114 struct NineBaseTexture9
*tex
)
117 NineBindTextureToDevice(device
, slot
, tex
);
119 nine_bind(slot
, tex
);
122 /* Copy state marked changed in @mask from @src to @dst.
123 * If @apply is false, updating dst->changed can be omitted.
127 nine_state_copy_common(struct NineDevice9
*device
,
128 struct nine_state
*dst
,
129 struct nine_state
*src
,
130 struct nine_state
*mask
, /* aliases either src or dst */
132 struct nine_range_pool
*pool
)
136 DBG("apply:%d changed.group: %x\n", (int)apply
, (int)mask
->changed
.group
);
138 /* device changed.* are unused.
139 * Instead nine_context_apply_stateblock is used and will
140 * internally set the right context->changed fields.
141 * Uncomment these only if we want to apply a stateblock onto a stateblock.
144 * dst->changed.group |= mask->changed.group;
147 if (mask
->changed
.group
& NINE_STATE_VIEWPORT
)
148 dst
->viewport
= src
->viewport
;
149 if (mask
->changed
.group
& NINE_STATE_SCISSOR
)
150 dst
->scissor
= src
->scissor
;
152 if (mask
->changed
.group
& NINE_STATE_VS
)
153 nine_bind(&dst
->vs
, src
->vs
);
154 if (mask
->changed
.group
& NINE_STATE_PS
)
155 nine_bind(&dst
->ps
, src
->ps
);
159 * Various possibilities for optimization here, like creating a per-SB
160 * constant buffer, or memcmp'ing for changes.
161 * Will do that later depending on what works best for specific apps.
163 * Note: Currently when we apply stateblocks, it's always on the device state.
164 * Should it affect recording stateblocks ? Since it's on device state, there
165 * is no need to copy which ranges are dirty. If it turns out we should affect
166 * recording stateblocks, the info should be copied.
168 if (mask
->changed
.group
& NINE_STATE_VS_CONST
) {
169 struct nine_range
*r
;
170 for (r
= mask
->changed
.vs_const_f
; r
; r
= r
->next
) {
171 memcpy(&dst
->vs_const_f
[r
->bgn
* 4],
172 &src
->vs_const_f
[r
->bgn
* 4],
173 (r
->end
- r
->bgn
) * 4 * sizeof(float));
175 for (r
= mask
->changed
.vs_const_i
; r
; r
= r
->next
) {
176 memcpy(&dst
->vs_const_i
[r
->bgn
* 4],
177 &src
->vs_const_i
[r
->bgn
* 4],
178 (r
->end
- r
->bgn
) * 4 * sizeof(int));
180 for (r
= mask
->changed
.vs_const_b
; r
; r
= r
->next
) {
181 memcpy(&dst
->vs_const_b
[r
->bgn
],
182 &src
->vs_const_b
[r
->bgn
],
183 (r
->end
- r
->bgn
) * sizeof(int));
187 /* Pixel constants. */
188 if (mask
->changed
.group
& NINE_STATE_PS_CONST
) {
189 struct nine_range
*r
;
190 for (r
= mask
->changed
.ps_const_f
; r
; r
= r
->next
) {
191 memcpy(&dst
->ps_const_f
[r
->bgn
* 4],
192 &src
->ps_const_f
[r
->bgn
* 4],
193 (r
->end
- r
->bgn
) * 4 * sizeof(float));
195 if (mask
->changed
.ps_const_i
) {
196 uint16_t m
= mask
->changed
.ps_const_i
;
197 for (i
= ffs(m
) - 1, m
>>= i
; m
; ++i
, m
>>= 1)
199 memcpy(dst
->ps_const_i
[i
], src
->ps_const_i
[i
], 4 * sizeof(int));
201 if (mask
->changed
.ps_const_b
) {
202 uint16_t m
= mask
->changed
.ps_const_b
;
203 for (i
= ffs(m
) - 1, m
>>= i
; m
; ++i
, m
>>= 1)
205 dst
->ps_const_b
[i
] = src
->ps_const_b
[i
];
210 * TODO: Maybe build a list ?
212 for (i
= 0; i
< ARRAY_SIZE(mask
->changed
.rs
); ++i
) {
213 uint32_t m
= mask
->changed
.rs
[i
];
215 * dst->changed.rs[i] |= m; */
217 const int r
= ffs(m
) - 1;
219 DBG("State %d %s = %d\n", i
* 32 + r
, nine_d3drs_to_string(i
* 32 + r
), (int)src
->rs_advertised
[i
* 32 + r
]);
220 dst
->rs_advertised
[i
* 32 + r
] = src
->rs_advertised
[i
* 32 + r
];
226 if (mask
->changed
.ucp
) {
227 DBG("ucp: %x\n", mask
->changed
.ucp
);
228 for (i
= 0; i
< PIPE_MAX_CLIP_PLANES
; ++i
)
229 if (mask
->changed
.ucp
& (1 << i
))
230 memcpy(dst
->clip
.ucp
[i
],
231 src
->clip
.ucp
[i
], sizeof(src
->clip
.ucp
[0]));
233 * dst->changed.ucp |= mask->changed.ucp;*/
237 if (mask
->changed
.group
& NINE_STATE_SAMPLER
) {
238 for (s
= 0; s
< NINE_MAX_SAMPLERS
; ++s
) {
239 if (mask
->changed
.sampler
[s
] == 0x3ffe) {
240 memcpy(&dst
->samp_advertised
[s
], &src
->samp_advertised
[s
], sizeof(dst
->samp_advertised
[s
]));
242 uint32_t m
= mask
->changed
.sampler
[s
];
243 DBG("samp %d: changed = %x\n", i
, (int)m
);
245 const int i
= ffs(m
) - 1;
247 dst
->samp_advertised
[s
][i
] = src
->samp_advertised
[s
][i
];
251 * dst->changed.sampler[s] |= mask->changed.sampler[s];*/
256 if (mask
->changed
.group
& NINE_STATE_IDXBUF
)
257 NineStateBlock9_BindBuffer(device
,
259 (struct NineBuffer9
**)&dst
->idxbuf
,
260 (struct NineBuffer9
*)src
->idxbuf
);
262 /* Vertex streams. */
263 if (mask
->changed
.vtxbuf
| mask
->changed
.stream_freq
) {
264 DBG("vtxbuf/stream_freq: %x/%x\n", mask
->changed
.vtxbuf
, mask
->changed
.stream_freq
);
265 uint32_t m
= mask
->changed
.vtxbuf
| mask
->changed
.stream_freq
;
266 for (i
= 0; m
; ++i
, m
>>= 1) {
267 if (mask
->changed
.vtxbuf
& (1 << i
)) {
268 NineStateBlock9_BindBuffer(device
,
270 (struct NineBuffer9
**)&dst
->stream
[i
],
271 (struct NineBuffer9
*)src
->stream
[i
]);
272 if (src
->stream
[i
]) {
273 dst
->vtxbuf
[i
].buffer_offset
= src
->vtxbuf
[i
].buffer_offset
;
274 dst
->vtxbuf
[i
].stride
= src
->vtxbuf
[i
].stride
;
277 if (mask
->changed
.stream_freq
& (1 << i
))
278 dst
->stream_freq
[i
] = src
->stream_freq
[i
];
282 * dst->changed.vtxbuf |= mask->changed.vtxbuf;
283 * dst->changed.stream_freq |= mask->changed.stream_freq;
288 if (mask
->changed
.texture
) {
289 uint32_t m
= mask
->changed
.texture
;
290 for (s
= 0; m
; ++s
, m
>>= 1)
292 NineStateBlock9_BindTexture(device
, apply
, &dst
->texture
[s
], src
->texture
[s
]);
295 if (!(mask
->changed
.group
& NINE_STATE_FF
))
297 WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n");
299 /* Fixed function state. */
301 if (mask
->changed
.group
& NINE_STATE_FF_MATERIAL
)
302 dst
->ff
.material
= src
->ff
.material
;
304 if (mask
->changed
.group
& NINE_STATE_FF_PS_CONSTS
) {
305 for (s
= 0; s
< NINE_MAX_TEXTURE_STAGES
; ++s
) {
306 for (i
= 0; i
< NINED3DTSS_COUNT
; ++i
)
307 if (mask
->ff
.changed
.tex_stage
[s
][i
/ 32] & (1 << (i
% 32)))
308 dst
->ff
.tex_stage
[s
][i
] = src
->ff
.tex_stage
[s
][i
];
311 * TODO: it's 32 exactly, just offset by 1 as 0 is unused
312 * dst->ff.changed.tex_stage[s][0] |=
313 * mask->ff.changed.tex_stage[s][0];
314 * dst->ff.changed.tex_stage[s][1] |=
315 * mask->ff.changed.tex_stage[s][1];
319 if (mask
->changed
.group
& NINE_STATE_FF_LIGHTING
) {
320 unsigned num_lights
= MAX2(dst
->ff
.num_lights
, src
->ff
.num_lights
);
321 /* Can happen in Capture() if device state has created new lights after
322 * the stateblock was created.
323 * Can happen in Apply() if the stateblock had recorded the creation of
325 if (dst
->ff
.num_lights
< num_lights
) {
326 dst
->ff
.light
= REALLOC(dst
->ff
.light
,
327 dst
->ff
.num_lights
* sizeof(D3DLIGHT9
),
328 num_lights
* sizeof(D3DLIGHT9
));
329 memset(&dst
->ff
.light
[dst
->ff
.num_lights
], 0, (num_lights
- dst
->ff
.num_lights
) * sizeof(D3DLIGHT9
));
330 /* if mask == dst, a Type of 0 will trigger
331 * "dst->ff.light[i] = src->ff.light[i];" later,
332 * which is what we want in that case. */
334 for (i
= dst
->ff
.num_lights
; i
< num_lights
; ++i
)
335 dst
->ff
.light
[i
].Type
= (D3DLIGHTTYPE
)NINED3DLIGHT_INVALID
;
337 dst
->ff
.num_lights
= num_lights
;
339 /* Can happen in Capture() if the stateblock had recorded the creation of
341 * Can happen in Apply() if device state has created new lights after
342 * the stateblock was created. */
343 if (src
->ff
.num_lights
< num_lights
) {
344 src
->ff
.light
= REALLOC(src
->ff
.light
,
345 src
->ff
.num_lights
* sizeof(D3DLIGHT9
),
346 num_lights
* sizeof(D3DLIGHT9
));
347 memset(&src
->ff
.light
[src
->ff
.num_lights
], 0, (num_lights
- src
->ff
.num_lights
) * sizeof(D3DLIGHT9
));
348 for (i
= src
->ff
.num_lights
; i
< num_lights
; ++i
)
349 src
->ff
.light
[i
].Type
= (D3DLIGHTTYPE
)NINED3DLIGHT_INVALID
;
350 src
->ff
.num_lights
= num_lights
;
352 /* Note: mask is either src or dst, so at this point src, dst and mask
353 * have num_lights lights. */
354 for (i
= 0; i
< num_lights
; ++i
)
355 if (mask
->ff
.light
[i
].Type
!= NINED3DLIGHT_INVALID
)
356 dst
->ff
.light
[i
] = src
->ff
.light
[i
];
358 memcpy(dst
->ff
.active_light
, src
->ff
.active_light
, sizeof(src
->ff
.active_light
) );
359 dst
->ff
.num_lights_active
= src
->ff
.num_lights_active
;
361 if (mask
->changed
.group
& NINE_STATE_FF_VSTRANSF
) {
362 for (i
= 0; i
< ARRAY_SIZE(mask
->ff
.changed
.transform
); ++i
) {
363 if (!mask
->ff
.changed
.transform
[i
])
365 for (s
= i
* 32; s
< (i
* 32 + 32); ++s
) {
366 if (!(mask
->ff
.changed
.transform
[i
] & (1 << (s
% 32))))
368 *nine_state_access_transform(&dst
->ff
, s
, TRUE
) =
369 *nine_state_access_transform(&src
->ff
, s
, FALSE
);
372 * dst->ff.changed.transform[i] |= mask->ff.changed.transform[i];*/
378 nine_state_copy_common_all(struct NineDevice9
*device
,
379 struct nine_state
*dst
,
380 struct nine_state
*src
,
381 struct nine_state
*help
,
383 struct nine_range_pool
*pool
,
384 const int MaxStreams
)
389 * dst->changed.group |= src->changed.group;
392 dst
->viewport
= src
->viewport
;
393 dst
->scissor
= src
->scissor
;
395 nine_bind(&dst
->vs
, src
->vs
);
396 nine_bind(&dst
->ps
, src
->ps
);
400 * Various possibilities for optimization here, like creating a per-SB
401 * constant buffer, or memcmp'ing for changes.
402 * Will do that later depending on what works best for specific apps.
405 memcpy(&dst
->vs_const_f
[0],
406 &src
->vs_const_f
[0], VS_CONST_F_SIZE(device
));
408 memcpy(dst
->vs_const_i
, src
->vs_const_i
, VS_CONST_I_SIZE(device
));
409 memcpy(dst
->vs_const_b
, src
->vs_const_b
, VS_CONST_B_SIZE(device
));
412 /* Pixel constants. */
414 struct nine_range
*r
= help
->changed
.ps_const_f
;
415 memcpy(&dst
->ps_const_f
[0],
416 &src
->ps_const_f
[0], (r
->end
- r
->bgn
) * 4 * sizeof(float));
418 memcpy(dst
->ps_const_i
, src
->ps_const_i
, sizeof(dst
->ps_const_i
));
419 memcpy(dst
->ps_const_b
, src
->ps_const_b
, sizeof(dst
->ps_const_b
));
423 memcpy(dst
->rs_advertised
, src
->rs_advertised
, sizeof(dst
->rs_advertised
));
425 * memcpy(dst->changed.rs, src->changed.rs, sizeof(dst->changed.rs));*/
429 memcpy(&dst
->clip
, &src
->clip
, sizeof(dst
->clip
));
431 * dst->changed.ucp = src->changed.ucp;*/
434 memcpy(dst
->samp_advertised
, src
->samp_advertised
, sizeof(dst
->samp_advertised
));
436 * memcpy(dst->changed.sampler,
437 * src->changed.sampler, sizeof(dst->changed.sampler));*/
440 NineStateBlock9_BindBuffer(device
,
442 (struct NineBuffer9
**)&dst
->idxbuf
,
443 (struct NineBuffer9
*)src
->idxbuf
);
445 /* Vertex streams. */
447 for (i
= 0; i
< ARRAY_SIZE(dst
->stream
); ++i
) {
448 NineStateBlock9_BindBuffer(device
,
450 (struct NineBuffer9
**)&dst
->stream
[i
],
451 (struct NineBuffer9
*)src
->stream
[i
]);
452 if (src
->stream
[i
]) {
453 dst
->vtxbuf
[i
].buffer_offset
= src
->vtxbuf
[i
].buffer_offset
;
454 dst
->vtxbuf
[i
].stride
= src
->vtxbuf
[i
].stride
;
456 dst
->stream_freq
[i
] = src
->stream_freq
[i
];
459 * dst->changed.vtxbuf = (1ULL << MaxStreams) - 1;
460 * dst->changed.stream_freq = (1ULL << MaxStreams) - 1;
466 for (i
= 0; i
< NINE_MAX_SAMPLERS
; i
++)
467 NineStateBlock9_BindTexture(device
, apply
, &dst
->texture
[i
], src
->texture
[i
]);
470 /* keep this check in case we want to disable FF */
471 if (!(help
->changed
.group
& NINE_STATE_FF
))
473 WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n");
475 /* Fixed function state. */
476 dst
->ff
.material
= src
->ff
.material
;
478 memcpy(dst
->ff
.tex_stage
, src
->ff
.tex_stage
, sizeof(dst
->ff
.tex_stage
));
479 /* if (apply) TODO: memset
480 * memcpy(dst->ff.changed.tex_stage,
481 * src->ff.changed.tex_stage, sizeof(dst->ff.changed.tex_stage));*/
485 if (dst
->ff
.num_lights
< src
->ff
.num_lights
) {
486 dst
->ff
.light
= REALLOC(dst
->ff
.light
,
487 dst
->ff
.num_lights
* sizeof(D3DLIGHT9
),
488 src
->ff
.num_lights
* sizeof(D3DLIGHT9
));
489 dst
->ff
.num_lights
= src
->ff
.num_lights
;
491 memcpy(dst
->ff
.light
,
492 src
->ff
.light
, src
->ff
.num_lights
* sizeof(dst
->ff
.light
[0]));
494 memcpy(dst
->ff
.active_light
, src
->ff
.active_light
, sizeof(src
->ff
.active_light
) );
495 dst
->ff
.num_lights_active
= src
->ff
.num_lights_active
;
500 /* Increase dst size if required (to copy the new states).
501 * Increase src size if required (to initialize missing transforms).
503 if (dst
->ff
.num_transforms
!= src
->ff
.num_transforms
) {
504 int num_transforms
= MAX2(src
->ff
.num_transforms
, dst
->ff
.num_transforms
);
505 nine_state_resize_transform(&src
->ff
, num_transforms
);
506 nine_state_resize_transform(&dst
->ff
, num_transforms
);
508 memcpy(dst
->ff
.transform
,
509 src
->ff
.transform
, dst
->ff
.num_transforms
* sizeof(D3DMATRIX
));
510 /* Apply is always used on device state.
511 * src is then the D3DSBT_ALL stateblock which
512 * ff.changed.transform indicates all matrices are dirty.
515 * memcpy(dst->ff.changed.transform,
516 * src->ff.changed.transform, sizeof(dst->ff.changed.transform));*/
520 /* Capture those bits of current device state that have been changed between
521 * BeginStateBlock and EndStateBlock.
524 NineStateBlock9_Capture( struct NineStateBlock9
*This
)
526 struct NineDevice9
*device
= This
->base
.device
;
527 struct nine_state
*dst
= &This
->state
;
528 struct nine_state
*src
= &device
->state
;
529 const int MaxStreams
= device
->caps
.MaxStreams
;
531 DBG("This=%p\n", This
);
533 if (This
->type
== NINESBT_ALL
)
534 nine_state_copy_common_all(device
, dst
, src
, dst
, FALSE
, NULL
, MaxStreams
);
536 nine_state_copy_common(device
, dst
, src
, dst
, FALSE
, NULL
);
538 if (dst
->changed
.group
& NINE_STATE_VDECL
)
539 nine_bind(&dst
->vdecl
, src
->vdecl
);
544 /* Set state managed by this StateBlock as current device state. */
546 NineStateBlock9_Apply( struct NineStateBlock9
*This
)
548 struct NineDevice9
*device
= This
->base
.device
;
549 struct nine_state
*dst
= &device
->state
;
550 struct nine_state
*src
= &This
->state
;
551 struct nine_range_pool
*pool
= &device
->range_pool
;
552 const int MaxStreams
= device
->caps
.MaxStreams
;
554 DBG("This=%p\n", This
);
556 if (This
->type
== NINESBT_ALL
)
557 nine_state_copy_common_all(device
, dst
, src
, src
, TRUE
, pool
, MaxStreams
);
559 nine_state_copy_common(device
, dst
, src
, src
, TRUE
, pool
);
561 nine_context_apply_stateblock(device
, src
);
563 if ((src
->changed
.group
& NINE_STATE_VDECL
) && src
->vdecl
)
564 nine_bind(&dst
->vdecl
, src
->vdecl
);
569 IDirect3DStateBlock9Vtbl NineStateBlock9_vtable
= {
570 (void *)NineUnknown_QueryInterface
,
571 (void *)NineUnknown_AddRef
,
572 (void *)NineUnknown_Release
,
573 (void *)NineUnknown_GetDevice
, /* actually part of StateBlock9 iface */
574 (void *)NineStateBlock9_Capture
,
575 (void *)NineStateBlock9_Apply
578 static const GUID
*NineStateBlock9_IIDs
[] = {
579 &IID_IDirect3DStateBlock9
,
585 NineStateBlock9_new( struct NineDevice9
*pDevice
,
586 struct NineStateBlock9
**ppOut
,
587 enum nine_stateblock_type type
)
589 NINE_DEVICE_CHILD_NEW(StateBlock9
, ppOut
, pDevice
, type
);