Important
There is another bytecode format used in Destiny that looks a lot like this one, but is mostly unrelated to TFX bytecode
Opcode | Name | Arguments | Pop count | Operation | Notes |
---|---|---|---|---|---|
0x01 |
add | 2 | push(t1 + t0 ) |
||
0x02 |
subtract | 2 | push(t1 - t0 ) |
||
0x03 |
multiply | 2 | push(t1 * t0 ) |
||
0x04 |
divide | 2 | push(t1 / t0 ) |
||
0x05 |
multiply2 | 2 | push(t1 * t0 ) |
Exactly the same as normal multiply | |
0x06 |
add2 | 2 | push(t1 + t0 ) |
Exactly the same as normal add | |
0x07 |
is_zero | 2 | push(t0 == float4(0) ) |
Sets each element that is zero to 1 | |
0x08 |
min | 2 | push(min(t1, t0) ) |
||
0x09 |
max | 2 | push(max(t1, t0) ) |
||
0x0a |
less_than | 2 | push(t0 < t1 ) |
||
0x0b |
dot | 2 | push(dot(t1, t0) ) |
||
0x0c |
merge1_3 | 2 | push(float4(t1.x, t0.xyz) ) |
||
0x0d |
merge2_2 | 2 | push(float4(t1.xy, t0.xy) ) |
||
0x0e |
unk0e | ||||
0x0f |
unk0f | ||||
0x10 |
lerp | 3 | push(lerp(t2, t1, t0) ) |
||
0x11 |
lerp_saturated | push(saturate(lerp(t2, t1, t0)) ) |
|||
0x12 |
multiply_add | 3 | push(t1 * t2 + t0 ) |
||
0x13 |
clamp | 3 | push(clamp(t2, t1, t0) ) |
||
0x14 |
unk14 | ||||
0x15 |
abs | 1 | push(abs(t0) ) |
||
0x16 |
signum | 1 | push(sign(t0) ) |
||
0x17 |
floor | 1 | push(floor(t0) ) |
||
0x18 |
ceil | 1 | push(ceil(t0) ) |
||
0x19 |
round | 1 | push(round(t0) ) |
||
0x1a |
frac | 1 | push(frac(t0) ) |
||
0x1b |
unk1b | ||||
0x1c |
unk1c | ||||
0x1d |
negate | 1 | push(-t0 ) |
||
0x1e |
vector_rotations_sin | 1 | push(_trig_helper_vector_sin_rotations_estimate(t0) ) |
See below for implementation | |
0x1f |
vector_rotations_cos | 1 | push(_trig_helper_vector_cos_rotations_estimate(t0) ) |
See below for implementation | |
0x20 |
vector_rotations_sin_cos | 1 | push(_trig_helper_vector_sin_cos_rotations_estimate(t0) ) |
See below for implementation | |
0x21 |
permute_extend_x | 1 | push(v.xxxx ) |
Same as permute 0b00_00_00_00 |
|
0x22 |
permute | fields | 1 | push(v.???? ) |
fields is a bitfield specifying the swizzle patterns, 2 bits per element, starting with the MSB |
0x23 |
saturate | 1 | push(saturate(t0) ) |
||
0x24 |
unk24 | ||||
0x25 |
unk25 | ||||
0x26 |
unk26 | ||||
0x27 |
triangle | 1 | push(triangle(t0) ) |
See below for implementation | |
0x28 |
jitter | 1 | push(jitter(t0) ) |
See below for implementation | |
0x29 |
wander | 1 | push(wander(t0) ) |
See below for implementation | |
0x2a |
rand | 1 | push(rand(t0) ) |
See below for implementation | |
0x2b |
rand_smooth | 1 | push(rand_smooth(t0) ) |
See below for implementation | |
0x2c |
unk2c | ||||
0x2d |
unk2d | ||||
0x2e |
transform_vec4 | 5 | push(mul(t0, float4x4(t1, t2, t3, t4)) ) |
Order of the matrix depends on how you push it | |
0x34 |
push_const_vec4 | constant_index | 0 | push(constants[constant_index] ) |
|
0x35 |
lerp_constant | constant_start | 1 | push(lerp(constants[constant_start], constants[constant_start+1], t0) ) |
|
0x36 |
lerp_constant_saturated | constant_start | 1 | push(saturate(lerp(constants[constant_start], constants[constant_start+1], t0)) ) |
|
0x37 |
unk37 | unk1 | |||
0x38 |
unk38 | unk1 | |||
0x39 |
unk39 | unk1 | |||
0x3a |
unk3a | unk1 | |||
0x3b |
unk_load_constant | constant,_index | 0 | ||
0x3c |
push_extern_input_float | extern, offset | 0 | push(get_extern<float>(stack, extern, offset*4) ) |
(offset is in bytes) |
0x3d |
push_extern_input_vec4 | extern, offset | 0 | push(get_extern<float4>(stack, extern, offset*16) ) |
(offset is in bytes) |
0x3e |
push_extern_input_mat4 | extern, offset | 0 | push(get_extern<float4x4>(stack, extern, offset*16) ) |
(offset is in bytes) |
0x3f |
push_extern_input_u64 | extern, offset | 0 | push(get_extern<u64>(stack, extern, offset*8) ) |
Used for shader resource handles in DX11 (offset is in bytes) |
0x40 |
push_extern_input_u32 | extern, offset | 0 | push(get_extern<u32>(stack, extern, offset*4) ) |
(offset is in bytes) |
0x41 |
push_extern_input_u64_unknown | extern, offset | 0 | push(get_extern<u64>(stack, extern, offset*8) ) |
(offset is in bytes) |
0x42 |
unk42 | ||||
0x43 |
push_from_output | element | 0 | push(cbuffer[element] ) |
|
0x44 |
pop_output | element | 1 | cbuffer[element] = t0 |
Cbuffer is an array of float4's |
0x45 |
pop_output_mat4 | element | 4 | cbuffer[element..element+4] = [t0, t1, t2, t3] |
|
0x46 |
push_temp | slot | 0 | push(temp[slot] ) |
|
0x47 |
pop_temp | slot | 1 | temp[slot] = t0 |
|
0x48 |
set_shader_resource | value | value is ttttsssss , where t is a TfxShaderStage , and s the assignment slot |
||
0x49 |
unk49 | unk1 | |||
0x4a |
set_shader_sampler | value | See set_shader_resource for decoding the value |
||
0x4b |
unk4b | unk1 | |||
0x4c |
unk4c | unk1 | |||
0x4d |
push_sampler | index | push(technique_samplers[index] ) |
||
0x4e |
unk4e | unk1, unk2, unk3, unk4 | |||
0x4f |
unk4f | unk1 | |||
0x50 |
unk50 | unk1 | |||
0x51 |
unk51 | ||||
0x52 |
unk52 | unk1, unk2 | |||
0x53 |
unk53 | unk1, unk2 | |||
0x54 |
unk54 | unk1, unk2 | |||
0x55 |
unk55 | ||||
0x56 |
unk56 | ||||
0x57 |
unk57 | ||||
0x58 |
unk58 |