0

I was trying out C++20 ranges while working on my Vulkan project, I decided I wanted to try to check if a layer was available before the client added it in my builder object.

I set up my layer properties vector like so:

//...
vkEnumerateInstanceLayerProperties(&amount_of_layers, nullptr);
std::vector<VkLayerProperties> layer_properties(amount_of_layers);
vkEnumerateInstanceLayerProperties(&amount_of_layers, layer_properties.data());
//...

If I print them out like so, it works just fine:

for(auto& current_properties : layer_properties)
    std::cout << current_properties.layerName << "\n";

The problem comes when I tried to use ranges to filter them, this is not the original filter I tried to apply, but this has similar problems:

auto available_layers = layer_properties | std::views::filter( 
    [&](auto current_layer_properties) {
        return std::string{current_layer_properties.layerName}.size() % 2 == 0;
    }
);

I just need a count at this point, not to iterate so I just store it in available_layers.

However if I try to print out current_layer_properties.layerName I get the first few layer names, and then what looks like a bunch of data that is from the data segment of the Vulkan library binaries, it looks like JSON.

VK_LAYER_MESA_device_select
VK_LAYER_INTEL_nullhw
VK_LAYER_MESA_overlay
VK_LAYER_LUNARG_monitor
VK_LAYER_KHRONOS_synchronization2
VK_LAYER_LUNARG_api_dump
E_CREATE_NEW",
                                    "label": "Log File Overwrite",
                                    "description": "Specifies that log file initialization should overwrite an existing file when true, or append to an existing file when false.",
                                    "type": "BOOL",
                                    "default": true
                                }
                            ]
                        }
                    ]
                }
            ]
        }
//...

Same happens if I try to apply std::views::transform and turn layer_properties into a container/view of std::string the same thing happens.

Sometimes depending on my filter (I use a find to find a string in it, then omit the element if its not found) it goes on forever.

Am I doing something wrong with ranges? Or does this have something to do with Vulkan? Does it have something to do with some sort of side effect these LunarG .gfxr/gfxrecon_capture log files I am seeing(the erroneous output looks related, but could be totally random)?

UPDATE[ 0 ]:

Someone in the comments requested I show how I print things, it has changed as I have debugged, but I will put it here (it also crashes without printing)

In the lambda for std::filter and/or std::transform I have put variations of the following:

std::cout << current_layer_properties.layerName << "\n";
std::cout << current_layer_properties << "\n"; //When I apply std::transform and turn it into a std::string or std::string_view
log<LogType::Debug>(std::cout, current_layer_properties);

Here is my log function

template<typename LogParameterType>
void log(
              LogParameterType& log, 
              const std::string_view message, 
              const std::source_location location = 
                      std::source_location::current()
          )
      {
          if constexpr(DebugParameterConstant == true 
                  && LogParameterConstant == LogType::Debug)
              return;
          log << to_string(LogParameterConstant) << "::"                                     
                  << location.file_name() << "(" 
                  << location.line() << ":" 
                  << location.column() << ")::" 
                  << location.function_name() << ": "
                  << message << "\n";
      }

My debug layer is not working but here is the function it is suppose to run:

//If anyone can think of a better way to do this please let me know :)
     void vulkan_log(
             VkDebugUtilsMessageSeverityFlagBitsEXT vulkan_log_type, 
             VkDebugUtilsMessageTypeFlagsEXT message_type,  
             const VkDebugUtilsMessengerCallbackDataEXT* callback_data 
        )
     {
         LogType log_type = LogType::Unkown;
         std::string message_type_string = to_string(message_type);
         switch(vulkan_log_type)
         {
             case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: 
             {
                 std::cerr << message_type_string;
                 log<LogType::Diagnostic>(std::cerr, callback_data->pMessage);
                 break;
             }
             case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: 
             {
                 std::cerr << message_type_string;
                 log<LogType::Error>(std::cerr, callback_data->pMessage);
                 break;
             }
             case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:  
             {
                 std::cerr << message_type_string;
                 log<LogType::Warning>(std::cerr, callback_data->pMessage);
                 break;
             }
             case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: 
             {
                 std::cout << message_type_string;
                 log<LogType::Note>(std::cout, callback_data->pMessage);
                 break;
             }
             default: 
                 break;
         }
     }

Thanks!

  • TFB
  • 2
    How are you printing out the layer names? You show some code which prints them out, but also say that code works fine... – vandench Jun 13 '22 at 20:44
  • 1
    What happens when the filter is trivial (`return true;`)? – YurkoFlisk Jun 13 '22 at 20:45
  • @vandench I use `std::cout` or my log function which forwards to `std::cout` – The Floating Brain Jun 13 '22 at 20:46
  • @YurkoFlisk it crashes, it tells me its a segfault, but it seems to be iterating forever, could be both – The Floating Brain Jun 13 '22 at 20:46
  • 1
    Do your `vkEnumerateInstanceLayerProperties` calls execute successfully? What is their return code? Also, does `amount_of_layers` change after the second call (per [documentation](https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceLayerProperties.html) it can)? – YurkoFlisk Jun 13 '22 at 21:06
  • @YurkoFlisk they both return `VK_SUCCESS`, the only thing I do in between is allocate an `std::vector` I copied the value of `amount_of_layers` and compared it to the copy after the second call, it stayed the same. – The Floating Brain Jun 13 '22 at 21:12
  • 1
    @YurkoFlisk excuse me, the number of layers did change! – The Floating Brain Jun 13 '22 at 21:14
  • 1
    It became less I guess? Now you have uninitialized elements in vector. – YurkoFlisk Jun 13 '22 at 21:23
  • @YurkoFlisk Yep, however even after resizing the array to the changed size, it still crashes – The Floating Brain Jun 13 '22 at 21:25
  • @YurkoFlisk Actually, sorry again, my sentry was wrong (I checked to see if they were equal instead of not equal -- oops), it did not change – The Floating Brain Jun 13 '22 at 21:27
  • I see this now ```an API calls and logs them to a capture file. Other tools in the GFXReconstruct suite can inspect, modify, or replay capture files generated by this component.``` ... – The Floating Brain Jun 13 '22 at 21:28
  • ```EnumeratePhysicalDevices will fail when the selected Profile is not supported. t when copying pages from the page_guard shadow allocation to the real allocation. This data loss can result in visible corruption during capture. Forcing buffer sizes and alignments to a multiple of the system page size prevents multiple buffers from being bound to the same page, avoiding data loss from simultaneous CPU writes to the shadow allocation and GPU writes to the real allocation for different buffers bound to the same page. This option is only available for the Vulkan API.``` – The Floating Brain Jun 13 '22 at 21:28
  • 1
    How exactly do you print `available_layers`? Please edit your question and include the code. BTW, in lambda you can capture by reference and avoid unnecessary copy of `current_layer_properties`, and also directly use `strlen` to calculate length of `layerName` (or construct `std::string_view`) instead of creating `std::string` making a copy with potential dynamical allocation. – YurkoFlisk Jun 13 '22 at 22:09
  • @YurkoFlisk I dont print `available_layers` I have printed `requested_layers` and `layer_properties` I will update it. I could pass by reference, I was just debugging and didnt want to add another include for `strlen` :P – The Floating Brain Jun 13 '22 at 23:42

0 Answers0