[Vulkan] Rectangle and quad list geometry shader generation

This commit is contained in:
Triang3l 2022-05-10 21:48:18 +03:00
parent b9256fcdbd
commit 73d574a046
8 changed files with 846 additions and 608 deletions

View File

@ -1,391 +0,0 @@
// Generated with `xb buildshaders`.
#if 0
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 10
; Bound: 24886
; Schema: 0
OpCapability Geometry
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %5663 "main" %5305 %3631 %3144 %4930
OpExecutionMode %5663 Triangles
OpExecutionMode %5663 Invocations 1
OpExecutionMode %5663 OutputTriangleStrip
OpExecutionMode %5663 OutputVertices 6
OpMemberDecorate %_struct_1017 0 BuiltIn Position
OpDecorate %_struct_1017 Block
OpDecorate %3631 Location 0
OpDecorate %3144 Location 0
OpMemberDecorate %_struct_1018 0 BuiltIn Position
OpDecorate %_struct_1018 Block
OpDecorate %7509 NoContraction
OpDecorate %15269 NoContraction
OpDecorate %24885 NoContraction
OpDecorate %14166 NoContraction
OpDecorate %7062 NoContraction
%void = OpTypeVoid
%1282 = OpTypeFunction %void
%bool = OpTypeBool
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_struct_1017 = OpTypeStruct %v4float
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%_arr__struct_1017_uint_3 = OpTypeArray %_struct_1017 %uint_3
%_ptr_Input__arr__struct_1017_uint_3 = OpTypePointer Input %_arr__struct_1017_uint_3
%5305 = OpVariable %_ptr_Input__arr__struct_1017_uint_3 Input
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Input_v4float = OpTypePointer Input %v4float
%v4bool = OpTypeVector %bool 4
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%uint_0 = OpConstant %uint 0
%uint_16 = OpConstant %uint 16
%_arr_v4float_uint_16 = OpTypeArray %v4float %uint_16
%_ptr_Output__arr_v4float_uint_16 = OpTypePointer Output %_arr_v4float_uint_16
%3631 = OpVariable %_ptr_Output__arr_v4float_uint_16 Output
%_arr__arr_v4float_uint_16_uint_3 = OpTypeArray %_arr_v4float_uint_16 %uint_3
%_ptr_Input__arr__arr_v4float_uint_16_uint_3 = OpTypePointer Input %_arr__arr_v4float_uint_16_uint_3
%3144 = OpVariable %_ptr_Input__arr__arr_v4float_uint_16_uint_3 Input
%_ptr_Input__arr_v4float_uint_16 = OpTypePointer Input %_arr_v4float_uint_16
%_struct_1018 = OpTypeStruct %v4float
%_ptr_Output__struct_1018 = OpTypePointer Output %_struct_1018
%4930 = OpVariable %_ptr_Output__struct_1018 Output
%_ptr_Output_v4float = OpTypePointer Output %v4float
%v3float = OpTypeVector %float 3
%float_n1 = OpConstant %float -1
%float_1 = OpConstant %float 1
%266 = OpConstantComposite %v3float %float_n1 %float_1 %float_1
%2582 = OpConstantComposite %v3float %float_1 %float_n1 %float_1
%267 = OpConstantComposite %v3float %float_1 %float_1 %float_n1
%v3bool = OpTypeVector %bool 3
%5663 = OpFunction %void None %1282
%15110 = OpLabel
OpSelectionMerge %23648 None
OpSwitch %uint_0 %11880
%11880 = OpLabel
%23974 = OpAccessChain %_ptr_Input_v4float %5305 %int_0 %int_0
%20722 = OpLoad %v4float %23974
%16842 = OpIsNan %v4bool %20722
%9783 = OpAny %bool %16842
%11671 = OpLogicalNot %bool %9783
OpSelectionMerge %7750 None
OpBranchConditional %11671 %12129 %7750
%12129 = OpLabel
%19939 = OpAccessChain %_ptr_Input_v4float %5305 %int_1 %int_0
%20723 = OpLoad %v4float %19939
%18381 = OpIsNan %v4bool %20723
%14860 = OpAny %bool %18381
OpBranch %7750
%7750 = OpLabel
%24534 = OpPhi %bool %9783 %11880 %14860 %12129
%22068 = OpLogicalNot %bool %24534
OpSelectionMerge %9251 None
OpBranchConditional %22068 %12130 %9251
%12130 = OpLabel
%19940 = OpAccessChain %_ptr_Input_v4float %5305 %int_2 %int_0
%20724 = OpLoad %v4float %19940
%18382 = OpIsNan %v4bool %20724
%14861 = OpAny %bool %18382
OpBranch %9251
%9251 = OpLabel
%10924 = OpPhi %bool %24534 %7750 %14861 %12130
OpSelectionMerge %7205 None
OpBranchConditional %10924 %21992 %7205
%21992 = OpLabel
OpBranch %23648
%7205 = OpLabel
OpBranch %6529
%6529 = OpLabel
%23131 = OpPhi %uint %uint_0 %7205 %11651 %14551
%13910 = OpULessThan %bool %23131 %uint_3
OpLoopMerge %8693 %14551 None
OpBranchConditional %13910 %14551 %8693
%14551 = OpLabel
%18153 = OpAccessChain %_ptr_Input__arr_v4float_uint_16 %3144 %23131
%16222 = OpLoad %_arr_v4float_uint_16 %18153
OpStore %3631 %16222
%16679 = OpAccessChain %_ptr_Input_v4float %5305 %23131 %int_0
%7391 = OpLoad %v4float %16679
%22888 = OpAccessChain %_ptr_Output_v4float %4930 %int_0
OpStore %22888 %7391
OpEmitVertex
%11651 = OpIAdd %uint %23131 %int_1
OpBranch %6529
%8693 = OpLabel
OpEndPrimitive
%12070 = OpAccessChain %_ptr_Input_v4float %5305 %int_1 %int_0
%6301 = OpLoad %v4float %12070
%18018 = OpVectorShuffle %v3float %6301 %6301 0 1 2
%12374 = OpVectorShuffle %v3float %20722 %20722 0 1 2
%18845 = OpFSub %v3float %18018 %12374
%18938 = OpAccessChain %_ptr_Input_v4float %5305 %int_2 %int_0
%13501 = OpLoad %v4float %18938
%9022 = OpVectorShuffle %v3float %13501 %13501 0 1 2
%7477 = OpFSub %v3float %9022 %12374
%11062 = OpFSub %v3float %9022 %18018
%14931 = OpDot %float %18845 %18845
%23734 = OpDot %float %7477 %7477
%22344 = OpDot %float %11062 %11062
%24721 = OpFOrdGreaterThan %bool %22344 %14931
OpSelectionMerge %15688 None
OpBranchConditional %24721 %13839 %15688
%13839 = OpLabel
%21187 = OpFOrdGreaterThan %bool %22344 %23734
OpBranch %15688
%15688 = OpLabel
%10925 = OpPhi %bool %24721 %8693 %21187 %13839
OpSelectionMerge %11701 None
OpBranchConditional %10925 %12131 %13261
%12131 = OpLabel
%18154 = OpAccessChain %_ptr_Input__arr_v4float_uint_16 %3144 %int_2
%16223 = OpLoad %_arr_v4float_uint_16 %18154
OpStore %3631 %16223
%19413 = OpAccessChain %_ptr_Output_v4float %4930 %int_0
OpStore %19413 %13501
OpEmitVertex
%22812 = OpAccessChain %_ptr_Input__arr_v4float_uint_16 %3144 %int_1
%11341 = OpLoad %_arr_v4float_uint_16 %22812
OpStore %3631 %11341
OpStore %19413 %6301
OpEmitVertex
OpBranch %11701
%13261 = OpLabel
%23993 = OpFOrdGreaterThan %bool %23734 %14931
OpSelectionMerge %15689 None
OpBranchConditional %23993 %13840 %15689
%13840 = OpLabel
%21188 = OpFOrdGreaterThan %bool %23734 %22344
OpBranch %15689
%15689 = OpLabel
%10926 = OpPhi %bool %23993 %13261 %21188 %13840
OpSelectionMerge %11046 None
OpBranchConditional %10926 %12132 %11589
%12132 = OpLabel
%18155 = OpAccessChain %_ptr_Input__arr_v4float_uint_16 %3144 %int_0
%16224 = OpLoad %_arr_v4float_uint_16 %18155
OpStore %3631 %16224
%19414 = OpAccessChain %_ptr_Output_v4float %4930 %int_0
OpStore %19414 %20722
OpEmitVertex
%22813 = OpAccessChain %_ptr_Input__arr_v4float_uint_16 %3144 %int_2
%11342 = OpLoad %_arr_v4float_uint_16 %22813
OpStore %3631 %11342
OpStore %19414 %13501
OpEmitVertex
OpBranch %11046
%11589 = OpLabel
%20575 = OpAccessChain %_ptr_Input__arr_v4float_uint_16 %3144 %int_1
%16225 = OpLoad %_arr_v4float_uint_16 %20575
OpStore %3631 %16225
%19415 = OpAccessChain %_ptr_Output_v4float %4930 %int_0
OpStore %19415 %6301
OpEmitVertex
%22814 = OpAccessChain %_ptr_Input__arr_v4float_uint_16 %3144 %int_0
%11343 = OpLoad %_arr_v4float_uint_16 %22814
OpStore %3631 %11343
OpStore %19415 %20722
OpEmitVertex
OpBranch %11046
%11046 = OpLabel
%16046 = OpCompositeConstruct %v3bool %10926 %10926 %10926
%20034 = OpSelect %v3float %16046 %2582 %267
OpBranch %11701
%11701 = OpLabel
%10540 = OpPhi %v3float %266 %12131 %20034 %11046
OpBranch %19952
%19952 = OpLabel
%23132 = OpPhi %uint %uint_0 %11701 %21301 %11859
%13911 = OpULessThan %bool %23132 %uint_16
OpLoopMerge %14959 %11859 None
OpBranchConditional %13911 %11859 %14959
%11859 = OpLabel
%19851 = OpCompositeExtract %float %10540 0
%12487 = OpAccessChain %_ptr_Input_v4float %3144 %int_0 %23132
%12683 = OpLoad %v4float %12487
%8719 = OpVectorTimesScalar %v4float %12683 %19851
%15671 = OpCompositeExtract %float %10540 1
%17096 = OpAccessChain %_ptr_Input_v4float %3144 %int_1 %23132
%13595 = OpLoad %v4float %17096
%19790 = OpVectorTimesScalar %v4float %13595 %15671
%20206 = OpFAdd %v4float %8719 %19790
%10579 = OpCompositeExtract %float %10540 2
%16297 = OpAccessChain %_ptr_Input_v4float %3144 %int_2 %23132
%13596 = OpLoad %v4float %16297
%19486 = OpVectorTimesScalar %v4float %13596 %10579
%22917 = OpFAdd %v4float %20206 %19486
%16419 = OpAccessChain %_ptr_Output_v4float %3631 %23132
OpStore %16419 %22917
%21301 = OpIAdd %uint %23132 %int_1
OpBranch %19952
%14959 = OpLabel
%9332 = OpCompositeExtract %float %10540 0
%7509 = OpVectorTimesScalar %v4float %20722 %9332
%6858 = OpCompositeExtract %float %10540 1
%15269 = OpVectorTimesScalar %v4float %6301 %6858
%24885 = OpFAdd %v4float %7509 %15269
%17621 = OpCompositeExtract %float %10540 2
%14166 = OpVectorTimesScalar %v4float %13501 %17621
%7062 = OpFAdd %v4float %24885 %14166
%18129 = OpAccessChain %_ptr_Output_v4float %4930 %int_0
OpStore %18129 %7062
OpEmitVertex
OpEndPrimitive
OpBranch %23648
%23648 = OpLabel
OpReturn
OpFunctionEnd
#endif
const uint32_t primitive_rectangle_list_gs[] = {
0x07230203, 0x00010000, 0x0008000A, 0x00006136, 0x00000000, 0x00020011,
0x00000002, 0x0006000B, 0x00000001, 0x4C534C47, 0x6474732E, 0x3035342E,
0x00000000, 0x0003000E, 0x00000000, 0x00000001, 0x0009000F, 0x00000003,
0x0000161F, 0x6E69616D, 0x00000000, 0x000014B9, 0x00000E2F, 0x00000C48,
0x00001342, 0x00030010, 0x0000161F, 0x00000016, 0x00040010, 0x0000161F,
0x00000000, 0x00000001, 0x00030010, 0x0000161F, 0x0000001D, 0x00040010,
0x0000161F, 0x0000001A, 0x00000006, 0x00050048, 0x000003F9, 0x00000000,
0x0000000B, 0x00000000, 0x00030047, 0x000003F9, 0x00000002, 0x00040047,
0x00000E2F, 0x0000001E, 0x00000000, 0x00040047, 0x00000C48, 0x0000001E,
0x00000000, 0x00050048, 0x000003FA, 0x00000000, 0x0000000B, 0x00000000,
0x00030047, 0x000003FA, 0x00000002, 0x00030047, 0x00001D55, 0x0000002A,
0x00030047, 0x00003BA5, 0x0000002A, 0x00030047, 0x00006135, 0x0000002A,
0x00030047, 0x00003756, 0x0000002A, 0x00030047, 0x00001B96, 0x0000002A,
0x00020013, 0x00000008, 0x00030021, 0x00000502, 0x00000008, 0x00020014,
0x00000009, 0x00030016, 0x0000000D, 0x00000020, 0x00040017, 0x0000001D,
0x0000000D, 0x00000004, 0x0003001E, 0x000003F9, 0x0000001D, 0x00040015,
0x0000000B, 0x00000020, 0x00000000, 0x0004002B, 0x0000000B, 0x00000A13,
0x00000003, 0x0004001C, 0x00000A0F, 0x000003F9, 0x00000A13, 0x00040020,
0x000000C9, 0x00000001, 0x00000A0F, 0x0004003B, 0x000000C9, 0x000014B9,
0x00000001, 0x00040015, 0x0000000C, 0x00000020, 0x00000001, 0x0004002B,
0x0000000C, 0x00000A0B, 0x00000000, 0x00040020, 0x0000029A, 0x00000001,
0x0000001D, 0x00040017, 0x00000011, 0x00000009, 0x00000004, 0x0004002B,
0x0000000C, 0x00000A0E, 0x00000001, 0x0004002B, 0x0000000C, 0x00000A11,
0x00000002, 0x0004002B, 0x0000000B, 0x00000A0A, 0x00000000, 0x0004002B,
0x0000000B, 0x00000A3A, 0x00000010, 0x0004001C, 0x0000066B, 0x0000001D,
0x00000A3A, 0x00040020, 0x000008E8, 0x00000003, 0x0000066B, 0x0004003B,
0x000008E8, 0x00000E2F, 0x00000003, 0x0004001C, 0x000001AC, 0x0000066B,
0x00000A13, 0x00040020, 0x00000429, 0x00000001, 0x000001AC, 0x0004003B,
0x00000429, 0x00000C48, 0x00000001, 0x00040020, 0x000008E9, 0x00000001,
0x0000066B, 0x0003001E, 0x000003FA, 0x0000001D, 0x00040020, 0x00000676,
0x00000003, 0x000003FA, 0x0004003B, 0x00000676, 0x00001342, 0x00000003,
0x00040020, 0x0000029B, 0x00000003, 0x0000001D, 0x00040017, 0x00000018,
0x0000000D, 0x00000003, 0x0004002B, 0x0000000D, 0x00000341, 0xBF800000,
0x0004002B, 0x0000000D, 0x0000008A, 0x3F800000, 0x0006002C, 0x00000018,
0x0000010A, 0x00000341, 0x0000008A, 0x0000008A, 0x0006002C, 0x00000018,
0x00000A16, 0x0000008A, 0x00000341, 0x0000008A, 0x0006002C, 0x00000018,
0x0000010B, 0x0000008A, 0x0000008A, 0x00000341, 0x00040017, 0x00000010,
0x00000009, 0x00000003, 0x00050036, 0x00000008, 0x0000161F, 0x00000000,
0x00000502, 0x000200F8, 0x00003B06, 0x000300F7, 0x00005C60, 0x00000000,
0x000300FB, 0x00000A0A, 0x00002E68, 0x000200F8, 0x00002E68, 0x00060041,
0x0000029A, 0x00005DA6, 0x000014B9, 0x00000A0B, 0x00000A0B, 0x0004003D,
0x0000001D, 0x000050F2, 0x00005DA6, 0x0004009C, 0x00000011, 0x000041CA,
0x000050F2, 0x0004009A, 0x00000009, 0x00002637, 0x000041CA, 0x000400A8,
0x00000009, 0x00002D97, 0x00002637, 0x000300F7, 0x00001E46, 0x00000000,
0x000400FA, 0x00002D97, 0x00002F61, 0x00001E46, 0x000200F8, 0x00002F61,
0x00060041, 0x0000029A, 0x00004DE3, 0x000014B9, 0x00000A0E, 0x00000A0B,
0x0004003D, 0x0000001D, 0x000050F3, 0x00004DE3, 0x0004009C, 0x00000011,
0x000047CD, 0x000050F3, 0x0004009A, 0x00000009, 0x00003A0C, 0x000047CD,
0x000200F9, 0x00001E46, 0x000200F8, 0x00001E46, 0x000700F5, 0x00000009,
0x00005FD6, 0x00002637, 0x00002E68, 0x00003A0C, 0x00002F61, 0x000400A8,
0x00000009, 0x00005634, 0x00005FD6, 0x000300F7, 0x00002423, 0x00000000,
0x000400FA, 0x00005634, 0x00002F62, 0x00002423, 0x000200F8, 0x00002F62,
0x00060041, 0x0000029A, 0x00004DE4, 0x000014B9, 0x00000A11, 0x00000A0B,
0x0004003D, 0x0000001D, 0x000050F4, 0x00004DE4, 0x0004009C, 0x00000011,
0x000047CE, 0x000050F4, 0x0004009A, 0x00000009, 0x00003A0D, 0x000047CE,
0x000200F9, 0x00002423, 0x000200F8, 0x00002423, 0x000700F5, 0x00000009,
0x00002AAC, 0x00005FD6, 0x00001E46, 0x00003A0D, 0x00002F62, 0x000300F7,
0x00001C25, 0x00000000, 0x000400FA, 0x00002AAC, 0x000055E8, 0x00001C25,
0x000200F8, 0x000055E8, 0x000200F9, 0x00005C60, 0x000200F8, 0x00001C25,
0x000200F9, 0x00001981, 0x000200F8, 0x00001981, 0x000700F5, 0x0000000B,
0x00005A5B, 0x00000A0A, 0x00001C25, 0x00002D83, 0x000038D7, 0x000500B0,
0x00000009, 0x00003656, 0x00005A5B, 0x00000A13, 0x000400F6, 0x000021F5,
0x000038D7, 0x00000000, 0x000400FA, 0x00003656, 0x000038D7, 0x000021F5,
0x000200F8, 0x000038D7, 0x00050041, 0x000008E9, 0x000046E9, 0x00000C48,
0x00005A5B, 0x0004003D, 0x0000066B, 0x00003F5E, 0x000046E9, 0x0003003E,
0x00000E2F, 0x00003F5E, 0x00060041, 0x0000029A, 0x00004127, 0x000014B9,
0x00005A5B, 0x00000A0B, 0x0004003D, 0x0000001D, 0x00001CDF, 0x00004127,
0x00050041, 0x0000029B, 0x00005968, 0x00001342, 0x00000A0B, 0x0003003E,
0x00005968, 0x00001CDF, 0x000100DA, 0x00050080, 0x0000000B, 0x00002D83,
0x00005A5B, 0x00000A0E, 0x000200F9, 0x00001981, 0x000200F8, 0x000021F5,
0x000100DB, 0x00060041, 0x0000029A, 0x00002F26, 0x000014B9, 0x00000A0E,
0x00000A0B, 0x0004003D, 0x0000001D, 0x0000189D, 0x00002F26, 0x0008004F,
0x00000018, 0x00004662, 0x0000189D, 0x0000189D, 0x00000000, 0x00000001,
0x00000002, 0x0008004F, 0x00000018, 0x00003056, 0x000050F2, 0x000050F2,
0x00000000, 0x00000001, 0x00000002, 0x00050083, 0x00000018, 0x0000499D,
0x00004662, 0x00003056, 0x00060041, 0x0000029A, 0x000049FA, 0x000014B9,
0x00000A11, 0x00000A0B, 0x0004003D, 0x0000001D, 0x000034BD, 0x000049FA,
0x0008004F, 0x00000018, 0x0000233E, 0x000034BD, 0x000034BD, 0x00000000,
0x00000001, 0x00000002, 0x00050083, 0x00000018, 0x00001D35, 0x0000233E,
0x00003056, 0x00050083, 0x00000018, 0x00002B36, 0x0000233E, 0x00004662,
0x00050094, 0x0000000D, 0x00003A53, 0x0000499D, 0x0000499D, 0x00050094,
0x0000000D, 0x00005CB6, 0x00001D35, 0x00001D35, 0x00050094, 0x0000000D,
0x00005748, 0x00002B36, 0x00002B36, 0x000500BA, 0x00000009, 0x00006091,
0x00005748, 0x00003A53, 0x000300F7, 0x00003D48, 0x00000000, 0x000400FA,
0x00006091, 0x0000360F, 0x00003D48, 0x000200F8, 0x0000360F, 0x000500BA,
0x00000009, 0x000052C3, 0x00005748, 0x00005CB6, 0x000200F9, 0x00003D48,
0x000200F8, 0x00003D48, 0x000700F5, 0x00000009, 0x00002AAD, 0x00006091,
0x000021F5, 0x000052C3, 0x0000360F, 0x000300F7, 0x00002DB5, 0x00000000,
0x000400FA, 0x00002AAD, 0x00002F63, 0x000033CD, 0x000200F8, 0x00002F63,
0x00050041, 0x000008E9, 0x000046EA, 0x00000C48, 0x00000A11, 0x0004003D,
0x0000066B, 0x00003F5F, 0x000046EA, 0x0003003E, 0x00000E2F, 0x00003F5F,
0x00050041, 0x0000029B, 0x00004BD5, 0x00001342, 0x00000A0B, 0x0003003E,
0x00004BD5, 0x000034BD, 0x000100DA, 0x00050041, 0x000008E9, 0x0000591C,
0x00000C48, 0x00000A0E, 0x0004003D, 0x0000066B, 0x00002C4D, 0x0000591C,
0x0003003E, 0x00000E2F, 0x00002C4D, 0x0003003E, 0x00004BD5, 0x0000189D,
0x000100DA, 0x000200F9, 0x00002DB5, 0x000200F8, 0x000033CD, 0x000500BA,
0x00000009, 0x00005DB9, 0x00005CB6, 0x00003A53, 0x000300F7, 0x00003D49,
0x00000000, 0x000400FA, 0x00005DB9, 0x00003610, 0x00003D49, 0x000200F8,
0x00003610, 0x000500BA, 0x00000009, 0x000052C4, 0x00005CB6, 0x00005748,
0x000200F9, 0x00003D49, 0x000200F8, 0x00003D49, 0x000700F5, 0x00000009,
0x00002AAE, 0x00005DB9, 0x000033CD, 0x000052C4, 0x00003610, 0x000300F7,
0x00002B26, 0x00000000, 0x000400FA, 0x00002AAE, 0x00002F64, 0x00002D45,
0x000200F8, 0x00002F64, 0x00050041, 0x000008E9, 0x000046EB, 0x00000C48,
0x00000A0B, 0x0004003D, 0x0000066B, 0x00003F60, 0x000046EB, 0x0003003E,
0x00000E2F, 0x00003F60, 0x00050041, 0x0000029B, 0x00004BD6, 0x00001342,
0x00000A0B, 0x0003003E, 0x00004BD6, 0x000050F2, 0x000100DA, 0x00050041,
0x000008E9, 0x0000591D, 0x00000C48, 0x00000A11, 0x0004003D, 0x0000066B,
0x00002C4E, 0x0000591D, 0x0003003E, 0x00000E2F, 0x00002C4E, 0x0003003E,
0x00004BD6, 0x000034BD, 0x000100DA, 0x000200F9, 0x00002B26, 0x000200F8,
0x00002D45, 0x00050041, 0x000008E9, 0x0000505F, 0x00000C48, 0x00000A0E,
0x0004003D, 0x0000066B, 0x00003F61, 0x0000505F, 0x0003003E, 0x00000E2F,
0x00003F61, 0x00050041, 0x0000029B, 0x00004BD7, 0x00001342, 0x00000A0B,
0x0003003E, 0x00004BD7, 0x0000189D, 0x000100DA, 0x00050041, 0x000008E9,
0x0000591E, 0x00000C48, 0x00000A0B, 0x0004003D, 0x0000066B, 0x00002C4F,
0x0000591E, 0x0003003E, 0x00000E2F, 0x00002C4F, 0x0003003E, 0x00004BD7,
0x000050F2, 0x000100DA, 0x000200F9, 0x00002B26, 0x000200F8, 0x00002B26,
0x00060050, 0x00000010, 0x00003EAE, 0x00002AAE, 0x00002AAE, 0x00002AAE,
0x000600A9, 0x00000018, 0x00004E42, 0x00003EAE, 0x00000A16, 0x0000010B,
0x000200F9, 0x00002DB5, 0x000200F8, 0x00002DB5, 0x000700F5, 0x00000018,
0x0000292C, 0x0000010A, 0x00002F63, 0x00004E42, 0x00002B26, 0x000200F9,
0x00004DF0, 0x000200F8, 0x00004DF0, 0x000700F5, 0x0000000B, 0x00005A5C,
0x00000A0A, 0x00002DB5, 0x00005335, 0x00002E53, 0x000500B0, 0x00000009,
0x00003657, 0x00005A5C, 0x00000A3A, 0x000400F6, 0x00003A6F, 0x00002E53,
0x00000000, 0x000400FA, 0x00003657, 0x00002E53, 0x00003A6F, 0x000200F8,
0x00002E53, 0x00050051, 0x0000000D, 0x00004D8B, 0x0000292C, 0x00000000,
0x00060041, 0x0000029A, 0x000030C7, 0x00000C48, 0x00000A0B, 0x00005A5C,
0x0004003D, 0x0000001D, 0x0000318B, 0x000030C7, 0x0005008E, 0x0000001D,
0x0000220F, 0x0000318B, 0x00004D8B, 0x00050051, 0x0000000D, 0x00003D37,
0x0000292C, 0x00000001, 0x00060041, 0x0000029A, 0x000042C8, 0x00000C48,
0x00000A0E, 0x00005A5C, 0x0004003D, 0x0000001D, 0x0000351B, 0x000042C8,
0x0005008E, 0x0000001D, 0x00004D4E, 0x0000351B, 0x00003D37, 0x00050081,
0x0000001D, 0x00004EEE, 0x0000220F, 0x00004D4E, 0x00050051, 0x0000000D,
0x00002953, 0x0000292C, 0x00000002, 0x00060041, 0x0000029A, 0x00003FA9,
0x00000C48, 0x00000A11, 0x00005A5C, 0x0004003D, 0x0000001D, 0x0000351C,
0x00003FA9, 0x0005008E, 0x0000001D, 0x00004C1E, 0x0000351C, 0x00002953,
0x00050081, 0x0000001D, 0x00005985, 0x00004EEE, 0x00004C1E, 0x00050041,
0x0000029B, 0x00004023, 0x00000E2F, 0x00005A5C, 0x0003003E, 0x00004023,
0x00005985, 0x00050080, 0x0000000B, 0x00005335, 0x00005A5C, 0x00000A0E,
0x000200F9, 0x00004DF0, 0x000200F8, 0x00003A6F, 0x00050051, 0x0000000D,
0x00002474, 0x0000292C, 0x00000000, 0x0005008E, 0x0000001D, 0x00001D55,
0x000050F2, 0x00002474, 0x00050051, 0x0000000D, 0x00001ACA, 0x0000292C,
0x00000001, 0x0005008E, 0x0000001D, 0x00003BA5, 0x0000189D, 0x00001ACA,
0x00050081, 0x0000001D, 0x00006135, 0x00001D55, 0x00003BA5, 0x00050051,
0x0000000D, 0x000044D5, 0x0000292C, 0x00000002, 0x0005008E, 0x0000001D,
0x00003756, 0x000034BD, 0x000044D5, 0x00050081, 0x0000001D, 0x00001B96,
0x00006135, 0x00003756, 0x00050041, 0x0000029B, 0x000046D1, 0x00001342,
0x00000A0B, 0x0003003E, 0x000046D1, 0x00001B96, 0x000100DA, 0x000100DB,
0x000200F9, 0x00005C60, 0x000200F8, 0x00005C60, 0x000100FD, 0x00010038,
};

View File

@ -1,103 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2022 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#version 460
#extension GL_GOOGLE_include_directive : require
#include "xenos_gs.glsli"
layout(triangles) in;
layout(triangle_strip, max_vertices=6) out;
void main() {
if (any(isnan(gl_in[0].gl_Position)) || any(isnan(gl_in[1].gl_Position)) ||
any(isnan(gl_in[2].gl_Position))) {
return;
}
uint i;
for (i = 0; i < 3u; ++i) {
xe_out_interpolators = xe_in_interpolators[i];
gl_Position = gl_in[i].gl_Position;
EmitVertex();
}
EndPrimitive();
// Find the diagonal (the edge that is longer than both the other two) and
// mirror the other vertex across it.
vec3 edge_01 = gl_in[1].gl_Position.xyz - gl_in[0].gl_Position.xyz;
vec3 edge_02 = gl_in[2].gl_Position.xyz - gl_in[0].gl_Position.xyz;
vec3 edge_12 = gl_in[2].gl_Position.xyz - gl_in[1].gl_Position.xyz;
vec3 edge_squares = vec3(
dot(edge_01, edge_01), dot(edge_02, edge_02), dot(edge_12, edge_12));
vec3 v3_signs;
if (edge_squares.z > edge_squares.x && edge_squares.z > edge_squares.y) {
// 12 is the diagonal. Most games use this form.
//
// 0 ------ 1 0: -1,-1
// | - | 1: 1,-1
// | // | 2: -1, 1
// | - | 3: [ 1, 1 ]
// 2 ----- [3]
//
// 0 ------ 2 0: -1,-1
// | - | 1: -1, 1
// | // | 2: 1,-1
// | - | 3: [ 1, 1 ]
// 1 ------[3]
xe_out_interpolators = xe_in_interpolators[2];
gl_Position = gl_in[2].gl_Position;
EmitVertex();
xe_out_interpolators = xe_in_interpolators[1];
gl_Position = gl_in[1].gl_Position;
EmitVertex();
v3_signs = vec3(-1.0, 1.0, 1.0);
} else if (edge_squares.y > edge_squares.x &&
edge_squares.y > edge_squares.z) {
// 02 is the diagonal.
//
// 0 ------ 1 0: -1,-1
// | - | 1: 1,-1
// | \\ | 2: 1, 1
// | - | 3: [-1, 1 ]
// [3] ----- 2
xe_out_interpolators = xe_in_interpolators[0];
gl_Position = gl_in[0].gl_Position;
EmitVertex();
xe_out_interpolators = xe_in_interpolators[2];
gl_Position = gl_in[2].gl_Position;
EmitVertex();
v3_signs = vec3(1.0, -1.0, 1.0);
} else {
// 01 is the diagonal. Not seen in any game so far.
//
// 0 ------ 2 0: -1,-1
// | - | 1: 1, 1
// | \\ | 2: 1,-1
// | - | 3: [-1, 1 ]
// [3] ----- 1
xe_out_interpolators = xe_in_interpolators[1];
gl_Position = gl_in[1].gl_Position;
EmitVertex();
xe_out_interpolators = xe_in_interpolators[0];
gl_Position = gl_in[0].gl_Position;
EmitVertex();
v3_signs = vec3(1.0, 1.0, -1.0);
}
for (i = 0; i < 16u; ++i) {
xe_out_interpolators[i] = v3_signs.x * xe_in_interpolators[0][i] +
v3_signs.y * xe_in_interpolators[1][i] +
v3_signs.z * xe_in_interpolators[2][i];
}
gl_Position = v3_signs.x * gl_in[0].gl_Position +
v3_signs.y * gl_in[1].gl_Position +
v3_signs.z * gl_in[2].gl_Position;
EmitVertex();
EndPrimitive();
}

View File

@ -1,25 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2022 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D12_SHADERS_XENOS_GS_GLSLI_
#define XENIA_GPU_D3D12_SHADERS_XENOS_GS_GLSLI_
layout(location=0) in vec4 xe_in_interpolators[][16];
in gl_PerVertex {
vec4 gl_Position;
} gl_in[];
layout(location=0) out vec4 xe_out_interpolators[16];
out gl_PerVertex {
precise vec4 gl_Position;
};
#endif // XENIA_GPU_D3D12_SHADERS_XENOS_GS_GLSLI_

View File

@ -932,64 +932,34 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
} }
// Create the Xenia-specific outputs. // Create the Xenia-specific outputs.
// TODO(Triang3l): Change to an interpolator array.
for (uint32_t i = 0; i < xenos::kMaxInterpolators; ++i) { for (uint32_t i = 0; i < xenos::kMaxInterpolators; ++i) {
spv::Id interpolator = builder_->createVariable( spv::Id interpolator = builder_->createVariable(
spv::NoPrecision, spv::StorageClassOutput, type_float4_, spv::NoPrecision, spv::StorageClassOutput, type_float4_,
(kInterpolatorNamePrefix + std::to_string(i)).c_str()); (kInterpolatorNamePrefix + std::to_string(i)).c_str());
input_output_interpolators_[i] = interpolator; input_output_interpolators_[i] = interpolator;
builder_->addDecoration(interpolator, spv::DecorationLocation, int(i)); builder_->addDecoration(interpolator, spv::DecorationLocation, int(i));
builder_->addDecoration(interpolator, spv::DecorationInvariant);
main_interface_.push_back(interpolator); main_interface_.push_back(interpolator);
} }
// Create the entire GLSL 4.50 gl_PerVertex output similar to what glslang // Create the gl_PerVertex output for used system outputs.
// does. Members (like gl_PointSize) don't need to be used, and also
// ClipDistance and CullDistance may exist even if the device doesn't support
// them, as long as the capabilities aren't enabled, and nothing is stored to
// them.
if (features_.clip_distance) {
builder_->addCapability(spv::CapabilityClipDistance);
}
if (features_.cull_distance) {
builder_->addCapability(spv::CapabilityCullDistance);
}
std::vector<spv::Id> struct_per_vertex_members; std::vector<spv::Id> struct_per_vertex_members;
struct_per_vertex_members.reserve(kOutputPerVertexMemberCount); struct_per_vertex_members.reserve(kOutputPerVertexMemberCount);
struct_per_vertex_members.push_back(type_float4_); struct_per_vertex_members.push_back(type_float4_);
struct_per_vertex_members.push_back(type_float_);
// TODO(Triang3l): Specialization constant for ucp_cull_only_ena, for 6 + 1
// or 1 + 7 array sizes.
struct_per_vertex_members.push_back(builder_->makeArrayType(
type_float_, builder_->makeUintConstant(features_.clip_distance ? 6 : 1),
0));
struct_per_vertex_members.push_back(
builder_->makeArrayType(type_float_, builder_->makeUintConstant(1), 0));
spv::Id type_struct_per_vertex = spv::Id type_struct_per_vertex =
builder_->makeStructType(struct_per_vertex_members, "gl_PerVertex"); builder_->makeStructType(struct_per_vertex_members, "gl_PerVertex");
builder_->addMemberName(type_struct_per_vertex,
kOutputPerVertexMemberPosition, "gl_Position");
builder_->addMemberDecoration(type_struct_per_vertex, builder_->addMemberDecoration(type_struct_per_vertex,
kOutputPerVertexMemberPosition, kOutputPerVertexMemberPosition,
spv::DecorationInvariant); spv::DecorationInvariant);
builder_->addMemberDecoration(type_struct_per_vertex, builder_->addMemberDecoration(type_struct_per_vertex,
kOutputPerVertexMemberPosition, kOutputPerVertexMemberPosition,
spv::DecorationBuiltIn, spv::BuiltInPosition); spv::DecorationBuiltIn, spv::BuiltInPosition);
builder_->addMemberDecoration(type_struct_per_vertex,
kOutputPerVertexMemberPointSize,
spv::DecorationBuiltIn, spv::BuiltInPointSize);
builder_->addMemberDecoration(type_struct_per_vertex,
kOutputPerVertexMemberClipDistance,
spv::DecorationInvariant);
builder_->addMemberDecoration(
type_struct_per_vertex, kOutputPerVertexMemberClipDistance,
spv::DecorationBuiltIn, spv::BuiltInClipDistance);
builder_->addMemberDecoration(type_struct_per_vertex,
kOutputPerVertexMemberCullDistance,
spv::DecorationInvariant);
builder_->addMemberDecoration(
type_struct_per_vertex, kOutputPerVertexMemberCullDistance,
spv::DecorationBuiltIn, spv::BuiltInCullDistance);
builder_->addDecoration(type_struct_per_vertex, spv::DecorationBlock); builder_->addDecoration(type_struct_per_vertex, spv::DecorationBlock);
output_per_vertex_ = output_per_vertex_ = builder_->createVariable(
builder_->createVariable(spv::NoPrecision, spv::StorageClassOutput, spv::NoPrecision, spv::StorageClassOutput, type_struct_per_vertex, "");
type_struct_per_vertex, "xe_out_gl_PerVertex");
main_interface_.push_back(output_per_vertex_); main_interface_.push_back(output_per_vertex_);
} }
@ -1178,18 +1148,6 @@ void SpirvShaderTranslator::CompleteVertexOrTessEvalShaderInMain() {
std::move(composite_construct_op)); std::move(composite_construct_op));
} }
builder_->createStore(position, position_ptr); builder_->createStore(position, position_ptr);
// Write 1 to point size (using a geometry shader or another kind of fallback
// to expand point sprites - point size support is not guaranteed, and the
// size would also be limited, and can't be controlled independently along two
// axes).
id_vector_temp_.clear();
id_vector_temp_.push_back(
builder_->makeIntConstant(kOutputPerVertexMemberPointSize));
builder_->createStore(
const_float_1_,
builder_->createAccessChain(spv::StorageClassOutput, output_per_vertex_,
id_vector_temp_));
} }
void SpirvShaderTranslator::StartFragmentShaderBeforeMain() { void SpirvShaderTranslator::StartFragmentShaderBeforeMain() {

View File

@ -459,9 +459,6 @@ class SpirvShaderTranslator : public ShaderTranslator {
enum OutputPerVertexMember : unsigned int { enum OutputPerVertexMember : unsigned int {
kOutputPerVertexMemberPosition, kOutputPerVertexMemberPosition,
kOutputPerVertexMemberPointSize,
kOutputPerVertexMemberClipDistance,
kOutputPerVertexMemberCullDistance,
kOutputPerVertexMemberCount, kOutputPerVertexMemberCount,
}; };
spv::Id output_per_vertex_; spv::Id output_per_vertex_;

View File

@ -11,9 +11,12 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstdint>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <utility>
#include "third_party/glslang/SPIRV/SpvBuilder.h"
#include "xenia/base/assert.h" #include "xenia/base/assert.h"
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
#include "xenia/base/math.h" #include "xenia/base/math.h"
@ -33,11 +36,6 @@ namespace xe {
namespace gpu { namespace gpu {
namespace vulkan { namespace vulkan {
// Generated with `xb buildshaders`.
namespace shaders {
#include "xenia/gpu/shaders/bytecode/vulkan_spirv/primitive_rectangle_list_gs.h"
} // namespace shaders
VulkanPipelineCache::VulkanPipelineCache( VulkanPipelineCache::VulkanPipelineCache(
VulkanCommandProcessor& command_processor, VulkanCommandProcessor& command_processor,
const RegisterFile& register_file, const RegisterFile& register_file,
@ -51,20 +49,6 @@ VulkanPipelineCache::~VulkanPipelineCache() { Shutdown(); }
bool VulkanPipelineCache::Initialize() { bool VulkanPipelineCache::Initialize() {
const ui::vulkan::VulkanProvider& provider = const ui::vulkan::VulkanProvider& provider =
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider();
const VkPhysicalDeviceFeatures& device_features = provider.device_features();
if (device_features.geometryShader) {
gs_rectangle_list_ = ui::vulkan::util::CreateShaderModule(
provider, shaders::primitive_rectangle_list_gs,
sizeof(shaders::primitive_rectangle_list_gs));
if (gs_rectangle_list_ == VK_NULL_HANDLE) {
XELOGE(
"VulkanPipelineCache: Failed to create the rectangle list geometry "
"shader");
Shutdown();
return false;
}
}
shader_translator_ = std::make_unique<SpirvShaderTranslator>( shader_translator_ = std::make_unique<SpirvShaderTranslator>(
SpirvShaderTranslator::Features(provider)); SpirvShaderTranslator::Features(provider));
@ -80,10 +64,14 @@ void VulkanPipelineCache::Shutdown() {
ClearCache(); ClearCache();
shader_translator_.reset(); for (const auto& geometry_shader_pair : geometry_shaders_) {
if (geometry_shader_pair.second != VK_NULL_HANDLE) {
dfn.vkDestroyShaderModule(device, geometry_shader_pair.second, nullptr);
}
}
geometry_shaders_.clear();
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyShaderModule, device, shader_translator_.reset();
gs_rectangle_list_);
} }
void VulkanPipelineCache::ClearCache() { void VulkanPipelineCache::ClearCache() {
@ -255,6 +243,14 @@ bool VulkanPipelineCache::ConfigurePipeline(
if (!pipeline_layout) { if (!pipeline_layout) {
return false; return false;
} }
VkShaderModule geometry_shader = VK_NULL_HANDLE;
GeometryShaderKey geometry_shader_key;
if (GetGeometryShaderKey(description.geometry_shader, geometry_shader_key)) {
geometry_shader = GetGeometryShader(geometry_shader_key);
if (geometry_shader == VK_NULL_HANDLE) {
return false;
}
}
VkRenderPass render_pass = VkRenderPass render_pass =
render_target_cache_.GetRenderPass(render_pass_key); render_target_cache_.GetRenderPass(render_pass_key);
if (render_pass == VK_NULL_HANDLE) { if (render_pass == VK_NULL_HANDLE) {
@ -266,6 +262,7 @@ bool VulkanPipelineCache::ConfigurePipeline(
creation_arguments.pipeline = &pipeline; creation_arguments.pipeline = &pipeline;
creation_arguments.vertex_shader = vertex_shader; creation_arguments.vertex_shader = vertex_shader;
creation_arguments.pixel_shader = pixel_shader; creation_arguments.pixel_shader = pixel_shader;
creation_arguments.geometry_shader = geometry_shader;
creation_arguments.render_pass = render_pass; creation_arguments.render_pass = render_pass;
if (!EnsurePipelineCreated(creation_arguments)) { if (!EnsurePipelineCreated(creation_arguments)) {
return false; return false;
@ -419,6 +416,7 @@ bool VulkanPipelineCache::GetCurrentStateDescription(
primitive_topology = PipelinePrimitiveTopology::kTriangleList; primitive_topology = PipelinePrimitiveTopology::kTriangleList;
break; break;
case xenos::PrimitiveType::kQuadList: case xenos::PrimitiveType::kQuadList:
geometry_shader = PipelineGeometryShader::kQuadList;
primitive_topology = PipelinePrimitiveTopology::kLineListWithAdjacency; primitive_topology = PipelinePrimitiveTopology::kLineListWithAdjacency;
break; break;
default: default:
@ -686,6 +684,782 @@ bool VulkanPipelineCache::ArePipelineRequirementsMet(
return true; return true;
} }
bool VulkanPipelineCache::GetGeometryShaderKey(
PipelineGeometryShader geometry_shader_type, GeometryShaderKey& key_out) {
if (geometry_shader_type == PipelineGeometryShader::kNone) {
return false;
}
GeometryShaderKey key;
key.type = geometry_shader_type;
// TODO(Triang3l): Make the linkage parameters depend on the real needs of the
// vertex and the pixel shader.
key.interpolator_count = xenos::kMaxInterpolators;
key.user_clip_plane_count = /* 6 */ 0;
key.user_clip_plane_cull = 0;
key.has_vertex_kill_and = /* 1 */ 0;
key.has_point_size = /* 1 */ 0;
key.has_point_coordinates = /* 1 */ 0;
key_out = key;
return true;
}
VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
auto it = geometry_shaders_.find(key);
if (it != geometry_shaders_.end()) {
return it->second;
}
std::vector<spv::Id> id_vector_temp;
std::vector<unsigned int> uint_vector_temp;
spv::ExecutionMode input_primitive_execution_mode = spv::ExecutionMode(0);
uint32_t input_primitive_vertex_count = 0;
spv::ExecutionMode output_primitive_execution_mode = spv::ExecutionMode(0);
uint32_t output_max_vertices = 0;
switch (key.type) {
case PipelineGeometryShader::kRectangleList:
// Triangle to a strip of 2 triangles.
input_primitive_execution_mode = spv::ExecutionModeTriangles;
input_primitive_vertex_count = 3;
output_primitive_execution_mode = spv::ExecutionModeOutputTriangleStrip;
output_max_vertices = 4;
break;
case PipelineGeometryShader::kQuadList:
// 4 vertices passed via a line list with adjacency to a strip of 2
// triangles.
input_primitive_execution_mode = spv::ExecutionModeInputLinesAdjacency;
input_primitive_vertex_count = 4;
output_primitive_execution_mode = spv::ExecutionModeOutputTriangleStrip;
output_max_vertices = 4;
break;
default:
assert_unhandled_case(key.type);
}
uint32_t clip_distance_count =
key.user_clip_plane_cull ? 0 : key.user_clip_plane_count;
uint32_t cull_distance_count =
(key.user_clip_plane_cull ? key.user_clip_plane_count : 0) +
key.has_vertex_kill_and;
spv::Builder builder(spv::Spv_1_0,
(SpirvShaderTranslator::kSpirvMagicToolId << 16) | 1,
nullptr);
spv::Id ext_inst_glsl_std_450 = builder.import("GLSL.std.450");
builder.addCapability(spv::CapabilityGeometry);
if (clip_distance_count) {
builder.addCapability(spv::CapabilityClipDistance);
}
if (cull_distance_count) {
builder.addCapability(spv::CapabilityCullDistance);
}
builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
builder.setSource(spv::SourceLanguageUnknown, 0);
// TODO(Triang3l): Shader float controls (NaN preservation most importantly).
std::vector<spv::Id> main_interface;
spv::Id type_void = builder.makeVoidType();
spv::Id type_bool = builder.makeBoolType();
spv::Id type_bool4 = builder.makeVectorType(type_bool, 4);
spv::Id type_int = builder.makeIntType(32);
spv::Id type_float = builder.makeFloatType(32);
spv::Id type_float4 = builder.makeVectorType(type_float, 4);
spv::Id type_clip_distances =
clip_distance_count
? builder.makeArrayType(
type_float, builder.makeUintConstant(clip_distance_count), 0)
: spv::NoType;
spv::Id type_cull_distances =
cull_distance_count
? builder.makeArrayType(
type_float, builder.makeUintConstant(cull_distance_count), 0)
: spv::NoType;
spv::Id type_interpolators =
key.interpolator_count
? builder.makeArrayType(
type_float4, builder.makeUintConstant(key.interpolator_count),
0)
: spv::NoType;
spv::Id type_point_coordinates = key.has_point_coordinates
? builder.makeVectorType(type_float, 2)
: spv::NoType;
// Inputs and outputs - matching glslang order, in gl_PerVertex gl_in[],
// user-defined outputs, user-defined inputs, out gl_PerVertex.
// TODO(Triang3l): Point parameters from the system uniform buffer.
spv::Id const_input_primitive_vertex_count =
builder.makeUintConstant(input_primitive_vertex_count);
// in gl_PerVertex gl_in[].
// gl_Position.
id_vector_temp.clear();
uint32_t member_in_gl_per_vertex_position = uint32_t(id_vector_temp.size());
id_vector_temp.push_back(type_float4);
spv::Id const_member_in_gl_per_vertex_position =
builder.makeIntConstant(int32_t(member_in_gl_per_vertex_position));
// gl_ClipDistance.
uint32_t member_in_gl_per_vertex_clip_distance = UINT32_MAX;
spv::Id const_member_in_gl_per_vertex_clip_distance = spv::NoResult;
if (clip_distance_count) {
member_in_gl_per_vertex_clip_distance = uint32_t(id_vector_temp.size());
id_vector_temp.push_back(type_clip_distances);
const_member_in_gl_per_vertex_clip_distance =
builder.makeIntConstant(int32_t(member_in_gl_per_vertex_clip_distance));
}
// gl_CullDistance.
uint32_t member_in_gl_per_vertex_cull_distance = UINT32_MAX;
if (cull_distance_count) {
member_in_gl_per_vertex_cull_distance = uint32_t(id_vector_temp.size());
id_vector_temp.push_back(type_cull_distances);
}
// Structure and array.
spv::Id type_struct_in_gl_per_vertex =
builder.makeStructType(id_vector_temp, "gl_PerVertex");
builder.addMemberName(type_struct_in_gl_per_vertex,
member_in_gl_per_vertex_position, "gl_Position");
builder.addMemberDecoration(type_struct_in_gl_per_vertex,
member_in_gl_per_vertex_position,
spv::DecorationBuiltIn, spv::BuiltInPosition);
if (clip_distance_count) {
builder.addMemberName(type_struct_in_gl_per_vertex,
member_in_gl_per_vertex_clip_distance,
"gl_ClipDistance");
builder.addMemberDecoration(
type_struct_in_gl_per_vertex, member_in_gl_per_vertex_clip_distance,
spv::DecorationBuiltIn, spv::BuiltInClipDistance);
}
if (cull_distance_count) {
builder.addMemberName(type_struct_in_gl_per_vertex,
member_in_gl_per_vertex_cull_distance,
"gl_CullDistance");
builder.addMemberDecoration(
type_struct_in_gl_per_vertex, member_in_gl_per_vertex_cull_distance,
spv::DecorationBuiltIn, spv::BuiltInCullDistance);
}
builder.addDecoration(type_struct_in_gl_per_vertex, spv::DecorationBlock);
spv::Id type_array_in_gl_per_vertex = builder.makeArrayType(
type_struct_in_gl_per_vertex, const_input_primitive_vertex_count, 0);
spv::Id in_gl_per_vertex =
builder.createVariable(spv::NoPrecision, spv::StorageClassInput,
type_array_in_gl_per_vertex, "gl_in");
main_interface.push_back(in_gl_per_vertex);
// Interpolators output.
spv::Id out_interpolators = spv::NoResult;
if (key.interpolator_count) {
out_interpolators =
builder.createVariable(spv::NoPrecision, spv::StorageClassOutput,
type_interpolators, "xe_out_interpolators");
builder.addDecoration(out_interpolators, spv::DecorationLocation, 0);
builder.addDecoration(out_interpolators, spv::DecorationInvariant);
main_interface.push_back(out_interpolators);
}
// Point coordinate output.
spv::Id out_point_coordinates = spv::NoResult;
if (key.has_point_coordinates) {
out_point_coordinates = builder.createVariable(
spv::NoPrecision, spv::StorageClassOutput, type_point_coordinates,
"xe_out_point_coordinates");
builder.addDecoration(out_point_coordinates, spv::DecorationLocation,
key.interpolator_count);
builder.addDecoration(out_point_coordinates, spv::DecorationInvariant);
main_interface.push_back(out_point_coordinates);
}
// Interpolator input.
spv::Id in_interpolators = spv::NoResult;
if (key.interpolator_count) {
in_interpolators = builder.createVariable(
spv::NoPrecision, spv::StorageClassInput,
builder.makeArrayType(type_interpolators,
const_input_primitive_vertex_count, 0),
"xe_in_interpolators");
builder.addDecoration(in_interpolators, spv::DecorationLocation, 0);
main_interface.push_back(in_interpolators);
}
// Point size input.
spv::Id in_point_size = spv::NoResult;
if (key.has_point_size) {
in_point_size = builder.createVariable(
spv::NoPrecision, spv::StorageClassInput,
builder.makeArrayType(type_float, const_input_primitive_vertex_count,
0),
"xe_in_point_size");
builder.addDecoration(in_point_size, spv::DecorationLocation,
key.interpolator_count);
main_interface.push_back(in_point_size);
}
// out gl_PerVertex.
// gl_Position.
id_vector_temp.clear();
uint32_t member_out_gl_per_vertex_position = uint32_t(id_vector_temp.size());
id_vector_temp.push_back(type_float4);
spv::Id const_member_out_gl_per_vertex_position =
builder.makeIntConstant(int32_t(member_out_gl_per_vertex_position));
// gl_ClipDistance.
uint32_t member_out_gl_per_vertex_clip_distance = UINT32_MAX;
spv::Id const_member_out_gl_per_vertex_clip_distance = spv::NoResult;
if (clip_distance_count) {
member_out_gl_per_vertex_clip_distance = uint32_t(id_vector_temp.size());
id_vector_temp.push_back(type_clip_distances);
const_member_out_gl_per_vertex_clip_distance = builder.makeIntConstant(
int32_t(member_out_gl_per_vertex_clip_distance));
}
// Structure.
spv::Id type_struct_out_gl_per_vertex =
builder.makeStructType(id_vector_temp, "gl_PerVertex");
builder.addMemberName(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_position, "gl_Position");
builder.addMemberDecoration(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_position,
spv::DecorationInvariant);
builder.addMemberDecoration(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_position,
spv::DecorationBuiltIn, spv::BuiltInPosition);
if (clip_distance_count) {
builder.addMemberName(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_clip_distance,
"gl_ClipDistance");
builder.addMemberDecoration(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_clip_distance,
spv::DecorationInvariant);
builder.addMemberDecoration(
type_struct_out_gl_per_vertex, member_out_gl_per_vertex_clip_distance,
spv::DecorationBuiltIn, spv::BuiltInClipDistance);
}
builder.addDecoration(type_struct_out_gl_per_vertex, spv::DecorationBlock);
spv::Id out_gl_per_vertex =
builder.createVariable(spv::NoPrecision, spv::StorageClassOutput,
type_struct_out_gl_per_vertex, "");
main_interface.push_back(out_gl_per_vertex);
// Begin the main function.
std::vector<spv::Id> main_param_types;
std::vector<std::vector<spv::Decoration>> main_precisions;
spv::Block* main_entry;
spv::Function* main_function =
builder.makeFunctionEntry(spv::NoPrecision, type_void, "main",
main_param_types, main_precisions, &main_entry);
spv::Instruction* entry_point =
builder.addEntryPoint(spv::ExecutionModelGeometry, main_function, "main");
for (spv::Id interface_id : main_interface) {
entry_point->addIdOperand(interface_id);
}
builder.addExecutionMode(main_function, input_primitive_execution_mode);
builder.addExecutionMode(main_function, spv::ExecutionModeInvocations, 1);
builder.addExecutionMode(main_function, output_primitive_execution_mode);
builder.addExecutionMode(main_function, spv::ExecutionModeOutputVertices,
int(output_max_vertices));
// Note that after every OpEmitVertex, all output variables are undefined.
// Discard the whole primitive if any vertex has a NaN position (may also be
// set to NaN for emulation of vertex killing with the OR operator).
for (uint32_t i = 0; i < input_primitive_vertex_count; ++i) {
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(builder.makeIntConstant(int32_t(i)));
id_vector_temp.push_back(const_member_in_gl_per_vertex_position);
spv::Id position_is_nan = builder.createUnaryOp(
spv::OpAny, type_bool,
builder.createUnaryOp(
spv::OpIsNan, type_bool4,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision)));
spv::Block& discard_predecessor = *builder.getBuildPoint();
spv::Block& discard_then_block = builder.makeNewBlock();
spv::Block& discard_merge_block = builder.makeNewBlock();
{
std::unique_ptr<spv::Instruction> selection_merge_op(
std::make_unique<spv::Instruction>(spv::OpSelectionMerge));
selection_merge_op->addIdOperand(discard_merge_block.getId());
selection_merge_op->addImmediateOperand(
spv::SelectionControlDontFlattenMask);
discard_predecessor.addInstruction(std::move(selection_merge_op));
}
{
std::unique_ptr<spv::Instruction> branch_conditional_op(
std::make_unique<spv::Instruction>(spv::OpBranchConditional));
branch_conditional_op->addIdOperand(position_is_nan);
branch_conditional_op->addIdOperand(discard_then_block.getId());
branch_conditional_op->addIdOperand(discard_merge_block.getId());
branch_conditional_op->addImmediateOperand(1);
branch_conditional_op->addImmediateOperand(2);
discard_predecessor.addInstruction(std::move(branch_conditional_op));
}
discard_then_block.addPredecessor(&discard_predecessor);
discard_merge_block.addPredecessor(&discard_predecessor);
builder.setBuildPoint(&discard_then_block);
builder.createNoResultOp(spv::OpReturn);
builder.setBuildPoint(&discard_merge_block);
}
// Cull the whole primitive if any cull distance for all vertices in the
// primitive is < 0.
// TODO(Triang3l): For points, handle ps_ucp_mode (transform the host clip
// space to the guest one, calculate the distances to the user clip planes,
// cull using the distance from the center for modes 0, 1 and 2, cull and clip
// per-vertex for modes 2 and 3) - except for the vertex kill flag.
if (cull_distance_count) {
spv::Id const_member_in_gl_per_vertex_cull_distance =
builder.makeIntConstant(int32_t(member_in_gl_per_vertex_cull_distance));
spv::Id const_float_0 = builder.makeFloatConstant(0.0f);
spv::Id cull_condition = spv::NoResult;
for (uint32_t i = 0; i < cull_distance_count; ++i) {
for (uint32_t j = 0; j < input_primitive_vertex_count; ++j) {
id_vector_temp.clear();
id_vector_temp.reserve(3);
id_vector_temp.push_back(builder.makeIntConstant(int32_t(j)));
id_vector_temp.push_back(const_member_in_gl_per_vertex_cull_distance);
id_vector_temp.push_back(builder.makeIntConstant(int32_t(i)));
spv::Id cull_distance_is_negative = builder.createBinOp(
spv::OpFOrdLessThan, type_bool,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision),
const_float_0);
if (cull_condition != spv::NoResult) {
cull_condition =
builder.createBinOp(spv::OpLogicalAnd, type_bool, cull_condition,
cull_distance_is_negative);
} else {
cull_condition = cull_distance_is_negative;
}
}
}
assert_true(cull_condition != spv::NoResult);
spv::Block& discard_predecessor = *builder.getBuildPoint();
spv::Block& discard_then_block = builder.makeNewBlock();
spv::Block& discard_merge_block = builder.makeNewBlock();
{
std::unique_ptr<spv::Instruction> selection_merge_op(
std::make_unique<spv::Instruction>(spv::OpSelectionMerge));
selection_merge_op->addIdOperand(discard_merge_block.getId());
selection_merge_op->addImmediateOperand(
spv::SelectionControlDontFlattenMask);
discard_predecessor.addInstruction(std::move(selection_merge_op));
}
{
std::unique_ptr<spv::Instruction> branch_conditional_op(
std::make_unique<spv::Instruction>(spv::OpBranchConditional));
branch_conditional_op->addIdOperand(cull_condition);
branch_conditional_op->addIdOperand(discard_then_block.getId());
branch_conditional_op->addIdOperand(discard_merge_block.getId());
branch_conditional_op->addImmediateOperand(1);
branch_conditional_op->addImmediateOperand(2);
discard_predecessor.addInstruction(std::move(branch_conditional_op));
}
discard_then_block.addPredecessor(&discard_predecessor);
discard_merge_block.addPredecessor(&discard_predecessor);
builder.setBuildPoint(&discard_then_block);
builder.createNoResultOp(spv::OpReturn);
builder.setBuildPoint(&discard_merge_block);
}
switch (key.type) {
case PipelineGeometryShader::kRectangleList: {
// Construct a strip with the fourth vertex generated by mirroring a
// vertex across the longest edge (the diagonal).
//
// Possible options:
//
// 0---1
// | /|
// | / | - 12 is the longest edge, strip 0123 (most commonly used)
// |/ | v3 = v0 + (v1 - v0) + (v2 - v0), or v3 = -v0 + v1 + v2
// 2--[3]
//
// 1---2
// | /|
// | / | - 20 is the longest edge, strip 1203
// |/ |
// 0--[3]
//
// 2---0
// | /|
// | / | - 01 is the longest edge, strip 2013
// |/ |
// 1--[3]
spv::Id const_int_0 = builder.makeIntConstant(0);
spv::Id const_int_1 = builder.makeIntConstant(1);
spv::Id const_int_2 = builder.makeIntConstant(2);
spv::Id const_int_3 = builder.makeIntConstant(3);
// Get squares of edge lengths to choose the longest edge.
// [0] - 12, [1] - 20, [2] - 01.
spv::Id edge_lengths[3];
id_vector_temp.resize(3);
id_vector_temp[1] = const_member_in_gl_per_vertex_position;
for (uint32_t i = 0; i < 3; ++i) {
id_vector_temp[0] = builder.makeIntConstant(int32_t((1 + i) % 3));
id_vector_temp[2] = const_int_0;
spv::Id edge_0_x = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[2] = const_int_1;
spv::Id edge_0_y = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[0] = builder.makeIntConstant(int32_t((2 + i) % 3));
id_vector_temp[2] = const_int_0;
spv::Id edge_1_x = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[2] = const_int_1;
spv::Id edge_1_y = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
spv::Id edge_x =
builder.createBinOp(spv::OpFSub, type_float, edge_1_x, edge_0_x);
spv::Id edge_y =
builder.createBinOp(spv::OpFSub, type_float, edge_1_y, edge_0_y);
edge_lengths[i] = builder.createBinOp(
spv::OpFAdd, type_float,
builder.createBinOp(spv::OpFMul, type_float, edge_x, edge_x),
builder.createBinOp(spv::OpFMul, type_float, edge_y, edge_y));
}
// Choose the index of the first vertex in the strip based on which edge
// is the longest, and calculate the indices of the other vertices.
spv::Id vertex_indices[3];
// If 12 > 20 && 12 > 01, then 12 is the longest edge, and the strip is
// 0123. Otherwise, if 20 > 01, then 20 is the longest, and the strip is
// 1203, but if not, 01 is the longest, and the strip is 2013.
vertex_indices[0] = builder.createTriOp(
spv::OpSelect, type_int,
builder.createBinOp(
spv::OpLogicalAnd, type_bool,
builder.createBinOp(spv::OpFOrdGreaterThan, type_bool,
edge_lengths[0], edge_lengths[1]),
builder.createBinOp(spv::OpFOrdGreaterThan, type_bool,
edge_lengths[0], edge_lengths[2])),
const_int_0,
builder.createTriOp(
spv::OpSelect, type_int,
builder.createBinOp(spv::OpFOrdGreaterThan, type_bool,
edge_lengths[1], edge_lengths[2]),
const_int_1, const_int_2));
for (uint32_t i = 1; i < 3; ++i) {
// vertex_indices[i] = (vertex_indices[0] + i) % 3
spv::Id vertex_index_without_wrapping =
builder.createBinOp(spv::OpIAdd, type_int, vertex_indices[0],
builder.makeIntConstant(int32_t(i)));
vertex_indices[i] = builder.createTriOp(
spv::OpSelect, type_int,
builder.createBinOp(spv::OpSLessThan, type_bool,
vertex_index_without_wrapping, const_int_3),
vertex_index_without_wrapping,
builder.createBinOp(spv::OpISub, type_int,
vertex_index_without_wrapping, const_int_3));
}
// Initialize the point coordinates output for safety if this shader type
// is used with has_point_coordinates for some reason.
spv::Id const_point_coordinates_zero = spv::NoResult;
if (key.has_point_coordinates) {
spv::Id const_float_0 = builder.makeFloatConstant(0.0f);
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(const_float_0);
id_vector_temp.push_back(const_float_0);
const_point_coordinates_zero = builder.makeCompositeConstant(
type_point_coordinates, id_vector_temp);
}
// Emit the triangle in the strip that consists of the original vertices.
for (uint32_t i = 0; i < 3; ++i) {
spv::Id vertex_index = vertex_indices[i];
// Interpolators.
if (key.interpolator_count) {
id_vector_temp.clear();
id_vector_temp.push_back(vertex_index);
builder.createStore(
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
spv::NoPrecision),
out_interpolators);
}
// Point coordinates.
if (key.has_point_coordinates) {
builder.createStore(const_point_coordinates_zero,
out_point_coordinates);
}
// Position.
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(vertex_index);
id_vector_temp.push_back(const_member_in_gl_per_vertex_position);
spv::Id vertex_position = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp.clear();
id_vector_temp.push_back(const_member_out_gl_per_vertex_position);
builder.createStore(
vertex_position,
builder.createAccessChain(spv::StorageClassOutput,
out_gl_per_vertex, id_vector_temp));
// Clip distances.
if (clip_distance_count) {
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(vertex_index);
id_vector_temp.push_back(const_member_in_gl_per_vertex_clip_distance);
spv::Id vertex_clip_distances = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision);
id_vector_temp.clear();
id_vector_temp.push_back(
const_member_out_gl_per_vertex_clip_distance);
builder.createStore(
vertex_clip_distances,
builder.createAccessChain(spv::StorageClassOutput,
out_gl_per_vertex, id_vector_temp));
}
// Emit the vertex.
builder.createNoResultOp(spv::OpEmitVertex);
}
// Construct the fourth vertex.
// Interpolators.
for (uint32_t i = 0; i < key.interpolator_count; ++i) {
spv::Id const_int_i = builder.makeIntConstant(int32_t(i));
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(vertex_indices[0]);
id_vector_temp.push_back(const_int_i);
spv::Id vertex_interpolator_v0 = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_interpolators,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[0] = vertex_indices[1];
spv::Id vertex_interpolator_v01 = builder.createBinOp(
spv::OpFSub, type_float4,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
spv::NoPrecision),
vertex_interpolator_v0);
builder.addDecoration(vertex_interpolator_v01,
spv::DecorationNoContraction);
id_vector_temp[0] = vertex_indices[2];
spv::Id vertex_interpolator_v3 = builder.createBinOp(
spv::OpFAdd, type_float4, vertex_interpolator_v01,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
spv::NoPrecision));
builder.addDecoration(vertex_interpolator_v3,
spv::DecorationNoContraction);
id_vector_temp.clear();
id_vector_temp.push_back(const_int_i);
builder.createStore(
vertex_interpolator_v3,
builder.createAccessChain(spv::StorageClassOutput,
out_interpolators, id_vector_temp));
}
// Point coordinates.
if (key.has_point_coordinates) {
builder.createStore(const_point_coordinates_zero,
out_point_coordinates);
}
// Position.
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(vertex_indices[0]);
id_vector_temp.push_back(const_member_in_gl_per_vertex_position);
spv::Id vertex_position_v0 = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[0] = vertex_indices[1];
spv::Id vertex_position_v01 = builder.createBinOp(
spv::OpFSub, type_float4,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision),
vertex_position_v0);
builder.addDecoration(vertex_position_v01, spv::DecorationNoContraction);
id_vector_temp[0] = vertex_indices[2];
spv::Id vertex_position_v3 = builder.createBinOp(
spv::OpFAdd, type_float4, vertex_position_v01,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision));
builder.addDecoration(vertex_position_v3, spv::DecorationNoContraction);
id_vector_temp.clear();
id_vector_temp.push_back(const_member_out_gl_per_vertex_position);
builder.createStore(
vertex_position_v3,
builder.createAccessChain(spv::StorageClassOutput, out_gl_per_vertex,
id_vector_temp));
// Clip distances.
for (uint32_t i = 0; i < clip_distance_count; ++i) {
spv::Id const_int_i = builder.makeIntConstant(int32_t(i));
id_vector_temp.clear();
id_vector_temp.reserve(3);
id_vector_temp.push_back(vertex_indices[0]);
id_vector_temp.push_back(const_member_in_gl_per_vertex_clip_distance);
id_vector_temp.push_back(const_int_i);
spv::Id vertex_clip_distance_v0 = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[0] = vertex_indices[1];
spv::Id vertex_clip_distance_v01 = builder.createBinOp(
spv::OpFSub, type_float,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision),
vertex_clip_distance_v0);
builder.addDecoration(vertex_clip_distance_v01,
spv::DecorationNoContraction);
id_vector_temp[0] = vertex_indices[2];
spv::Id vertex_clip_distance_v3 = builder.createBinOp(
spv::OpFAdd, type_float, vertex_clip_distance_v01,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision));
builder.addDecoration(vertex_clip_distance_v3,
spv::DecorationNoContraction);
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(const_member_in_gl_per_vertex_clip_distance);
id_vector_temp.push_back(const_int_i);
builder.createStore(
vertex_clip_distance_v3,
builder.createAccessChain(spv::StorageClassOutput,
out_gl_per_vertex, id_vector_temp));
}
// Emit the vertex.
builder.createNoResultOp(spv::OpEmitVertex);
builder.createNoResultOp(spv::OpEndPrimitive);
} break;
case PipelineGeometryShader::kQuadList: {
// Initialize the point coordinates output for safety if this shader type
// is used with has_point_coordinates for some reason.
spv::Id const_point_coordinates_zero = spv::NoResult;
if (key.has_point_coordinates) {
spv::Id const_float_0 = builder.makeFloatConstant(0.0f);
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(const_float_0);
id_vector_temp.push_back(const_float_0);
const_point_coordinates_zero = builder.makeCompositeConstant(
type_point_coordinates, id_vector_temp);
}
// Build the triangle strip from the original quad vertices in the
// 0, 1, 3, 2 order (like specified for GL_QUAD_STRIP).
// TODO(Triang3l): Find the correct decomposition of quads into triangles
// on the real hardware.
for (uint32_t i = 0; i < 4; ++i) {
spv::Id const_vertex_index =
builder.makeIntConstant(int32_t(i ^ (i >> 1)));
// Interpolators.
if (key.interpolator_count) {
id_vector_temp.clear();
id_vector_temp.push_back(const_vertex_index);
builder.createStore(
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
spv::NoPrecision),
out_interpolators);
}
// Point coordinates.
if (key.has_point_coordinates) {
builder.createStore(const_point_coordinates_zero,
out_point_coordinates);
}
// Position.
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(const_vertex_index);
id_vector_temp.push_back(const_member_in_gl_per_vertex_position);
spv::Id vertex_position = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp.clear();
id_vector_temp.push_back(const_member_out_gl_per_vertex_position);
builder.createStore(
vertex_position,
builder.createAccessChain(spv::StorageClassOutput,
out_gl_per_vertex, id_vector_temp));
// Clip distances.
if (clip_distance_count) {
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(const_vertex_index);
id_vector_temp.push_back(const_member_in_gl_per_vertex_clip_distance);
spv::Id vertex_clip_distances = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision);
id_vector_temp.clear();
id_vector_temp.push_back(
const_member_out_gl_per_vertex_clip_distance);
builder.createStore(
vertex_clip_distances,
builder.createAccessChain(spv::StorageClassOutput,
out_gl_per_vertex, id_vector_temp));
}
// Emit the vertex.
builder.createNoResultOp(spv::OpEmitVertex);
}
builder.createNoResultOp(spv::OpEndPrimitive);
} break;
default:
assert_unhandled_case(key.type);
}
// End the main function.
builder.leaveFunction();
// Serialize the shader code.
std::vector<unsigned int> shader_code;
builder.dump(shader_code);
// Create the shader module, and store the handle even if creation fails not
// to try to create it again later.
const ui::vulkan::VulkanProvider& provider =
command_processor_.GetVulkanProvider();
VkShaderModule shader_module = ui::vulkan::util::CreateShaderModule(
provider, reinterpret_cast<const uint32_t*>(shader_code.data()),
sizeof(uint32_t) * shader_code.size());
if (shader_module == VK_NULL_HANDLE) {
XELOGE(
"VulkanPipelineCache: Failed to create the primitive type geometry "
"shader 0x{:08X}",
key.key);
}
geometry_shaders_.emplace(key, shader_module);
return shader_module;
}
bool VulkanPipelineCache::EnsurePipelineCreated( bool VulkanPipelineCache::EnsurePipelineCreated(
const PipelineCreationArguments& creation_arguments) { const PipelineCreationArguments& creation_arguments) {
if (creation_arguments.pipeline->second.pipeline != VK_NULL_HANDLE) { if (creation_arguments.pipeline->second.pipeline != VK_NULL_HANDLE) {
@ -739,15 +1513,7 @@ bool VulkanPipelineCache::EnsurePipelineCreated(
shader_stage_vertex.pName = "main"; shader_stage_vertex.pName = "main";
shader_stage_vertex.pSpecializationInfo = nullptr; shader_stage_vertex.pSpecializationInfo = nullptr;
// Geometry shader. // Geometry shader.
VkShaderModule geometry_shader = VK_NULL_HANDLE; if (creation_arguments.geometry_shader != VK_NULL_HANDLE) {
switch (description.geometry_shader) {
case PipelineGeometryShader::kRectangleList:
geometry_shader = gs_rectangle_list_;
break;
default:
break;
}
if (geometry_shader != VK_NULL_HANDLE) {
VkPipelineShaderStageCreateInfo& shader_stage_geometry = VkPipelineShaderStageCreateInfo& shader_stage_geometry =
shader_stages[shader_stage_count++]; shader_stages[shader_stage_count++];
shader_stage_geometry.sType = shader_stage_geometry.sType =
@ -755,7 +1521,7 @@ bool VulkanPipelineCache::EnsurePipelineCreated(
shader_stage_geometry.pNext = nullptr; shader_stage_geometry.pNext = nullptr;
shader_stage_geometry.flags = 0; shader_stage_geometry.flags = 0;
shader_stage_geometry.stage = VK_SHADER_STAGE_GEOMETRY_BIT; shader_stage_geometry.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
shader_stage_geometry.module = geometry_shader; shader_stage_geometry.module = creation_arguments.geometry_shader;
shader_stage_geometry.pName = "main"; shader_stage_geometry.pName = "main";
shader_stage_geometry.pSpecializationInfo = nullptr; shader_stage_geometry.pSpecializationInfo = nullptr;
} }

View File

@ -86,6 +86,7 @@ class VulkanPipelineCache {
enum class PipelineGeometryShader : uint32_t { enum class PipelineGeometryShader : uint32_t {
kNone, kNone,
kRectangleList, kRectangleList,
kQuadList,
}; };
enum class PipelinePrimitiveTopology : uint32_t { enum class PipelinePrimitiveTopology : uint32_t {
@ -205,9 +206,37 @@ class VulkanPipelineCache {
std::pair<const PipelineDescription, Pipeline>* pipeline; std::pair<const PipelineDescription, Pipeline>* pipeline;
const VulkanShader::VulkanTranslation* vertex_shader; const VulkanShader::VulkanTranslation* vertex_shader;
const VulkanShader::VulkanTranslation* pixel_shader; const VulkanShader::VulkanTranslation* pixel_shader;
VkShaderModule geometry_shader;
VkRenderPass render_pass; VkRenderPass render_pass;
}; };
union GeometryShaderKey {
uint32_t key;
struct {
PipelineGeometryShader type : 2;
uint32_t interpolator_count : 5;
uint32_t user_clip_plane_count : 3;
uint32_t user_clip_plane_cull : 1;
uint32_t has_vertex_kill_and : 1;
uint32_t has_point_size : 1;
uint32_t has_point_coordinates : 1;
};
GeometryShaderKey() : key(0) { static_assert_size(*this, sizeof(key)); }
struct Hasher {
size_t operator()(const GeometryShaderKey& key) const {
return std::hash<uint32_t>{}(key.key);
}
};
bool operator==(const GeometryShaderKey& other_key) const {
return key == other_key.key;
}
bool operator!=(const GeometryShaderKey& other_key) const {
return !(*this == other_key);
}
};
// Can be called from multiple threads. // Can be called from multiple threads.
bool TranslateAnalyzedShader(SpirvShaderTranslator& translator, bool TranslateAnalyzedShader(SpirvShaderTranslator& translator,
VulkanShader::VulkanTranslation& translation); VulkanShader::VulkanTranslation& translation);
@ -227,6 +256,10 @@ class VulkanPipelineCache {
// Whether the pipeline for the given description is supported by the device. // Whether the pipeline for the given description is supported by the device.
bool ArePipelineRequirementsMet(const PipelineDescription& description) const; bool ArePipelineRequirementsMet(const PipelineDescription& description) const;
static bool GetGeometryShaderKey(PipelineGeometryShader geometry_shader_type,
GeometryShaderKey& key_out);
VkShaderModule GetGeometryShader(GeometryShaderKey key);
// Can be called from creation threads - all needed data must be fully set up // Can be called from creation threads - all needed data must be fully set up
// at the point of the call: shaders must be translated, pipeline layout and // at the point of the call: shaders must be translated, pipeline layout and
// render pass objects must be available. // render pass objects must be available.
@ -237,8 +270,6 @@ class VulkanPipelineCache {
const RegisterFile& register_file_; const RegisterFile& register_file_;
VulkanRenderTargetCache& render_target_cache_; VulkanRenderTargetCache& render_target_cache_;
VkShaderModule gs_rectangle_list_ = VK_NULL_HANDLE;
// Temporary storage for AnalyzeUcode calls on the processor thread. // Temporary storage for AnalyzeUcode calls on the processor thread.
StringBuffer ucode_disasm_buffer_; StringBuffer ucode_disasm_buffer_;
// Reusable shader translator on the command processor thread. // Reusable shader translator on the command processor thread.
@ -249,6 +280,12 @@ class VulkanPipelineCache {
xe::hash::IdentityHasher<uint64_t>> xe::hash::IdentityHasher<uint64_t>>
shaders_; shaders_;
// Geometry shaders for Xenos primitive types not supported by Vulkan.
// Stores VK_NULL_HANDLE if failed to create.
std::unordered_map<GeometryShaderKey, VkShaderModule,
GeometryShaderKey::Hasher>
geometry_shaders_;
std::unordered_map<PipelineDescription, Pipeline, PipelineDescription::Hasher> std::unordered_map<PipelineDescription, Pipeline, PipelineDescription::Hasher>
pipelines_; pipelines_;

View File

@ -28,17 +28,16 @@ VulkanPrimitiveProcessor::~VulkanPrimitiveProcessor() { Shutdown(true); }
bool VulkanPrimitiveProcessor::Initialize() { bool VulkanPrimitiveProcessor::Initialize() {
// TODO(Triang3l): fullDrawIndexUint32 feature check and indirect index fetch. // TODO(Triang3l): fullDrawIndexUint32 feature check and indirect index fetch.
// TODO(Triang3l): geometryShader check for quads when geometry shaders are
// added.
const ui::vulkan::VulkanProvider& provider = const ui::vulkan::VulkanProvider& provider =
command_processor_.GetVulkanProvider(); command_processor_.GetVulkanProvider();
const VkPhysicalDeviceFeatures& device_features = provider.device_features();
const VkPhysicalDevicePortabilitySubsetFeaturesKHR* const VkPhysicalDevicePortabilitySubsetFeaturesKHR*
device_portability_subset_features = device_portability_subset_features =
provider.device_portability_subset_features(); provider.device_portability_subset_features();
if (!InitializeCommon(true, if (!InitializeCommon(true,
!device_portability_subset_features || !device_portability_subset_features ||
device_portability_subset_features->triangleFans, device_portability_subset_features->triangleFans,
false, false)) { false, device_features.geometryShader)) {
Shutdown(); Shutdown();
return false; return false;
} }