1//
2// Copyright (C) 2024 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17package vulkan_xml
18
19import (
20	"berberis/cpp_types"
21	"fmt"
22	"testing"
23)
24
25func TestUnmarshallNameAsString(t *testing.T) {
26	registry, err := Unmarshal([]byte(`
27		<?xml version="1.0" encoding="UTF-8"?>
28		<registry>
29			<types>
30                <type>This type is <name>int</name></type>
31				<type category="test">Here is <name>type_name</name></type>
32			</types>
33		</registry>`))
34	if err != nil {
35		t.Error("Failed to parse test XML")
36		return
37	}
38	if registry.Types[0].Name != "int" {
39		t.Error("Name of type improperly parsed")
40	}
41	if registry.Types[1].Name != "type_name" {
42		t.Error("Name of type improperly parsed")
43	}
44}
45
46func TestUnknownType(t *testing.T) {
47	_, err := Unmarshal([]byte(`
48		<?xml version="1.0" encoding="UTF-8"?>
49		<registry>
50			<types>
51				<type name="Foo"/>
52			</types>
53		</registry>`))
54	if err == nil {
55		t.Error("XML was errorneously accepted")
56		return
57	}
58	if err.Error() != "Unknown type without category: \"Foo\"" {
59		t.Error("Unexpected error: \"" + err.Error() + "\"")
60	}
61}
62
63func TestStructType(t *testing.T) {
64	registry, err := Unmarshal([]byte(`
65		<?xml version="1.0" encoding="UTF-8"?>
66		<registry>
67			<types>
68				<type category="union" name="Union">
69					<member><type>float</type> <name>float32</name>[4]</member>
70					<member>const <type>int32_t</type> <name>int32</name>[4]</member>
71				</type>
72			</types>
73		</registry>`))
74	if err != nil {
75		t.Error("Failed to parse test XML")
76		return
77	}
78	if registry.Types[0].Members[0].Name != "float32" {
79		t.Error("Name of member improperly parsed")
80	}
81	if registry.Types[0].Members[1].Name != "int32" {
82		t.Error("Name of member improperly parsed")
83	}
84
85}
86
87func TestEnumWarts(t *testing.T) {
88	registry, err := Unmarshal([]byte(`
89		<?xml version="1.0" encoding="UTF-8"?>
90		<registry>
91			<enums name="API Constants">
92				<enum value="1000.0f"
93				      name="VK_LOD_CLAMP_NONE"
94				      comment="We don't care about this enum value but our parser shouldn't choke on it"/>
95				<enum value="0"
96				      name="VK_FALSE"
97				      comment="We don't care about thus enum value but our parser shouldn't choke on it"/>
98			</enums>
99			<feature api="vulkan" name="VK_VERSION_1_0" number="1.0">
100				<require comment="API constants">
101					<enum name="VK_FALSE"/>
102				</require>
103			</feature>
104		</registry>`))
105	if err != nil {
106		t.Error("Failed to parse test XML")
107		return
108	}
109	_, _, _, _, _, err = VulkanTypesfromXML(registry)
110	if err != nil {
111		t.Error("Failed to parse test XML")
112		return
113	}
114}
115
116func TestEnumExtend(t *testing.T) {
117	registry, err := Unmarshal([]byte(`
118		<?xml version="1.0" encoding="UTF-8"?>
119		<registry>
120			<types>
121				<type name="VkStructureType" category="enum"/>
122			</types>
123			<feature api="vulkan" name="VK_VERSION_1_1" number="1.1">
124				<require>
125					<enum extends="VkStructureType" extnumber="158" offset="1" name="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO"/>
126				</require>
127			</feature>
128			<extensions>
129				<extension name="VK_KHR_swapchain" number="2">
130					<require>
131						<enum value="70" name="VK_KHR_SWAPCHAIN_SPEC_VERSION"/>
132						<enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PRESENT_INFO_KHR"/>
133					</require>
134				</extension>
135			</extensions>
136		</registry>`))
137	if err != nil {
138		t.Error("Failed to parse test XML")
139		return
140	}
141	_, types, _, _, extensions, err := VulkanTypesfromXML(registry)
142	if err != nil {
143		t.Error("Failed to parse test XML")
144		return
145	}
146	if extension_spec, ok := extensions["VK_KHR_swapchain"]; ok {
147		if extension_spec != 70 {
148			t.Error("VK_KHR_swapchain spec is not 70")
149		}
150	} else {
151		t.Error("VK_KHR_swapchain extension not found")
152	}
153	if typе, ok := types["VkStructureType"]; ok {
154		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
155			if typе.Kind(arch) != cpp_types.Enum {
156				t.Error("VkStructureType is not enum")
157			}
158			if typе.Elem(arch).Kind(arch) != cpp_types.Int32T {
159				t.Error("VkStructureType is not std::int32_t-based enum")
160			}
161			if typе.NumField(arch) != 2 {
162				t.Error("VkStructureType is supposed to have two fields")
163			}
164			enumerator := typе.Field(0, arch).(cpp_types.EnumFieldInfo)
165			if enumerator.Name() != "VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO" {
166				t.Error("VkStructureType's first element is not VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO")
167			}
168			if enumerator.Value() != 1000157001 {
169				t.Error("VkStructureType's first element is not 1000157001")
170			}
171			enumerator = typе.Field(1, arch).(cpp_types.EnumFieldInfo)
172			if enumerator.Name() != "VK_STRUCTURE_TYPE_PRESENT_INFO_KHR" {
173				t.Error("VkStructureType's first element is not VK_STRUCTURE_TYPE_PRESENT_INFO_KHR")
174			}
175			if enumerator.Value() != 1000001001 {
176				t.Error("VkStructureType's first element is not 1000001001")
177			}
178		}
179		return
180	}
181	t.Error("VkStructureType type wasn't parsed")
182}
183
184func TestEnumUInt32(t *testing.T) {
185	registry, err := Unmarshal([]byte(`
186		<?xml version="1.0" encoding="UTF-8"?>
187		<registry>
188			<types>
189				<type name="VkImageCreateFlagBits" category="enum"/>
190			</types>
191			<enums name="VkImageCreateFlagBits" type="enum">
192				<enum bitpos="31"
193				      name="VK_IMAGE_RESERVED_31_BIT"
194				      comment="Note: that value doesn't fit into int32_t but does fit into uint32_t"/>
195			</enums>
196		</registry>`))
197	if err != nil {
198		t.Error("Failed to parse test XML")
199		return
200	}
201	_, types, _, _, _, err := VulkanTypesfromXML(registry)
202	if err != nil {
203		t.Error("Failed to parse test XML")
204		return
205	}
206	if typе, ok := types["VkImageCreateFlagBits"]; ok {
207		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
208			if typе.Kind(arch) != cpp_types.Enum {
209				t.Error("VkImageCreateFlagBits is not enum")
210			}
211			if typе.Elem(arch).Kind(arch) != cpp_types.UInt32T {
212				t.Error("VkImageCreateFlagBits is not std::uint32_t-based enum")
213			}
214			if typе.NumField(arch) != 1 {
215				t.Error("VkImageCreateFlagBits is supposed to have two fields")
216			}
217			enumerator := typе.Field(0, arch).(cpp_types.EnumFieldInfo)
218			if enumerator.Name() != "VK_IMAGE_RESERVED_31_BIT" {
219				t.Error("VkImageCreateFlagBits's first element is not VK_IMAGE_RESERVED_31_BIT")
220			}
221			if enumerator.Value() != 0x80000000 {
222				t.Error("VkImageCreateFlagBits's first element is not 0x80000000")
223			}
224		}
225		return
226	}
227	t.Error("VkImageCreateFlagBits type wasn't parsed")
228}
229
230func TestEnum64bit(t *testing.T) {
231	registry, err := Unmarshal([]byte(`
232		<?xml version="1.0" encoding="UTF-8"?>
233		<registry>
234			<types>
235				<type name="Vk64BitEnum" category="enum"/>
236			</types>
237			<enums name="Vk64BitEnum" type="enum">
238				<enum value="0x100000000" name="VK_64_BIT_ENUM_TEST_VALUE"/>
239			</enums>
240		</registry>`))
241	if err != nil {
242		t.Error("Failed to parse test XML")
243		return
244	}
245	_, types, _, _, _, err := VulkanTypesfromXML(registry)
246	if err != nil {
247		t.Error("Failed to parse test XML")
248		return
249	}
250	if typе, ok := types["Vk64BitEnum"]; ok {
251		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
252			if typе.Kind(arch) != cpp_types.Enum {
253				t.Error("Vk64BitEnum is not enum")
254			}
255			if typе.Elem(arch).Kind(arch) != cpp_types.Int64T {
256				t.Error("Vk64BitEnum is not std::int64_t-based enum")
257			}
258			if typе.NumField(arch) != 1 {
259				t.Error("Vk64BitEnum is supposed to have one field")
260			}
261			enumerator := typе.Field(0, arch).(cpp_types.EnumFieldInfo)
262			if enumerator.Name() != "VK_64_BIT_ENUM_TEST_VALUE" {
263				t.Error("Vk64BitEnum's first element is not VK_64_BIT_ENUM_TEST_VALUE")
264			}
265			if enumerator.Value() != 0x100000000 {
266				t.Error("Vk64BitEnum's first element is not 0x100000000")
267			}
268		}
269		return
270	}
271	t.Error("Vk64BitEnum type wasn't parsed")
272}
273
274func TestHandle(t *testing.T) {
275	registry, err := Unmarshal([]byte(`
276		<?xml version="1.0" encoding="UTF-8"?>
277		<registry>
278			<types>
279				<type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>VkInstance</name>)</type>
280			</types>
281		</registry>`))
282	if err != nil {
283		t.Error("Failed to parse test XML")
284		return
285	}
286	_, types, _, _, _, err := VulkanTypesfromXML(registry)
287	if err != nil {
288		t.Error("Failed to parse test XML")
289		return
290	}
291	if typе, ok := types["VkInstance"]; ok {
292		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
293			if typе.Kind(arch) != cpp_types.Alias {
294				t.Error("vkInstance is not alias")
295				continue
296			}
297			if typе.Elem(arch).Kind(arch) != cpp_types.Ptr {
298				t.Error("vkInstance is not pointer alias")
299				continue
300			}
301			if typе.Elem(arch).Elem(arch).Kind(arch) != cpp_types.Opaque {
302				t.Error("vkInstance is not pointer alias to opaque type")
303				continue
304			}
305		}
306		return
307	}
308	t.Error("vkInstance type wasn't parsed")
309}
310
311func TestNondispatchableHandle(t *testing.T) {
312	registry, err := Unmarshal([]byte(`
313		<?xml version="1.0" encoding="UTF-8"?>
314		<registry>
315			<types>
316				<type category="handle"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkFence</name>)</type>
317			</types>
318		</registry>`))
319	if err != nil {
320		t.Error("Failed to parse test XML")
321		return
322	}
323	_, types, _, _, _, err := VulkanTypesfromXML(registry)
324	if err != nil {
325		t.Error("Failed to parse test XML")
326		return
327	}
328	if typе, ok := types["VkFence"]; ok {
329		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
330			if typе.Kind(arch) != cpp_types.Alias {
331				t.Error("VkFence is not alias")
332				continue
333			}
334			if arch%2 == 0 {
335				if typе.Elem(arch) != cpp_types.UInt64TType {
336					t.Error("VkFence is not uint64_t alias")
337					continue
338				}
339			} else {
340				if typе.Elem(arch).Kind(arch) != cpp_types.Ptr {
341					t.Error("VkFence is not pointer alias")
342					continue
343				}
344				if typе.Elem(arch).Elem(arch).Kind(arch) != cpp_types.Opaque {
345					t.Error("VkFence is not pointer alias to opaque type")
346					continue
347				}
348			}
349		}
350		return
351	}
352	t.Error("VkFence type wasn't parsed")
353}
354
355func TestFuncPtr(t *testing.T) {
356	registry, err := Unmarshal([]byte(`
357		<?xml version="1.0" encoding="UTF-8"?>
358		<registry>
359			<types>
360				<type category="funcpointer">typedef void (VKAPI_PTR *<name>PFN_vkVoidFunction</name>)(void);</type>
361				<type category="funcpointer" requires="VkDebugUtilsMessengerCallbackDataEXT">
362					typedef uint32_t (VKAPI_PTR *<name>PFN_vkDebugUtilsMessengerCallbackEXT</name>)(
363						<type>uint8_t</type>                                          pIndex,
364						const <type>VkDebugUtilsMessengerCallbackDataEXT</type>*      pCallbackData,
365						<type>void</type>*                                            pUserData);
366				</type>
367			</types>
368		</registry>`))
369	if err != nil {
370		t.Error("Failed to parse test XML")
371		return
372	}
373	_, types, _, _, _, err := VulkanTypesfromXML(registry)
374	if err != nil {
375		t.Error("Failed to parse test XML")
376		return
377	}
378	if typе, ok := types["PFN_vkVoidFunction"]; ok {
379		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
380			if typе.Kind(arch) != cpp_types.Ptr ||
381				typе.Elem(arch).Kind(arch) != cpp_types.Func {
382				t.Error("PFN_vkVoidFunction is not function pointer")
383				continue
384			}
385			if typе.Elem(arch).Elem(arch).Kind(arch) != cpp_types.Void {
386				t.Error("PFN_vkVoidFunction return type is not void")
387			}
388			if typе.Elem(arch).NumField(arch) != 0 {
389				t.Error("PFN_vkVoidFunction is not zero-argument function")
390			}
391		}
392	} else {
393		t.Error("PFN_vkVoidFunction type wasn't parsed")
394	}
395	if typе, ok := types["PFN_vkDebugUtilsMessengerCallbackEXT"]; ok {
396		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
397			if typе.Kind(arch) != cpp_types.Ptr ||
398				typе.Elem(arch).Kind(arch) != cpp_types.Func {
399				t.Error("VkDebugUtilsMessengerCallbackDataEXT is not function pointer")
400				continue
401			}
402			if typе.Elem(arch).Elem(arch).Kind(arch) != cpp_types.UInt32T {
403				t.Error("VkDebugUtilsMessengerCallbackDataEXT return type is not uint32_t")
404			}
405			if typе.Elem(arch).NumField(arch) != 3 {
406				t.Error("VkDebugUtilsMessengerCallbackDataEXT is not two-argument function")
407			}
408			field0 := typе.Elem(arch).Field(0, arch)
409			if field0.Name() != "pIndex" {
410				t.Error("First argument of VkDebugUtilsMessengerCallbackDataEXT is not pIndex")
411			}
412			if field0.Type().Kind(arch) != cpp_types.UInt8T {
413				t.Error("First argument of VkDebugUtilsMessengerCallbackDataEXT has wrong type")
414			}
415			field1 := typе.Elem(arch).Field(1, arch)
416			if field1.Name() != "pCallbackData" {
417				t.Error("Second argument of VkDebugUtilsMessengerCallbackDataEXT is not pCallbackData")
418			}
419			if field1.Type().Kind(arch) != cpp_types.Ptr ||
420				field1.Type().Elem(arch).Kind(arch) != cpp_types.Const ||
421				field1.Type().Elem(arch).Elem(arch).Kind(arch) != cpp_types.Opaque ||
422				field1.Type().Elem(arch).Elem(arch).Name(arch) != "VkDebugUtilsMessengerCallbackDataEXT" {
423				t.Error("Second argument of VkDebugUtilsMessengerCallbackDataEXT has wrong type")
424			}
425			field2 := typе.Elem(arch).Field(2, arch)
426			if field2.Name() != "pUserData" {
427				t.Error("Third argument of VkDebugUtilsMessengerCallbackDataEXT is not pUserData")
428			}
429			if field2.Type().Kind(arch) != cpp_types.Ptr ||
430				field2.Type().Elem(arch).Kind(arch) != cpp_types.Void {
431				t.Error("Third argument of VkDebugUtilsMessengerCallbackDataEXT has wrong type")
432			}
433		}
434	} else {
435		t.Error("PFN_vkDebugUtilsMessengerCallbackEXT type wasn't parsed")
436	}
437}
438
439func TestStruct(t *testing.T) {
440	registry, err := Unmarshal([]byte(`
441		<?xml version="1.0" encoding="UTF-8"?>
442		<registry>
443			<types>
444				<type category="basetype">typedef <type>uint32_t</type> <name>VkFlags</name>;</type>
445				<type name="VkStructureType" category="enum"/>
446				<type requires="VkGeometryInstanceFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkGeometryInstanceFlagsKHR</name>;</type>
447				<type category="struct" name="VkBaseOutStructure">
448					<member><type>VkStructureType</type> <name>sType</name></member>
449					<member>struct <type>VkBaseOutStructure</type>* <name>pNext</name></member>
450				</type>
451				<type category="struct" name="VkBaseInStructure">
452					<member><type>VkStructureType</type> <name>sType</name></member>
453					<member>const struct <type>VkBaseInStructure</type>* <name>pNext</name></member>
454				</type>
455				<type category="struct" name="VkAccelerationStructureInstanceKHR">
456					<comment>The bitfields in this structure are non-normative since bitfield ordering is implementation-defined in C. The specification defines the normative layout.</comment>
457					<member><type>VkTransformMatrixKHR</type> <name>transform</name></member>
458					<member><type>uint32_t</type> <name>instanceCustomIndex</name>:24</member>
459					<member><type>uint32_t</type> <name>mask</name>:8</member>
460					<member><type>uint32_t</type> <name>instanceShaderBindingTableRecordOffset</name>:24</member>
461					<member optional="true"><type>VkGeometryInstanceFlagsKHR</type> <name>flags</name>:8</member>
462					<member><type>uint64_t</type> <name>accelerationStructureReference</name></member>
463				</type>
464				<type category="struct" name="VkTransformMatrixKHR">
465					<member><type>float</type> <name>matrix</name>[3][4]</member>
466				</type>
467			</types>
468		</registry>`))
469	if err != nil {
470		t.Error("Failed to parse test XML")
471		return
472	}
473	_, types, _, _, _, err := VulkanTypesfromXML(registry)
474	if err != nil {
475		t.Error("Failed to parse test XML")
476		return
477	}
478	if typе, ok := types["VkBaseOutStructure"]; ok {
479		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
480			if typе.Kind(arch) != cpp_types.Struct {
481				t.Error("VkBaseOutStructure is not a struct")
482				continue
483			}
484			if typе.NumField(arch) != 2 {
485				t.Error("VkBaseOutStructure is not two-field struct")
486				continue
487			}
488			field0 := typе.Field(0, arch)
489			if field0.Name() != "sType" {
490				t.Error("First field of VkBaseOutStructure is not sType")
491			}
492			if field0.Type().Kind(arch) != cpp_types.Enum ||
493				field0.Type().Elem(arch).Kind(arch) != cpp_types.Int32T {
494				t.Error("First field of VkBaseOutStructure has wrong type")
495			}
496			field1 := typе.Field(1, arch)
497			if field1.Name() != "pNext" {
498				t.Error("Second field of VkBaseOutStructure is not pNext")
499			}
500			if field1.Type().Kind(arch) != cpp_types.Ptr ||
501				field1.Type().Elem(arch).Kind(arch) != cpp_types.Struct {
502				t.Error("Second field of VkBaseOutStructure has wrong type")
503			}
504		}
505	} else {
506		t.Error("VkBaseOutStructure type wasn't parsed")
507	}
508	if typе, ok := types["VkBaseInStructure"]; ok {
509		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
510			if typе.Kind(arch) != cpp_types.Struct {
511				t.Error("VkBaseInStructure is not a struct")
512				continue
513			}
514			if typе.NumField(arch) != 2 {
515				t.Error("VkBaseInStructure is not two-field struct")
516			}
517			field0 := typе.Field(0, arch)
518			if field0.Name() != "sType" {
519				t.Error("First field of VkBaseInStructure is not sType")
520			}
521			if field0.Type().Kind(arch) != cpp_types.Enum ||
522				field0.Type().Elem(arch).Kind(arch) != cpp_types.Int32T {
523				t.Error("First field of VkBaseInStructure has wrong type")
524			}
525			field1 := typе.Field(1, arch)
526			if field1.Name() != "pNext" {
527				t.Error("Second field of VkBaseInStructuree is not pNext")
528			}
529			if field1.Type().Kind(arch) != cpp_types.Ptr ||
530				field1.Type().Elem(arch).Kind(arch) != cpp_types.Const ||
531				field1.Type().Elem(arch).Elem(arch).Kind(arch) != cpp_types.Struct {
532				t.Error("Second field of VkBaseInStructure has wrong type")
533			}
534		}
535	} else {
536		t.Error("VkBaseInStructure type wasn't parsed")
537	}
538	if typе, ok := types["VkTransformMatrixKHR"]; ok {
539		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
540			if typе.Kind(arch) != cpp_types.Struct {
541				t.Error("VkTransformMatrixKHR is not a struct")
542				continue
543			}
544			if typе.NumField(arch) != 1 {
545				t.Error("VkTransformMatrixKHR is not one-field struct")
546			}
547			field0 := typе.Field(0, arch)
548			if field0.Name() != "matrix" {
549				t.Error("First field of VkTransformMatrixKHR is not matrix")
550			}
551			if field0.Type().Kind(arch) != cpp_types.Array ||
552				field0.Type().NumField(arch) != 4 ||
553				field0.Type().Elem(arch).Kind(arch) != cpp_types.Array ||
554				field0.Type().Elem(arch).NumField(arch) != 3 ||
555				field0.Type().Elem(arch).Elem(arch).Kind(arch) != cpp_types.Float32 {
556				t.Error("First field of VkTransformMatrixKHR has wrong type")
557			}
558		}
559	} else {
560		t.Error("PFN_vkDebugUtilsMessengerCallbackEXT type wasn't parsed")
561	}
562	if typе, ok := types["VkAccelerationStructureInstanceKHR"]; ok {
563		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
564			if typе.Kind(arch) != cpp_types.Struct {
565				t.Error("VkAccelerationStructureInstanceKHR is not a struct")
566				continue
567			}
568			if typе.NumField(arch) != 6 {
569				t.Error("VkAccelerationStructureInstanceKHR is not six-field struct")
570			}
571			assertLayout := func(t *testing.T, field_no uint, field cpp_types.FieldInfo, field_name string, size, offset uint) {
572				if field.Name() != field_name {
573					t.Error(fmt.Sprintf("Field %d of VkAccelerationStructureInstanceKHR is not %s", field_no, field_name))
574				}
575				if field.Type().Bits(arch) != size {
576					t.Error(fmt.Sprintf("Field %d of VkAccelerationStructureInstanceKHR size is not %d bit", field_no, size))
577				}
578				if field.(cpp_types.StructFieldInfo).Offset() != offset {
579					t.Error(fmt.Sprintf("Field %d of VkAccelerationStructureInstanceKHR offset is not %d bit", field_no, offset))
580				}
581			}
582			field0 := typе.Field(0, arch)
583			assertLayout(t, 1, field0, "transform", 384, 0)
584			if field0.Type().Kind(arch) != cpp_types.Struct ||
585				field0.Type().Name(arch) != "struct VkTransformMatrixKHR" {
586				t.Error("First field of VkAccelerationStructureInstanceKHR has wrong type")
587			}
588			// Note: bitfields maybe represented differently but we don't care as long as
589			// size and offsets match our expectations.
590			field1 := typе.Field(1, arch)
591			assertLayout(t, 2, field1, "instanceCustomIndex", 24, 384)
592			field2 := typе.Field(2, arch)
593			assertLayout(t, 3, field2, "mask", 8, 408)
594			field3 := typе.Field(3, arch)
595			assertLayout(t, 4, field3, "instanceShaderBindingTableRecordOffset", 24, 416)
596			field4 := typе.Field(4, arch)
597			assertLayout(t, 5, field4, "flags", 8, 440)
598			field5 := typе.Field(5, arch)
599			assertLayout(t, 6, field5, "accelerationStructureReference", 64, 448)
600			if field5.Type().Kind(arch) != cpp_types.UInt64T {
601				t.Error("Sixth field of VkAccelerationStructureInstanceKHR wrong type")
602			}
603		}
604	} else {
605		t.Error("PFN_vkDebugUtilsMessengerCallbackEXT type wasn't parsed")
606	}
607}
608
609func TestCommand(t *testing.T) {
610	registry, err := Unmarshal([]byte(`
611		<?xml version="1.0" encoding="UTF-8"?>
612		<registry>
613			<types>
614				<type category="define">
615#define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* object;</type>
616				<type category="handle" parent="VkCommandPool"><type>VK_DEFINE_HANDLE</type>(<name>VkCommandBuffer</name>)</type>
617			</types>
618			<commands>
619				<command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
620					<proto><type>void</type> <name>vkCmdSetBlendConstants</name></proto>
621					<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
622					<param><type>uint32_t</type> <name>blendConstantsLen</name></param>
623					<param len="blendConstantsLen">const <type>float</type> <name>blendConstants</name>[4]</param>
624				</command>
625			</commands>
626		</registry>`))
627	if err != nil {
628		t.Error("Failed to parse test XML")
629		return
630	}
631	_, _, _, commands, _, err := VulkanTypesfromXML(registry)
632	if err != nil {
633		t.Error("Failed to parse test XML")
634		return
635	}
636	if command, ok := commands["vkCmdSetBlendConstants"]; ok {
637		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
638			if command.Kind(arch) != cpp_types.Func {
639				t.Error("vkCmdSetBlendConstants is not a function")
640				continue
641			}
642			if command.Elem(arch).Kind(arch) != cpp_types.Void {
643				t.Error("vkCmdSetBlendConstants is not a void function")
644			}
645			if command.NumField(arch) != 3 {
646				t.Error("vkCmdSetBlendConstants is not three-argument function")
647				continue
648			}
649			field0 := command.Field(0, arch)
650			if field0.Name() != "commandBuffer" {
651				t.Error("First argument of vkCmdSetBlendConstants is not commandBuffer")
652			}
653			if field0.Type().Kind(arch) != cpp_types.Alias ||
654				field0.Type().Elem(arch).Kind(arch) != cpp_types.Ptr ||
655				field0.Type().Elem(arch).Elem(arch).Kind(arch) != cpp_types.Opaque ||
656				field0.Type().Elem(arch).Elem(arch).Name(arch) != "struct VkCommandBuffer_T" {
657				t.Error("First field of vkCmdSetBlendConstants has wrong type")
658			}
659			field1 := command.Field(1, arch)
660			if field1.Name() != "blendConstantsLen" {
661				t.Error("Second argument of vkCmdSetBlendConstants is not blendConstants")
662			}
663			if field1.Type().Kind(arch) != cpp_types.UInt32T {
664				t.Error("Second field of vkCmdSetBlendConstants has wrong type")
665			}
666			field2 := command.Field(2, arch)
667			if field2.Name() != "blendConstants" {
668				t.Error("Third argument of vkCmdSetBlendConstants is not blendConstants")
669			}
670			if field2.Type().Kind(arch) != cpp_types.Ptr ||
671				field2.Type().Elem(arch).Kind(arch) != cpp_types.Const ||
672				field2.Type().Elem(arch).Elem(arch).Kind(arch) != cpp_types.Float32 ||
673				field2.BaseFieldInfo().(ExtendedFieldInfo).Length().Name() != field1.Name() ||
674				field2.BaseFieldInfo().(ExtendedFieldInfo).Length().Type() != field1.Type() {
675				t.Error("Third field of vkCmdSetBlendConstants has wrong type")
676			}
677		}
678	} else {
679		t.Error("vkCmdSetBlendConstants command wasn't parsed")
680	}
681}
682
683func TestCommandWithComplexLen(t *testing.T) {
684	registry, err := Unmarshal([]byte(`
685		<?xml version="1.0" encoding="UTF-8"?>
686		<registry>
687			<types>
688				<type category="define">
689#define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* object;</type>
690				<type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>VkDescriptorPool</name>)</type>
691				<type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>VkDescriptorSet</name>)</type>
692				<type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>VkDescriptorSetLayout</name>)</type>
693				<type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>VkDevice</name>)</type>
694				<type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>VkStructureType</name>)</type>
695				<type category="struct" name="VkDescriptorSetAllocateInfo">
696					<member values="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
697					<member optional="true">const <type>void</type>* <name>pNext</name></member>
698					<member><type>VkDescriptorPool</type> <name>descriptorPool</name></member>
699					<member><type>uint32_t</type> <name>descriptorSetCount</name></member>
700					<member len="descriptorSetCount">const <type>VkDescriptorSetLayout</type>* <name>pSetLayouts</name></member>
701				</type>
702			</types>
703			<commands>
704				<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_FRAGMENTED_POOL,VK_ERROR_OUT_OF_POOL_MEMORY">
705					<proto><type>void</type> <name>vkAllocateDescriptorSets</name></proto>
706					<param><type>VkDevice</type> <name>device</name></param>
707					<param externsync="pAllocateInfo-&gt;descriptorPool">const <type>VkDescriptorSetAllocateInfo</type>* <name>pAllocateInfo</name></param>
708					<param len="pAllocateInfo-&gt;descriptorSetCount"><type>VkDescriptorSet</type>* <name>pDescriptorSets</name></param>
709				</command>
710			</commands>
711		</registry>`))
712	if err != nil {
713		t.Error("Failed to parse test XML" + err.Error())
714		return
715	}
716	_, types, _, commands, _, err := VulkanTypesfromXML(registry)
717	if err != nil {
718		t.Error("Failed to parse test XML")
719		return
720	}
721	if command, ok := commands["vkAllocateDescriptorSets"]; ok {
722		for arch := cpp_types.FirstArch; arch <= cpp_types.LastArch; arch++ {
723			if command.Kind(arch) != cpp_types.Func {
724				t.Error("vkAllocateDescriptorSets is not a function")
725				continue
726			}
727			if command.Elem(arch).Kind(arch) != cpp_types.Void {
728				t.Error("vkAllocateDescriptorSets is not a void function")
729			}
730			if command.NumField(arch) != 3 {
731				t.Error("vkAllocateDescriptorSets is not three-argument function")
732				continue
733			}
734			field0 := command.Field(0, arch)
735			if field0.Name() != "device" {
736				t.Error("First argument of vkAllocateDescriptorSets is not device")
737			}
738			if field0.Type().Kind(arch) != cpp_types.Alias ||
739				field0.Type().Elem(arch).Kind(arch) != cpp_types.Ptr ||
740				field0.Type().Elem(arch).Elem(arch).Kind(arch) != cpp_types.Opaque ||
741				field0.Type().Elem(arch).Elem(arch).Name(arch) != "struct VkDevice_T" {
742				t.Error("First field of vkAllocateDescriptorSets has wrong type")
743			}
744			field1 := command.Field(1, arch)
745			if field1.Name() != "pAllocateInfo" {
746				t.Error("Second argument of vkAllocateDescriptorSets is not pAllocateInfo")
747			}
748			if field1.Type().Kind(arch) != cpp_types.Ptr ||
749				field1.Type().Elem(arch).Kind(arch) != cpp_types.Const ||
750				field1.Type().Elem(arch).Elem(arch).Kind(arch) != cpp_types.Struct ||
751				field1.Type().Elem(arch).Elem(arch).Name(arch) != "struct VkDescriptorSetAllocateInfo" {
752				t.Error("First field of vkAllocateDescriptorSets has wrong type")
753			}
754			field2 := command.Field(2, arch)
755			if field2.Name() != "pDescriptorSets" {
756				t.Error("Third argument of vkAllocateDescriptorSets is not pDescriptorSets")
757			}
758			field1_3 := types["VkDescriptorSetAllocateInfo"].Field(3, arch)
759			if field2.Type().Kind(arch) != cpp_types.Ptr ||
760				field2.Type().Elem(arch).Kind(arch) != cpp_types.Alias ||
761				field2.Type().Elem(arch).Elem(arch).Kind(arch) != cpp_types.Ptr ||
762				field2.Type().Elem(arch).Elem(arch).Elem(arch).Kind(arch) != cpp_types.Opaque ||
763				field2.Type().Elem(arch).Elem(arch).Elem(arch).Name(arch) != "struct VkDescriptorSet_T" ||
764				field2.BaseFieldInfo().(ExtendedFieldInfo).Length().Name() != field1.Name() ||
765				field2.BaseFieldInfo().(ExtendedFieldInfo).Length().Type() != field1.Type() ||
766				field2.BaseFieldInfo().(ExtendedFieldInfo).NestedField().Name() != field1_3.Name() ||
767				field2.BaseFieldInfo().(ExtendedFieldInfo).NestedField().Type() != field1_3.Type() {
768				t.Error("Third field of vkAllocateDescriptorSets has wrong type")
769			}
770		}
771	} else {
772		t.Error("vkCmdSetBlendConstants command wasn't parsed")
773	}
774}
775