Difference between revisions of "NV2A/Pixel Combiner"
(Found another nvidia mirror for BRDFs.pdf; added to archive.org) |
|||
| (14 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
== Data types == | == Data types == | ||
| Line 11: | Line 5: | ||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! floating-point !! 8-bit fixed-point !! 9-bit fixed-point !! 16 bit fixed-point | + | ! floating-point !! 8-bit fixed-point !! 9-bit fixed-point !! 16-bit fixed-point |
|- | |- | ||
| 1.0 || n/a || 255 || n/a | | 1.0 || n/a || 255 || n/a | ||
| Line 26: | Line 20: | ||
|} | |} | ||
| − | == Texturing modes == | + | This means: |
| + | |||
| + | * 8-bit fixed-point: [-128, 127] → [-128/128, 127/128] → [-1.0, 0.99218...] | ||
| + | * 9-bit fixed-point: [-256, 255] → [-256/255, 255/255] → [-1.00392..., 1.0] | ||
| + | * 16-bit fixed-point: [-32768, 32767] → [-32768/32768, 32767/32768] → [-1.0, 0.99996...] | ||
| + | |||
| + | It is not known if the NV2A really implements these 3 datatypes. | ||
| + | It is also not yet known how exactly conversion or negation of these types would work. | ||
| + | |||
| + | == Texture Shaders == | ||
| + | |||
| + | The NV2A implements at least parts of the following OpenGL extensions: | ||
| + | |||
| + | * [https://www.khronos.org/registry/OpenGL/extensions/NV/NV_texture_shader.txt NV_texture_shader] | ||
| + | * [https://www.khronos.org/registry/OpenGL/extensions/NV/NV_texture_shader2.txt NV_texture_shader2] | ||
| + | * [https://www.khronos.org/registry/OpenGL/extensions/NV/NV_texture_shader3.txt NV_texture_shader3]{{citation needed}} | ||
| + | |||
| + | === Texturing modes === | ||
{|class="wikitable" | {|class="wikitable" | ||
!ID | !ID | ||
!Name | !Name | ||
| + | !D3D name | ||
!GL Name | !GL Name | ||
!Stage 1 | !Stage 1 | ||
| Line 39: | Line 51: | ||
|- | |- | ||
|0x00 | |0x00 | ||
| − | |PS_TEXTUREMODES_NONE | + | |PS_TEXTUREMODES_NONE |
| + | | | ||
|NONE | |NONE | ||
|{{yes}} | |{{yes}} | ||
| Line 48: | Line 61: | ||
|- | |- | ||
|0x01 | |0x01 | ||
| − | |PS_TEXTUREMODES_PROJECT2D | + | |PS_TEXTUREMODES_PROJECT2D |
| + | |tex | ||
|TEXTURE_2D | |TEXTURE_2D | ||
|{{yes}} | |{{yes}} | ||
| Line 58: | Line 72: | ||
|0x02 | |0x02 | ||
|PS_TEXTUREMODES_PROJECT3D | |PS_TEXTUREMODES_PROJECT3D | ||
| + | |tex | ||
|TEXTURE_3D | |TEXTURE_3D | ||
|{{yes}} | |{{yes}} | ||
| Line 67: | Line 82: | ||
|0x03 | |0x03 | ||
|PS_TEXTUREMODES_CUBEMAP | |PS_TEXTUREMODES_CUBEMAP | ||
| + | |tex | ||
|TEXTURE_CUBE_MAP_ARB | |TEXTURE_CUBE_MAP_ARB | ||
|{{yes}} | |{{yes}} | ||
| Line 75: | Line 91: | ||
|- | |- | ||
|0x04 | |0x04 | ||
| − | |PS_TEXTUREMODES_PASSTHRU | + | |PS_TEXTUREMODES_PASSTHRU |
| + | |texcoord | ||
|PASS_THROUGH_NV | |PASS_THROUGH_NV | ||
|{{yes}} | |{{yes}} | ||
| Line 84: | Line 101: | ||
|- | |- | ||
|0x05 | |0x05 | ||
| − | |PS_TEXTUREMODES_CLIPPLANE | + | |PS_TEXTUREMODES_CLIPPLANE |
| + | |texkill | ||
|CULL_FRAGMENT_NV | |CULL_FRAGMENT_NV | ||
|{{yes}} | |{{yes}} | ||
| Line 93: | Line 111: | ||
|- | |- | ||
|0x06 | |0x06 | ||
| − | |PS_TEXTUREMODES_BUMPENVMAP | + | |PS_TEXTUREMODES_BUMPENVMAP |
| + | |texbem | ||
|OFFSET_TEXTURE_2D_NV | |OFFSET_TEXTURE_2D_NV | ||
|{{no}} | |{{no}} | ||
| Line 102: | Line 121: | ||
|- | |- | ||
|0x07 | |0x07 | ||
| − | |PS_TEXTUREMODES_BUMPENVMAP_LUM | + | |PS_TEXTUREMODES_BUMPENVMAP_LUM |
| + | |texbeml | ||
|OFFSET_TEXTURE_2D_SCALE_NV | |OFFSET_TEXTURE_2D_SCALE_NV | ||
|{{no}} | |{{no}} | ||
| Line 111: | Line 131: | ||
|- | |- | ||
|0x08 | |0x08 | ||
| − | |PS_TEXTUREMODES_BRDF | + | |PS_TEXTUREMODES_BRDF |
| + | |texbrdf | ||
| | | | ||
|{{no}} | |{{no}} | ||
| Line 120: | Line 141: | ||
|- | |- | ||
|0x09 | |0x09 | ||
| − | |PS_TEXTUREMODES_DOT_ST | + | |PS_TEXTUREMODES_DOT_ST |
| − | | | + | |texm3x2tex |
| + | |DOT_PRODUCT_TEXTURE_2D_NV | ||
|{{no}} | |{{no}} | ||
|{{no}} | |{{no}} | ||
| Line 129: | Line 151: | ||
|- | |- | ||
|0x0A | |0x0A | ||
| − | |PS_TEXTUREMODES_DOT_ZW | + | |PS_TEXTUREMODES_DOT_ZW |
| − | | | + | |texm3x2depth |
| + | |DOT_PRODUCT_DEPTH_REPLACE_NV | ||
|{{no}} | |{{no}} | ||
|{{no}} | |{{no}} | ||
| Line 139: | Line 162: | ||
|0x0B | |0x0B | ||
|PS_TEXTUREMODES_DOT_RFLCT_DIFF | |PS_TEXTUREMODES_DOT_RFLCT_DIFF | ||
| + | |texm3x3diff | ||
|DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV{{citation needed}} | |DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV{{citation needed}} | ||
|{{no}} | |{{no}} | ||
| Line 148: | Line 172: | ||
|0x0C | |0x0C | ||
|PS_TEXTUREMODES_DOT_RFLCT_SPEC | |PS_TEXTUREMODES_DOT_RFLCT_SPEC | ||
| − | |DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV | + | |texm3x3vspec |
| + | |DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV | ||
|{{no}} | |{{no}} | ||
|{{no}} | |{{no}} | ||
| Line 157: | Line 182: | ||
|0x0D | |0x0D | ||
|PS_TEXTUREMODES_DOT_STR_3D | |PS_TEXTUREMODES_DOT_STR_3D | ||
| + | |texm3x3tex | ||
|DOT_PRODUCT_TEXTURE_3D_NV | |DOT_PRODUCT_TEXTURE_3D_NV | ||
|{{no}} | |{{no}} | ||
| Line 166: | Line 192: | ||
|0x0E | |0x0E | ||
|PS_TEXTUREMODES_DOT_STR_CUBE | |PS_TEXTUREMODES_DOT_STR_CUBE | ||
| + | |texm3x3vspec | ||
|DOT_PRODUCT_REFLECT_CUBE_MAP_NV | |DOT_PRODUCT_REFLECT_CUBE_MAP_NV | ||
|{{no}} | |{{no}} | ||
| Line 174: | Line 201: | ||
|- | |- | ||
|0x0F | |0x0F | ||
| − | |PS_TEXTUREMODES_DPNDNT_AR | + | |PS_TEXTUREMODES_DPNDNT_AR |
| + | |texreg2ar | ||
|DEPENDENT_AR_TEXTURE_2D_NV | |DEPENDENT_AR_TEXTURE_2D_NV | ||
|{{no}} | |{{no}} | ||
| Line 183: | Line 211: | ||
|- | |- | ||
|0x10 | |0x10 | ||
| − | |PS_TEXTUREMODES_DPNDNT_GB | + | |PS_TEXTUREMODES_DPNDNT_GB |
| + | |texreg2gb | ||
|DEPENDENT_GB_TEXTURE_2D_NV | |DEPENDENT_GB_TEXTURE_2D_NV | ||
|{{no}} | |{{no}} | ||
| Line 193: | Line 222: | ||
|0x11 | |0x11 | ||
|PS_TEXTUREMODES_DOTPRODUCT | |PS_TEXTUREMODES_DOTPRODUCT | ||
| + | |texm3x3pad<br>texm3x2pad | ||
|DOT_PRODUCT_NV | |DOT_PRODUCT_NV | ||
|{{no}} | |{{no}} | ||
| Line 202: | Line 232: | ||
|0x12 | |0x12 | ||
|PS_TEXTUREMODES_DOT_RFLCT_SPEC_CONST | |PS_TEXTUREMODES_DOT_RFLCT_SPEC_CONST | ||
| + | |texm3x3spec | ||
|DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV | |DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV | ||
|{{no}} | |{{no}} | ||
| Line 210: | Line 241: | ||
|} | |} | ||
| − | + | === 0x08: PS_TEXTUREMODES_BRDF / texbrdf === | |
| − | * | + | |
| − | * | + | The BRDF texture shader is probably only exposed on original Xbox, but not in standard OpenGL or D3D drivers. |
| − | * | + | |
| − | * | + | These are some generic resources about BRDFs: |
| + | |||
| + | * [http://www.disneyanimation.com/technology/brdf.html Walt Disney BRDF Explorer] | ||
| + | * [https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf Walt Disney BRDF Paper] | ||
| + | * [https://math.nist.gov/~FHunt/appearance/brdf.html Collection of BRDF information] | ||
| + | * [http://www-graphics.stanford.edu/~smr/brdf/bv/ BRDF viewer]{{FIXME|reason=Find alternative; this one is hard to compile}} | ||
| + | * [https://www.merl.com/brdf/ BRDF Database by Mitsubishi] | ||
| + | |||
| + | * nvidia resources ''(The code and technique is probably not using the texture shader that is described here)'': | ||
| + | |||
| + | ** [https://web.archive.org/web/20200506033455/http://developer.download.nvidia.com/assets/gamedev/docs/BRDFs.pdf BRDFs.pdf] / [http://www.nvidia.in/attach/6669 BRDFs.ppt]{{FIXME|reason=URL dead; not in archive.org!}} | ||
| + | ** [https://web.archive.org/web/20191214200801/https://www.nvidia.com/attach/6568 BRDFIntro.pdf] / [https://web.archive.org/web/20191214200809/https://www.nvidia.com/attach/6569 BRDFIntro.doc] | ||
| + | ** [https://web.archive.org/web/20191214200757/https://www.nvidia.com/attach/6567 BRDFSeparable.pdf] / [https://web.archive.org/web/20191214200753/https://www.nvidia.com/attach/6566 BRDFSeparable.doc] | ||
| + | ** [https://web.archive.org/web/20191214200813/https://www.nvidia.com/attach/6570 brdfseparate.zip] | ||
| + | ** [https://web.archive.org/web/20191214200819/https://www.nvidia.com/attach/6571 brdfview.zip] | ||
| + | |||
| + | {{FIXME|reason=Describe Xbox specific BRDF texture shader}} | ||
| + | |||
| + | == Register combiners == | ||
| + | |||
| + | The NV2A implements at least parts of the following OpenGL extensions: | ||
| + | |||
| + | * [https://www.opengl.org/registry/specs/NV/register_combiners.txt NV_register_combiners] | ||
| + | * [https://www.opengl.org/registry/specs/NV/register_combiners2.txt NV_register_combiners2] | ||
| + | |||
| + | There's some additional features and oddities. | ||
| + | |||
| + | === DISCARD and ZERO are the same register === | ||
| + | |||
| + | On NV2A the DISCARD and ZERO register are the same index: writes are discarded / reads return zero. | ||
| + | |||
| + | This is different from NV_register_combiners where 2 different constants are used. | ||
| + | |||
| + | === Encoding of input swizzle === | ||
| + | |||
| + | NV2A uses a single ALPHA flag to specify the swizzle of inputs: | ||
| + | * 0 for <code>.rgb</code> (RGB portion only) and <code>.b</code> (ALPHA portion only). | ||
| + | * 1 for <code>.aaa</code> (RGB portion only) and <code>.a</code> (ALPHA portion only). | ||
| + | |||
| + | This is different from NV_register_combiners where each swizzle has its own constant. | ||
| + | |||
| + | === Per stage constant-colors === | ||
| + | |||
| + | The combiner setup switches between using the same <code>const0</code> and <code>const1</code> for all stages (<code>FACTOR#_SAME_FACTOR_ALL</code>), or using different constant-colors per stage (<code>FACTOR#_EACH_STAGE</code>). | ||
| + | |||
| + | On NV2A, the final-combiner does always have unique constants (even using <code>FACTOR#_SAME_FACTOR_ALL</code>) from all other stages. | ||
| + | If <code>FACTOR#_SAME_FACTOR_ALL</code> is used, the constant-colors for all other stages are taken from the very first stage. | ||
| + | This setting can be controlled independently for <code>const0</code> and <code>const1</code>. | ||
| + | |||
| + | This is different from NV_register_combiners2. If that GL extension isn't available / enabled, then the constants are shared between general combiner stages and the final combiner (which doesn't have unique colors then). Additionally, the GL extension can only control this for both constant-colors at the same time. | ||
| + | |||
| + | === Encoding of constant-colors === | ||
| + | |||
| + | On NV2A, the constant-colors are encoded as 8-bit unsigned int values, packed into a 32-bit ARGB value (<code>(a<<24 | r<<16 | g<<8 | b)</code>). | ||
| + | |||
| + | This is different from NV_register_combiners where constant-colors are specified as floats in RGBA format. | ||
| + | |||
| + | === BLUETOALPHA in RGB portion === | ||
| + | |||
| + | NV2A has a special flag to write the blue result (RGB portion) of the A/B and C/D computations to the alpha channel of the RGB portion output register. There's no such option for the AB/CD result. | ||
| + | {{FIXME|reason=Document specifics, tests proposed on https://github.com/JayFoxRox/nxdk/pull/33}} | ||
| + | |||
| + | This feature isn't available in GL, probably. | ||
| + | This is different from NV_register_combiners where the RGB portion always writes to <code>.rgb</code> of the output. | ||
| + | |||
| + | === Special "or" operation (MUX) modifier === | ||
| + | |||
| + | NV2A has a special flag to switch between MSB and LSB{{FIXME|reason=Unconfirmed / untested - doesn't make a lot of sense}} for the special "or" operation (MUX). | ||
| + | {{FIXME|reason=Check the comparison type}} | ||
| + | |||
| + | This feature isn't available in GL, probably. | ||
| + | This is different from NV_register_combiners where the special "or" operation (MUX) is always doing: <code>spare0_alpha >= 0.5 ? C*D : A*B</code>. | ||
== Debugging == | == Debugging == | ||
| Line 220: | Line 322: | ||
PIX from the Microsoft XDK provides great debugging capabilities. | PIX from the Microsoft XDK provides great debugging capabilities. | ||
| − | == References and links == | + | === References and links === |
| + | * [http://developer.download.nvidia.com/assets/gamedev/docs/ProgrammableTextureBlending.pdf Overview about programmable texture blending] <!-- Mirror: https://www.nvidia.com/object/programmable_texture_blending.html --> | ||
| + | * [http://developer.download.nvidia.com/assets/gamedev/docs/combiners.pdf Overview of register combiners] | ||
| + | * [https://github.com/XboxDev/nxdk/blob/77b5de45f0c64e70f2ff68248873448d5edccc71/tools/fp20compiler/ps1.0_program.cpp#L227 Code from nvparse (NVIDIA SDK 9.52) in nxdk, which handles shader to OpenGL conversion] | ||
* http://developer.download.nvidia.com/assets/gamedev/docs/GDC2K1_DX8_Pixel_Shaders.pdf | * http://developer.download.nvidia.com/assets/gamedev/docs/GDC2K1_DX8_Pixel_Shaders.pdf | ||
| − | + | ||
| + | [[Category:NV2A]] | ||
Latest revision as of 03:37, 6 May 2020
Data types
NV_texture_shader suggests that: "The 8-bit and 16-bit signed fixed-point types are used for signed internal texture formats, while the 9-bit signed fixed-point type is used for register combiners computations." Here is a table from the GL extension:
| floating-point | 8-bit fixed-point | 9-bit fixed-point | 16-bit fixed-point |
|---|---|---|---|
| 1.0 | n/a | 255 | n/a |
| 0.99996... | n/a | n/a | 32767 |
| 0.99218... | 127 | n/a | n/a |
| 0.0 | 0 | 0 | 0 |
| -1.0 | -128 | -255 | -32768 |
| -1.00392... | n/a | -256 | n/a |
This means:
- 8-bit fixed-point: [-128, 127] → [-128/128, 127/128] → [-1.0, 0.99218...]
- 9-bit fixed-point: [-256, 255] → [-256/255, 255/255] → [-1.00392..., 1.0]
- 16-bit fixed-point: [-32768, 32767] → [-32768/32768, 32767/32768] → [-1.0, 0.99996...]
It is not known if the NV2A really implements these 3 datatypes. It is also not yet known how exactly conversion or negation of these types would work.
Texture Shaders
The NV2A implements at least parts of the following OpenGL extensions:
Texturing modes
| ID | Name | D3D name | GL Name | Stage 1 | Stage 2 | Stage 3 | Stage 4 | Notes |
|---|---|---|---|---|---|---|---|---|
| 0x00 | PS_TEXTUREMODES_NONE | NONE | ✔ | ✔ | ✔ | ✔ | ||
| 0x01 | PS_TEXTUREMODES_PROJECT2D | tex | TEXTURE_2D | ✔ | ✔ | ✔ | ✔ | |
| 0x02 | PS_TEXTUREMODES_PROJECT3D | tex | TEXTURE_3D | ✔ | ✔ | ✔ | ✔ | |
| 0x03 | PS_TEXTUREMODES_CUBEMAP | tex | TEXTURE_CUBE_MAP_ARB | ✔ | ✔ | ✔ | ✔ | |
| 0x04 | PS_TEXTUREMODES_PASSTHRU | texcoord | PASS_THROUGH_NV | ✔ | ✔ | ✔ | ✔ | |
| 0x05 | PS_TEXTUREMODES_CLIPPLANE | texkill | CULL_FRAGMENT_NV | ✔ | ✔ | ✔ | ✔ | |
| 0x06 | PS_TEXTUREMODES_BUMPENVMAP | texbem | OFFSET_TEXTURE_2D_NV | ✗ | ✔ | ✔ | ✔ | |
| 0x07 | PS_TEXTUREMODES_BUMPENVMAP_LUM | texbeml | OFFSET_TEXTURE_2D_SCALE_NV | ✗ | ✔ | ✔ | ✔ | |
| 0x08 | PS_TEXTUREMODES_BRDF | texbrdf | ✗ | ✗ | ✔ | ✔ | ||
| 0x09 | PS_TEXTUREMODES_DOT_ST | texm3x2tex | DOT_PRODUCT_TEXTURE_2D_NV | ✗ | ✗ | ✔ | ✔ | |
| 0x0A | PS_TEXTUREMODES_DOT_ZW | texm3x2depth | DOT_PRODUCT_DEPTH_REPLACE_NV | ✗ | ✗ | ✔ | ✔ | |
| 0x0B | PS_TEXTUREMODES_DOT_RFLCT_DIFF | texm3x3diff | DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV[citation needed] | ✗ | ✗ | ✔ | ✗ | |
| 0x0C | PS_TEXTUREMODES_DOT_RFLCT_SPEC | texm3x3vspec | DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV | ✗ | ✗ | ✗ | ✔ | |
| 0x0D | PS_TEXTUREMODES_DOT_STR_3D | texm3x3tex | DOT_PRODUCT_TEXTURE_3D_NV | ✗ | ✗ | ✗ | ✔ | |
| 0x0E | PS_TEXTUREMODES_DOT_STR_CUBE | texm3x3vspec | DOT_PRODUCT_REFLECT_CUBE_MAP_NV | ✗ | ✗ | ✗ | ✔ | |
| 0x0F | PS_TEXTUREMODES_DPNDNT_AR | texreg2ar | DEPENDENT_AR_TEXTURE_2D_NV | ✗ | ✔ | ✔ | ✔ | |
| 0x10 | PS_TEXTUREMODES_DPNDNT_GB | texreg2gb | DEPENDENT_GB_TEXTURE_2D_NV | ✗ | ✔ | ✔ | ✔ | |
| 0x11 | PS_TEXTUREMODES_DOTPRODUCT | texm3x3pad texm3x2pad |
DOT_PRODUCT_NV | ✗ | ✔ | ✔ | ✗ | |
| 0x12 | PS_TEXTUREMODES_DOT_RFLCT_SPEC_CONST | texm3x3spec | DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV | ✗ | ✗ | ✗ | ✔ |
0x08: PS_TEXTUREMODES_BRDF / texbrdf
The BRDF texture shader is probably only exposed on original Xbox, but not in standard OpenGL or D3D drivers.
These are some generic resources about BRDFs:
- Walt Disney BRDF Explorer
- Walt Disney BRDF Paper
- Collection of BRDF information
- BRDF viewer[FIXME]
- BRDF Database by Mitsubishi
- nvidia resources (The code and technique is probably not using the texture shader that is described here):
[FIXME]
Register combiners
The NV2A implements at least parts of the following OpenGL extensions:
There's some additional features and oddities.
DISCARD and ZERO are the same register
On NV2A the DISCARD and ZERO register are the same index: writes are discarded / reads return zero.
This is different from NV_register_combiners where 2 different constants are used.
Encoding of input swizzle
NV2A uses a single ALPHA flag to specify the swizzle of inputs:
- 0 for
.rgb(RGB portion only) and.b(ALPHA portion only). - 1 for
.aaa(RGB portion only) and.a(ALPHA portion only).
This is different from NV_register_combiners where each swizzle has its own constant.
Per stage constant-colors
The combiner setup switches between using the same const0 and const1 for all stages (FACTOR#_SAME_FACTOR_ALL), or using different constant-colors per stage (FACTOR#_EACH_STAGE).
On NV2A, the final-combiner does always have unique constants (even using FACTOR#_SAME_FACTOR_ALL) from all other stages.
If FACTOR#_SAME_FACTOR_ALL is used, the constant-colors for all other stages are taken from the very first stage.
This setting can be controlled independently for const0 and const1.
This is different from NV_register_combiners2. If that GL extension isn't available / enabled, then the constants are shared between general combiner stages and the final combiner (which doesn't have unique colors then). Additionally, the GL extension can only control this for both constant-colors at the same time.
Encoding of constant-colors
On NV2A, the constant-colors are encoded as 8-bit unsigned int values, packed into a 32-bit ARGB value ((a<<24 | r<<16 | g<<8 | b)).
This is different from NV_register_combiners where constant-colors are specified as floats in RGBA format.
BLUETOALPHA in RGB portion
NV2A has a special flag to write the blue result (RGB portion) of the A/B and C/D computations to the alpha channel of the RGB portion output register. There's no such option for the AB/CD result. [FIXME]
This feature isn't available in GL, probably.
This is different from NV_register_combiners where the RGB portion always writes to .rgb of the output.
Special "or" operation (MUX) modifier
NV2A has a special flag to switch between MSB and LSB[FIXME] for the special "or" operation (MUX). [FIXME]
This feature isn't available in GL, probably.
This is different from NV_register_combiners where the special "or" operation (MUX) is always doing: spare0_alpha >= 0.5 ? C*D : A*B.
Debugging
PIX from the Microsoft XDK provides great debugging capabilities.