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 35 HRESULT 36 NineStateBlock9_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 60 void 61 NineStateBlock9_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 67 nine_state_clear(state, false); 68 69 FREE(state->vs_const_f); 70 FREE(state->ps_const_f); 71 FREE(state->vs_const_i); 72 FREE(state->vs_const_b); 73 74 FREE(state->ff.light); 75 76 FREE(state->ff.transform); 77 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); 81 } 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); 85 } 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); 89 } 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); 93 } 94 95 NineUnknown_dtor(&This->base); 96 } 97 98 static void 99 NineStateBlock9_BindBuffer( struct NineDevice9 *device, 100 boolean applyToDevice, 101 struct NineBuffer9 **slot, 102 struct NineBuffer9 *buf ) 103 { 104 if (applyToDevice) 105 NineBindBufferToDevice(device, slot, buf); 106 else 107 nine_bind(slot, buf); 108 } 109 110 static void 111 NineStateBlock9_BindTexture( struct NineDevice9 *device, 112 boolean applyToDevice, 113 struct NineBaseTexture9 **slot, 114 struct NineBaseTexture9 *tex ) 115 { 116 if (applyToDevice) 117 NineBindTextureToDevice(device, slot, tex); 118 else 119 nine_bind(slot, tex); 120 } 121 122 /* Copy state marked changed in @mask from @src to @dst. 123 * If @apply is false, updating dst->changed can be omitted. 124 * TODO: compare ? 125 */ 126 static void 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 */ 131 const boolean apply, 132 struct nine_range_pool *pool) 133 { 134 unsigned i, s; 135 136 DBG("apply:%d changed.group: %x\n", (int)apply, (int)mask->changed.group ); 137 if (apply) 138 dst->changed.group |= mask->changed.group; 139 140 if (mask->changed.group & NINE_STATE_VIEWPORT) 141 dst->viewport = src->viewport; 142 if (mask->changed.group & NINE_STATE_SCISSOR) 143 dst->scissor = src->scissor; 144 145 if (mask->changed.group & NINE_STATE_VS) 146 nine_bind(&dst->vs, src->vs); 147 if (mask->changed.group & NINE_STATE_PS) 148 nine_bind(&dst->ps, src->ps); 149 150 /* Vertex constants. 151 * 152 * Various possibilities for optimization here, like creating a per-SB 153 * constant buffer, or memcmp'ing for changes. 154 * Will do that later depending on what works best for specific apps. 155 * 156 * Note: Currently when we apply stateblocks, it's always on the device state. 157 * Should it affect recording stateblocks ? Since it's on device state, there 158 * is no need to copy which ranges are dirty. If it turns out we should affect 159 * recording stateblocks, the info should be copied. 160 */ 161 if (mask->changed.group & NINE_STATE_VS_CONST) { 162 struct nine_range *r; 163 for (r = mask->changed.vs_const_f; r; r = r->next) { 164 memcpy(&dst->vs_const_f[r->bgn * 4], 165 &src->vs_const_f[r->bgn * 4], 166 (r->end - r->bgn) * 4 * sizeof(float)); 167 } 168 for (r = mask->changed.vs_const_i; r; r = r->next) { 169 memcpy(&dst->vs_const_i[r->bgn * 4], 170 &src->vs_const_i[r->bgn * 4], 171 (r->end - r->bgn) * 4 * sizeof(int)); 172 } 173 for (r = mask->changed.vs_const_b; r; r = r->next) { 174 memcpy(&dst->vs_const_b[r->bgn], 175 &src->vs_const_b[r->bgn], 176 (r->end - r->bgn) * sizeof(int)); 177 } 178 } 179 180 /* Pixel constants. */ 181 if (mask->changed.group & NINE_STATE_PS_CONST) { 182 struct nine_range *r; 183 for (r = mask->changed.ps_const_f; r; r = r->next) { 184 memcpy(&dst->ps_const_f[r->bgn * 4], 185 &src->ps_const_f[r->bgn * 4], 186 (r->end - r->bgn) * 4 * sizeof(float)); 187 } 188 if (mask->changed.ps_const_i) { 189 uint16_t m = mask->changed.ps_const_i; 190 for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1) 191 if (m & 1) 192 memcpy(dst->ps_const_i[i], src->ps_const_i[i], 4 * sizeof(int)); 193 } 194 if (mask->changed.ps_const_b) { 195 uint16_t m = mask->changed.ps_const_b; 196 for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1) 197 if (m & 1) 198 dst->ps_const_b[i] = src->ps_const_b[i]; 199 } 200 } 201 202 /* Render states. 203 * TODO: Maybe build a list ? 204 */ 205 for (i = 0; i < ARRAY_SIZE(dst->changed.rs); ++i) { 206 uint32_t m = mask->changed.rs[i]; 207 if (apply) 208 dst->changed.rs[i] |= m; 209 while (m) { 210 const int r = ffs(m) - 1; 211 m &= ~(1 << r); 212 DBG("State %d %s = %d\n", i * 32 + r, nine_d3drs_to_string(i * 32 + r), (int)src->rs_advertised[i * 32 + r]); 213 dst->rs_advertised[i * 32 + r] = src->rs_advertised[i * 32 + r]; 214 } 215 } 216 217 218 /* Clip planes. */ 219 if (mask->changed.ucp) { 220 DBG("ucp: %x\n", mask->changed.ucp); 221 for (i = 0; i < PIPE_MAX_CLIP_PLANES; ++i) 222 if (mask->changed.ucp & (1 << i)) 223 memcpy(dst->clip.ucp[i], 224 src->clip.ucp[i], sizeof(src->clip.ucp[0])); 225 if (apply) 226 dst->changed.ucp |= mask->changed.ucp; 227 } 228 229 /* Sampler state. */ 230 if (mask->changed.group & NINE_STATE_SAMPLER) { 231 for (s = 0; s < NINE_MAX_SAMPLERS; ++s) { 232 if (mask->changed.sampler[s] == 0x3ffe) { 233 memcpy(&dst->samp_advertised[s], &src->samp_advertised[s], sizeof(dst->samp_advertised[s])); 234 } else { 235 uint32_t m = mask->changed.sampler[s]; 236 DBG("samp %d: changed = %x\n", i, (int)m); 237 while (m) { 238 const int i = ffs(m) - 1; 239 m &= ~(1 << i); 240 dst->samp_advertised[s][i] = src->samp_advertised[s][i]; 241 } 242 } 243 if (apply) 244 dst->changed.sampler[s] |= mask->changed.sampler[s]; 245 } 246 } 247 248 /* Index buffer. */ 249 if (mask->changed.group & NINE_STATE_IDXBUF) 250 NineStateBlock9_BindBuffer(device, 251 apply, 252 (struct NineBuffer9 **)&dst->idxbuf, 253 (struct NineBuffer9 *)src->idxbuf); 254 255 /* Vertex streams. */ 256 if (mask->changed.vtxbuf | mask->changed.stream_freq) { 257 DBG("vtxbuf/stream_freq: %x/%x\n", mask->changed.vtxbuf, mask->changed.stream_freq); 258 uint32_t m = mask->changed.vtxbuf | mask->changed.stream_freq; 259 for (i = 0; m; ++i, m >>= 1) { 260 if (mask->changed.vtxbuf & (1 << i)) { 261 NineStateBlock9_BindBuffer(device, 262 apply, 263 (struct NineBuffer9 **)&dst->stream[i], 264 (struct NineBuffer9 *)src->stream[i]); 265 if (src->stream[i]) { 266 dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset; 267 dst->vtxbuf[i].stride = src->vtxbuf[i].stride; 268 } 269 } 270 if (mask->changed.stream_freq & (1 << i)) 271 dst->stream_freq[i] = src->stream_freq[i]; 272 } 273 if (apply) { 274 dst->changed.vtxbuf |= mask->changed.vtxbuf; 275 dst->changed.stream_freq |= mask->changed.stream_freq; 276 } 277 } 278 279 /* Textures */ 280 if (mask->changed.texture) { 281 uint32_t m = mask->changed.texture; 282 for (s = 0; m; ++s, m >>= 1) 283 if (m & 1) 284 NineStateBlock9_BindTexture(device, apply, &dst->texture[s], src->texture[s]); 285 } 286 287 if (!(mask->changed.group & NINE_STATE_FF)) 288 return; 289 WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n"); 290 291 /* Fixed function state. */ 292 293 if (mask->changed.group & NINE_STATE_FF_MATERIAL) 294 dst->ff.material = src->ff.material; 295 296 if (mask->changed.group & NINE_STATE_FF_PSSTAGES) { 297 for (s = 0; s < NINE_MAX_TEXTURE_STAGES; ++s) { 298 for (i = 0; i < NINED3DTSS_COUNT; ++i) 299 if (mask->ff.changed.tex_stage[s][i / 32] & (1 << (i % 32))) 300 dst->ff.tex_stage[s][i] = src->ff.tex_stage[s][i]; 301 if (apply) { 302 /* TODO: it's 32 exactly, just offset by 1 as 0 is unused */ 303 dst->ff.changed.tex_stage[s][0] |= 304 mask->ff.changed.tex_stage[s][0]; 305 dst->ff.changed.tex_stage[s][1] |= 306 mask->ff.changed.tex_stage[s][1]; 307 } 308 } 309 } 310 if (mask->changed.group & NINE_STATE_FF_LIGHTING) { 311 unsigned num_lights = MAX2(dst->ff.num_lights, src->ff.num_lights); 312 /* Can happen in Capture() if device state has created new lights after 313 * the stateblock was created. 314 * Can happen in Apply() if the stateblock had recorded the creation of 315 * new lights. */ 316 if (dst->ff.num_lights < num_lights) { 317 dst->ff.light = REALLOC(dst->ff.light, 318 dst->ff.num_lights * sizeof(D3DLIGHT9), 319 num_lights * sizeof(D3DLIGHT9)); 320 memset(&dst->ff.light[dst->ff.num_lights], 0, (num_lights - dst->ff.num_lights) * sizeof(D3DLIGHT9)); 321 /* if mask == dst, a Type of 0 will trigger 322 * "dst->ff.light[i] = src->ff.light[i];" later, 323 * which is what we want in that case. */ 324 if (mask != dst) { 325 for (i = dst->ff.num_lights; i < num_lights; ++i) 326 dst->ff.light[i].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID; 327 } 328 dst->ff.num_lights = num_lights; 329 } 330 /* Can happen in Capture() if the stateblock had recorded the creation of 331 * new lights. 332 * Can happen in Apply() if device state has created new lights after 333 * the stateblock was created. */ 334 if (src->ff.num_lights < num_lights) { 335 src->ff.light = REALLOC(src->ff.light, 336 src->ff.num_lights * sizeof(D3DLIGHT9), 337 num_lights * sizeof(D3DLIGHT9)); 338 memset(&src->ff.light[src->ff.num_lights], 0, (num_lights - src->ff.num_lights) * sizeof(D3DLIGHT9)); 339 for (i = src->ff.num_lights; i < num_lights; ++i) 340 src->ff.light[i].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID; 341 src->ff.num_lights = num_lights; 342 } 343 /* Note: mask is either src or dst, so at this point src, dst and mask 344 * have num_lights lights. */ 345 for (i = 0; i < num_lights; ++i) 346 if (mask->ff.light[i].Type != NINED3DLIGHT_INVALID) 347 dst->ff.light[i] = src->ff.light[i]; 348 349 memcpy(dst->ff.active_light, src->ff.active_light, sizeof(src->ff.active_light) ); 350 dst->ff.num_lights_active = src->ff.num_lights_active; 351 } 352 if (mask->changed.group & NINE_STATE_FF_VSTRANSF) { 353 for (i = 0; i < ARRAY_SIZE(mask->ff.changed.transform); ++i) { 354 if (!mask->ff.changed.transform[i]) 355 continue; 356 for (s = i * 32; s < (i * 32 + 32); ++s) { 357 if (!(mask->ff.changed.transform[i] & (1 << (s % 32)))) 358 continue; 359 *nine_state_access_transform(&dst->ff, s, TRUE) = 360 *nine_state_access_transform( /* const because !alloc */ 361 (struct nine_ff_state *)&src->ff, s, FALSE); 362 } 363 if (apply) 364 dst->ff.changed.transform[i] |= mask->ff.changed.transform[i]; 365 } 366 } 367 } 368 369 static void 370 nine_state_copy_common_all(struct NineDevice9 *device, 371 struct nine_state *dst, 372 const struct nine_state *src, 373 struct nine_state *help, 374 const boolean apply, 375 struct nine_range_pool *pool, 376 const int MaxStreams) 377 { 378 unsigned i; 379 380 if (apply) 381 dst->changed.group |= src->changed.group; 382 383 dst->viewport = src->viewport; 384 dst->scissor = src->scissor; 385 386 nine_bind(&dst->vs, src->vs); 387 nine_bind(&dst->ps, src->ps); 388 389 /* Vertex constants. 390 * 391 * Various possibilities for optimization here, like creating a per-SB 392 * constant buffer, or memcmp'ing for changes. 393 * Will do that later depending on what works best for specific apps. 394 */ 395 if (1) { 396 memcpy(&dst->vs_const_f[0], 397 &src->vs_const_f[0], VS_CONST_F_SIZE(device)); 398 399 memcpy(dst->vs_const_i, src->vs_const_i, VS_CONST_I_SIZE(device)); 400 memcpy(dst->vs_const_b, src->vs_const_b, VS_CONST_B_SIZE(device)); 401 } 402 403 /* Pixel constants. */ 404 if (1) { 405 struct nine_range *r = help->changed.ps_const_f; 406 memcpy(&dst->ps_const_f[0], 407 &src->ps_const_f[0], (r->end - r->bgn) * 4 * sizeof(float)); 408 409 memcpy(dst->ps_const_i, src->ps_const_i, sizeof(dst->ps_const_i)); 410 memcpy(dst->ps_const_b, src->ps_const_b, sizeof(dst->ps_const_b)); 411 } 412 413 /* Render states. */ 414 memcpy(dst->rs_advertised, src->rs_advertised, sizeof(dst->rs_advertised)); 415 if (apply) 416 memcpy(dst->changed.rs, src->changed.rs, sizeof(dst->changed.rs)); 417 418 419 /* Clip planes. */ 420 memcpy(&dst->clip, &src->clip, sizeof(dst->clip)); 421 if (apply) 422 dst->changed.ucp = src->changed.ucp; 423 424 /* Sampler state. */ 425 memcpy(dst->samp_advertised, src->samp_advertised, sizeof(dst->samp_advertised)); 426 if (apply) 427 memcpy(dst->changed.sampler, 428 src->changed.sampler, sizeof(dst->changed.sampler)); 429 430 /* Index buffer. */ 431 NineStateBlock9_BindBuffer(device, 432 apply, 433 (struct NineBuffer9 **)&dst->idxbuf, 434 (struct NineBuffer9 *)src->idxbuf); 435 436 /* Vertex streams. */ 437 if (1) { 438 for (i = 0; i < ARRAY_SIZE(dst->stream); ++i) { 439 NineStateBlock9_BindBuffer(device, 440 apply, 441 (struct NineBuffer9 **)&dst->stream[i], 442 (struct NineBuffer9 *)src->stream[i]); 443 if (src->stream[i]) { 444 dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset; 445 dst->vtxbuf[i].stride = src->vtxbuf[i].stride; 446 } 447 dst->stream_freq[i] = src->stream_freq[i]; 448 } 449 if (apply) { 450 dst->changed.vtxbuf = (1ULL << MaxStreams) - 1; 451 dst->changed.stream_freq = (1ULL << MaxStreams) - 1; 452 } 453 } 454 455 /* Textures */ 456 if (1) { 457 for (i = 0; i < device->caps.MaxSimultaneousTextures; i++) 458 NineStateBlock9_BindTexture(device, apply, &dst->texture[i], src->texture[i]); 459 } 460 461 /* keep this check in case we want to disable FF */ 462 if (!(help->changed.group & NINE_STATE_FF)) 463 return; 464 WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n"); 465 466 /* Fixed function state. */ 467 dst->ff.material = src->ff.material; 468 469 memcpy(dst->ff.tex_stage, src->ff.tex_stage, sizeof(dst->ff.tex_stage)); 470 if (apply) /* TODO: memset */ 471 memcpy(dst->ff.changed.tex_stage, 472 src->ff.changed.tex_stage, sizeof(dst->ff.changed.tex_stage)); 473 474 /* Lights. */ 475 if (1) { 476 if (dst->ff.num_lights < src->ff.num_lights) { 477 dst->ff.light = REALLOC(dst->ff.light, 478 dst->ff.num_lights * sizeof(D3DLIGHT9), 479 src->ff.num_lights * sizeof(D3DLIGHT9)); 480 dst->ff.num_lights = src->ff.num_lights; 481 } 482 memcpy(dst->ff.light, 483 src->ff.light, src->ff.num_lights * sizeof(dst->ff.light[0])); 484 485 memcpy(dst->ff.active_light, src->ff.active_light, sizeof(src->ff.active_light) ); 486 dst->ff.num_lights_active = src->ff.num_lights_active; 487 } 488 489 /* Transforms. */ 490 if (1) { 491 if (dst->ff.num_transforms < src->ff.num_transforms) { 492 dst->ff.transform = REALLOC(dst->ff.transform, 493 dst->ff.num_transforms * sizeof(dst->ff.transform[0]), 494 src->ff.num_transforms * sizeof(src->ff.transform[0])); 495 dst->ff.num_transforms = src->ff.num_transforms; 496 } 497 memcpy(dst->ff.transform, 498 src->ff.transform, src->ff.num_transforms * sizeof(D3DMATRIX)); 499 if (apply) /* TODO: memset */ 500 memcpy(dst->ff.changed.transform, 501 src->ff.changed.transform, sizeof(dst->ff.changed.transform)); 502 } 503 } 504 505 /* Capture those bits of current device state that have been changed between 506 * BeginStateBlock and EndStateBlock. 507 */ 508 HRESULT NINE_WINAPI 509 NineStateBlock9_Capture( struct NineStateBlock9 *This ) 510 { 511 struct NineDevice9 *device = This->base.device; 512 struct nine_state *dst = &This->state; 513 struct nine_state *src = &device->state; 514 const int MaxStreams = device->caps.MaxStreams; 515 516 DBG("This=%p\n", This); 517 518 if (This->type == NINESBT_ALL) 519 nine_state_copy_common_all(device, dst, src, dst, FALSE, NULL, MaxStreams); 520 else 521 nine_state_copy_common(device, dst, src, dst, FALSE, NULL); 522 523 if (dst->changed.group & NINE_STATE_VDECL) 524 nine_bind(&dst->vdecl, src->vdecl); 525 526 return D3D_OK; 527 } 528 529 /* Set state managed by this StateBlock as current device state. */ 530 HRESULT NINE_WINAPI 531 NineStateBlock9_Apply( struct NineStateBlock9 *This ) 532 { 533 struct NineDevice9 *device = This->base.device; 534 struct nine_state *dst = &device->state; 535 struct nine_state *src = &This->state; 536 struct nine_range_pool *pool = &device->range_pool; 537 const int MaxStreams = device->caps.MaxStreams; 538 539 DBG("This=%p\n", This); 540 541 if (This->type == NINESBT_ALL) 542 nine_state_copy_common_all(device, dst, src, src, TRUE, pool, MaxStreams); 543 else 544 nine_state_copy_common(device, dst, src, src, TRUE, pool); 545 546 nine_context_apply_stateblock(device, src); 547 548 if ((src->changed.group & NINE_STATE_VDECL) && src->vdecl) 549 nine_bind(&dst->vdecl, src->vdecl); 550 551 return D3D_OK; 552 } 553 554 IDirect3DStateBlock9Vtbl NineStateBlock9_vtable = { 555 (void *)NineUnknown_QueryInterface, 556 (void *)NineUnknown_AddRef, 557 (void *)NineUnknown_Release, 558 (void *)NineUnknown_GetDevice, /* actually part of StateBlock9 iface */ 559 (void *)NineStateBlock9_Capture, 560 (void *)NineStateBlock9_Apply 561 }; 562 563 static const GUID *NineStateBlock9_IIDs[] = { 564 &IID_IDirect3DStateBlock9, 565 &IID_IUnknown, 566 NULL 567 }; 568 569 HRESULT 570 NineStateBlock9_new( struct NineDevice9 *pDevice, 571 struct NineStateBlock9 **ppOut, 572 enum nine_stateblock_type type) 573 { 574 NINE_DEVICE_CHILD_NEW(StateBlock9, ppOut, pDevice, type); 575 } 576