1/* 2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.com> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 22 23#include "stateblock9.h" 24#include "device9.h" 25#include "basetexture9.h" 26#include "nine_helpers.h" 27#include "vertexdeclaration9.h" 28#include "vertexbuffer9.h" 29#include "indexbuffer9.h" 30 31#define DBG_CHANNEL DBG_STATEBLOCK 32 33/* XXX TODO: handling of lights is broken */ 34 35HRESULT 36NineStateBlock9_ctor( struct NineStateBlock9 *This, 37 struct NineUnknownParams *pParams, 38 enum nine_stateblock_type type ) 39{ 40 HRESULT hr = NineUnknown_ctor(&This->base, pParams); 41 42 DBG("This=%p pParams=%p type=%d\n", This, pParams, type); 43 44 if (FAILED(hr)) 45 return hr; 46 47 This->type = type; 48 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) 55 return E_OUTOFMEMORY; 56 57 return D3D_OK; 58} 59 60void 61NineStateBlock9_dtor( struct NineStateBlock9 *This ) 62{ 63 struct nine_state *state = &This->state; 64 struct nine_range *r; 65 struct nine_range_pool *pool = &This->base.device->range_pool; 66 unsigned i; 67 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); 76 77 nine_bind(&state->idxbuf, NULL); 78 for (i = 0; i < NINE_MAX_SAMPLERS; ++i) 79 nine_bind(&state->texture[i], NULL); 80 81 FREE(state->vs_const_f); 82 FREE(state->ps_const_f); 83 FREE(state->vs_const_i); 84 FREE(state->vs_const_b); 85 86 FREE(state->ff.light); 87 88 FREE(state->ff.transform); 89 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); 93 } 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); 97 } 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); 101 } 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); 105 } 106 107 NineUnknown_dtor(&This->base); 108} 109 110static void 111NineStateBlock9_BindBuffer( struct NineDevice9 *device, 112 boolean applyToDevice, 113 struct NineBuffer9 **slot, 114 struct NineBuffer9 *buf ) 115{ 116 if (applyToDevice) 117 NineBindBufferToDevice(device, slot, buf); 118 else 119 nine_bind(slot, buf); 120} 121 122static void 123NineStateBlock9_BindTexture( struct NineDevice9 *device, 124 boolean applyToDevice, 125 struct NineBaseTexture9 **slot, 126 struct NineBaseTexture9 *tex ) 127{ 128 if (applyToDevice) 129 NineBindTextureToDevice(device, slot, tex); 130 else 131 nine_bind(slot, tex); 132} 133 134/* Copy state marked changed in @mask from @src to @dst. 135 * If @apply is false, updating dst->changed can be omitted. 136 * TODO: compare ? 137 */ 138static void 139nine_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 */ 143 const boolean apply, 144 struct nine_range_pool *pool) 145{ 146 unsigned i, s; 147 148 DBG("apply:%d changed.group: %x\n", (int)apply, (int)mask->changed.group ); 149 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. 154 * 155 * if (apply) 156 * dst->changed.group |= mask->changed.group; 157 */ 158 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; 163 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); 168 169 /* Vertex constants. 170 * 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. 174 * 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. 179 */ 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)); 186 } 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)); 191 } 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)); 196 } 197 } 198 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)); 206 } 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) 210 if (m & 1) 211 memcpy(dst->ps_const_i[i], src->ps_const_i[i], 4 * sizeof(int)); 212 } 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) 216 if (m & 1) 217 dst->ps_const_b[i] = src->ps_const_b[i]; 218 } 219 } 220 221 /* Render states. 222 * TODO: Maybe build a list ? 223 */ 224 for (i = 0; i < ARRAY_SIZE(mask->changed.rs); ++i) { 225 uint32_t m = mask->changed.rs[i]; 226 /* if (apply) 227 * dst->changed.rs[i] |= m; */ 228 while (m) { 229 const int r = ffs(m) - 1; 230 m &= ~(1 << r); 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]; 233 } 234 } 235 236 237 /* Clip planes. */ 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])); 244 /* if (apply) 245 * dst->changed.ucp |= mask->changed.ucp;*/ 246 } 247 248 /* Sampler state. */ 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])); 253 } else { 254 uint32_t m = mask->changed.sampler[s]; 255 DBG("samp %d: changed = %x\n", i, (int)m); 256 while (m) { 257 const int i = ffs(m) - 1; 258 m &= ~(1 << i); 259 dst->samp_advertised[s][i] = src->samp_advertised[s][i]; 260 } 261 } 262 /* if (apply) 263 * dst->changed.sampler[s] |= mask->changed.sampler[s];*/ 264 } 265 } 266 267 /* Index buffer. */ 268 if (mask->changed.group & NINE_STATE_IDXBUF) 269 NineStateBlock9_BindBuffer(device, 270 apply, 271 (struct NineBuffer9 **)&dst->idxbuf, 272 (struct NineBuffer9 *)src->idxbuf); 273 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, 281 apply, 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; 287 } 288 } 289 if (mask->changed.stream_freq & (1 << i)) 290 dst->stream_freq[i] = src->stream_freq[i]; 291 } 292 /* 293 * if (apply) { 294 * dst->changed.vtxbuf |= mask->changed.vtxbuf; 295 * dst->changed.stream_freq |= mask->changed.stream_freq; 296 * }*/ 297 } 298 299 /* Textures */ 300 if (mask->changed.texture) { 301 uint32_t m = mask->changed.texture; 302 for (s = 0; m; ++s, m >>= 1) 303 if (m & 1) 304 NineStateBlock9_BindTexture(device, apply, &dst->texture[s], src->texture[s]); 305 } 306 307 if (!(mask->changed.group & NINE_STATE_FF)) 308 return; 309 WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n"); 310 311 /* Fixed function state. */ 312 313 if (mask->changed.group & NINE_STATE_FF_MATERIAL) 314 dst->ff.material = src->ff.material; 315 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]; 321 /* 322 * if (apply) { 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]; 328 * }*/ 329 } 330 } 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 336 * new lights. */ 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. */ 345 if (mask != dst) { 346 for (i = dst->ff.num_lights; i < num_lights; ++i) 347 dst->ff.light[i].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID; 348 } 349 dst->ff.num_lights = num_lights; 350 } 351 /* Can happen in Capture() if the stateblock had recorded the creation of 352 * new lights. 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; 363 } 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]; 369 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; 372 } 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]) 376 continue; 377 for (s = i * 32; s < (i * 32 + 32); ++s) { 378 if (!(mask->ff.changed.transform[i] & (1 << (s % 32)))) 379 continue; 380 *nine_state_access_transform(&dst->ff, s, TRUE) = 381 *nine_state_access_transform(&src->ff, s, FALSE); 382 } 383 /* if (apply) 384 * dst->ff.changed.transform[i] |= mask->ff.changed.transform[i];*/ 385 } 386 } 387} 388 389static void 390nine_state_copy_common_all(struct NineDevice9 *device, 391 struct nine_state *dst, 392 struct nine_state *src, 393 struct nine_state *help, 394 const boolean apply, 395 struct nine_range_pool *pool, 396 const int MaxStreams) 397{ 398 unsigned i; 399 400 /* if (apply) 401 * dst->changed.group |= src->changed.group; 402 */ 403 404 dst->viewport = src->viewport; 405 dst->scissor = src->scissor; 406 407 nine_bind(&dst->vs, src->vs); 408 nine_bind(&dst->ps, src->ps); 409 410 /* Vertex constants. 411 * 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. 415 */ 416 if (1) { 417 memcpy(&dst->vs_const_f[0], 418 &src->vs_const_f[0], VS_CONST_F_SIZE(device)); 419 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)); 422 } 423 424 /* Pixel constants. */ 425 if (1) { 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)); 429 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)); 432 } 433 434 /* Render states. */ 435 memcpy(dst->rs_advertised, src->rs_advertised, sizeof(dst->rs_advertised)); 436 /* if (apply) 437 * memcpy(dst->changed.rs, src->changed.rs, sizeof(dst->changed.rs));*/ 438 439 440 /* Clip planes. */ 441 memcpy(&dst->clip, &src->clip, sizeof(dst->clip)); 442 /* if (apply) 443 * dst->changed.ucp = src->changed.ucp;*/ 444 445 /* Sampler state. */ 446 memcpy(dst->samp_advertised, src->samp_advertised, sizeof(dst->samp_advertised)); 447 /* if (apply) 448 * memcpy(dst->changed.sampler, 449 * src->changed.sampler, sizeof(dst->changed.sampler));*/ 450 451 /* Index buffer. */ 452 NineStateBlock9_BindBuffer(device, 453 apply, 454 (struct NineBuffer9 **)&dst->idxbuf, 455 (struct NineBuffer9 *)src->idxbuf); 456 457 /* Vertex streams. */ 458 if (1) { 459 for (i = 0; i < ARRAY_SIZE(dst->stream); ++i) { 460 NineStateBlock9_BindBuffer(device, 461 apply, 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; 467 } 468 dst->stream_freq[i] = src->stream_freq[i]; 469 } 470 /* if (apply) { 471 * dst->changed.vtxbuf = (1ULL << MaxStreams) - 1; 472 * dst->changed.stream_freq = (1ULL << MaxStreams) - 1; 473 * }*/ 474 } 475 476 /* Textures */ 477 if (1) { 478 for (i = 0; i < NINE_MAX_SAMPLERS; i++) 479 NineStateBlock9_BindTexture(device, apply, &dst->texture[i], src->texture[i]); 480 } 481 482 /* keep this check in case we want to disable FF */ 483 if (!(help->changed.group & NINE_STATE_FF)) 484 return; 485 WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n"); 486 487 /* Fixed function state. */ 488 dst->ff.material = src->ff.material; 489 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));*/ 494 495 /* Lights. */ 496 if (1) { 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; 502 } 503 memcpy(dst->ff.light, 504 src->ff.light, src->ff.num_lights * sizeof(dst->ff.light[0])); 505 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; 508 } 509 510 /* Transforms. */ 511 if (1) { 512 /* Increase dst size if required (to copy the new states). 513 * Increase src size if required (to initialize missing transforms). 514 */ 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); 519 } 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. 525 * 526 * if (apply) 527 * memcpy(dst->ff.changed.transform, 528 * src->ff.changed.transform, sizeof(dst->ff.changed.transform));*/ 529 } 530} 531 532/* Capture those bits of current device state that have been changed between 533 * BeginStateBlock and EndStateBlock. 534 */ 535HRESULT NINE_WINAPI 536NineStateBlock9_Capture( struct NineStateBlock9 *This ) 537{ 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; 542 543 DBG("This=%p\n", This); 544 545 if (This->type == NINESBT_ALL) 546 nine_state_copy_common_all(device, dst, src, dst, FALSE, NULL, MaxStreams); 547 else 548 nine_state_copy_common(device, dst, src, dst, FALSE, NULL); 549 550 if (dst->changed.group & NINE_STATE_VDECL) 551 nine_bind(&dst->vdecl, src->vdecl); 552 553 return D3D_OK; 554} 555 556/* Set state managed by this StateBlock as current device state. */ 557HRESULT NINE_WINAPI 558NineStateBlock9_Apply( struct NineStateBlock9 *This ) 559{ 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; 565 566 DBG("This=%p\n", This); 567 568 if (This->type == NINESBT_ALL) 569 nine_state_copy_common_all(device, dst, src, src, TRUE, pool, MaxStreams); 570 else 571 nine_state_copy_common(device, dst, src, src, TRUE, pool); 572 573 nine_context_apply_stateblock(device, src); 574 575 if ((src->changed.group & NINE_STATE_VDECL) && src->vdecl) 576 nine_bind(&dst->vdecl, src->vdecl); 577 578 return D3D_OK; 579} 580 581IDirect3DStateBlock9Vtbl 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 588}; 589 590static const GUID *NineStateBlock9_IIDs[] = { 591 &IID_IDirect3DStateBlock9, 592 &IID_IUnknown, 593 NULL 594}; 595 596HRESULT 597NineStateBlock9_new( struct NineDevice9 *pDevice, 598 struct NineStateBlock9 **ppOut, 599 enum nine_stateblock_type type) 600{ 601 NINE_DEVICE_CHILD_NEW(StateBlock9, ppOut, pDevice, type); 602} 603