1 /*
2 * Copyright (C) 2021 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
17 #include "Vulkan.h"
18
19 #include <iostream>
20 #include <string>
21 #include <unordered_set>
22 #include <vector>
23
24 VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
25
26 namespace gfxstream {
27 namespace {
28
29 constexpr const bool kEnableValidationLayers = false;
30
VulkanDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,VkDebugUtilsMessageTypeFlagsEXT,const VkDebugUtilsMessengerCallbackDataEXT * pCallbackData,void *)31 static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugCallback(
32 VkDebugUtilsMessageSeverityFlagBitsEXT severity,
33 VkDebugUtilsMessageTypeFlagsEXT,
34 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
35 void*) {
36 if (severity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
37 std::cout << pCallbackData->pMessage << std::endl;
38 } else if (severity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
39 std::cout << pCallbackData->pMessage << std::endl;
40 } else if (severity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
41 std::cout << pCallbackData->pMessage << std::endl;
42 } else if (severity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
43 std::cout << pCallbackData->pMessage << std::endl;
44 }
45 return VK_FALSE;
46 }
47
GetMemoryType(const vkhpp::PhysicalDevice & physical_device,uint32_t memory_type_mask,vkhpp::MemoryPropertyFlags memoryProperties)48 uint32_t GetMemoryType(const vkhpp::PhysicalDevice& physical_device,
49 uint32_t memory_type_mask,
50 vkhpp::MemoryPropertyFlags memoryProperties) {
51 const auto props = physical_device.getMemoryProperties();
52 for (uint32_t i = 0; i < props.memoryTypeCount; i++) {
53 if (!(memory_type_mask & (1 << i))) {
54 continue;
55 }
56 if ((props.memoryTypes[i].propertyFlags & memoryProperties) != memoryProperties) {
57 continue;
58 }
59 return i;
60 }
61 return -1;
62 }
63
64 } // namespace
65
DoCreateBuffer(const vkhpp::PhysicalDevice & physical_device,const vkhpp::UniqueDevice & device,vkhpp::DeviceSize buffer_size,vkhpp::BufferUsageFlags buffer_usages,vkhpp::MemoryPropertyFlags bufferMemoryProperties)66 gfxstream::expected<Vk::BufferWithMemory, vkhpp::Result> DoCreateBuffer(
67 const vkhpp::PhysicalDevice& physical_device,
68 const vkhpp::UniqueDevice& device, vkhpp::DeviceSize buffer_size,
69 vkhpp::BufferUsageFlags buffer_usages,
70 vkhpp::MemoryPropertyFlags bufferMemoryProperties) {
71 const vkhpp::BufferCreateInfo bufferCreateInfo = {
72 .size = static_cast<VkDeviceSize>(buffer_size),
73 .usage = buffer_usages,
74 .sharingMode = vkhpp::SharingMode::eExclusive,
75 };
76 auto buffer = VK_EXPECT_RV(device->createBufferUnique(bufferCreateInfo));
77
78 vkhpp::MemoryRequirements bufferMemoryRequirements{};
79 device->getBufferMemoryRequirements(*buffer, &bufferMemoryRequirements);
80
81 const auto bufferMemoryType =
82 GetMemoryType(physical_device,
83 bufferMemoryRequirements.memoryTypeBits,
84 bufferMemoryProperties);
85
86 const vkhpp::MemoryAllocateInfo bufferMemoryAllocateInfo = {
87 .allocationSize = bufferMemoryRequirements.size,
88 .memoryTypeIndex = bufferMemoryType,
89 };
90 auto bufferMemory = VK_EXPECT_RV(device->allocateMemoryUnique(bufferMemoryAllocateInfo));
91
92 VK_EXPECT_RESULT(device->bindBufferMemory(*buffer, *bufferMemory, 0));
93
94 return Vk::BufferWithMemory{
95 .buffer = std::move(buffer),
96 .bufferMemory = std::move(bufferMemory),
97 };
98 }
99
100 /*static*/
Load(const std::vector<std::string> & requestedInstanceExtensions,const std::vector<std::string> & requestedInstanceLayers,const std::vector<std::string> & requestedDeviceExtensions)101 gfxstream::expected<Vk, vkhpp::Result> Vk::Load(
102 const std::vector<std::string>& requestedInstanceExtensions,
103 const std::vector<std::string>& requestedInstanceLayers,
104 const std::vector<std::string>& requestedDeviceExtensions) {
105 vkhpp::DynamicLoader loader;
106
107 VULKAN_HPP_DEFAULT_DISPATCHER.init(
108 loader.getProcAddress<PFN_vkGetInstanceProcAddr>(
109 "vkGetInstanceProcAddr"));
110
111 std::vector<const char*> requestedInstanceExtensionsChars;
112 requestedInstanceExtensionsChars.reserve(requestedInstanceExtensions.size());
113 for (const auto& e : requestedInstanceExtensions) {
114 requestedInstanceExtensionsChars.push_back(e.c_str());
115 }
116 if (kEnableValidationLayers) {
117 requestedInstanceExtensionsChars.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
118 }
119
120 std::vector<const char*> requestedInstanceLayersChars;
121 requestedInstanceLayersChars.reserve(requestedInstanceLayers.size());
122 for (const auto& l : requestedInstanceLayers) {
123 requestedInstanceLayersChars.push_back(l.c_str());
124 }
125
126 const vkhpp::ApplicationInfo applicationInfo = {
127 .pApplicationName = "Cuttlefish Graphics Detector",
128 .applicationVersion = 1,
129 .pEngineName = "Cuttlefish Graphics Detector",
130 .engineVersion = 1,
131 .apiVersion = VK_API_VERSION_1_2,
132 };
133 const vkhpp::InstanceCreateInfo instanceCreateInfo = {
134 .pApplicationInfo = &applicationInfo,
135 .enabledLayerCount = static_cast<uint32_t>(requestedInstanceLayersChars.size()),
136 .ppEnabledLayerNames = requestedInstanceLayersChars.data(),
137 .enabledExtensionCount = static_cast<uint32_t>(requestedInstanceExtensionsChars.size()),
138 .ppEnabledExtensionNames = requestedInstanceExtensionsChars.data(),
139 };
140
141 auto instance = VK_EXPECT_RV(vkhpp::createInstanceUnique(instanceCreateInfo));
142
143 VULKAN_HPP_DEFAULT_DISPATCHER.init(*instance);
144
145 std::optional<vkhpp::UniqueDebugUtilsMessengerEXT> debugMessenger;
146 if (kEnableValidationLayers) {
147 const vkhpp::DebugUtilsMessengerCreateInfoEXT debugCreateInfo = {
148 .messageSeverity = vkhpp::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
149 vkhpp::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
150 vkhpp::DebugUtilsMessageSeverityFlagBitsEXT::eError,
151 .messageType = vkhpp::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
152 vkhpp::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
153 vkhpp::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
154 .pfnUserCallback = VulkanDebugCallback,
155 .pUserData = nullptr,
156 };
157 debugMessenger = VK_EXPECT_RV(instance->createDebugUtilsMessengerEXTUnique(debugCreateInfo));
158 }
159
160 const auto physicalDevices = VK_EXPECT_RV(instance->enumeratePhysicalDevices());
161 vkhpp::PhysicalDevice physicalDevice = std::move(physicalDevices[0]);
162
163
164 std::unordered_set<std::string> availableDeviceExtensions;
165 {
166 const auto exts = VK_EXPECT_RV(physicalDevice.enumerateDeviceExtensionProperties());
167 for (const auto& ext : exts) {
168 availableDeviceExtensions.emplace(ext.extensionName);
169 }
170 }
171
172 const auto features2 =
173 physicalDevice
174 .getFeatures2<vkhpp::PhysicalDeviceFeatures2, //
175 vkhpp::PhysicalDeviceSamplerYcbcrConversionFeatures>();
176
177 bool ycbcr_conversion_needed = false;
178
179 std::vector<const char*> requestedDeviceExtensionsChars;
180 requestedDeviceExtensionsChars.reserve(requestedDeviceExtensions.size());
181 for (const auto& e : requestedDeviceExtensions) {
182 if (e == std::string(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME)) {
183 // The interface of VK_KHR_sampler_ycbcr_conversion was promoted to core
184 // in Vulkan 1.1 but the feature/functionality is still optional. Check
185 // here:
186 const auto& sampler_features =
187 features2.get<vkhpp::PhysicalDeviceSamplerYcbcrConversionFeatures>();
188
189 if (sampler_features.samplerYcbcrConversion == VK_FALSE) {
190 return gfxstream::unexpected(vkhpp::Result::eErrorExtensionNotPresent);
191 }
192 ycbcr_conversion_needed = true;
193 } else {
194 if (availableDeviceExtensions.find(e) == availableDeviceExtensions.end()) {
195 return gfxstream::unexpected(vkhpp::Result::eErrorExtensionNotPresent);
196 }
197 requestedDeviceExtensionsChars.push_back(e.c_str());
198 }
199 }
200
201 uint32_t queueFamilyIndex = -1;
202 {
203 const auto props = physicalDevice.getQueueFamilyProperties();
204 for (uint32_t i = 0; i < props.size(); i++) {
205 const auto& prop = props[i];
206 if (prop.queueFlags & vkhpp::QueueFlagBits::eGraphics) {
207 queueFamilyIndex = i;
208 break;
209 }
210 }
211 }
212
213 const float queue_priority = 1.0f;
214 const vkhpp::DeviceQueueCreateInfo device_queue_create_info = {
215 .queueFamilyIndex = queueFamilyIndex,
216 .queueCount = 1,
217 .pQueuePriorities = &queue_priority,
218 };
219 const vkhpp::PhysicalDeviceVulkan11Features device_enable_features = {
220 .samplerYcbcrConversion = ycbcr_conversion_needed,
221 };
222 const vkhpp::DeviceCreateInfo deviceCreateInfo = {
223 .pNext = &device_enable_features,
224 .queueCreateInfoCount = 1,
225 .pQueueCreateInfos = &device_queue_create_info,
226 .enabledLayerCount = static_cast<uint32_t>(requestedInstanceLayersChars.size()),
227 .ppEnabledLayerNames = requestedInstanceLayersChars.data(),
228 .enabledExtensionCount = static_cast<uint32_t>(requestedDeviceExtensionsChars.size()),
229 .ppEnabledExtensionNames = requestedDeviceExtensionsChars.data(),
230 };
231 auto device = VK_EXPECT_RV(physicalDevice.createDeviceUnique(deviceCreateInfo));
232 auto queue = device->getQueue(queueFamilyIndex, 0);
233
234 const vkhpp::CommandPoolCreateInfo commandPoolCreateInfo = {
235 .queueFamilyIndex = queueFamilyIndex,
236 };
237 auto commandPool = VK_EXPECT_RV(device->createCommandPoolUnique(commandPoolCreateInfo));
238
239 auto stagingBuffer =
240 VK_EXPECT(DoCreateBuffer(physicalDevice, device, kStagingBufferSize,
241 vkhpp::BufferUsageFlagBits::eTransferDst |
242 vkhpp::BufferUsageFlagBits::eTransferSrc,
243 vkhpp::MemoryPropertyFlagBits::eHostVisible |
244 vkhpp::MemoryPropertyFlagBits::eHostCoherent));
245
246 return Vk(std::move(loader),
247 std::move(instance),
248 std::move(debugMessenger),
249 std::move(physicalDevice),
250 std::move(device),
251 std::move(queue),
252 queueFamilyIndex,
253 std::move(commandPool),
254 std::move(stagingBuffer.buffer),
255 std::move(stagingBuffer.bufferMemory));
256 }
257
CreateBuffer(vkhpp::DeviceSize bufferSize,vkhpp::BufferUsageFlags bufferUsages,vkhpp::MemoryPropertyFlags bufferMemoryProperties)258 gfxstream::expected<Vk::BufferWithMemory, vkhpp::Result> Vk::CreateBuffer(
259 vkhpp::DeviceSize bufferSize,
260 vkhpp::BufferUsageFlags bufferUsages,
261 vkhpp::MemoryPropertyFlags bufferMemoryProperties) {
262 return DoCreateBuffer(mPhysicalDevice,
263 mDevice,
264 bufferSize,
265 bufferUsages,
266 bufferMemoryProperties);
267 }
268
CreateBufferWithData(vkhpp::DeviceSize bufferSize,vkhpp::BufferUsageFlags bufferUsages,vkhpp::MemoryPropertyFlags bufferMemoryProperties,const uint8_t * buffer_data)269 gfxstream::expected<Vk::BufferWithMemory, vkhpp::Result> Vk::CreateBufferWithData(
270 vkhpp::DeviceSize bufferSize,
271 vkhpp::BufferUsageFlags bufferUsages,
272 vkhpp::MemoryPropertyFlags bufferMemoryProperties,
273 const uint8_t* buffer_data) {
274 auto buffer = VK_EXPECT(CreateBuffer(
275 bufferSize,
276 bufferUsages | vkhpp::BufferUsageFlagBits::eTransferDst,
277 bufferMemoryProperties));
278
279 void* mapped = VK_EXPECT_RV(mDevice->mapMemory(*mStagingBufferMemory, 0, kStagingBufferSize));
280
281 std::memcpy(mapped, buffer_data, bufferSize);
282
283 mDevice->unmapMemory(*mStagingBufferMemory);
284
285 DoCommandsImmediate([&](vkhpp::UniqueCommandBuffer& cmd) {
286 const std::vector<vkhpp::BufferCopy> regions = {
287 vkhpp::BufferCopy{
288 .srcOffset = 0,
289 .dstOffset = 0,
290 .size = bufferSize,
291 },
292 };
293 cmd->copyBuffer(*mStagingBuffer, *buffer.buffer, regions);
294 return vkhpp::Result::eSuccess;
295 });
296
297 return std::move(buffer);
298 }
299
CreateImage(uint32_t width,uint32_t height,vkhpp::Format format,vkhpp::ImageUsageFlags usages,vkhpp::MemoryPropertyFlags memoryProperties,vkhpp::ImageLayout returnedLayout)300 gfxstream::expected<Vk::ImageWithMemory, vkhpp::Result> Vk::CreateImage(
301 uint32_t width,
302 uint32_t height,
303 vkhpp::Format format,
304 vkhpp::ImageUsageFlags usages,
305 vkhpp::MemoryPropertyFlags memoryProperties,
306 vkhpp::ImageLayout returnedLayout) {
307 const vkhpp::ImageCreateInfo imageCreateInfo = {
308 .imageType = vkhpp::ImageType::e2D,
309 .format = format,
310 .extent = {
311 .width = width,
312 .height = height,
313 .depth = 1,
314 },
315 .mipLevels = 1,
316 .arrayLayers = 1,
317 .samples = vkhpp::SampleCountFlagBits::e1,
318 .tiling = vkhpp::ImageTiling::eOptimal,
319 .usage = usages,
320 .sharingMode = vkhpp::SharingMode::eExclusive,
321 .initialLayout = vkhpp::ImageLayout::eUndefined,
322 };
323 auto image = VK_EXPECT_RV(mDevice->createImageUnique(imageCreateInfo));
324
325 const auto memoryRequirements = mDevice->getImageMemoryRequirements(*image);
326 const uint32_t memoryIndex =
327 GetMemoryType(mPhysicalDevice,
328 memoryRequirements.memoryTypeBits,
329 memoryProperties);
330
331 const vkhpp::MemoryAllocateInfo imageMemoryAllocateInfo = {
332 .allocationSize = memoryRequirements.size,
333 .memoryTypeIndex = memoryIndex,
334 };
335 auto imageMemory = VK_EXPECT_RV(mDevice->allocateMemoryUnique(imageMemoryAllocateInfo));
336
337 mDevice->bindImageMemory(*image, *imageMemory, 0);
338
339 const vkhpp::ImageViewCreateInfo imageViewCreateInfo = {
340 .image = *image,
341 .viewType = vkhpp::ImageViewType::e2D,
342 .format = format,
343 .components = {
344 .r = vkhpp::ComponentSwizzle::eIdentity,
345 .g = vkhpp::ComponentSwizzle::eIdentity,
346 .b = vkhpp::ComponentSwizzle::eIdentity,
347 .a = vkhpp::ComponentSwizzle::eIdentity,
348 },
349 .subresourceRange = {
350 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
351 .baseMipLevel = 0,
352 .levelCount = 1,
353 .baseArrayLayer = 0,
354 .layerCount = 1,
355 },
356 };
357 auto imageView = VK_EXPECT_RV(mDevice->createImageViewUnique(imageViewCreateInfo));
358
359 VK_EXPECT_RESULT(DoCommandsImmediate([&](vkhpp::UniqueCommandBuffer& cmd) {
360 const std::vector<vkhpp::ImageMemoryBarrier> imageMemoryBarriers = {
361 vkhpp::ImageMemoryBarrier{
362 .srcAccessMask = {},
363 .dstAccessMask = vkhpp::AccessFlagBits::eTransferWrite,
364 .oldLayout = vkhpp::ImageLayout::eUndefined,
365 .newLayout = returnedLayout,
366 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
367 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
368 .image = *image,
369 .subresourceRange = {
370 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
371 .baseMipLevel = 0,
372 .levelCount = 1,
373 .baseArrayLayer = 0,
374 .layerCount = 1,
375 },
376 },
377 };
378 cmd->pipelineBarrier(
379 /*srcStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
380 /*dstStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
381 /*dependencyFlags=*/{},
382 /*memoryBarriers=*/{},
383 /*bufferMemoryBarriers=*/{},
384 /*imageMemoryBarriers=*/imageMemoryBarriers);
385
386 return vkhpp::Result::eSuccess;
387 }));
388
389 return ImageWithMemory{
390 .image = std::move(image),
391 .imageMemory = std::move(imageMemory),
392 .imageView = std::move(imageView),
393 };
394 }
395
DownloadImage(uint32_t width,uint32_t height,const vkhpp::UniqueImage & image,vkhpp::ImageLayout currentLayout,vkhpp::ImageLayout returnedLayout)396 gfxstream::expected<std::vector<uint8_t>, vkhpp::Result> Vk::DownloadImage(
397 uint32_t width,
398 uint32_t height,
399 const vkhpp::UniqueImage& image,
400 vkhpp::ImageLayout currentLayout,
401 vkhpp::ImageLayout returnedLayout) {
402 VK_EXPECT_RESULT(
403 DoCommandsImmediate([&](vkhpp::UniqueCommandBuffer& cmd) {
404 if (currentLayout != vkhpp::ImageLayout::eTransferSrcOptimal) {
405 const std::vector<vkhpp::ImageMemoryBarrier> imageMemoryBarriers = {
406 vkhpp::ImageMemoryBarrier{
407 .srcAccessMask = vkhpp::AccessFlagBits::eMemoryRead |
408 vkhpp::AccessFlagBits::eMemoryWrite,
409 .dstAccessMask = vkhpp::AccessFlagBits::eTransferRead,
410 .oldLayout = currentLayout,
411 .newLayout = vkhpp::ImageLayout::eTransferSrcOptimal,
412 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
413 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
414 .image = *image,
415 .subresourceRange = {
416 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
417 .baseMipLevel = 0,
418 .levelCount = 1,
419 .baseArrayLayer = 0,
420 .layerCount = 1,
421 },
422 },
423 };
424 cmd->pipelineBarrier(
425 /*srcStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
426 /*dstStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
427 /*dependencyFlags=*/{},
428 /*memoryBarriers=*/{},
429 /*bufferMemoryBarriers=*/{},
430 /*imageMemoryBarriers=*/imageMemoryBarriers);
431 }
432
433 const std::vector<vkhpp::BufferImageCopy> regions = {
434 vkhpp::BufferImageCopy{
435 .bufferOffset = 0,
436 .bufferRowLength = 0,
437 .bufferImageHeight = 0,
438 .imageSubresource =
439 {
440 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
441 .mipLevel = 0,
442 .baseArrayLayer = 0,
443 .layerCount = 1,
444 },
445 .imageOffset =
446 {
447 .x = 0,
448 .y = 0,
449 .z = 0,
450 },
451 .imageExtent =
452 {
453 .width = width,
454 .height = height,
455 .depth = 1,
456 },
457 },
458 };
459 cmd->copyImageToBuffer(*image,
460 vkhpp::ImageLayout::eTransferSrcOptimal,
461 *mStagingBuffer, regions);
462
463 if (returnedLayout != vkhpp::ImageLayout::eTransferSrcOptimal) {
464 const std::vector<vkhpp::ImageMemoryBarrier> imageMemoryBarriers = {
465 vkhpp::ImageMemoryBarrier{
466 .srcAccessMask = vkhpp::AccessFlagBits::eTransferRead,
467 .dstAccessMask = vkhpp::AccessFlagBits::eMemoryRead |
468 vkhpp::AccessFlagBits::eMemoryWrite,
469 .oldLayout = vkhpp::ImageLayout::eTransferSrcOptimal,
470 .newLayout = returnedLayout,
471 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
472 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
473 .image = *image,
474 .subresourceRange = {
475 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
476 .baseMipLevel = 0,
477 .levelCount = 1,
478 .baseArrayLayer = 0,
479 .layerCount = 1,
480 },
481 },
482 };
483 cmd->pipelineBarrier(
484 /*srcStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
485 /*dstStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
486 /*dependencyFlags=*/{},
487 /*memoryBarriers=*/{},
488 /*bufferMemoryBarriers=*/{},
489 /*imageMemoryBarriers=*/imageMemoryBarriers);
490 }
491
492 return vkhpp::Result::eSuccess;
493 }));
494
495 auto* mapped = reinterpret_cast<uint8_t*>(
496 VK_EXPECT_RV(mDevice->mapMemory(*mStagingBufferMemory, 0, kStagingBufferSize)));
497
498 std::vector<uint8_t> outPixels;
499 outPixels.resize(width * height * 4);
500
501 std::memcpy(outPixels.data(), mapped, outPixels.size());
502
503 mDevice->unmapMemory(*mStagingBufferMemory);
504
505 return outPixels;
506 }
507
CreateYuvImage(uint32_t width,uint32_t height,vkhpp::ImageUsageFlags usages,vkhpp::MemoryPropertyFlags memoryProperties,vkhpp::ImageLayout layout)508 gfxstream::expected<Vk::YuvImageWithMemory, vkhpp::Result> Vk::CreateYuvImage(
509 uint32_t width,
510 uint32_t height,
511 vkhpp::ImageUsageFlags usages,
512 vkhpp::MemoryPropertyFlags memoryProperties,
513 vkhpp::ImageLayout layout) {
514 const vkhpp::SamplerYcbcrConversionCreateInfo conversionCreateInfo = {
515 .format = vkhpp::Format::eG8B8R83Plane420Unorm,
516 .ycbcrModel = vkhpp::SamplerYcbcrModelConversion::eYcbcr601,
517 .ycbcrRange = vkhpp::SamplerYcbcrRange::eItuNarrow,
518 .components = {
519 .r = vkhpp::ComponentSwizzle::eIdentity,
520 .g = vkhpp::ComponentSwizzle::eIdentity,
521 .b = vkhpp::ComponentSwizzle::eIdentity,
522 .a = vkhpp::ComponentSwizzle::eIdentity,
523 },
524 .xChromaOffset = vkhpp::ChromaLocation::eMidpoint,
525 .yChromaOffset = vkhpp::ChromaLocation::eMidpoint,
526 .chromaFilter = vkhpp::Filter::eLinear,
527 .forceExplicitReconstruction = VK_FALSE,
528 };
529 auto imageSamplerConversion = VK_EXPECT_RV(mDevice->createSamplerYcbcrConversionUnique(conversionCreateInfo));
530
531 const vkhpp::SamplerYcbcrConversionInfo samplerConversionInfo = {
532 .conversion = *imageSamplerConversion,
533 };
534 const vkhpp::SamplerCreateInfo samplerCreateInfo = {
535 .pNext = &samplerConversionInfo,
536 .magFilter = vkhpp::Filter::eLinear,
537 .minFilter = vkhpp::Filter::eLinear,
538 .mipmapMode = vkhpp::SamplerMipmapMode::eNearest,
539 .addressModeU = vkhpp::SamplerAddressMode::eClampToEdge,
540 .addressModeV = vkhpp::SamplerAddressMode::eClampToEdge,
541 .addressModeW = vkhpp::SamplerAddressMode::eClampToEdge,
542 .mipLodBias = 0.0f,
543 .anisotropyEnable = VK_FALSE,
544 .maxAnisotropy = 1.0f,
545 .compareEnable = VK_FALSE,
546 .compareOp = vkhpp::CompareOp::eLessOrEqual,
547 .minLod = 0.0f,
548 .maxLod = 0.25f,
549 .borderColor = vkhpp::BorderColor::eIntTransparentBlack,
550 .unnormalizedCoordinates = VK_FALSE,
551 };
552 auto imageSampler = VK_EXPECT_RV(mDevice->createSamplerUnique(samplerCreateInfo));
553
554 const vkhpp::ImageCreateInfo imageCreateInfo = {
555 .imageType = vkhpp::ImageType::e2D,
556 .format = vkhpp::Format::eG8B8R83Plane420Unorm,
557 .extent = {
558 .width = width,
559 .height = height,
560 .depth = 1,
561 },
562 .mipLevels = 1,
563 .arrayLayers = 1,
564 .samples = vkhpp::SampleCountFlagBits::e1,
565 .tiling = vkhpp::ImageTiling::eOptimal,
566 .usage = usages,
567 .sharingMode = vkhpp::SharingMode::eExclusive,
568 .initialLayout = vkhpp::ImageLayout::eUndefined,
569 };
570 auto image = VK_EXPECT_RV(mDevice->createImageUnique(imageCreateInfo));
571
572 const auto memoryRequirements = mDevice->getImageMemoryRequirements(*image);
573
574 const uint32_t memoryIndex =
575 GetMemoryType(mPhysicalDevice,
576 memoryRequirements.memoryTypeBits,
577 memoryProperties);
578
579 const vkhpp::MemoryAllocateInfo imageMemoryAllocateInfo = {
580 .allocationSize = memoryRequirements.size,
581 .memoryTypeIndex = memoryIndex,
582 };
583 auto imageMemory = VK_EXPECT_RV(mDevice->allocateMemoryUnique(imageMemoryAllocateInfo));
584
585 mDevice->bindImageMemory(*image, *imageMemory, 0);
586
587 const vkhpp::ImageViewCreateInfo imageViewCreateInfo = {
588 .pNext = &samplerConversionInfo,
589 .image = *image,
590 .viewType = vkhpp::ImageViewType::e2D,
591 .format = vkhpp::Format::eG8B8R83Plane420Unorm,
592 .components = {
593 .r = vkhpp::ComponentSwizzle::eIdentity,
594 .g = vkhpp::ComponentSwizzle::eIdentity,
595 .b = vkhpp::ComponentSwizzle::eIdentity,
596 .a = vkhpp::ComponentSwizzle::eIdentity,
597 },
598 .subresourceRange = {
599 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
600 .baseMipLevel = 0,
601 .levelCount = 1,
602 .baseArrayLayer = 0,
603 .layerCount = 1,
604 },
605 };
606 auto imageView = VK_EXPECT_RV(mDevice->createImageViewUnique(imageViewCreateInfo));
607
608 VK_EXPECT_RESULT(DoCommandsImmediate([&](vkhpp::UniqueCommandBuffer& cmd) {
609 const std::vector<vkhpp::ImageMemoryBarrier> imageMemoryBarriers = {
610 vkhpp::ImageMemoryBarrier{
611 .srcAccessMask = {},
612 .dstAccessMask = vkhpp::AccessFlagBits::eTransferWrite,
613 .oldLayout = vkhpp::ImageLayout::eUndefined,
614 .newLayout = layout,
615 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
616 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
617 .image = *image,
618 .subresourceRange = {
619 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
620 .baseMipLevel = 0,
621 .levelCount = 1,
622 .baseArrayLayer = 0,
623 .layerCount = 1,
624 },
625
626 },
627 };
628 cmd->pipelineBarrier(
629 /*srcStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
630 /*dstStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
631 /*dependencyFlags=*/{},
632 /*memoryBarriers=*/{},
633 /*bufferMemoryBarriers=*/{},
634 /*imageMemoryBarriers=*/imageMemoryBarriers);
635 return vkhpp::Result::eSuccess;
636 }));
637
638 return YuvImageWithMemory{
639 .imageSamplerConversion = std::move(imageSamplerConversion),
640 .imageSampler = std::move(imageSampler),
641 .imageMemory = std::move(imageMemory),
642 .image = std::move(image),
643 .imageView = std::move(imageView),
644 };
645 }
646
LoadYuvImage(const vkhpp::UniqueImage & image,uint32_t width,uint32_t height,const std::vector<uint8_t> & imageDataY,const std::vector<uint8_t> & imageDataU,const std::vector<uint8_t> & imageDataV,vkhpp::ImageLayout currentLayout,vkhpp::ImageLayout returnedLayout)647 vkhpp::Result Vk::LoadYuvImage(
648 const vkhpp::UniqueImage& image,
649 uint32_t width,
650 uint32_t height,
651 const std::vector<uint8_t>& imageDataY,
652 const std::vector<uint8_t>& imageDataU,
653 const std::vector<uint8_t>& imageDataV,
654 vkhpp::ImageLayout currentLayout,
655 vkhpp::ImageLayout returnedLayout) {
656 auto* mapped = reinterpret_cast<uint8_t*>(VK_TRY_RV(mDevice->mapMemory(*mStagingBufferMemory, 0, kStagingBufferSize)));
657
658 const VkDeviceSize yOffset = 0;
659 const VkDeviceSize uOffset = imageDataY.size();
660 const VkDeviceSize vOffset = imageDataY.size() + imageDataU.size();
661 std::memcpy(mapped + yOffset, imageDataY.data(), imageDataY.size());
662 std::memcpy(mapped + uOffset, imageDataU.data(), imageDataU.size());
663 std::memcpy(mapped + vOffset, imageDataV.data(), imageDataV.size());
664 mDevice->unmapMemory(*mStagingBufferMemory);
665
666 return DoCommandsImmediate([&](vkhpp::UniqueCommandBuffer& cmd) {
667 if (currentLayout != vkhpp::ImageLayout::eTransferDstOptimal) {
668 const std::vector<vkhpp::ImageMemoryBarrier> imageMemoryBarriers = {
669 vkhpp::ImageMemoryBarrier{
670 .srcAccessMask = vkhpp::AccessFlagBits::eMemoryRead |
671 vkhpp::AccessFlagBits::eMemoryWrite,
672 .dstAccessMask = vkhpp::AccessFlagBits::eTransferWrite,
673 .oldLayout = currentLayout,
674 .newLayout = vkhpp::ImageLayout::eTransferDstOptimal,
675 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
676 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
677 .image = *image,
678 .subresourceRange = {
679 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
680 .baseMipLevel = 0,
681 .levelCount = 1,
682 .baseArrayLayer = 0,
683 .layerCount = 1,
684 },
685
686 },
687 };
688 cmd->pipelineBarrier(
689 /*srcStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
690 /*dstStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
691 /*dependencyFlags=*/{},
692 /*memoryBarriers=*/{},
693 /*bufferMemoryBarriers=*/{},
694 /*imageMemoryBarriers=*/imageMemoryBarriers);
695 }
696
697 const std::vector<vkhpp::BufferImageCopy> imageCopyRegions = {
698 vkhpp::BufferImageCopy{
699 .bufferOffset = yOffset,
700 .bufferRowLength = 0,
701 .bufferImageHeight = 0,
702 .imageSubresource = {
703 .aspectMask = vkhpp::ImageAspectFlagBits::ePlane0,
704 .mipLevel = 0,
705 .baseArrayLayer = 0,
706 .layerCount = 1,
707 },
708 .imageOffset = {
709 .x = 0,
710 .y = 0,
711 .z = 0,
712 },
713 .imageExtent = {
714 .width = width,
715 .height = height,
716 .depth = 1,
717 },
718 },
719 vkhpp::BufferImageCopy{
720 .bufferOffset = uOffset,
721 .bufferRowLength = 0,
722 .bufferImageHeight = 0,
723 .imageSubresource = {
724 .aspectMask = vkhpp::ImageAspectFlagBits::ePlane1,
725 .mipLevel = 0,
726 .baseArrayLayer = 0,
727 .layerCount = 1,
728 },
729 .imageOffset = {
730 .x = 0,
731 .y = 0,
732 .z = 0,
733 },
734 .imageExtent = {
735 .width = width / 2,
736 .height = height / 2,
737 .depth = 1,
738 },
739 },
740 vkhpp::BufferImageCopy{
741 .bufferOffset = vOffset,
742 .bufferRowLength = 0,
743 .bufferImageHeight = 0,
744 .imageSubresource = {
745 .aspectMask = vkhpp::ImageAspectFlagBits::ePlane2,
746 .mipLevel = 0,
747 .baseArrayLayer = 0,
748 .layerCount = 1,
749 },
750 .imageOffset = {
751 .x = 0,
752 .y = 0,
753 .z = 0,
754 },
755 .imageExtent = {
756 .width = width / 2,
757 .height = height / 2,
758 .depth = 1,
759 },
760 },
761 };
762 cmd->copyBufferToImage(*mStagingBuffer,
763 *image,
764 vkhpp::ImageLayout::eTransferDstOptimal,
765 imageCopyRegions);
766
767 if (returnedLayout != vkhpp::ImageLayout::eTransferDstOptimal) {
768 const std::vector<vkhpp::ImageMemoryBarrier> imageMemoryBarriers = {
769 vkhpp::ImageMemoryBarrier{
770 .srcAccessMask = vkhpp::AccessFlagBits::eTransferWrite,
771 .dstAccessMask = vkhpp::AccessFlagBits::eMemoryRead |
772 vkhpp::AccessFlagBits::eMemoryWrite,
773 .oldLayout = vkhpp::ImageLayout::eTransferDstOptimal,
774 .newLayout = returnedLayout,
775 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
776 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
777 .image = *image,
778 .subresourceRange = {
779 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
780 .baseMipLevel = 0,
781 .levelCount = 1,
782 .baseArrayLayer = 0,
783 .layerCount = 1,
784 },
785 },
786 };
787 cmd->pipelineBarrier(
788 /*srcStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
789 /*dstStageMask=*/vkhpp::PipelineStageFlagBits::eAllCommands,
790 /*dependencyFlags=*/{},
791 /*memoryBarriers=*/{},
792 /*bufferMemoryBarriers=*/{},
793 /*imageMemoryBarriers=*/imageMemoryBarriers);
794 }
795 return vkhpp::Result::eSuccess;
796 });
797 }
798
799 gfxstream::expected<Vk::FramebufferWithAttachments, vkhpp::Result>
CreateFramebuffer(uint32_t width,uint32_t height,vkhpp::Format color_format,vkhpp::Format depth_format)800 Vk::CreateFramebuffer(
801 uint32_t width,
802 uint32_t height,
803 vkhpp::Format color_format,
804 vkhpp::Format depth_format) {
805 std::optional<Vk::ImageWithMemory> colorAttachment;
806 if (color_format != vkhpp::Format::eUndefined) {
807 colorAttachment =
808 GFXSTREAM_EXPECT(CreateImage(width, height, color_format,
809 vkhpp::ImageUsageFlagBits::eColorAttachment |
810 vkhpp::ImageUsageFlagBits::eTransferSrc,
811 vkhpp::MemoryPropertyFlagBits::eDeviceLocal,
812 vkhpp::ImageLayout::eColorAttachmentOptimal));
813 }
814
815 std::optional<Vk::ImageWithMemory> depthAttachment;
816 if (depth_format != vkhpp::Format::eUndefined) {
817 depthAttachment =
818 GFXSTREAM_EXPECT(CreateImage(width, height, depth_format,
819 vkhpp::ImageUsageFlagBits::eDepthStencilAttachment |
820 vkhpp::ImageUsageFlagBits::eTransferSrc,
821 vkhpp::MemoryPropertyFlagBits::eDeviceLocal,
822 vkhpp::ImageLayout::eDepthStencilAttachmentOptimal));
823 }
824
825 std::vector<vkhpp::AttachmentDescription> attachments;
826
827 std::optional<vkhpp::AttachmentReference> colorAttachment_reference;
828 if (color_format != vkhpp::Format::eUndefined) {
829 attachments.push_back(vkhpp::AttachmentDescription{
830 .format = color_format,
831 .samples = vkhpp::SampleCountFlagBits::e1,
832 .loadOp = vkhpp::AttachmentLoadOp::eClear,
833 .storeOp = vkhpp::AttachmentStoreOp::eStore,
834 .stencilLoadOp = vkhpp::AttachmentLoadOp::eClear,
835 .stencilStoreOp = vkhpp::AttachmentStoreOp::eStore,
836 .initialLayout = vkhpp::ImageLayout::eColorAttachmentOptimal,
837 .finalLayout = vkhpp::ImageLayout::eColorAttachmentOptimal,
838 });
839
840 colorAttachment_reference = vkhpp::AttachmentReference{
841 .attachment = static_cast<uint32_t>(attachments.size() - 1),
842 .layout = vkhpp::ImageLayout::eColorAttachmentOptimal,
843 };
844 }
845
846 std::optional<vkhpp::AttachmentReference> depthAttachment_reference;
847 if (depth_format != vkhpp::Format::eUndefined) {
848 attachments.push_back(vkhpp::AttachmentDescription{
849 .format = depth_format,
850 .samples = vkhpp::SampleCountFlagBits::e1,
851 .loadOp = vkhpp::AttachmentLoadOp::eClear,
852 .storeOp = vkhpp::AttachmentStoreOp::eStore,
853 .stencilLoadOp = vkhpp::AttachmentLoadOp::eClear,
854 .stencilStoreOp = vkhpp::AttachmentStoreOp::eStore,
855 .initialLayout = vkhpp::ImageLayout::eColorAttachmentOptimal,
856 .finalLayout = vkhpp::ImageLayout::eColorAttachmentOptimal,
857 });
858
859 depthAttachment_reference = vkhpp::AttachmentReference{
860 .attachment = static_cast<uint32_t>(attachments.size() - 1),
861 .layout = vkhpp::ImageLayout::eDepthStencilAttachmentOptimal,
862 };
863 }
864
865 vkhpp::SubpassDependency dependency = {
866 .srcSubpass = 0,
867 .dstSubpass = 0,
868 .srcStageMask = {},
869 .dstStageMask = vkhpp::PipelineStageFlagBits::eFragmentShader,
870 .srcAccessMask = {},
871 .dstAccessMask = vkhpp::AccessFlagBits::eInputAttachmentRead,
872 .dependencyFlags = vkhpp::DependencyFlagBits::eByRegion,
873 };
874 if (color_format != vkhpp::Format::eUndefined) {
875 dependency.srcStageMask |=
876 vkhpp::PipelineStageFlagBits::eColorAttachmentOutput;
877 dependency.dstStageMask |=
878 vkhpp::PipelineStageFlagBits::eColorAttachmentOutput;
879 dependency.srcAccessMask |= vkhpp::AccessFlagBits::eColorAttachmentWrite;
880 }
881 if (depth_format != vkhpp::Format::eUndefined) {
882 dependency.srcStageMask |=
883 vkhpp::PipelineStageFlagBits::eColorAttachmentOutput;
884 dependency.dstStageMask |=
885 vkhpp::PipelineStageFlagBits::eColorAttachmentOutput;
886 dependency.srcAccessMask |= vkhpp::AccessFlagBits::eColorAttachmentWrite;
887 }
888
889 vkhpp::SubpassDescription subpass = {
890 .pipelineBindPoint = vkhpp::PipelineBindPoint::eGraphics,
891 .inputAttachmentCount = 0,
892 .pInputAttachments = nullptr,
893 .colorAttachmentCount = 0,
894 .pColorAttachments = nullptr,
895 .pResolveAttachments = nullptr,
896 .pDepthStencilAttachment = nullptr,
897 .pPreserveAttachments = nullptr,
898 };
899 if (color_format != vkhpp::Format::eUndefined) {
900 subpass.colorAttachmentCount = 1;
901 subpass.pColorAttachments = &*colorAttachment_reference;
902 }
903 if (depth_format != vkhpp::Format::eUndefined) {
904 subpass.pDepthStencilAttachment = &*depthAttachment_reference;
905 }
906
907 const vkhpp::RenderPassCreateInfo renderpassCreateInfo = {
908 .attachmentCount = static_cast<uint32_t>(attachments.size()),
909 .pAttachments = attachments.data(),
910 .subpassCount = 1,
911 .pSubpasses = &subpass,
912 .dependencyCount = 1,
913 .pDependencies = &dependency,
914 };
915 auto renderpass = VK_EXPECT_RV(mDevice->createRenderPassUnique(renderpassCreateInfo));
916
917 std::vector<vkhpp::ImageView> framebufferAttachments;
918 if (colorAttachment) {
919 framebufferAttachments.push_back(*colorAttachment->imageView);
920 }
921 if (depthAttachment) {
922 framebufferAttachments.push_back(*depthAttachment->imageView);
923 }
924 const vkhpp::FramebufferCreateInfo framebufferCreateInfo = {
925 .renderPass = *renderpass,
926 .attachmentCount = static_cast<uint32_t>(framebufferAttachments.size()),
927 .pAttachments = framebufferAttachments.data(),
928 .width = width,
929 .height = height,
930 .layers = 1,
931 };
932 auto framebuffer = VK_EXPECT_RV(mDevice->createFramebufferUnique(framebufferCreateInfo));
933
934 return Vk::FramebufferWithAttachments{
935 .colorAttachment = std::move(colorAttachment),
936 .depthAttachment = std::move(depthAttachment),
937 .renderpass = std::move(renderpass),
938 .framebuffer = std::move(framebuffer),
939 };
940 }
941
DoCommandsImmediate(const std::function<vkhpp::Result (vkhpp::UniqueCommandBuffer &)> & func,const std::vector<vkhpp::UniqueSemaphore> & semaphores_wait,const std::vector<vkhpp::UniqueSemaphore> & semaphores_signal)942 vkhpp::Result Vk::DoCommandsImmediate(
943 const std::function<vkhpp::Result(vkhpp::UniqueCommandBuffer&)>& func,
944 const std::vector<vkhpp::UniqueSemaphore>& semaphores_wait,
945 const std::vector<vkhpp::UniqueSemaphore>& semaphores_signal) {
946 const vkhpp::CommandBufferAllocateInfo commandBufferAllocateInfo = {
947 .commandPool = *mCommandPool,
948 .level = vkhpp::CommandBufferLevel::ePrimary,
949 .commandBufferCount = 1,
950 };
951 auto commandBuffers = VK_TRY_RV(mDevice->allocateCommandBuffersUnique(commandBufferAllocateInfo));
952 auto commandBuffer = std::move(commandBuffers[0]);
953
954 const vkhpp::CommandBufferBeginInfo commandBufferBeginInfo = {
955 .flags = vkhpp::CommandBufferUsageFlagBits::eOneTimeSubmit,
956 };
957 commandBuffer->begin(commandBufferBeginInfo);
958 VK_TRY(func(commandBuffer));
959 commandBuffer->end();
960
961 std::vector<vkhpp::CommandBuffer> commandBufferHandles;
962 commandBufferHandles.push_back(*commandBuffer);
963
964 std::vector<vkhpp::Semaphore> semaphoreHandlesWait;
965 semaphoreHandlesWait.reserve(semaphores_wait.size());
966 for (const auto& s : semaphores_wait) {
967 semaphoreHandlesWait.emplace_back(*s);
968 }
969
970 std::vector<vkhpp::Semaphore> semaphoreHandlesSignal;
971 semaphoreHandlesSignal.reserve(semaphores_signal.size());
972 for (const auto& s : semaphores_signal) {
973 semaphoreHandlesSignal.emplace_back(*s);
974 }
975
976 vkhpp::SubmitInfo submitInfo = {
977 .commandBufferCount = static_cast<uint32_t>(commandBufferHandles.size()),
978 .pCommandBuffers = commandBufferHandles.data(),
979 };
980 if (!semaphoreHandlesWait.empty()) {
981 submitInfo.waitSemaphoreCount = static_cast<uint32_t>(semaphoreHandlesWait.size());
982 submitInfo.pWaitSemaphores = semaphoreHandlesWait.data();
983 }
984 if (!semaphoreHandlesSignal.empty()) {
985 submitInfo.signalSemaphoreCount = static_cast<uint32_t>(semaphoreHandlesSignal.size());
986 submitInfo.pSignalSemaphores = semaphoreHandlesSignal.data();
987 }
988 mQueue.submit(submitInfo);
989 mQueue.waitIdle();
990
991 return vkhpp::Result::eSuccess;
992 }
993
994 } // namespace gfxstream
995