• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "VulkanStream.h"
15 
16 #include "IOStream.h"
17 
18 #include "common/goldfish_vk_deepcopy.h"
19 #include "common/goldfish_vk_extension_structs.h"
20 #include "common/goldfish_vk_marshaling.h"
21 #include "common/goldfish_vk_reserved_marshaling.h"
22 #include "common/goldfish_vk_testing.h"
23 
24 #include "android/base/ArraySize.h"
25 #include "android/base/BumpPool.h"
26 
27 #include <gtest/gtest.h>
28 #include <string.h>
29 #include <vulkan.h>
30 
31 using android::base::arraySize;
32 
33 namespace goldfish_vk {
34 
35 class TestStream : public IOStream {
36 public:
37     static constexpr size_t kBufSize = 1024;
TestStream()38     TestStream() : IOStream(kBufSize) { }
39 protected:
40 
getDmaForReading(uint64_t guest_paddr)41     void* getDmaForReading(uint64_t guest_paddr) override { return nullptr; }
unlockDma(uint64_t guest_paddr)42     void unlockDma(uint64_t guest_paddr) override { }
43 
44     // VulkanStream should never use these functions.
allocBuffer(size_t minSize)45     void* allocBuffer(size_t minSize) override {
46         fprintf(stderr, "%s: FATAL: not intended for use!\n", __func__);
47         abort();
48     }
49 
commitBuffer(size_t size)50     int commitBuffer(size_t size) override {
51         fprintf(stderr, "%s: FATAL: not intended for use!\n", __func__);
52         abort();
53     }
54 
readRaw(void * buf,size_t * inout_len)55     const unsigned char *readRaw(void *buf, size_t *inout_len) override {
56         fprintf(stderr, "%s: FATAL: not intended for use!\n", __func__);
57         abort();
58     }
59 
onSave(android::base::Stream *)60     void onSave(android::base::Stream*) override {
61         fprintf(stderr, "%s: FATAL: not intended for use!\n", __func__);
62         abort();
63 
64     }
65 
onLoad(android::base::Stream *)66     virtual unsigned char* onLoad(android::base::Stream*) override {
67         fprintf(stderr, "%s: FATAL: not intended for use!\n", __func__);
68         abort();
69     }
70 
writeFully(const void * buffer,size_t size)71     int writeFully(const void* buffer, size_t size) override {
72         if (mBuffer.size() < mWriteCursor + size) {
73             mBuffer.resize(mWriteCursor + size);
74         }
75 
76         memcpy(mBuffer.data() + mWriteCursor, buffer, size);
77 
78         mWriteCursor += size;
79 
80         if (mReadCursor == mWriteCursor) {
81             clear();
82         }
83         return 0;
84     }
85 
readFully(void * buf,size_t len)86     const unsigned char* readFully(void* buf, size_t len) override {
87         EXPECT_LE(mReadCursor + len, mBuffer.size());
88         memcpy(buf, mBuffer.data() + mReadCursor, len);
89 
90         mReadCursor += len;
91 
92         if (mReadCursor == mWriteCursor) {
93             clear();
94         }
95         return (unsigned char*)buf;
96     }
97 
98 private:
clear()99     void clear() {
100         mBuffer.clear();
101         mReadCursor = 0;
102         mWriteCursor = 0;
103     }
104 
105     size_t mReadCursor = 0;
106     size_t mWriteCursor = 0;
107     std::vector<char> mBuffer;
108 };
109 
110 // Just see whether the test class is OK
TEST(VulkanStream,Basic)111 TEST(VulkanStream, Basic) {
112     TestStream testStream;
113     VulkanStream stream(&testStream);
114 
115     const uint32_t testInt = 6;
116     stream.putBe32(testInt);
117     EXPECT_EQ(testInt, stream.getBe32());
118 
119     const std::string testString = "Hello World";
120     stream.putString(testString);
121     EXPECT_EQ(testString, stream.getString());
122 }
123 
124 // Try a "basic" Vulkan struct (VkInstanceCreateInfo)
TEST(VulkanStream,testMarshalVulkanStruct)125 TEST(VulkanStream, testMarshalVulkanStruct) {
126     TestStream testStream;
127     VulkanStream stream(&testStream);
128 
129     VkApplicationInfo appInfo = {
130         VK_STRUCTURE_TYPE_APPLICATION_INFO,
131         0, // pNext
132         "VulkanStreamTest", // application name
133         6, // application version
134         "VulkanStreamTestEngine", //engine name
135         4, // engine version,
136         VK_API_VERSION_1_0,
137     };
138 
139     const char* const layerNames[] = {
140         "layer0",
141         "layer1: test layer",
142     };
143 
144     const char* const extensionNames[] = {
145         "VK_KHR_8bit_storage",
146         "VK_KHR_android_surface",
147         "VK_MVK_macos_surface",
148     };
149 
150     VkInstanceCreateInfo forMarshaling = {
151         VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
152         0, // pNext
153         0, // flags,
154         &appInfo, // pApplicationInfo,
155         arraySize(layerNames),
156         layerNames,
157         arraySize(extensionNames),
158         extensionNames
159     };
160 
161     marshal_VkInstanceCreateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forMarshaling);
162 
163     VkInstanceCreateInfo forUnmarshaling;
164     memset(&forUnmarshaling, 0x0, sizeof(VkInstanceCreateInfo));
165 
166     // Before unmarshaling, these structs should be different.
167     // Test that the generated comparator can detect inequality.
168     int inequalities = 0;
169     checkEqual_VkInstanceCreateInfo(
170         &forMarshaling, &forUnmarshaling, [&inequalities](const char* errMsg) {
171         (void)errMsg;
172         ++inequalities;
173     });
174 
175     EXPECT_GT(inequalities, 0);
176 
177     unmarshal_VkInstanceCreateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forUnmarshaling);
178 
179     // Check that the strings are equal as well.
180 
181     EXPECT_STREQ(
182         forMarshaling.pApplicationInfo->pApplicationName,
183         forUnmarshaling.pApplicationInfo->pApplicationName);
184 
185     EXPECT_STREQ(
186         forMarshaling.pApplicationInfo->pEngineName,
187         forUnmarshaling.pApplicationInfo->pEngineName);
188 
189     for (size_t i = 0; i < arraySize(layerNames); ++i) {
190         EXPECT_STREQ(
191                 forMarshaling.ppEnabledLayerNames[i],
192                 forUnmarshaling.ppEnabledLayerNames[i]);
193     }
194 
195     for (size_t i = 0; i < arraySize(extensionNames); ++i) {
196         EXPECT_STREQ(
197                 forMarshaling.ppEnabledExtensionNames[i],
198                 forUnmarshaling.ppEnabledExtensionNames[i]);
199     }
200 
201     EXPECT_EQ(forMarshaling.sType, forUnmarshaling.sType);
202     EXPECT_EQ(forMarshaling.pNext, forUnmarshaling.pNext);
203     EXPECT_EQ(forMarshaling.flags, forUnmarshaling.flags);
204     EXPECT_EQ(forMarshaling.pApplicationInfo->sType,
205               forUnmarshaling.pApplicationInfo->sType);
206     EXPECT_EQ(forMarshaling.pApplicationInfo->apiVersion,
207               forUnmarshaling.pApplicationInfo->apiVersion);
208 
209     checkEqual_VkInstanceCreateInfo(
210         &forMarshaling, &forUnmarshaling, [](const char* errMsg) {
211         EXPECT_TRUE(false) << errMsg;
212     });
213 }
214 
215 // Try a Vulkan struct that has non-ptr structs in it
TEST(VulkanStream,testMarshalVulkanStructWithNonPtrStruct)216 TEST(VulkanStream, testMarshalVulkanStructWithNonPtrStruct) {
217     TestStream testStream;
218     VulkanStream stream(&testStream);
219 
220     VkPhysicalDeviceProperties forMarshaling = {
221         VK_API_VERSION_1_0,
222         0,
223         0x8086,
224         0x7800,
225         VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
226         "Intel740",
227         "123456789abcdef",
228         {
229             0x00, // maxImageDimension1D;
230             0x01, // maxImageDimension2D;
231             0x02, // maxImageDimension3D;
232             0x03, // maxImageDimensionCube;
233             0x04, // maxImageArrayLayers;
234             0x05, // maxTexelBufferElements;
235             0x06, // maxUniformBufferRange;
236             0x07, // maxStorageBufferRange;
237             0x08, // maxPushConstantsSize;
238             0x09, // maxMemoryAllocationCount;
239             0x0a, // maxSamplerAllocationCount;
240             0x0b, // bufferImageGranularity;
241             0x0c, // sparseAddressSpaceSize;
242             0x0d, // maxBoundDescriptorSets;
243             0x0e, // maxPerStageDescriptorSamplers;
244             0x0f, // maxPerStageDescriptorUniformBuffers;
245             0x10, // maxPerStageDescriptorStorageBuffers;
246             0x11, // maxPerStageDescriptorSampledImages;
247             0x12, // maxPerStageDescriptorStorageImages;
248             0x13, // maxPerStageDescriptorInputAttachments;
249             0x14, // maxPerStageResources;
250             0x15, // maxDescriptorSetSamplers;
251             0x16, // maxDescriptorSetUniformBuffers;
252             0x17, // maxDescriptorSetUniformBuffersDynamic;
253             0x18, // maxDescriptorSetStorageBuffers;
254             0x19, // maxDescriptorSetStorageBuffersDynamic;
255             0x1a, // maxDescriptorSetSampledImages;
256             0x1b, // maxDescriptorSetStorageImages;
257             0x1c, // maxDescriptorSetInputAttachments;
258             0x1d, // maxVertexInputAttributes;
259             0x1e, // maxVertexInputBindings;
260             0x1f, // maxVertexInputAttributeOffset;
261             0x20, // maxVertexInputBindingStride;
262             0x21, // maxVertexOutputComponents;
263             0x22, // maxTessellationGenerationLevel;
264             0x23, // maxTessellationPatchSize;
265             0x24, // maxTessellationControlPerVertexInputComponents;
266             0x25, // maxTessellationControlPerVertexOutputComponents;
267             0x26, // maxTessellationControlPerPatchOutputComponents;
268             0x27, // maxTessellationControlTotalOutputComponents;
269             0x28, // maxTessellationEvaluationInputComponents;
270             0x29, // maxTessellationEvaluationOutputComponents;
271             0x2a, // maxGeometryShaderInvocations;
272             0x2b, // maxGeometryInputComponents;
273             0x2c, // maxGeometryOutputComponents;
274             0x2d, // maxGeometryOutputVertices;
275             0x2e, // maxGeometryTotalOutputComponents;
276             0x2f, // maxFragmentInputComponents;
277             0x30, // maxFragmentOutputAttachments;
278             0x31, // maxFragmentDualSrcAttachments;
279             0x32, // maxFragmentCombinedOutputResources;
280             0x33, // maxComputeSharedMemorySize;
281             { 0x1, 0x2, 0x3 }, // maxComputeWorkGroupCount[3];
282             0x35, // maxComputeWorkGroupInvocations;
283             { 0x4, 0x5, 0x6 }, // maxComputeWorkGroupSize[3];
284             0x37, // subPixelPrecisionBits;
285             0x38, // subTexelPrecisionBits;
286             0x39, // mipmapPrecisionBits;
287             0x3a, // maxDrawIndexedIndexValue;
288             0x3b, // maxDrawIndirectCount;
289             1.0f, // maxSamplerLodBias;
290             1.0f, // maxSamplerAnisotropy;
291             0x3e, // maxViewports;
292             { 0x7, 0x8 }, // maxViewportDimensions[2];
293             { 0.4f, 0.5f }, // viewportBoundsRange[2];
294             0x41, // viewportSubPixelBits;
295             0x42, // minMemoryMapAlignment;
296             0x43, // minTexelBufferOffsetAlignment;
297             0x44, // minUniformBufferOffsetAlignment;
298             0x45, // minStorageBufferOffsetAlignment;
299             0x46, // minTexelOffset;
300             0x47, // maxTexelOffset;
301             0x48, // minTexelGatherOffset;
302             0x49, // maxTexelGatherOffset;
303             10.0f, // minInterpolationOffset;
304             11.0f, // maxInterpolationOffset;
305             0x4c, // subPixelInterpolationOffsetBits;
306             0x4d, // maxFramebufferWidth;
307             0x4e, // maxFramebufferHeight;
308             0x4f, // maxFramebufferLayers;
309             0x50, // framebufferColorSampleCounts;
310             0x51, // framebufferDepthSampleCounts;
311             0x52, // framebufferStencilSampleCounts;
312             0x53, // framebufferNoAttachmentsSampleCounts;
313             0x54, // maxColorAttachments;
314             0x55, // sampledImageColorSampleCounts;
315             0x56, // sampledImageIntegerSampleCounts;
316             0x57, // sampledImageDepthSampleCounts;
317             0x58, // sampledImageStencilSampleCounts;
318             0x59, // storageImageSampleCounts;
319             0x5a, // maxSampleMaskWords;
320             0x5b, // timestampComputeAndGraphics;
321             100.0f, // timestampPeriod;
322             0x5d, // maxClipDistances;
323             0x5e, // maxCullDistances;
324             0x5f, // maxCombinedClipAndCullDistances;
325             0x60, // discreteQueuePriorities;
326             { 0.0f, 1.0f }, // pointSizeRange[2];
327             { 1.0f, 2.0f }, // lineWidthRange[2];
328             3.0f, // pointSizeGranularity;
329             4.0f, // lineWidthGranularity;
330             0x65, // strictLines;
331             0x66, // standardSampleLocations;
332             0x67, // optimalBufferCopyOffsetAlignment;
333             0x68, // optimalBufferCopyRowPitchAlignment;
334             0x69, // nonCoherentAtomSize;
335         },
336         {
337             0xff, // residencyStandard2DBlockShape;
338             0x00, // residencyStandard2DMultisampleBlockShape;
339             0x11, // residencyStandard3DBlockShape;
340             0x22, // residencyAlignedMipSize;
341             0x33, // residencyNonResidentStrict;
342         },
343     };
344 
345     marshal_VkPhysicalDeviceProperties(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forMarshaling);
346 
347     VkPhysicalDeviceProperties forUnmarshaling;
348     memset(&forUnmarshaling, 0x0, sizeof(VkPhysicalDeviceLimits));
349 
350     // Test the autogenerated testing code
351     int inequalities = 0;
352     checkEqual_VkPhysicalDeviceProperties(
353         &forMarshaling, &forUnmarshaling, [&inequalities](const char* errMsg) {
354         (void)errMsg;
355         ++inequalities;
356     });
357 
358     EXPECT_GT(inequalities, 0);
359 
360     unmarshal_VkPhysicalDeviceProperties(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forUnmarshaling);
361 
362     // Test the autogenerated testing code
363     EXPECT_EQ(VK_API_VERSION_1_0, forUnmarshaling.apiVersion);
364     EXPECT_EQ(VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, forUnmarshaling.deviceType);
365     EXPECT_EQ(2.0f, forUnmarshaling.limits.lineWidthRange[1]);
366     EXPECT_EQ(11.0f, forUnmarshaling.limits.maxInterpolationOffset);
367 
368     checkEqual_VkPhysicalDeviceProperties(
369         &forMarshaling, &forUnmarshaling, [](const char* errMsg) {
370         EXPECT_TRUE(false) << errMsg;
371     });
372 }
373 
374 // Try a Vulkan struct that has ptr fields with count (dynamic arrays)
TEST(VulkanStream,testMarshalVulkanStructWithPtrFields)375 TEST(VulkanStream, testMarshalVulkanStructWithPtrFields) {
376     TestStream testStream;
377     VulkanStream stream(&testStream);
378 
379     const uint32_t bindCount = 14;
380 
381     std::vector<VkSparseImageMemoryBind> sparseBinds;
382 
383     for (uint32_t i = 0; i < bindCount; i++) {
384         VkSparseImageMemoryBind sparseBind = {
385             // VkImageSubresource subresource
386             {
387                 VK_IMAGE_ASPECT_COLOR_BIT |
388                 VK_IMAGE_ASPECT_DEPTH_BIT,
389                 i,
390                 i * 2,
391             },
392             // VkOffset3D offset
393             { 1, 2 + (int32_t)i, 3},
394             // VkExtent3D extent
395             { 10, 20 * i, 30},
396             // VkDeviceMemory memory
397             (VkDeviceMemory)(uintptr_t)(0xff - i),
398             // VkDeviceSize memoryOffset
399             0x12345678 + i,
400             // VkSparseMemoryBindFlags flags
401             VK_SPARSE_MEMORY_BIND_METADATA_BIT,
402         };
403 
404         sparseBinds.push_back(sparseBind);
405     }
406 
407     VkSparseImageMemoryBindInfo forMarshaling = {
408         (VkImage)(uintptr_t)54,
409         bindCount,
410         sparseBinds.data(),
411     };
412 
413     marshal_VkSparseImageMemoryBindInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forMarshaling);
414 
415     VkSparseImageMemoryBindInfo forUnmarshaling = {
416         0, 0, nullptr,
417     };
418 
419     unmarshal_VkSparseImageMemoryBindInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forUnmarshaling);
420 
421     EXPECT_EQ(bindCount, forUnmarshaling.bindCount);
422     EXPECT_EQ(forMarshaling.image, forUnmarshaling.image);
423 
424     // Test some values in there so we know the autogenerated
425     // compare code works.
426     for (uint32_t i = 0; i < bindCount; i++) {
427         EXPECT_EQ(forMarshaling.pBinds[i].memoryOffset,
428                   forUnmarshaling.pBinds[i].memoryOffset);
429         EXPECT_EQ(forMarshaling.pBinds[i].memoryOffset,
430                   forUnmarshaling.pBinds[i].memoryOffset);
431         EXPECT_EQ(forMarshaling.pBinds[i].subresource.arrayLayer,
432                   forUnmarshaling.pBinds[i].subresource.arrayLayer);
433     }
434 
435     checkEqual_VkSparseImageMemoryBindInfo(
436         &forMarshaling, &forUnmarshaling, [](const char* errMsg) {
437         EXPECT_TRUE(false) << errMsg;
438     });
439 }
440 
441 // Try a Vulkan struct that has ptr fields that are not structs
TEST(VulkanStream,testMarshalVulkanStructWithSimplePtrFields)442 TEST(VulkanStream, testMarshalVulkanStructWithSimplePtrFields) {
443     TestStream testStream;
444     VulkanStream stream(&testStream);
445 
446     const uint32_t queueCount = 4;
447 
448     std::vector<float> queuePriorities;
449 
450     for (uint32_t i = 0; i < queueCount; i++) {
451         queuePriorities.push_back(i * 4.0f);
452     }
453 
454     VkDeviceQueueCreateInfo forMarshaling = {
455         VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
456         0,
457         0,
458         1,
459         queueCount,
460         queuePriorities.data(),
461     };
462 
463     VkDeviceQueueCreateInfo forUnmarshaling = {
464         VK_STRUCTURE_TYPE_APPLICATION_INFO,
465         0,
466         0,
467         0,
468         0,
469         nullptr,
470     };
471 
472     marshal_VkDeviceQueueCreateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forMarshaling);
473     unmarshal_VkDeviceQueueCreateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forUnmarshaling);
474 
475     // As always, test the autogenerated tester.
476     for (uint32_t i = 0; i < queueCount; i++) {
477         EXPECT_EQ(forMarshaling.pQueuePriorities[i], forUnmarshaling.pQueuePriorities[i]);
478     }
479 
480     checkEqual_VkDeviceQueueCreateInfo(
481         &forMarshaling, &forUnmarshaling, [](const char* errMsg) {
482         EXPECT_TRUE(false) << errMsg;
483     });
484 }
485 
486 // Vulkan struct with a void* field that refers to actual data
487 // that needs to get transmitted over
TEST(VulkanStream,testMarshalVulkanStructWithVoidPtrToData)488 TEST(VulkanStream, testMarshalVulkanStructWithVoidPtrToData) {
489     TestStream testStream;
490     VulkanStream stream(&testStream);
491 
492     // Not going to validate the map entries---
493     // that's the validation layer's job,
494     // and this is just to make sure values match.
495     const uint32_t numEntries = 5;
496     const size_t dataSize = 54;
497 
498     std::vector<VkSpecializationMapEntry> entries(numEntries);
499 
500     for (uint32_t i = 0; i < numEntries; i++) {
501         entries[i].constantID = 8 * i + 0;
502         entries[i].offset = 8 * i + 1;
503         entries[i].size = 8 * i + 2;
504     }
505 
506     std::vector<uint8_t> data(dataSize);
507 
508     for (size_t i = 0; i < dataSize; i++) {
509         data[i] = (uint8_t)i;
510     }
511 
512     VkSpecializationInfo forMarshaling = {
513         numEntries,
514         entries.data(),
515         dataSize,
516         data.data(),
517     };
518 
519     VkSpecializationInfo forUnmarshaling;
520     memset(&forUnmarshaling, 0x0, sizeof(VkSpecializationInfo));
521 
522     int inequalities = 0;
523     checkEqual_VkSpecializationInfo(
524         &forMarshaling, &forUnmarshaling, [&inequalities](const char* errMsg) {
525         ++inequalities;
526     });
527 
528     EXPECT_GT(inequalities, 0);
529 
530     marshal_VkSpecializationInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forMarshaling);
531     unmarshal_VkSpecializationInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forUnmarshaling);
532 
533     checkEqual_VkSpecializationInfo(
534         &forMarshaling, &forUnmarshaling, [](const char* errMsg) {
535         EXPECT_TRUE(false) << errMsg;
536     });
537 }
538 
539 // Tests that marshal + unmarshal is equivalent to deepcopy.
TEST(VulkanStream,testDeepcopyEquivalence)540 TEST(VulkanStream, testDeepcopyEquivalence) {
541     BumpPool pool;
542     TestStream testStream;
543     VulkanStream stream(&testStream);
544 
545     VkApplicationInfo appInfo = {
546         VK_STRUCTURE_TYPE_APPLICATION_INFO,
547         0, // pNext
548         "VulkanStreamTest", // application name
549         6, // application version
550         "VulkanStreamTestEngine", //engine name
551         4, // engine version,
552         VK_API_VERSION_1_0,
553     };
554 
555     const char* const layerNames[] = {
556         "layer0",
557         "layer1: test layer",
558     };
559 
560     const char* const extensionNames[] = {
561         "VK_KHR_8bit_storage",
562         "VK_KHR_android_surface",
563         "VK_MVK_macos_surface",
564     };
565 
566     VkInstanceCreateInfo forMarshaling = {
567         VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
568         0, // pNext
569         0, // flags,
570         &appInfo, // pApplicationInfo,
571         arraySize(layerNames),
572         layerNames,
573         arraySize(extensionNames),
574         extensionNames
575     };
576 
577     marshal_VkInstanceCreateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forMarshaling);
578 
579     VkInstanceCreateInfo forUnmarshaling;
580     VkInstanceCreateInfo forDeepcopy;
581 
582     unmarshal_VkInstanceCreateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forUnmarshaling);
583     deepcopy_VkInstanceCreateInfo(&pool, VK_STRUCTURE_TYPE_MAX_ENUM, &forMarshaling, &forDeepcopy);
584 
585     checkEqual_VkInstanceCreateInfo(
586         &forMarshaling, &forUnmarshaling, [](const char* errMsg) {
587         EXPECT_TRUE(false) << errMsg;
588     });
589 
590     checkEqual_VkInstanceCreateInfo(
591         &forMarshaling, &forDeepcopy, [](const char* errMsg) {
592         EXPECT_TRUE(false) << errMsg;
593     });
594 }
595 
596 // Tests that a struct with an extension struct attached
597 // is properly marshaled/unmarshaled.
TEST(VulkanStream,testStructExtension)598 TEST(VulkanStream, testStructExtension) {
599     BumpPool pool;
600     TestStream testStream;
601     VulkanStream stream(&testStream);
602 
603     VkImage image = (VkImage)1;
604     VkBuffer buffer = (VkBuffer)2;
605 
606     VkMemoryDedicatedAllocateInfo dedicatedAllocInfo = {
607         VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, 0,
608         image, buffer,
609     };
610 
611     VkMemoryAllocateInfo forMarshaling = {
612         VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
613         &dedicatedAllocInfo,
614         4096,
615         5,
616     };
617 
618     marshal_VkMemoryAllocateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forMarshaling);
619 
620     VkMemoryAllocateInfo forUnmarshaling;
621     unmarshal_VkMemoryAllocateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forUnmarshaling);
622 
623     VkMemoryDedicatedAllocateInfo* copiedDedicated =
624         (VkMemoryDedicatedAllocateInfo*)forUnmarshaling.pNext;
625 
626     EXPECT_EQ(VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
627               copiedDedicated->sType);
628     EXPECT_EQ(image, copiedDedicated->image);
629     EXPECT_EQ(buffer, copiedDedicated->buffer);
630 
631     checkEqual_VkMemoryAllocateInfo(
632         &forMarshaling, &forUnmarshaling, [](const char* errMsg) {
633         EXPECT_TRUE(false) << errMsg;
634     });
635 
636     VkMemoryAllocateInfo forDeepcopy;
637     deepcopy_VkMemoryAllocateInfo(&pool, VK_STRUCTURE_TYPE_MAX_ENUM, &forMarshaling, &forDeepcopy);
638 
639     copiedDedicated =
640         (VkMemoryDedicatedAllocateInfo*)forDeepcopy.pNext;
641 
642     EXPECT_EQ(VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
643               copiedDedicated->sType);
644     EXPECT_EQ(image, copiedDedicated->image);
645     EXPECT_EQ(buffer, copiedDedicated->buffer);
646 
647     checkEqual_VkMemoryAllocateInfo(
648         &forMarshaling, &forDeepcopy, [](const char* errMsg) {
649         EXPECT_TRUE(false) << errMsg;
650     });
651 }
652 
TEST(VulkanStream,testConflictStructExtensions_marshaling)653 TEST(VulkanStream, testConflictStructExtensions_marshaling) {
654     BumpPool pool;
655     TestStream testStream;
656     VulkanStream stream(&testStream);
657 
658     VkStructureType conflictSType0 = static_cast<VkStructureType>(1000218000u);
659     {
660         VkImportColorBufferGOOGLE importColorBuffer = {
661             .sType = conflictSType0,
662             .pNext = nullptr,
663             .colorBuffer = 0xabcd1234,
664         };
665         VkMemoryAllocateInfo forMarshaling = {
666             .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
667             .pNext = &importColorBuffer,
668             .allocationSize = 0xcdab,
669             .memoryTypeIndex = 0xabcd,
670         };
671         marshal_VkMemoryAllocateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forMarshaling);
672 
673         VkMemoryAllocateInfo forUnmarshaling;
674         unmarshal_VkMemoryAllocateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forUnmarshaling);
675         ASSERT_TRUE(forUnmarshaling.pNext);
676         const VkImportColorBufferGOOGLE* ext = reinterpret_cast<const VkImportColorBufferGOOGLE*>(forUnmarshaling.pNext);
677 
678         EXPECT_EQ(ext->sType, VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE);
679         EXPECT_EQ(ext->pNext, nullptr);
680         EXPECT_EQ(ext->colorBuffer, importColorBuffer.colorBuffer);
681     }
682     {
683         VkPhysicalDeviceFragmentDensityMapFeaturesEXT densityMapFeatures = {
684             .sType = conflictSType0,
685             .pNext = nullptr,
686             .fragmentDensityMap = true,
687             .fragmentDensityMapDynamic = false,
688             .fragmentDensityMapNonSubsampledImages = true,
689         };
690         VkDeviceCreateInfo forMarshaling = {
691             .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
692             .pNext = &densityMapFeatures,
693         };
694         marshal_VkDeviceCreateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forMarshaling);
695 
696         VkDeviceCreateInfo forUnmarshaling;
697         unmarshal_VkDeviceCreateInfo(&stream, VK_STRUCTURE_TYPE_MAX_ENUM, &forUnmarshaling);
698         ASSERT_TRUE(forUnmarshaling.pNext);
699         const VkPhysicalDeviceFragmentDensityMapFeaturesEXT* ext = reinterpret_cast<const VkPhysicalDeviceFragmentDensityMapFeaturesEXT*>(forUnmarshaling.pNext);
700 
701         EXPECT_EQ(ext->sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT);
702         EXPECT_EQ(ext->pNext, nullptr);
703         EXPECT_EQ(ext->fragmentDensityMap, densityMapFeatures.fragmentDensityMap);
704         EXPECT_EQ(ext->fragmentDensityMapDynamic, densityMapFeatures.fragmentDensityMapDynamic);
705         EXPECT_EQ(ext->fragmentDensityMapNonSubsampledImages, densityMapFeatures.fragmentDensityMapNonSubsampledImages);
706     }
707 }
708 
TEST(VulkanStream,testConflictStructExtensions_size)709 TEST(VulkanStream, testConflictStructExtensions_size) {
710     BumpPool pool;
711     TestStream testStream;
712     VulkanStream stream(&testStream);
713 
714     VkStructureType conflictSType0 = static_cast<VkStructureType>(1000218000u);
715     {
716         VkImportColorBufferGOOGLE importColorBuffer = {
717             .sType = conflictSType0,
718             .pNext = nullptr,
719             .colorBuffer = 0xabcd1234,
720         };
721         VkMemoryAllocateInfo allocateInfo = {
722             .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
723             .pNext = &importColorBuffer,
724             .allocationSize = 0xcdab,
725             .memoryTypeIndex = 0xabcd,
726         };
727 
728         size_t size = goldfish_vk_extension_struct_size(allocateInfo.sType, &importColorBuffer);
729         EXPECT_EQ(size, sizeof(VkImportColorBufferGOOGLE));
730     }
731     {
732         VkPhysicalDeviceFragmentDensityMapFeaturesEXT densityMapFeatures = {
733             .sType = conflictSType0,
734             .pNext = nullptr,
735             .fragmentDensityMap = true,
736             .fragmentDensityMapDynamic = false,
737             .fragmentDensityMapNonSubsampledImages = true,
738         };
739         VkDeviceCreateInfo deviceCreateInfo = {
740             .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
741             .pNext = &densityMapFeatures,
742         };
743 
744         size_t size = goldfish_vk_extension_struct_size(deviceCreateInfo.sType, &densityMapFeatures);
745         EXPECT_EQ(size, sizeof(VkPhysicalDeviceFragmentDensityMapFeaturesEXT));
746     }
747 }
748 
749 } // namespace goldfish_vk
750