diff --git a/src/xenia/gpu/shaders/bytecode/vulkan_spirv/primitive_rectangle_list_gs.h b/src/xenia/gpu/shaders/bytecode/vulkan_spirv/primitive_rectangle_list_gs.h deleted file mode 100644 index 86590f170..000000000 --- a/src/xenia/gpu/shaders/bytecode/vulkan_spirv/primitive_rectangle_list_gs.h +++ /dev/null @@ -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, -}; diff --git a/src/xenia/gpu/shaders/primitive_rectangle_list.gs.glsl b/src/xenia/gpu/shaders/primitive_rectangle_list.gs.glsl deleted file mode 100644 index 1dd7f7edb..000000000 --- a/src/xenia/gpu/shaders/primitive_rectangle_list.gs.glsl +++ /dev/null @@ -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(); -} diff --git a/src/xenia/gpu/shaders/xenos_gs.glsli b/src/xenia/gpu/shaders/xenos_gs.glsli deleted file mode 100644 index f27b5cae3..000000000 --- a/src/xenia/gpu/shaders/xenos_gs.glsli +++ /dev/null @@ -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_ diff --git a/src/xenia/gpu/spirv_shader_translator.cc b/src/xenia/gpu/spirv_shader_translator.cc index 99d92b0c3..9cc6fec72 100644 --- a/src/xenia/gpu/spirv_shader_translator.cc +++ b/src/xenia/gpu/spirv_shader_translator.cc @@ -932,64 +932,34 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() { } // Create the Xenia-specific outputs. + // TODO(Triang3l): Change to an interpolator array. for (uint32_t i = 0; i < xenos::kMaxInterpolators; ++i) { spv::Id interpolator = builder_->createVariable( spv::NoPrecision, spv::StorageClassOutput, type_float4_, (kInterpolatorNamePrefix + std::to_string(i)).c_str()); input_output_interpolators_[i] = interpolator; builder_->addDecoration(interpolator, spv::DecorationLocation, int(i)); + builder_->addDecoration(interpolator, spv::DecorationInvariant); main_interface_.push_back(interpolator); } - // Create the entire GLSL 4.50 gl_PerVertex output similar to what glslang - // 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); - } + // Create the gl_PerVertex output for used system outputs. std::vector struct_per_vertex_members; struct_per_vertex_members.reserve(kOutputPerVertexMemberCount); 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 = builder_->makeStructType(struct_per_vertex_members, "gl_PerVertex"); + builder_->addMemberName(type_struct_per_vertex, + kOutputPerVertexMemberPosition, "gl_Position"); builder_->addMemberDecoration(type_struct_per_vertex, kOutputPerVertexMemberPosition, spv::DecorationInvariant); builder_->addMemberDecoration(type_struct_per_vertex, kOutputPerVertexMemberPosition, 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); - output_per_vertex_ = - builder_->createVariable(spv::NoPrecision, spv::StorageClassOutput, - type_struct_per_vertex, "xe_out_gl_PerVertex"); + output_per_vertex_ = builder_->createVariable( + spv::NoPrecision, spv::StorageClassOutput, type_struct_per_vertex, ""); main_interface_.push_back(output_per_vertex_); } @@ -1178,18 +1148,6 @@ void SpirvShaderTranslator::CompleteVertexOrTessEvalShaderInMain() { std::move(composite_construct_op)); } 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() { diff --git a/src/xenia/gpu/spirv_shader_translator.h b/src/xenia/gpu/spirv_shader_translator.h index 69ae784f4..259b703c1 100644 --- a/src/xenia/gpu/spirv_shader_translator.h +++ b/src/xenia/gpu/spirv_shader_translator.h @@ -459,9 +459,6 @@ class SpirvShaderTranslator : public ShaderTranslator { enum OutputPerVertexMember : unsigned int { kOutputPerVertexMemberPosition, - kOutputPerVertexMemberPointSize, - kOutputPerVertexMemberClipDistance, - kOutputPerVertexMemberCullDistance, kOutputPerVertexMemberCount, }; spv::Id output_per_vertex_; diff --git a/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc b/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc index a096e18e7..db2d36d69 100644 --- a/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc +++ b/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc @@ -11,9 +11,12 @@ #include #include +#include #include #include +#include +#include "third_party/glslang/SPIRV/SpvBuilder.h" #include "xenia/base/assert.h" #include "xenia/base/logging.h" #include "xenia/base/math.h" @@ -33,11 +36,6 @@ namespace xe { namespace gpu { namespace vulkan { -// Generated with `xb buildshaders`. -namespace shaders { -#include "xenia/gpu/shaders/bytecode/vulkan_spirv/primitive_rectangle_list_gs.h" -} // namespace shaders - VulkanPipelineCache::VulkanPipelineCache( VulkanCommandProcessor& command_processor, const RegisterFile& register_file, @@ -51,20 +49,6 @@ VulkanPipelineCache::~VulkanPipelineCache() { Shutdown(); } bool VulkanPipelineCache::Initialize() { const ui::vulkan::VulkanProvider& provider = 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::Features(provider)); @@ -80,10 +64,14 @@ void VulkanPipelineCache::Shutdown() { 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, - gs_rectangle_list_); + shader_translator_.reset(); } void VulkanPipelineCache::ClearCache() { @@ -255,6 +243,14 @@ bool VulkanPipelineCache::ConfigurePipeline( if (!pipeline_layout) { 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 = render_target_cache_.GetRenderPass(render_pass_key); if (render_pass == VK_NULL_HANDLE) { @@ -266,6 +262,7 @@ bool VulkanPipelineCache::ConfigurePipeline( creation_arguments.pipeline = &pipeline; creation_arguments.vertex_shader = vertex_shader; creation_arguments.pixel_shader = pixel_shader; + creation_arguments.geometry_shader = geometry_shader; creation_arguments.render_pass = render_pass; if (!EnsurePipelineCreated(creation_arguments)) { return false; @@ -419,6 +416,7 @@ bool VulkanPipelineCache::GetCurrentStateDescription( primitive_topology = PipelinePrimitiveTopology::kTriangleList; break; case xenos::PrimitiveType::kQuadList: + geometry_shader = PipelineGeometryShader::kQuadList; primitive_topology = PipelinePrimitiveTopology::kLineListWithAdjacency; break; default: @@ -686,6 +684,782 @@ bool VulkanPipelineCache::ArePipelineRequirementsMet( 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 id_vector_temp; + std::vector 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 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 main_param_types; + std::vector> 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 selection_merge_op( + std::make_unique(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 branch_conditional_op( + std::make_unique(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 selection_merge_op( + std::make_unique(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 branch_conditional_op( + std::make_unique(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 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(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( const PipelineCreationArguments& creation_arguments) { if (creation_arguments.pipeline->second.pipeline != VK_NULL_HANDLE) { @@ -739,15 +1513,7 @@ bool VulkanPipelineCache::EnsurePipelineCreated( shader_stage_vertex.pName = "main"; shader_stage_vertex.pSpecializationInfo = nullptr; // Geometry shader. - VkShaderModule 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) { + if (creation_arguments.geometry_shader != VK_NULL_HANDLE) { VkPipelineShaderStageCreateInfo& shader_stage_geometry = shader_stages[shader_stage_count++]; shader_stage_geometry.sType = @@ -755,7 +1521,7 @@ bool VulkanPipelineCache::EnsurePipelineCreated( shader_stage_geometry.pNext = nullptr; shader_stage_geometry.flags = 0; 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.pSpecializationInfo = nullptr; } diff --git a/src/xenia/gpu/vulkan/vulkan_pipeline_cache.h b/src/xenia/gpu/vulkan/vulkan_pipeline_cache.h index f979b0b03..ceb04efcc 100644 --- a/src/xenia/gpu/vulkan/vulkan_pipeline_cache.h +++ b/src/xenia/gpu/vulkan/vulkan_pipeline_cache.h @@ -86,6 +86,7 @@ class VulkanPipelineCache { enum class PipelineGeometryShader : uint32_t { kNone, kRectangleList, + kQuadList, }; enum class PipelinePrimitiveTopology : uint32_t { @@ -205,9 +206,37 @@ class VulkanPipelineCache { std::pair* pipeline; const VulkanShader::VulkanTranslation* vertex_shader; const VulkanShader::VulkanTranslation* pixel_shader; + VkShaderModule geometry_shader; 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{}(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. bool TranslateAnalyzedShader(SpirvShaderTranslator& translator, VulkanShader::VulkanTranslation& translation); @@ -227,6 +256,10 @@ class VulkanPipelineCache { // Whether the pipeline for the given description is supported by the device. 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 // at the point of the call: shaders must be translated, pipeline layout and // render pass objects must be available. @@ -237,8 +270,6 @@ class VulkanPipelineCache { const RegisterFile& register_file_; VulkanRenderTargetCache& render_target_cache_; - VkShaderModule gs_rectangle_list_ = VK_NULL_HANDLE; - // Temporary storage for AnalyzeUcode calls on the processor thread. StringBuffer ucode_disasm_buffer_; // Reusable shader translator on the command processor thread. @@ -249,6 +280,12 @@ class VulkanPipelineCache { xe::hash::IdentityHasher> shaders_; + // Geometry shaders for Xenos primitive types not supported by Vulkan. + // Stores VK_NULL_HANDLE if failed to create. + std::unordered_map + geometry_shaders_; + std::unordered_map pipelines_; diff --git a/src/xenia/gpu/vulkan/vulkan_primitive_processor.cc b/src/xenia/gpu/vulkan/vulkan_primitive_processor.cc index 0d33aaf64..058b6a5d1 100644 --- a/src/xenia/gpu/vulkan/vulkan_primitive_processor.cc +++ b/src/xenia/gpu/vulkan/vulkan_primitive_processor.cc @@ -28,17 +28,16 @@ VulkanPrimitiveProcessor::~VulkanPrimitiveProcessor() { Shutdown(true); } bool VulkanPrimitiveProcessor::Initialize() { // 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 = command_processor_.GetVulkanProvider(); + const VkPhysicalDeviceFeatures& device_features = provider.device_features(); const VkPhysicalDevicePortabilitySubsetFeaturesKHR* device_portability_subset_features = provider.device_portability_subset_features(); if (!InitializeCommon(true, !device_portability_subset_features || device_portability_subset_features->triangleFans, - false, false)) { + false, device_features.geometryShader)) { Shutdown(); return false; }