Sfoglia il codice sorgente

파이프라인 정보 출력.

Hongtae Kim 6 anni fa
parent
commit
491fee1856
2 ha cambiato i file con 235 aggiunte e 169 eliminazioni
  1. 231
    169
      TestApp1/TestApp1.cpp
  2. 4
    0
      TestApp1/TestApp1.vcxproj

+ 231
- 169
TestApp1/TestApp1.cpp Vedi File

@@ -6,170 +6,237 @@
6 6
 #endif
7 7
 #include <DK.h>
8 8
 
9
+
10
+DKString ShaderStageNames(uint32_t s)
11
+{
12
+    DKArray<const char*> stages;
13
+    if (s & (uint32_t)DKShaderStage::Vertex)
14
+        stages.Add("Vertex");
15
+    if (s & (uint32_t)DKShaderStage::TessellationControl)
16
+        stages.Add("TessCtrl");
17
+    if (s & (uint32_t)DKShaderStage::TessellationEvaluation)
18
+        stages.Add("TessEval");
19
+    if (s & (uint32_t)DKShaderStage::Geometry)
20
+        stages.Add("Geometry");
21
+    if (s & (uint32_t)DKShaderStage::Fragment)
22
+        stages.Add("Fragment");
23
+    if (s & (uint32_t)DKShaderStage::Compute)
24
+        stages.Add("Compute");
25
+
26
+    if (stages.IsEmpty())
27
+        return "";
28
+
29
+    DKString str = stages.Value(0);
30
+    for (int i = 1; i < stages.Count(); ++i)
31
+        str += DKString::Format(", %ls", stages.Value(i));
32
+    return str;
33
+}
34
+
9 35
 const char* ShaderDataTypeStr(DKShaderDataType t)
10 36
 {
11
-	switch (t) {
12
-	case DKShaderDataType::Unknown:				return "Unknown";
13
-	case DKShaderDataType::None:				return "None";
14
-
15
-	case DKShaderDataType::Struct:				return "Struct";
16
-	case DKShaderDataType::Texture:				return "Texture";
17
-	case DKShaderDataType::Sampler:				return "Sampler";
18
-
19
-	case DKShaderDataType::Float:				return "Float";
20
-	case DKShaderDataType::Float2:				return "Float2";
21
-	case DKShaderDataType::Float3:				return "Float3";
22
-	case DKShaderDataType::Float4:				return "Float4";
23
-
24
-	case DKShaderDataType::Float2x2:			return "Float2x2";
25
-	case DKShaderDataType::Float2x3:			return "Float2x3";
26
-	case DKShaderDataType::Float2x4:			return "Float2x4";
27
-
28
-	case DKShaderDataType::Float3x2:			return "Float3x2";
29
-	case DKShaderDataType::Float3x3:			return "Float3x3";
30
-	case DKShaderDataType::Float3x4:			return "Float3x4";
31
-
32
-	case DKShaderDataType::Float4x2:			return "Float4x2";
33
-	case DKShaderDataType::Float4x3:			return "Float4x3";
34
-	case DKShaderDataType::Float4x4:			return "Float4x4";
35
-
36
-	case DKShaderDataType::Half:				return "Half";
37
-	case DKShaderDataType::Half2:				return "Half2";
38
-	case DKShaderDataType::Half3:				return "Half3";
39
-	case DKShaderDataType::Half4:				return "Half4";
40
-
41
-	case DKShaderDataType::Half2x2:				return "Half2x2";
42
-	case DKShaderDataType::Half2x3:				return "Half2x3";
43
-	case DKShaderDataType::Half2x4:				return "Half2x4";
44
-
45
-	case DKShaderDataType::Half3x2:				return "Half3x2";
46
-	case DKShaderDataType::Half3x3:				return "Half3x3";
47
-	case DKShaderDataType::Half3x4:				return "Half3x4";
48
-
49
-	case DKShaderDataType::Half4x2:				return "Half4x2";
50
-	case DKShaderDataType::Half4x3:				return "Half4x3";
51
-	case DKShaderDataType::Half4x4:				return "Half4x4";
52
-
53
-	case DKShaderDataType::Int:					return "Int";
54
-	case DKShaderDataType::Int2:				return "Int2";
55
-	case DKShaderDataType::Int3:				return "Int3";
56
-	case DKShaderDataType::Int4:				return "Int4";
57
-
58
-	case DKShaderDataType::UInt:				return "UInt";
59
-	case DKShaderDataType::UInt2:				return "UInt2";
60
-	case DKShaderDataType::UInt3:				return "UInt3";
61
-	case DKShaderDataType::UInt4:				return "UInt4";
62
-
63
-	case DKShaderDataType::Short:				return "Short";
64
-	case DKShaderDataType::Short2:				return "Short2";
65
-	case DKShaderDataType::Short3:				return "Short3";
66
-	case DKShaderDataType::Short4:				return "Short4";
67
-
68
-	case DKShaderDataType::UShort:				return "UShort";
69
-	case DKShaderDataType::UShort2:				return "UShort2";
70
-	case DKShaderDataType::UShort3:				return "UShort3";
71
-	case DKShaderDataType::UShort4:				return "UShort4";
72
-
73
-	case DKShaderDataType::Char:				return "Char";
74
-	case DKShaderDataType::Char2:				return "Char2";
75
-	case DKShaderDataType::Char3:				return "Char3";
76
-	case DKShaderDataType::Char4:				return "Char4";
77
-
78
-	case DKShaderDataType::UChar:				return "UChar";
79
-	case DKShaderDataType::UChar2:				return "UChar2";
80
-	case DKShaderDataType::UChar3:				return "UChar3";
81
-	case DKShaderDataType::UChar4:				return "UChar4";
82
-
83
-	case DKShaderDataType::Bool:				return "Bool";
84
-	case DKShaderDataType::Bool2:				return "Bool2";
85
-	case DKShaderDataType::Bool3:				return "Bool3";
86
-	case DKShaderDataType::Bool4:				return "Bool4";
87
-	}
88
-	return "Error";
37
+    switch (t) {
38
+    case DKShaderDataType::Unknown:				return "Unknown";
39
+    case DKShaderDataType::None:				return "None";
40
+
41
+    case DKShaderDataType::Struct:				return "Struct";
42
+    case DKShaderDataType::Texture:				return "Texture";
43
+    case DKShaderDataType::Sampler:				return "Sampler";
44
+
45
+    case DKShaderDataType::Float:				return "Float";
46
+    case DKShaderDataType::Float2:				return "Float2";
47
+    case DKShaderDataType::Float3:				return "Float3";
48
+    case DKShaderDataType::Float4:				return "Float4";
49
+
50
+    case DKShaderDataType::Float2x2:			return "Float2x2";
51
+    case DKShaderDataType::Float2x3:			return "Float2x3";
52
+    case DKShaderDataType::Float2x4:			return "Float2x4";
53
+
54
+    case DKShaderDataType::Float3x2:			return "Float3x2";
55
+    case DKShaderDataType::Float3x3:			return "Float3x3";
56
+    case DKShaderDataType::Float3x4:			return "Float3x4";
57
+
58
+    case DKShaderDataType::Float4x2:			return "Float4x2";
59
+    case DKShaderDataType::Float4x3:			return "Float4x3";
60
+    case DKShaderDataType::Float4x4:			return "Float4x4";
61
+
62
+    case DKShaderDataType::Half:				return "Half";
63
+    case DKShaderDataType::Half2:				return "Half2";
64
+    case DKShaderDataType::Half3:				return "Half3";
65
+    case DKShaderDataType::Half4:				return "Half4";
66
+
67
+    case DKShaderDataType::Half2x2:				return "Half2x2";
68
+    case DKShaderDataType::Half2x3:				return "Half2x3";
69
+    case DKShaderDataType::Half2x4:				return "Half2x4";
70
+
71
+    case DKShaderDataType::Half3x2:				return "Half3x2";
72
+    case DKShaderDataType::Half3x3:				return "Half3x3";
73
+    case DKShaderDataType::Half3x4:				return "Half3x4";
74
+
75
+    case DKShaderDataType::Half4x2:				return "Half4x2";
76
+    case DKShaderDataType::Half4x3:				return "Half4x3";
77
+    case DKShaderDataType::Half4x4:				return "Half4x4";
78
+
79
+    case DKShaderDataType::Int:					return "Int";
80
+    case DKShaderDataType::Int2:				return "Int2";
81
+    case DKShaderDataType::Int3:				return "Int3";
82
+    case DKShaderDataType::Int4:				return "Int4";
83
+
84
+    case DKShaderDataType::UInt:				return "UInt";
85
+    case DKShaderDataType::UInt2:				return "UInt2";
86
+    case DKShaderDataType::UInt3:				return "UInt3";
87
+    case DKShaderDataType::UInt4:				return "UInt4";
88
+
89
+    case DKShaderDataType::Short:				return "Short";
90
+    case DKShaderDataType::Short2:				return "Short2";
91
+    case DKShaderDataType::Short3:				return "Short3";
92
+    case DKShaderDataType::Short4:				return "Short4";
93
+
94
+    case DKShaderDataType::UShort:				return "UShort";
95
+    case DKShaderDataType::UShort2:				return "UShort2";
96
+    case DKShaderDataType::UShort3:				return "UShort3";
97
+    case DKShaderDataType::UShort4:				return "UShort4";
98
+
99
+    case DKShaderDataType::Char:				return "Char";
100
+    case DKShaderDataType::Char2:				return "Char2";
101
+    case DKShaderDataType::Char3:				return "Char3";
102
+    case DKShaderDataType::Char4:				return "Char4";
103
+
104
+    case DKShaderDataType::UChar:				return "UChar";
105
+    case DKShaderDataType::UChar2:				return "UChar2";
106
+    case DKShaderDataType::UChar3:				return "UChar3";
107
+    case DKShaderDataType::UChar4:				return "UChar4";
108
+
109
+    case DKShaderDataType::Bool:				return "Bool";
110
+    case DKShaderDataType::Bool2:				return "Bool2";
111
+    case DKShaderDataType::Bool3:				return "Bool3";
112
+    case DKShaderDataType::Bool4:				return "Bool4";
113
+    }
114
+    return "Error";
89 115
 }
90 116
 
91
-void PrintShaderResource(const DKShaderResource& res)
117
+void PrintShaderResource(const DKShaderResource& res, DKLogCategory c = DKLogCategory::Info)
92 118
 {
93
-	struct MemberPrinter
94
-	{
95
-		const DKShaderResource& res;
96
-		int indent;
97
-		void operator()(const DKShaderResourceStruct& str) const
98
-		{
99
-			DKString indentStr = "";
100
-			for (int i = 0; i < indent; ++i)
101
-			{
102
-				indentStr += "    ";
103
-			}
104
-			for (const DKShaderResourceStructMember& mem : str.members)
105
-			{
106
-				if (mem.count > 1)
107
-				{
108
-					DKLogI(" %ls+ %ls[%d] (%s, Offset: %d, Size: %d, Stride: %d)",
109
-						   (const wchar_t*)indentStr,
110
-						   (const wchar_t*)mem.name,
111
-						   mem.count,
112
-						   ShaderDataTypeStr(mem.dataType),
113
-						   mem.offset, mem.size, mem.stride);
114
-
115
-				}
116
-				else
117
-				{
118
-					DKLogI(" %ls+ %ls (%s, Offset: %d, Size: %d)",
119
-						   (const wchar_t*)indentStr,
120
-						   (const wchar_t*)mem.name,
121
-						   ShaderDataTypeStr(mem.dataType),
122
-						   mem.offset, mem.size);
123
-				}
124
-
125
-				auto* p = res.structTypeMemberMap.Find(mem.typeInfoKey);
126
-				if (p)
127
-				{
128
-					DKLogI(" %ls+TypeKey: %ls (struct)",
129
-						   (const wchar_t*)indentStr,
130
-						   (const wchar_t*)res.typeInfoKey);
131
-					MemberPrinter{ res, indent + 1 }.operator()(p->value);
132
-				}
133
-			}
134
-		}
135
-	};
136
-	if (res.count > 1)
137
-		DKLogI("ShaderResource: %ls[%d] (set=%d, binding=%d)",
138
-		(const wchar_t*)res.name, res.count, res.set, res.binding);
139
-	else
140
-		DKLogI("ShaderResource: %ls (set=%d, binding=%d)", (const wchar_t*)res.name, res.set, res.binding);
141
-
142
-	const char* type = "Unknown (ERROR)";
143
-	switch (res.type)
144
-	{
145
-	case DKShaderResource::TypeBuffer: type = "Buffer"; break;
146
-	case DKShaderResource::TypeTexture:	type = "Texture"; break;
147
-	case DKShaderResource::TypeSampler:	type = "Sampler"; break;
148
-	case DKShaderResource::TypeThreadgroupMemory:	type = "Threadinggroup"; break;
149
-	}
150
-	const char* access = "Unknown (ERROR)";
151
-	switch (res.access)
152
-	{
153
-		case DKShaderResource::AccessReadOnly:	access = "ReadOnly"; break;
154
-		case DKShaderResource::AccessWriteOnly:	access = "WriteOnly"; break;
155
-		case DKShaderResource::AccessReadWrite:	access = "ReadWrite"; break;
156
-	}
157
-	DKLogI(" +Type:%s, Access:%s, Enabled:%d Alignment:%d, Size:%d",
158
-		   type,
159
-		   access,
160
-		   int(res.enabled),
161
-		   res.typeInfo.buffer.alignment,
162
-		   res.typeInfo.buffer.size);
163
-	if (res.typeInfoKey.Length() > 0)
164
-		DKLogI(" +TypeKey: %ls (struct)", (const wchar_t*)res.typeInfoKey);
165
-	if (res.type == DKShaderResource::TypeBuffer)
166
-	{
167
-		auto p = res.structTypeMemberMap.Find(res.typeInfoKey);
168
-		if (p)
169
-			MemberPrinter{ res, 1 }.operator()(p->value);
170
-	}
119
+    struct MemberPrinter
120
+    {
121
+        const DKShaderResource& res;
122
+        int indent;
123
+        DKLogCategory c;
124
+        void operator()(const DKShaderResourceStruct& str) const
125
+        {
126
+            DKString indentStr = "";
127
+            for (int i = 0; i < indent; ++i)
128
+            {
129
+                indentStr += "    ";
130
+            }
131
+            for (const DKShaderResourceStructMember& mem : str.members)
132
+            {
133
+                if (mem.count > 1)
134
+                {
135
+                    DKLog(c, " %ls+ %ls[%d] (%s, Offset: %d, Stride: %d)",
136
+                        (const wchar_t*)indentStr,
137
+                          (const wchar_t*)mem.name,
138
+                          mem.count,
139
+                          ShaderDataTypeStr(mem.dataType),
140
+                          mem.offset, mem.stride);
141
+
142
+                }
143
+                else
144
+                {
145
+                    DKLog(c, " %ls+ %ls (%s, Offset: %d)",
146
+                        (const wchar_t*)indentStr,
147
+                          (const wchar_t*)mem.name,
148
+                          ShaderDataTypeStr(mem.dataType),
149
+                          mem.offset);
150
+                }
151
+
152
+                auto* p = res.structTypeMemberMap.Find(mem.typeInfoKey);
153
+                if (p)
154
+                {
155
+                    DKLog(c, " %ls  Struct \"%ls\"",
156
+                        (const wchar_t*)indentStr,
157
+                          (const wchar_t*)mem.typeInfoKey);
158
+                    MemberPrinter{ res, indent + 1, c}.operator()(p->value);
159
+                }
160
+            }
161
+        }
162
+    };
163
+
164
+
165
+    if (res.count > 1)
166
+        DKLog(c, "ShaderResource: %ls[%d] (set=%d, binding=%d, stages=%ls)",
167
+        (const wchar_t*)res.name, res.count, res.set, res.binding,
168
+              (const wchar_t*)ShaderStageNames(res.stages));
169
+    else
170
+        DKLog(c, "ShaderResource: %ls (set=%d, binding=%d, stages=%ls)",
171
+        (const wchar_t*)res.name, res.set, res.binding,
172
+              (const wchar_t*)ShaderStageNames(res.stages));
173
+
174
+    const char* type = "Unknown (ERROR)";
175
+    switch (res.type)
176
+    {
177
+    case DKShaderResource::TypeBuffer: type = "Buffer"; break;
178
+    case DKShaderResource::TypeTexture:	type = "Texture"; break;
179
+    case DKShaderResource::TypeSampler:	type = "Sampler"; break;
180
+    case DKShaderResource::TypeTextureSampler: type = "SampledTexture"; break;
181
+    }
182
+    const char* access = "Unknown (ERROR)";
183
+    switch (res.access)
184
+    {
185
+    case DKShaderResource::AccessReadOnly:	access = "ReadOnly"; break;
186
+    case DKShaderResource::AccessWriteOnly:	access = "WriteOnly"; break;
187
+    case DKShaderResource::AccessReadWrite:	access = "ReadWrite"; break;
188
+    }
189
+
190
+    if (res.type == DKShaderResource::TypeBuffer)
191
+    {
192
+        DKLog(c, " Type:%s, Access:%s, Enabled:%d, Size:%d",
193
+              type,
194
+              access,
195
+              int(res.enabled),
196
+              res.typeInfo.buffer.size);
197
+    }
198
+    else
199
+    {
200
+        DKLog(c, " Type:%s, Access:%s, Enabled:%d",
201
+              type,
202
+              access,
203
+              int(res.enabled));
204
+    }
205
+    if (res.typeInfoKey.Length() > 0)
206
+        DKLog(c, " Struct \"%ls\"", (const wchar_t*)res.typeInfoKey);
207
+    if (res.type == DKShaderResource::TypeBuffer)
208
+    {
209
+        auto p = res.structTypeMemberMap.Find(res.typeInfoKey);
210
+        if (p)
211
+            MemberPrinter{ res, 1 , c}.operator()(p->value);
212
+    }
171 213
 }
172 214
 
215
+void PrintPipelineReflection(const DKPipelineReflection* reflection, DKLogCategory c = DKLogCategory::Error)
216
+{
217
+    DKLog(c, "=========================================================");
218
+    DKLog(c, "PipelineReflection.InputAttributes: %d", reflection->inputAttributes.Count());
219
+    for (int i = 0; i < reflection->inputAttributes.Count(); ++i)
220
+    {
221
+        const DKShaderAttribute& attr = reflection->inputAttributes.Value(i);
222
+        DKLog(c, "  [in] ShaderAttribute[%d]: \"%ls\" (location:%u)",
223
+              i, (const wchar_t*)attr.name, attr.location);
224
+    }
225
+    DKLog(c, "---------------------------------------------------------");
226
+    DKLog(c, "PipelineReflection.Resources: %d", reflection->resources.Count());
227
+    for (auto& arg : reflection->resources)
228
+        PrintShaderResource(arg, c);
229
+    for (int i = 0; i < reflection->pushConstantLayouts.Count(); ++i)
230
+    {
231
+        const DKShaderPushConstantLayout& layout = reflection->pushConstantLayouts.Value(i);
232
+        DKLog(c, " PushConstant:%d \"%ls\" (offset:%u, size:%u, stages:%ls)",
233
+              i, (const wchar_t*)layout.name, layout.offset, layout.size,
234
+              (const wchar_t*)ShaderStageNames(layout.stages));
235
+    }
236
+    DKLog(c, "=========================================================");
237
+}
238
+
239
+
173 240
 class TestApp1 : public DKApplication
174 241
 {
175 242
 	DKObject<DKWindow> window;
@@ -182,8 +249,8 @@ public:
182 249
 	{
183 250
 		DKObject<DKData> vertData = resourcePool.LoadResourceData("triangle.vert.spv");
184 251
 		DKObject<DKData> fragData = resourcePool.LoadResourceData("triangle.frag.spv");
185
-		DKShader vertShader(vertData, DKShader::Vertex);
186
-		DKShader fragShader(fragData, DKShader::Fragment);
252
+		DKShader vertShader(vertData);
253
+		DKShader fragShader(fragData);
187 254
 
188 255
 		DKObject<DKGraphicsDevice> device = DKGraphicsDevice::SharedInstance();
189 256
 		DKObject<DKShaderModule> vertShaderModule = device->CreateShaderModule(&vertShader);
@@ -195,10 +262,10 @@ public:
195 262
 		DKObject<DKCommandQueue> queue = device->CreateCommandQueue(DKCommandQueue::Graphics);
196 263
 		DKObject<DKSwapChain> swapChain = queue->CreateSwapChain(window);
197 264
 
198
-		DKLog("VertexFunction.VertexAttributes: %d", vertShaderFunction->VertexAttributes().Count());
199
-		for (int i = 0; i < vertShaderFunction->VertexAttributes().Count(); ++i)
265
+		DKLog("VertexFunction.VertexAttributes: %d", vertShaderFunction->StageInputAttributes().Count());
266
+		for (int i = 0; i < vertShaderFunction->StageInputAttributes().Count(); ++i)
200 267
 		{
201
-			const DKVertexAttribute& attr = vertShaderFunction->VertexAttributes().Value(i);
268
+			const DKShaderAttribute& attr = vertShaderFunction->StageInputAttributes().Value(i);
202 269
 			DKLog("  --> VertexAttribute[%d]: \"%ls\" (location:%u)", i, (const wchar_t*)attr.name, attr.location);
203 270
 		}
204 271
 
@@ -245,16 +312,11 @@ public:
245 312
 		pipelineDescriptor.cullMode = DKCullMode::None;
246 313
 		pipelineDescriptor.rasterizationEnabled = true;
247 314
 
248
-		DKRenderPipelineReflection reflection;
315
+		DKPipelineReflection reflection;
249 316
 		DKObject<DKRenderPipelineState> pipelineState = device->CreateRenderPipeline(pipelineDescriptor, &reflection);
250 317
 		if (pipelineState)
251 318
 		{
252
-			DKLog("PipelineReflection.VertexResources: %d", reflection.vertexResources.Count());
253
-			for (auto& arg : reflection.vertexResources)
254
-				PrintShaderResource(arg);
255
-			DKLog("PipelineReflection.FragmentResources: %d", reflection.fragmentResources.Count());
256
-			for (auto& arg : reflection.fragmentResources)
257
-				PrintShaderResource(arg);
319
+            PrintPipelineReflection(&reflection, DKLogCategory::Verbose);
258 320
 		}
259 321
 
260 322
 		DKTimer timer;

+ 4
- 0
TestApp1/TestApp1.vcxproj Vedi File

@@ -96,6 +96,7 @@
96 96
       <Optimization>Disabled</Optimization>
97 97
       <PreprocessorDefinitions>DKGL_STATIC=1;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
98 98
       <AdditionalIncludeDirectories>../DK</AdditionalIncludeDirectories>
99
+      <LanguageStandard>stdcpp17</LanguageStandard>
99 100
     </ClCompile>
100 101
     <Link>
101 102
       <SubSystem>Windows</SubSystem>
@@ -117,6 +118,7 @@ xcopy /Y /D /R /Q /E "$(SolutionDir)Data" "$(OutDir)Data\"
117 118
       <Optimization>Disabled</Optimization>
118 119
       <PreprocessorDefinitions>DKGL_STATIC=1;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
119 120
       <AdditionalIncludeDirectories>../DK</AdditionalIncludeDirectories>
121
+      <LanguageStandard>stdcpp17</LanguageStandard>
120 122
     </ClCompile>
121 123
     <Link>
122 124
       <SubSystem>Windows</SubSystem>
@@ -140,6 +142,7 @@ xcopy /Y /D /R /Q /E "$(SolutionDir)Data" "$(OutDir)Data\"
140 142
       <IntrinsicFunctions>true</IntrinsicFunctions>
141 143
       <PreprocessorDefinitions>DKGL_STATIC=1;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
142 144
       <AdditionalIncludeDirectories>../DK</AdditionalIncludeDirectories>
145
+      <LanguageStandard>stdcpp17</LanguageStandard>
143 146
     </ClCompile>
144 147
     <Link>
145 148
       <SubSystem>Windows</SubSystem>
@@ -165,6 +168,7 @@ xcopy /Y /D /R /Q /E "$(SolutionDir)Data" "$(OutDir)Data\"
165 168
       <IntrinsicFunctions>true</IntrinsicFunctions>
166 169
       <PreprocessorDefinitions>DKGL_STATIC=1;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
167 170
       <AdditionalIncludeDirectories>../DK</AdditionalIncludeDirectories>
171
+      <LanguageStandard>stdcpp17</LanguageStandard>
168 172
     </ClCompile>
169 173
     <Link>
170 174
       <SubSystem>Windows</SubSystem>