概述
hlsl源代码
cbuffer cbPerObject : register(b0)
{
float4x4 gWorld;
};
struct VertexIn
{
float3 PosL : POSITION;
float4 Color : COLOR;
};
struct VertexOut
{
float4 PosH : SV_POSITION;
float4 Color : COLOR;
};
VertexOut VSMain(VertexIn vin)
{
VertexOut vout;
// Transform to homogeneous clip space.
vout.PosH = mul(float4(vin.PosL, 1.0f), gWorld);
// Just pass vertex color into the pixel shader.
vout.Color = vin.Color;
return vout;
}
spirv
省略掉dxil转spirv的过程。生成的spirv如下所示:
; SPIR-V
; Version: 1.3
; Generator: Unknown(30017); 21022
; Bound: 93
; Schema: 0
OpCapability Shader
%66 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %3 "main" %15 %17 %19 %20
OpName %3 "main"
OpName %10 ""
OpName %15 "POSITION"
OpName %17 "COLOR"
OpName %19 "SV_Position"
OpName %20 "COLOR"
OpDecorate %9 ArrayStride 16
OpMemberDecorate %10 0 Offset 0
OpDecorate %10 Block
OpDecorate %12 DescriptorSet 0
OpDecorate %12 Binding 0
OpDecorate %15 Location 0
OpDecorate %17 Location 1
OpDecorate %19 BuiltIn Position
OpDecorate %20 Location 1
%1 = OpTypeVoid
%2 = OpTypeFunction %1
%5 = OpTypeInt 32 0
%6 = OpConstant %5 4
%7 = OpTypeFloat 32
%8 = OpTypeVector %7 4
%9 = OpTypeArray %8 %6
%10 = OpTypeStruct %9
%11 = OpTypePointer Uniform %10
%12 = OpVariable %11 Uniform
%13 = OpTypeVector %7 3
%14 = OpTypePointer Input %13
%15 = OpVariable %14 Input
%16 = OpTypePointer Input %8
%17 = OpVariable %16 Input
%18 = OpTypePointer Output %8
%19 = OpVariable %18 Output
%20 = OpVariable %18 Output
%21 = OpTypePointer Input %7
%23 = OpConstant %5 0
%26 = OpConstant %5 1
%29 = OpConstant %5 2
%32 = OpConstant %5 3
%40 = OpTypePointer Uniform %8
%82 = OpTypePointer Output %7
%3 = OpFunction %1 None %2
%4 = OpLabel
OpBranch %91
%91 = OpLabel
%22 = OpAccessChain %21 %17 %23
%24 = OpLoad %7 %22
%25 = OpAccessChain %21 %17 %26
%27 = OpLoad %7 %25
%28 = OpAccessChain %21 %17 %29
%30 = OpLoad %7 %28
%31 = OpAccessChain %21 %17 %32
%33 = OpLoad %7 %31
%34 = OpAccessChain %21 %15 %23
%35 = OpLoad %7 %34
%36 = OpAccessChain %21 %15 %26
%37 = OpLoad %7 %36
%38 = OpAccessChain %21 %15 %29
%39 = OpLoad %7 %38
%41 = OpAccessChain %40 %12 %23 %23
%42 = OpLoad %8 %41
%43 = OpCompositeExtract %7 %42 0
%44 = OpCompositeExtract %7 %42 1
%45 = OpCompositeExtract %7 %42 2
%46 = OpCompositeExtract %7 %42 3
%47 = OpAccessChain %40 %12 %23 %26
%48 = OpLoad %8 %47
%49 = OpCompositeExtract %7 %48 0
%50 = OpCompositeExtract %7 %48 1
%51 = OpCompositeExtract %7 %48 2
%52 = OpCompositeExtract %7 %48 3
%53 = OpAccessChain %40 %12 %23 %29
%54 = OpLoad %8 %53
%55 = OpCompositeExtract %7 %54 0
%56 = OpCompositeExtract %7 %54 1
%57 = OpCompositeExtract %7 %54 2
%58 = OpCompositeExtract %7 %54 3
%59 = OpAccessChain %40 %12 %23 %32
%60 = OpLoad %8 %59
%61 = OpCompositeExtract %7 %60 0
%62 = OpCompositeExtract %7 %60 1
%63 = OpCompositeExtract %7 %60 2
%64 = OpCompositeExtract %7 %60 3
%65 = OpFMul %7 %43 %35
%67 = OpExtInst %7 %66 Fma %37 %44 %65
%68 = OpExtInst %7 %66 Fma %39 %45 %67
%69 = OpFAdd %7 %68 %46
%70 = OpFMul %7 %49 %35
%71 = OpExtInst %7 %66 Fma %37 %50 %70
%72 = OpExtInst %7 %66 Fma %39 %51 %71
%73 = OpFAdd %7 %72 %52
%74 = OpFMul %7 %55 %35
%75 = OpExtInst %7 %66 Fma %37 %56 %74
%76 = OpExtInst %7 %66 Fma %39 %57 %75
%77 = OpFAdd %7 %76 %58
%78 = OpFMul %7 %61 %35
%79 = OpExtInst %7 %66 Fma %37 %62 %78
%80 = OpExtInst %7 %66 Fma %39 %63 %79
%81 = OpFAdd %7 %80 %64
%83 = OpAccessChain %82 %19 %23
OpStore %83 %69
%84 = OpAccessChain %82 %19 %26
OpStore %84 %73
%85 = OpAccessChain %82 %19 %29
OpStore %85 %77
%86 = OpAccessChain %82 %19 %32
OpStore %86 %81
%87 = OpAccessChain %82 %20 %23
OpStore %87 %24
%88 = OpAccessChain %82 %20 %26
OpStore %88 %27
%89 = OpAccessChain %82 %20 %29
OpStore %89 %30
%90 = OpAccessChain %82 %20 %32
OpStore %90 %33
OpReturn
OpFunctionEnd
nir
在spirv转nir的函数中,可以选择运行的环境,有三个
enum nir_spirv_execution_environment {
NIR_SPIRV_VULKAN = 0,
NIR_SPIRV_OPENCL,
NIR_SPIRV_OPENGL,
};
函数原型
nir_shader *spirv_to_nir(const uint32_t *words, size_t word_count,
struct nir_spirv_specialization *specializations,
unsigned num_specializations,
gl_shader_stage stage, const char *entry_point_name,
const struct spirv_to_nir_options *options,
const nir_shader_compiler_options *nir_options);
如果选择vulkan环境,转换成的nir如下:
shader: MESA_SHADER_VERTEX
source_sha1: {0x9bc7cec5, 0x1e123084, 0x66e529c6, 0xe3ec410e, 0x2a9b196d}
internal: false
stage: 0
next_stage: 0
num_ubos: 1
subgroup_size: 0
inputs: 0
outputs: 0
uniforms: 0
decl_var shader_in INTERP_MODE_NONE none vec3 POSITION (VERT_ATTRIB_GENERIC0.xyz, 0, 0)
decl_var shader_in INTERP_MODE_NONE none vec4 COLOR (VERT_ATTRIB_GENERIC1.xyzw, 0, 0)
decl_var shader_out INTERP_MODE_NONE none vec4 SV_Position (VARYING_SLOT_POS.xyzw, 0, 0)
decl_var shader_out INTERP_MODE_NONE none vec4 COLOR#0 (VARYING_SLOT_VAR1.xyzw, 0, 0)
decl_var ubo INTERP_MODE_NONE none #1 (~0, 0, 0)
decl_function main (0 params)
impl main {
con block b0: // preds:
32 %0 = deref_var &COLOR (shader_in vec4)
32x4 %1 = @load_deref (%0) (access=none)
32 %8 = deref_var &POSITION (shader_in vec3)
32x3 %9 = @load_deref (%8) (access=none)
32 %14 = load_const (0x00000000 = 0.000000)
32x2 %15 = @vulkan_resource_index (%14) (desc_set=0, binding=0, desc_type=UBO)
32x2 %16 = @load_vulkan_descriptor (%15) (desc_type=UBO)
32x2 %17 = deref_cast ( *)%16 (ubo ) (ptr_stride=0, align_mul=0, align_offset=0)
32x2 %18 = deref_struct &%17->field0 (ubo vec4[4]) // &(( *)%16)->field0
32x2 %20 = deref_array &(*%18)[0] (ubo vec4) // &(( *)%16)->field0[0]
32x4 %21 = @load_deref (%20) (access=none)
32 %27 = load_const (0x00000001 = 0.000000)
32x2 %28 = deref_array &(*%18)[1] (ubo vec4) // &(( *)%16)->field0[1]
32x4 %29 = @load_deref (%28) (access=none)
32 %35 = load_const (0x00000002 = 0.000000)
32x2 %36 = deref_array &(*%18)[2] (ubo vec4) // &(( *)%16)->field0[2]
32x4 %37 = @load_deref (%36) (access=none)
32 %43 = load_const (0x00000003 = 0.000000)
32x2 %44 = deref_array &(*%18)[3] (ubo vec4) // &(( *)%16)->field0[3]
32x4 %45 = @load_deref (%44) (access=none)
32 %46 = fmul %21.x, %9.x
32 %47 = ffma %9.y, %21.y, %46
32 %48 = ffma %9.z, %21.z, %47
32 %49 = fadd %48, %21.w
32 %50 = fmul %29.x, %9.x
32 %51 = ffma %9.y, %29.y, %50
32 %52 = ffma %9.z, %29.z, %51
32 %53 = fadd %52, %29.w
32 %54 = fmul %37.x, %9.x
32 %55 = ffma %9.y, %37.y, %54
32 %56 = ffma %9.z, %37.z, %55
32 %57 = fadd %56, %37.w
32 %58 = fmul %45.x, %9.x
32 %59 = ffma %9.y, %45.y, %58
32 %60 = ffma %9.z, %45.z, %59
32 %61 = fadd %60, %45.w
32 %62 = deref_var &SV_Position (shader_out vec4)
32x4 %63 = @load_deref (%62) (access=none)
32x4 %64 = vec4 %49, %63.y, %63.z, %63.w
@store_deref (%62, %64) (wrmask=xyzw, access=none)
32x4 %66 = @load_deref (%62) (access=none)
32x4 %67 = vec4 %66.x, %53, %66.z, %66.w
@store_deref (%62, %67) (wrmask=xyzw, access=none)
32x4 %69 = @load_deref (%62) (access=none)
32x4 %70 = vec4 %69.x, %69.y, %57, %69.w
@store_deref (%62, %70) (wrmask=xyzw, access=none)
32x4 %72 = @load_deref (%62) (access=none)
32x4 %73 = vec4 %72.x, %72.y, %72.z, %61
@store_deref (%62, %73) (wrmask=xyzw, access=none)
32 %74 = deref_var &COLOR#0 (shader_out vec4)
32x4 %75 = @load_deref (%74) (access=none)
32x4 %76 = vec4 %1.x, %75.y, %75.z, %75.w
@store_deref (%74, %76) (wrmask=xyzw, access=none)
32x4 %78 = @load_deref (%74) (access=none)
32x4 %79 = vec4 %78.x, %1.y, %78.z, %78.w
@store_deref (%74, %79) (wrmask=xyzw, access=none)
32x4 %81 = @load_deref (%74) (access=none)
32x4 %82 = vec4 %81.x, %81.y, %1.z, %81.w
@store_deref (%74, %82) (wrmask=xyzw, access=none)
32x4 %84 = @load_deref (%74) (access=none)
32x4 %85 = vec4 %84.x, %84.y, %84.z, %1.w
@store_deref (%74, %85) (wrmask=xyzw, access=none)
return (pass_flags: 0xcd)
// succs: b1
block b1:
}
其中,下面的COLOR 和POSITION ,可以在nir_lower_io() pass中转换为load input
32 %0 = deref_var &COLOR (shader_in vec4)
32x4 %1 = @load_deref (%0) (access=none)
32 %8 = deref_var &POSITION (shader_in vec3)
32x3 %9 = @load_deref (%8) (access=none)
但是后面的ubo该如何去转换?
如果选择opengl环境,转换成的nir如下:
shader: MESA_SHADER_VERTEX
source_sha1: {0x9bc7cec5, 0x1e123084, 0x66e529c6, 0xe3ec410e, 0x2a9b196d}
internal: false
stage: 0
next_stage: 0
num_ubos: 1
subgroup_size: 0
inputs: 0
outputs: 0
uniforms: 0
decl_var shader_in INTERP_MODE_NONE none vec3 POSITION (VERT_ATTRIB_GENERIC0.xyz, 0, 0)
decl_var shader_in INTERP_MODE_NONE none vec4 COLOR (VERT_ATTRIB_GENERIC1.xyzw, 0, 0)
decl_var shader_out INTERP_MODE_NONE none vec4 SV_Position (VARYING_SLOT_POS.xyzw, 0, 0)
decl_var shader_out INTERP_MODE_NONE none vec4 COLOR#0 (VARYING_SLOT_VAR1.xyzw, 0, 0)
decl_var ubo INTERP_MODE_NONE none #1 (~0, 0, 0)
decl_function main (0 params)
impl main {
con block b0: // preds:
32 %0 = deref_var &COLOR (shader_in vec4)
32x4 %1 = @load_deref (%0) (access=none)
32 %8 = deref_var &POSITION (shader_in vec3)
32x3 %9 = @load_deref (%8) (access=none)
32x2 %14 = deref_var  (ubo )
32x2 %15 = deref_struct &%14->field0 (ubo vec4[4]) // .field0
32 %16 = load_const (0x00000000 = 0.000000)
32x2 %17 = deref_array &(*%15)[0] (ubo vec4) // .field0[0]
32x4 %18 = @load_deref (%17) (access=none)
32 %21 = load_const (0x00000001 = 0.000000)
32x2 %22 = deref_array &(*%15)[1] (ubo vec4) // .field0[1]
32x4 %23 = @load_deref (%22) (access=none)
32 %26 = load_const (0x00000002 = 0.000000)
32x2 %27 = deref_array &(*%15)[2] (ubo vec4) // .field0[2]
32x4 %28 = @load_deref (%27) (access=none)
32 %31 = load_const (0x00000003 = 0.000000)
32x2 %32 = deref_array &(*%15)[3] (ubo vec4) // .field0[3]
32x4 %33 = @load_deref (%32) (access=none)
32 %34 = fmul %18.x, %9.x
32 %35 = ffma %9.y, %18.y, %34
32 %36 = ffma %9.z, %18.z, %35
32 %37 = fadd %36, %18.w
32 %38 = fmul %23.x, %9.x
32 %39 = ffma %9.y, %23.y, %38
32 %40 = ffma %9.z, %23.z, %39
32 %41 = fadd %40, %23.w
32 %42 = fmul %28.x, %9.x
32 %43 = ffma %9.y, %28.y, %42
32 %44 = ffma %9.z, %28.z, %43
32 %45 = fadd %44, %28.w
32 %46 = fmul %33.x, %9.x
32 %47 = ffma %9.y, %33.y, %46
32 %48 = ffma %9.z, %33.z, %47
32 %49 = fadd %48, %33.w
32 %50 = deref_var &SV_Position (shader_out vec4)
32x4 %51 = @load_deref (%50) (access=none)
32x4 %52 = vec4 %37, %51.y, %51.z, %51.w
@store_deref (%50, %52) (wrmask=xyzw, access=none)
32x4 %54 = @load_deref (%50) (access=none)
32x4 %55 = vec4 %54.x, %41, %54.z, %54.w
@store_deref (%50, %55) (wrmask=xyzw, access=none)
32x4 %57 = @load_deref (%50) (access=none)
32x4 %58 = vec4 %57.x, %57.y, %45, %57.w
@store_deref (%50, %58) (wrmask=xyzw, access=none)
32x4 %60 = @load_deref (%50) (access=none)
32x4 %61 = vec4 %60.x, %60.y, %60.z, %49
@store_deref (%50, %61) (wrmask=xyzw, access=none)
32 %62 = deref_var &COLOR#0 (shader_out vec4)
32x4 %63 = @load_deref (%62) (access=none)
32x4 %64 = vec4 %1.x, %63.y, %63.z, %63.w
@store_deref (%62, %64) (wrmask=xyzw, access=none)
32x4 %66 = @load_deref (%62) (access=none)
32x4 %67 = vec4 %66.x, %1.y, %66.z, %66.w
@store_deref (%62, %67) (wrmask=xyzw, access=none)
32x4 %69 = @load_deref (%62) (access=none)
32x4 %70 = vec4 %69.x, %69.y, %1.z, %69.w
@store_deref (%62, %70) (wrmask=xyzw, access=none)
32x4 %72 = @load_deref (%62) (access=none)
32x4 %73 = vec4 %72.x, %72.y, %72.z, %1.w
@store_deref (%62, %73) (wrmask=xyzw, access=none)
return (pass_flags: 0xcd)
// succs: b1
block b1:
}
同样的,下面的COLOR 和POSITION ,可以在nir_lower_io() pass中转换为load input
32 %0 = deref_var &COLOR (shader_in vec4)
32x4 %1 = @load_deref (%0) (access=none)
32 %8 = deref_var &POSITION (shader_in vec3)
32x3 %9 = @load_deref (%8) (access=none)
但是后面的ubo该如何去转换?
分析
目前有两种解决方案
使用OpenGL环境
需要调用一个pass
NIR_PASS_V(nir, gl_nir_lower_buffers, prog);
函数实现如下
bool
gl_nir_lower_buffers(nir_shader *shader,
const struct gl_shader_program *shader_program)
{
bool progress = false;
nir_foreach_variable_with_modes(var, shader, nir_var_mem_ubo | nir_var_mem_ssbo) {
var->data.driver_location = -1;
progress = true;
}
/* First, we lower the derefs to turn block variable and array derefs into
* a nir_address_format_32bit_index_offset pointer. From there forward,
* we leave the derefs in place and let nir_lower_explicit_io handle them.
*/
nir_foreach_function_impl(impl, shader) {
if (lower_buffer_interface_derefs_impl(impl, shader_program))
progress = true;
}
/* If that did something, we validate and then call nir_lower_explicit_io
* to finish the process.
*/
if (progress) {
nir_validate_shader(shader, "Lowering buffer interface derefs");
nir_lower_explicit_io(shader, nir_var_mem_ubo | nir_var_mem_ssbo,
nir_address_format_32bit_index_offset);
}
return progress;
}
它可以lower ubo与ssbo,但是它需要gl_shader_program结构,它是mesa编译器编译gl后的一个结构,如果选择该解决方案需要填充该结构。
使用Vulkan环境
需要调用以下代码
NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_ubo | nir_var_mem_ssbo, nir_address_format_32bit_index_offset);
nir_shader_lower_instructions(nir, lower_vulkan_resource_index, lower_vri_instr, 0);
它可以lower ubo与ssbo。
static nir_def *lower_vri_instr(struct nir_builder *b,
nir_instr *instr, void *data_cb)
{
if (instr->type == nir_instr_type_intrinsic) {
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
switch (intrin->intrinsic) {
case nir_intrinsic_vulkan_resource_index:
return lower_vri_intrin_vri(b, instr, data_cb);
case nir_intrinsic_vulkan_resource_reindex:
return lower_vri_intrin_vrri(b, instr, data_cb);
case nir_intrinsic_load_vulkan_descriptor:
return lower_vri_intrin_lvd(b, instr, data_cb);
case nir_intrinsic_get_ssbo_size: {
/* Ignore the offset component. */
b->cursor = nir_before_instr(instr);
nir_def *resource = intrin->src[0].ssa;
nir_src_rewrite(&intrin->src[0], resource);
return NULL;
}
case nir_intrinsic_image_deref_sparse_load:
case nir_intrinsic_image_deref_load:
case nir_intrinsic_image_deref_store:
case nir_intrinsic_image_deref_atomic:
case nir_intrinsic_image_deref_atomic_swap:
case nir_intrinsic_image_deref_size:
case nir_intrinsic_image_deref_samples:
b->cursor = nir_before_instr(instr);
lower_image_intrinsic(b, intrin, data_cb);
return NULL;
default:
return NULL;
}
}
if (instr->type == nir_instr_type_tex) {
b->cursor = nir_before_instr(instr);
lower_vri_instr_tex(b, nir_instr_as_tex(instr), data_cb);
}
return NULL;
}
它可以lower 掉 resource_index 与 vulkan_descriptor,不过在lower的过程中也是需要vulkan的一些结构。
解决
综合考虑下,还是选择vulkan的环境,稍微简单点,而且可以面对各种灵活的转换。
lower后生成的nir如下
shader: MESA_SHADER_VERTEX
source_sha1: {0x9bc7cec5, 0x1e123084, 0x66e529c6, 0xe3ec410e, 0x2a9b196d}
internal: false
stage: 0
next_stage: 0
num_ubos: 1
subgroup_size: 0
inputs: 0
outputs: 0
uniforms: 0
decl_var shader_in INTERP_MODE_NONE none vec3 POSITION (VERT_ATTRIB_GENERIC0.xyz, 0, 0)
decl_var shader_in INTERP_MODE_NONE none vec4 COLOR (VERT_ATTRIB_GENERIC1.xyzw, 0, 0)
decl_var shader_out INTERP_MODE_NONE none vec4 SV_Position (VARYING_SLOT_POS.xyzw, 0, 0)
decl_var shader_out INTERP_MODE_NONE none vec4 COLOR#0 (VARYING_SLOT_VAR1.xyzw, 0, 0)
decl_var ubo INTERP_MODE_NONE none #1 (~0, 0, 0)
decl_function main (0 params)
impl main {
con block b0: // preds:
32 %0 = deref_var &COLOR (shader_in vec4)
32 %1 = load_const (0x00000000 = 0.000000)
32x4 %2 = @load_input (%1) (base=0, range=1, component=0, dest_type=float32, io location=VERT_ATTRIB_GENERIC1 slots=1) // POSITION
32 %3 = deref_var &POSITION (shader_in vec3)
32 %4 = load_const (0x00000000 = 0.000000)
32x3 %5 = @load_input (%4) (base=0, range=1, component=0, dest_type=float32, io location=VERT_ATTRIB_GENERIC0 slots=1) // POSITION
32 %6 = load_const (0x00000000 = 0.000000)
32 %71 = load_const (0x00000000 = 0.000000)
32 %72 = load_const (0x00000001 = 0.000000)
32x3 %73 = vec3 %72, %6, %71
32 %9 = load_const (0x00000010 = 0.000000 = 16)
32 %10 = amul %6, %9
32 %11 = mov %73.y
32 %12 = iadd %11, %10
32x2 %13 = vec2 %73.x, %12
32 %14 = mov %13.x
32 %15 = mov %13.y
32x4 %16 = @load_ubo (%14, %15) (access=none, align_mul=4, align_offset=0, range_base=0, range=16)
32 %17 = load_const (0x00000001 = 0.000000)
32 %18 = load_const (0x00000010 = 0.000000 = 16)
32 %19 = amul %17, %18
32 %20 = mov %73.y
32 %21 = iadd %20, %19
32x2 %22 = vec2 %73.x, %21
32 %23 = mov %22.x
32 %24 = mov %22.y
32x4 %25 = @load_ubo (%23, %24) (access=none, align_mul=4, align_offset=0, range_base=16, range=16)
32 %26 = load_const (0x00000002 = 0.000000)
32 %27 = load_const (0x00000010 = 0.000000 = 16)
32 %28 = amul %26, %27
32 %29 = mov %73.y
32 %30 = iadd %29, %28
32x2 %31 = vec2 %73.x, %30
32 %32 = mov %31.x
32 %33 = mov %31.y
32x4 %34 = @load_ubo (%32, %33) (access=none, align_mul=4, align_offset=0, range_base=32, range=16)
32 %35 = load_const (0x00000003 = 0.000000)
32 %36 = load_const (0x00000010 = 0.000000 = 16)
32 %37 = amul %35, %36
32 %38 = mov %73.y
32 %39 = iadd %38, %37
32x2 %40 = vec2 %73.x, %39
32 %41 = mov %40.x
32 %42 = mov %40.y
32x4 %43 = @load_ubo (%41, %42) (access=none, align_mul=4, align_offset=0, range_base=48, range=16)
32 %44 = fmul %16.x, %5.x
32 %45 = fmul %5.y, %16.y
32 %46 = fadd %45, %44
32 %47 = fmul %5.z, %16.z
32 %48 = fadd %47, %46
32 %49 = fadd %48, %16.w
32 %50 = fmul %25.x, %5.x
32 %51 = fmul %5.y, %25.y
32 %52 = fadd %51, %50
32 %53 = fmul %5.z, %25.z
32 %54 = fadd %53, %52
32 %55 = fadd %54, %25.w
32 %56 = fmul %34.x, %5.x
32 %57 = fmul %5.y, %34.y
32 %58 = fadd %57, %56
32 %59 = fmul %5.z, %34.z
32 %60 = fadd %59, %58
32 %61 = fadd %60, %34.w
32 %62 = fmul %43.x, %5.x
32 %63 = fmul %5.y, %43.y
32 %64 = fadd %63, %62
32 %65 = fmul %5.z, %43.z
32 %66 = fadd %65, %64
32 %67 = fadd %66, %43.w
32 %68 = deref_var &SV_Position (shader_out vec4)
32x4 %69 = vec4 %49, %55, %61, %67
@store_deref (%68, %69) (wrmask=xyzw, access=none)
32 %70 = deref_var &COLOR#0 (shader_out vec4)
@store_deref (%70, %2) (wrmask=xyzw, access=none)
return (pass_flags: 0xcd)
// succs: b1
block b1:
}