• Advertisement

Vulkan Secondary command buffers & staging buffers issues

Recommended Posts

So I've been trying to implement a multi-threaded resource system w/ vulkan in my free time, where a thread can request a resource to be loaded, and it gets pushed into a queue. On another thread, the resource (as of right now, a mesh) gets loaded from a file, and I map the data to a staging buffer. The issue comes in where I record the command buffer to copy the data to a GPU buffer. I record a secondary command buffer w/ just the vkCmdCopyBuffer command, and push it to a queue to be executed from a primary command buffer on the main thread to a transfer-only queue. As far as I can tell, the staging works fine, and the mesh is drawn and looks perfectly fine, but my validation layers (VK_LAYER_LUNARG_standard_validation) spam tell me: "vkCmdBindIndexBuffer(): Cannot read invalid region of memory allocation 0x16 for bound Buffer object 0x15, please fill the memory before using," and the vertex buffer binding gives me an identical message. Both buffers were created with the proper bits, TRANSFER_SRC for the staging buffer, TRANSFER_DST for the gpu buffer (plus index and vertex buffer usage bits). I use Vulkan Memory Allocator from GPUOpen to handle buffer memory allocation, and I'm careful to make sure that the staging buffer is mapped properly and isn't deleted before the command finishes. The validation layers stop spamming telling me this error if I switch the copy commands to using primary buffers, even when recorded in the same way (i.e. just changing the level parameter), but everything I've seen recommends recording secondary command buffers simultaneously on worker threads, and submitting them on the main thread later. Any ideas on why my validation layers are freaking out, or did I just skip over something when reading the spec?

Here's some relevant code:

Spoiler

Recording the secondary command buffer:


// on a worker thread

VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
allocInfo.commandPool = transferCommandPool;
allocInfo.commandBufferCount = 1;

VkCommandBuffer commandBuffer;
vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer); // Need to reuse, dont' alloc each time

// Iffy about this, what's the proper way to set this up?
VkCommandBufferInheritanceInfo inherInfo = {};
inherInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
inherInfo.renderPass = VK_NULL_HANDLE;
inherInfo.framebuffer = VK_NULL_HANDLE;
inherInfo.occlusionQueryEnable = VK_FALSE;

VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
beginInfo.pInheritanceInfo = &inherInfo;

vkBeginCommandBuffer(commandBuffer, &beginInfo);

VkBufferCopy vbCopyRegion = {};
vbCopyRegion.srcOffset = 0;
vbCopyRegion.dstOffset = 0;
vbCopyRegion.size = meshData.size();
vkCmdCopyBuffer(commandBuffer, stagingBuffer, meshBuffer, 1, &vbCopyRegion);

vkEndCommandBuffer(commandBuffer);

// push it to a queue

Recording the primary command buffer:


// on the main thread

// transferCommandQueuePrimaryBuffer is the primary command buffer I submit eachf rame
vkResetCommandBuffer(transferCommandQueuePrimaryBuffer, 0);

VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;

vkBeginCommandBuffer(transferCommandQueuePrimaryBuffer, &beginInfo);

// transferCommandQueue being a vector of secondary command buffers
vkCmdExecuteCommands(transferCommandQueuePrimaryBuffer, transferCommandQueue.size(), transferCommandQueue.data());

vkEndCommandBuffer(transferCommandQueuePrimaryBuffer);

VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &transferCommandQueuePrimaryBuffer;

vkQueueSubmit(transferQueue, 1, &submitInfo, transferCommandQueueSubmitFence);
vkQueueWaitIdle(transferQueue); // placeholder sync while I work on making a way to properly signal the resource has been loaded (w/ fences probably)

 

 

Share this post


Link to post
Share on other sites
Advertisement

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By turanszkij
      Hi, right now building my engine in visual studio involves a shader compiling step to build hlsl 5.0 shaders. I have a separate project which only includes shader sources and the compiler is the visual studio integrated fxc compiler. I like this method because on any PC that has visual studio installed, I can just download the solution from GitHub and everything just builds without additional dependencies and using the latest version of the compiler. I also like it because the shaders are included in the solution explorer and easy to browse, and double-click to open (opening files can be really a pain in the ass in visual studio run in admin mode). Also it's nice that VS displays the build output/errors in the output window.
      But now I have the HLSL 6 compiler and want to build hlsl 6 shaders as well (and as I understand I can also compile vulkan compatible shaders with it later). Any idea how to do this nicely? I want only a single project containing shader sources, like it is now, but build them for different targets. I guess adding different building projects would be the way to go that reference the shader source project? But how would they differentiate from shader type of the sources (eg. pixel shader, compute shader,etc.)? Now the shader building project contains for each shader the shader type, how can other building projects reference that?
      Anyone with some experience in this?
    • By mark_braga
      I am working on a compute shader in Vulkan which does some image processing and has 1024 * 5=5120 loop iterations (5 outer and 1024 inner)
      If I do this, I get a device lost error after the succeeding call to queueSubmit after the image processing queueSubmit
      // Image processing dispatch submit(); waitForFence(); // All calls to submit after this will give the device lost error If I lower the number of loops from 1024 to 256 => 5 * 256 = 1280 loop iterations, it works fine. The shader does some pretty heavy arithmetic operations but the number of resources bound is 3 (one SRV, one UAV, and one sampler). The thread group size is x=16 ,y=16,z=1
      So my question - Is there a hardware limit to the number of loop executions/number of instructions per shader?
    • By AxeGuywithanAxe
      I wanted to see how others are currently handling descriptor heap updates and management.
      I've read a few articles and there tends to be three major strategies :
      1 ) You split up descriptor heaps per shader stage ( i.e one for vertex shader , pixel , hull, etc)
      2) You have one descriptor heap for an entire pipeline
      3) You split up descriptor heaps for update each update frequency (i.e EResourceSet_PerInstance , EResourceSet_PerPass , EResourceSet_PerMaterial, etc)
      The benefits of the first two approaches is that it makes it easier to port current code, and descriptor / resource descriptor management and updating tends to be easier to manage, but it seems to be not as efficient.
      The benefits of the third approach seems to be that it's the most efficient because you only manage and update objects when they change.
    • By khawk
      CRYENGINE has released their latest version with support for Vulkan, Substance integration, and more. Learn more from their announcement and check out the highlights below.
      Substance Integration
      CRYENGINE uses Substance internally in their workflow and have released a direct integration.
       
      Vulkan API
      A beta version of the Vulkan renderer to accompany the DX12 implementation. Vulkan is a cross-platform 3D graphics and compute API that enables developers to have high-performance real-time 3D graphics applications with balanced CPU/GPU usage. 

       
      Entity Components
      CRYENGINE has addressed a longstanding issue with game code managing entities within the level. The Entity Component System adds a modular and intuitive method to construct games.
      And More
      View the full release details at the CRYENGINE announcement here.

      View full story
    • By khawk
      The AMD GPU Open website has posted a brief tutorial providing an overview of objects in the Vulkan API. From the article:
      Read more at http://gpuopen.com/understanding-vulkan-objects/.


      View full story
  • Advertisement