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
;
68 for (i
= 0; i
< ARRAY_SIZE(state
->rt
); ++i
)
69 nine_bind(&state
->rt
[i
], NULL
);
70 nine_bind(&state
->ds
, NULL
);
71 nine_bind(&state
->vs
, NULL
);
72 nine_bind(&state
->ps
, NULL
);
73 nine_bind(&state
->vdecl
, NULL
);
74 for (i
= 0; i
< PIPE_MAX_ATTRIBS
; ++i
)
75 nine_bind(&state
->stream
[i
], NULL
);
77 nine_bind(&state
->idxbuf
, NULL
);
78 for (i
= 0; i
< NINE_MAX_SAMPLERS
; ++i
)
79 nine_bind(&state
->texture
[i
], NULL
);
81 FREE(state
->vs_const_f
);
82 FREE(state
->ps_const_f
);
83 FREE(state
->vs_const_i
);
84 FREE(state
->vs_const_b
);
86 FREE(state
->ff
.light
);
88 FREE(state
->ff
.transform
);
90 if (This
->state
.changed
.ps_const_f
) {
91 for (r
= This
->state
.changed
.ps_const_f
; r
->next
; r
= r
->next
);
92 nine_range_pool_put_chain(pool
, This
->state
.changed
.ps_const_f
, r
);
94 if (This
->state
.changed
.vs_const_f
) {
95 for (r
= This
->state
.changed
.vs_const_f
; r
->next
; r
= r
->next
);
96 nine_range_pool_put_chain(pool
, This
->state
.changed
.vs_const_f
, r
);
98 if (This
->state
.changed
.vs_const_i
) {
99 for (r
= This
->state
.changed
.vs_const_i
; r
->next
; r
= r
->next
);
100 nine_range_pool_put_chain(pool
, This
->state
.changed
.vs_const_i
, r
);
102 if (This
->state
.changed
.vs_const_b
) {
103 for (r
= This
->state
.changed
.vs_const_b
; r
->next
; r
= r
->next
);
104 nine_range_pool_put_chain(pool
, This
->state
.changed
.vs_const_b
, r
);
107 NineUnknown_dtor(&This
->base
);
111 NineStateBlock9_BindBuffer( struct NineDevice9
*device
,
112 boolean applyToDevice
,
113 struct NineBuffer9
**slot
,
114 struct NineBuffer9
*buf
)
117 NineBindBufferToDevice(device
, slot
, buf
);
119 nine_bind(slot
, buf
);
123 NineStateBlock9_BindTexture( struct NineDevice9
*device
,
124 boolean applyToDevice
,
125 struct NineBaseTexture9
**slot
,
126 struct NineBaseTexture9
*tex
)
129 NineBindTextureToDevice(device
, slot
, tex
);
131 nine_bind(slot
, tex
);
134 /* Copy state marked changed in @mask from @src to @dst.
135 * If @apply is false, updating dst->changed can be omitted.
139 nine_state_copy_common(struct NineDevice9
*device
,
140 struct nine_state
*dst
,
141 struct nine_state
*src
,
142 struct nine_state
*mask
, /* aliases either src or dst */
144 struct nine_range_pool
*pool
)
148 DBG("apply:%d changed.group: %x\n", (int)apply
, (int)mask
->changed
.group
);
150 /* device changed.* are unused.
151 * Instead nine_context_apply_stateblock is used and will
152 * internally set the right context->changed fields.
153 * Uncomment these only if we want to apply a stateblock onto a stateblock.
156 * dst->changed.group |= mask->changed.group;
159 if (mask
->changed
.group
& NINE_STATE_VIEWPORT
)
160 dst
->viewport
= src
->viewport
;
161 if (mask
->changed
.group
& NINE_STATE_SCISSOR
)
162 dst
->scissor
= src
->scissor
;
164 if (mask
->changed
.group
& NINE_STATE_VS
)
165 nine_bind(&dst
->vs
, src
->vs
);
166 if (mask
->changed
.group
& NINE_STATE_PS
)
167 nine_bind(&dst
->ps
, src
->ps
);
171 * Various possibilities for optimization here, like creating a per-SB
172 * constant buffer, or memcmp'ing for changes.
173 * Will do that later depending on what works best for specific apps.
175 * Note: Currently when we apply stateblocks, it's always on the device state.
176 * Should it affect recording stateblocks ? Since it's on device state, there
177 * is no need to copy which ranges are dirty. If it turns out we should affect
178 * recording stateblocks, the info should be copied.
180 if (mask
->changed
.group
& NINE_STATE_VS_CONST
) {
181 struct nine_range
*r
;
182 for (r
= mask
->changed
.vs_const_f
; r
; r
= r
->next
) {
183 memcpy(&dst
->vs_const_f
[r
->bgn
* 4],
184 &src
->vs_const_f
[r
->bgn
* 4],
185 (r
->end
- r
->bgn
) * 4 * sizeof(float));
187 for (r
= mask
->changed
.vs_const_i
; r
; r
= r
->next
) {
188 memcpy(&dst
->vs_const_i
[r
->bgn
* 4],
189 &src
->vs_const_i
[r
->bgn
* 4],
190 (r
->end
- r
->bgn
) * 4 * sizeof(int));
192 for (r
= mask
->changed
.vs_const_b
; r
; r
= r
->next
) {
193 memcpy(&dst
->vs_const_b
[r
->bgn
],
194 &src
->vs_const_b
[r
->bgn
],
195 (r
->end
- r
->bgn
) * sizeof(int));
199 /* Pixel constants. */
200 if (mask
->changed
.group
& NINE_STATE_PS_CONST
) {
201 struct nine_range
*r
;
202 for (r
= mask
->changed
.ps_const_f
; r
; r
= r
->next
) {
203 memcpy(&dst
->ps_const_f
[r
->bgn
* 4],
204 &src
->ps_const_f
[r
->bgn
* 4],
205 (r
->end
- r
->bgn
) * 4 * sizeof(float));
207 if (mask
->changed
.ps_const_i
) {
208 uint16_t m
= mask
->changed
.ps_const_i
;
209 for (i
= ffs(m
) - 1, m
>>= i
; m
; ++i
, m
>>= 1)
211 memcpy(dst
->ps_const_i
[i
], src
->ps_const_i
[i
], 4 * sizeof(int));
213 if (mask
->changed
.ps_const_b
) {
214 uint16_t m
= mask
->changed
.ps_const_b
;
215 for (i
= ffs(m
) - 1, m
>>= i
; m
; ++i
, m
>>= 1)
217 dst
->ps_const_b
[i
] = src
->ps_const_b
[i
];
222 * TODO: Maybe build a list ?
224 for (i
= 0; i
< ARRAY_SIZE(mask
->changed
.rs
); ++i
) {
225 uint32_t m
= mask
->changed
.rs
[i
];
227 * dst->changed.rs[i] |= m; */
229 const int r
= ffs(m
) - 1;
231 DBG("State %d %s = %d\n", i
* 32 + r
, nine_d3drs_to_string(i
* 32 + r
), (int)src
->rs_advertised
[i
* 32 + r
]);
232 dst
->rs_advertised
[i
* 32 + r
] = src
->rs_advertised
[i
* 32 + r
];
238 if (mask
->changed
.ucp
) {
239 DBG("ucp: %x\n", mask
->changed
.ucp
);
240 for (i
= 0; i
< PIPE_MAX_CLIP_PLANES
; ++i
)
241 if (mask
->changed
.ucp
& (1 << i
))
242 memcpy(dst
->clip
.ucp
[i
],
243 src
->clip
.ucp
[i
], sizeof(src
->clip
.ucp
[0]));
245 * dst->changed.ucp |= mask->changed.ucp;*/
249 if (mask
->changed
.group
& NINE_STATE_SAMPLER
) {
250 for (s
= 0; s
< NINE_MAX_SAMPLERS
; ++s
) {
251 if (mask
->changed
.sampler
[s
] == 0x3ffe) {
252 memcpy(&dst
->samp_advertised
[s
], &src
->samp_advertised
[s
], sizeof(dst
->samp_advertised
[s
]));
254 uint32_t m
= mask
->changed
.sampler
[s
];
255 DBG("samp %d: changed = %x\n", i
, (int)m
);
257 const int i
= ffs(m
) - 1;
259 dst
->samp_advertised
[s
][i
] = src
->samp_advertised
[s
][i
];
263 * dst->changed.sampler[s] |= mask->changed.sampler[s];*/
268 if (mask
->changed
.group
& NINE_STATE_IDXBUF
)
269 NineStateBlock9_BindBuffer(device
,
271 (struct NineBuffer9
**)&dst
->idxbuf
,
272 (struct NineBuffer9
*)src
->idxbuf
);
274 /* Vertex streams. */
275 if (mask
->changed
.vtxbuf
| mask
->changed
.stream_freq
) {
276 DBG("vtxbuf/stream_freq: %x/%x\n", mask
->changed
.vtxbuf
, mask
->changed
.stream_freq
);
277 uint32_t m
= mask
->changed
.vtxbuf
| mask
->changed
.stream_freq
;
278 for (i
= 0; m
; ++i
, m
>>= 1) {
279 if (mask
->changed
.vtxbuf
& (1 << i
)) {
280 NineStateBlock9_BindBuffer(device
,
282 (struct NineBuffer9
**)&dst
->stream
[i
],
283 (struct NineBuffer9
*)src
->stream
[i
]);
284 if (src
->stream
[i
]) {
285 dst
->vtxbuf
[i
].buffer_offset
= src
->vtxbuf
[i
].buffer_offset
;
286 dst
->vtxbuf
[i
].stride
= src
->vtxbuf
[i
].stride
;
289 if (mask
->changed
.stream_freq
& (1 << i
))
290 dst
->stream_freq
[i
] = src
->stream_freq
[i
];
294 * dst->changed.vtxbuf |= mask->changed.vtxbuf;
295 * dst->changed.stream_freq |= mask->changed.stream_freq;
300 if (mask
->changed
.texture
) {
301 uint32_t m
= mask
->changed
.texture
;
302 for (s
= 0; m
; ++s
, m
>>= 1)
304 NineStateBlock9_BindTexture(device
, apply
, &dst
->texture
[s
], src
->texture
[s
]);
307 if (!(mask
->changed
.group
& NINE_STATE_FF
))
309 WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n");
311 /* Fixed function state. */
313 if (mask
->changed
.group
& NINE_STATE_FF_MATERIAL
)
314 dst
->ff
.material
= src
->ff
.material
;
316 if (mask
->changed
.group
& NINE_STATE_FF_PS_CONSTS
) {
317 for (s
= 0; s
< NINE_MAX_TEXTURE_STAGES
; ++s
) {
318 for (i
= 0; i
< NINED3DTSS_COUNT
; ++i
)
319 if (mask
->ff
.changed
.tex_stage
[s
][i
/ 32] & (1 << (i
% 32)))
320 dst
->ff
.tex_stage
[s
][i
] = src
->ff
.tex_stage
[s
][i
];
323 * TODO: it's 32 exactly, just offset by 1 as 0 is unused
324 * dst->ff.changed.tex_stage[s][0] |=
325 * mask->ff.changed.tex_stage[s][0];
326 * dst->ff.changed.tex_stage[s][1] |=
327 * mask->ff.changed.tex_stage[s][1];
331 if (mask
->changed
.group
& NINE_STATE_FF_LIGHTING
) {
332 unsigned num_lights
= MAX2(dst
->ff
.num_lights
, src
->ff
.num_lights
);
333 /* Can happen in Capture() if device state has created new lights after
334 * the stateblock was created.
335 * Can happen in Apply() if the stateblock had recorded the creation of
337 if (dst
->ff
.num_lights
< num_lights
) {
338 dst
->ff
.light
= REALLOC(dst
->ff
.light
,
339 dst
->ff
.num_lights
* sizeof(D3DLIGHT9
),
340 num_lights
* sizeof(D3DLIGHT9
));
341 memset(&dst
->ff
.light
[dst
->ff
.num_lights
], 0, (num_lights
- dst
->ff
.num_lights
) * sizeof(D3DLIGHT9
));
342 /* if mask == dst, a Type of 0 will trigger
343 * "dst->ff.light[i] = src->ff.light[i];" later,
344 * which is what we want in that case. */
346 for (i
= dst
->ff
.num_lights
; i
< num_lights
; ++i
)
347 dst
->ff
.light
[i
].Type
= (D3DLIGHTTYPE
)NINED3DLIGHT_INVALID
;
349 dst
->ff
.num_lights
= num_lights
;
351 /* Can happen in Capture() if the stateblock had recorded the creation of
353 * Can happen in Apply() if device state has created new lights after
354 * the stateblock was created. */
355 if (src
->ff
.num_lights
< num_lights
) {
356 src
->ff
.light
= REALLOC(src
->ff
.light
,
357 src
->ff
.num_lights
* sizeof(D3DLIGHT9
),
358 num_lights
* sizeof(D3DLIGHT9
));
359 memset(&src
->ff
.light
[src
->ff
.num_lights
], 0, (num_lights
- src
->ff
.num_lights
) * sizeof(D3DLIGHT9
));
360 for (i
= src
->ff
.num_lights
; i
< num_lights
; ++i
)
361 src
->ff
.light
[i
].Type
= (D3DLIGHTTYPE
)NINED3DLIGHT_INVALID
;
362 src
->ff
.num_lights
= num_lights
;
364 /* Note: mask is either src or dst, so at this point src, dst and mask
365 * have num_lights lights. */
366 for (i
= 0; i
< num_lights
; ++i
)
367 if (mask
->ff
.light
[i
].Type
!= NINED3DLIGHT_INVALID
)
368 dst
->ff
.light
[i
] = src
->ff
.light
[i
];
370 memcpy(dst
->ff
.active_light
, src
->ff
.active_light
, sizeof(src
->ff
.active_light
) );
371 dst
->ff
.num_lights_active
= src
->ff
.num_lights_active
;
373 if (mask
->changed
.group
& NINE_STATE_FF_VSTRANSF
) {
374 for (i
= 0; i
< ARRAY_SIZE(mask
->ff
.changed
.transform
); ++i
) {
375 if (!mask
->ff
.changed
.transform
[i
])
377 for (s
= i
* 32; s
< (i
* 32 + 32); ++s
) {
378 if (!(mask
->ff
.changed
.transform
[i
] & (1 << (s
% 32))))
380 *nine_state_access_transform(&dst
->ff
, s
, TRUE
) =
381 *nine_state_access_transform(&src
->ff
, s
, FALSE
);
384 * dst->ff.changed.transform[i] |= mask->ff.changed.transform[i];*/
390 nine_state_copy_common_all(struct NineDevice9
*device
,
391 struct nine_state
*dst
,
392 struct nine_state
*src
,
393 struct nine_state
*help
,
395 struct nine_range_pool
*pool
,
396 const int MaxStreams
)
401 * dst->changed.group |= src->changed.group;
404 dst
->viewport
= src
->viewport
;
405 dst
->scissor
= src
->scissor
;
407 nine_bind(&dst
->vs
, src
->vs
);
408 nine_bind(&dst
->ps
, src
->ps
);
412 * Various possibilities for optimization here, like creating a per-SB
413 * constant buffer, or memcmp'ing for changes.
414 * Will do that later depending on what works best for specific apps.
417 memcpy(&dst
->vs_const_f
[0],
418 &src
->vs_const_f
[0], VS_CONST_F_SIZE(device
));
420 memcpy(dst
->vs_const_i
, src
->vs_const_i
, VS_CONST_I_SIZE(device
));
421 memcpy(dst
->vs_const_b
, src
->vs_const_b
, VS_CONST_B_SIZE(device
));
424 /* Pixel constants. */
426 struct nine_range
*r
= help
->changed
.ps_const_f
;
427 memcpy(&dst
->ps_const_f
[0],
428 &src
->ps_const_f
[0], (r
->end
- r
->bgn
) * 4 * sizeof(float));
430 memcpy(dst
->ps_const_i
, src
->ps_const_i
, sizeof(dst
->ps_const_i
));
431 memcpy(dst
->ps_const_b
, src
->ps_const_b
, sizeof(dst
->ps_const_b
));
435 memcpy(dst
->rs_advertised
, src
->rs_advertised
, sizeof(dst
->rs_advertised
));
437 * memcpy(dst->changed.rs, src->changed.rs, sizeof(dst->changed.rs));*/
441 memcpy(&dst
->clip
, &src
->clip
, sizeof(dst
->clip
));
443 * dst->changed.ucp = src->changed.ucp;*/
446 memcpy(dst
->samp_advertised
, src
->samp_advertised
, sizeof(dst
->samp_advertised
));
448 * memcpy(dst->changed.sampler,
449 * src->changed.sampler, sizeof(dst->changed.sampler));*/
452 NineStateBlock9_BindBuffer(device
,
454 (struct NineBuffer9
**)&dst
->idxbuf
,
455 (struct NineBuffer9
*)src
->idxbuf
);
457 /* Vertex streams. */
459 for (i
= 0; i
< ARRAY_SIZE(dst
->stream
); ++i
) {
460 NineStateBlock9_BindBuffer(device
,
462 (struct NineBuffer9
**)&dst
->stream
[i
],
463 (struct NineBuffer9
*)src
->stream
[i
]);
464 if (src
->stream
[i
]) {
465 dst
->vtxbuf
[i
].buffer_offset
= src
->vtxbuf
[i
].buffer_offset
;
466 dst
->vtxbuf
[i
].stride
= src
->vtxbuf
[i
].stride
;
468 dst
->stream_freq
[i
] = src
->stream_freq
[i
];
471 * dst->changed.vtxbuf = (1ULL << MaxStreams) - 1;
472 * dst->changed.stream_freq = (1ULL << MaxStreams) - 1;
478 for (i
= 0; i
< NINE_MAX_SAMPLERS
; i
++)
479 NineStateBlock9_BindTexture(device
, apply
, &dst
->texture
[i
], src
->texture
[i
]);
482 /* keep this check in case we want to disable FF */
483 if (!(help
->changed
.group
& NINE_STATE_FF
))
485 WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n");
487 /* Fixed function state. */
488 dst
->ff
.material
= src
->ff
.material
;
490 memcpy(dst
->ff
.tex_stage
, src
->ff
.tex_stage
, sizeof(dst
->ff
.tex_stage
));
491 /* if (apply) TODO: memset
492 * memcpy(dst->ff.changed.tex_stage,
493 * src->ff.changed.tex_stage, sizeof(dst->ff.changed.tex_stage));*/
497 if (dst
->ff
.num_lights
< src
->ff
.num_lights
) {
498 dst
->ff
.light
= REALLOC(dst
->ff
.light
,
499 dst
->ff
.num_lights
* sizeof(D3DLIGHT9
),
500 src
->ff
.num_lights
* sizeof(D3DLIGHT9
));
501 dst
->ff
.num_lights
= src
->ff
.num_lights
;
503 memcpy(dst
->ff
.light
,
504 src
->ff
.light
, src
->ff
.num_lights
* sizeof(dst
->ff
.light
[0]));
506 memcpy(dst
->ff
.active_light
, src
->ff
.active_light
, sizeof(src
->ff
.active_light
) );
507 dst
->ff
.num_lights_active
= src
->ff
.num_lights_active
;
512 /* Increase dst size if required (to copy the new states).
513 * Increase src size if required (to initialize missing transforms).
515 if (dst
->ff
.num_transforms
!= src
->ff
.num_transforms
) {
516 int num_transforms
= MAX2(src
->ff
.num_transforms
, dst
->ff
.num_transforms
);
517 nine_state_resize_transform(&src
->ff
, num_transforms
);
518 nine_state_resize_transform(&dst
->ff
, num_transforms
);
520 memcpy(dst
->ff
.transform
,
521 src
->ff
.transform
, dst
->ff
.num_transforms
* sizeof(D3DMATRIX
));
522 /* Apply is always used on device state.
523 * src is then the D3DSBT_ALL stateblock which
524 * ff.changed.transform indicates all matrices are dirty.
527 * memcpy(dst->ff.changed.transform,
528 * src->ff.changed.transform, sizeof(dst->ff.changed.transform));*/
532 /* Capture those bits of current device state that have been changed between
533 * BeginStateBlock and EndStateBlock.
536 NineStateBlock9_Capture( struct NineStateBlock9
*This
)
538 struct NineDevice9
*device
= This
->base
.device
;
539 struct nine_state
*dst
= &This
->state
;
540 struct nine_state
*src
= &device
->state
;
541 const int MaxStreams
= device
->caps
.MaxStreams
;
543 DBG("This=%p\n", This
);
545 if (This
->type
== NINESBT_ALL
)
546 nine_state_copy_common_all(device
, dst
, src
, dst
, FALSE
, NULL
, MaxStreams
);
548 nine_state_copy_common(device
, dst
, src
, dst
, FALSE
, NULL
);
550 if (dst
->changed
.group
& NINE_STATE_VDECL
)
551 nine_bind(&dst
->vdecl
, src
->vdecl
);
556 /* Set state managed by this StateBlock as current device state. */
558 NineStateBlock9_Apply( struct NineStateBlock9
*This
)
560 struct NineDevice9
*device
= This
->base
.device
;
561 struct nine_state
*dst
= &device
->state
;
562 struct nine_state
*src
= &This
->state
;
563 struct nine_range_pool
*pool
= &device
->range_pool
;
564 const int MaxStreams
= device
->caps
.MaxStreams
;
566 DBG("This=%p\n", This
);
568 if (This
->type
== NINESBT_ALL
)
569 nine_state_copy_common_all(device
, dst
, src
, src
, TRUE
, pool
, MaxStreams
);
571 nine_state_copy_common(device
, dst
, src
, src
, TRUE
, pool
);
573 nine_context_apply_stateblock(device
, src
);
575 if ((src
->changed
.group
& NINE_STATE_VDECL
) && src
->vdecl
)
576 nine_bind(&dst
->vdecl
, src
->vdecl
);
581 IDirect3DStateBlock9Vtbl NineStateBlock9_vtable
= {
582 (void *)NineUnknown_QueryInterface
,
583 (void *)NineUnknown_AddRef
,
584 (void *)NineUnknown_Release
,
585 (void *)NineUnknown_GetDevice
, /* actually part of StateBlock9 iface */
586 (void *)NineStateBlock9_Capture
,
587 (void *)NineStateBlock9_Apply
590 static const GUID
*NineStateBlock9_IIDs
[] = {
591 &IID_IDirect3DStateBlock9
,
597 NineStateBlock9_new( struct NineDevice9
*pDevice
,
598 struct NineStateBlock9
**ppOut
,
599 enum nine_stateblock_type type
)
601 NINE_DEVICE_CHILD_NEW(StateBlock9
, ppOut
, pDevice
, type
);