• 9
• 11
• 9
• 20
• 12
• ### Similar Content

• I have a pretty good experience with multi gpu programming in D3D12. Now looking at Vulkan, although there are a few similarities, I cannot wrap my head around a few things due to the extremely sparse documentation (typical Khronos...)
In D3D12 -> You create a resource on GPU0 that is visible to GPU1 by setting the VisibleNodeMask to (00000011 where last two bits set means its visible to GPU0 and GPU1)
In Vulkan - I can see there is the VkBindImageMemoryDeviceGroupInfoKHR struct which you add to the pNext chain of VkBindImageMemoryInfoKHR and then call vkBindImageMemory2KHR. You also set the device indices which I assume is the same as the VisibleNodeMask except instead of a mask it is an array of indices. Till now it's fine.
Let's look at a typical SFR scenario:  Render left eye using GPU0 and right eye using GPU1
You have two textures. pTextureLeft is exclusive to GPU0 and pTextureRight is created on GPU1 but is visible to GPU0 so it can be sampled from GPU0 when we want to draw it to the swapchain. This is in the D3D12 world. How do I map this in Vulkan? Do I just set the device indices for pTextureRight as { 0, 1 }
Now comes the command buffer submission part that is even more confusing.
There is the struct VkDeviceGroupCommandBufferBeginInfoKHR. It accepts a device mask which I understand is similar to creating a command list with a certain NodeMask in D3D12.
So for GPU1 -> Since I am only rendering to the pTextureRight, I need to set the device mask as 2? (00000010)
For GPU0 -> Since I only render to pTextureLeft and finally sample pTextureLeft and pTextureRight to render to the swap chain, I need to set the device mask as 1? (00000001)
The same applies to VkDeviceGroupSubmitInfoKHR?
Now the fun part is it does not work  . Both command buffers render to the textures correctly. I verified this by reading back the textures and storing as png. The left texture is sampled correctly in the final composite pass. But I get a black in the area where the right texture should appear. Is there something that I am missing in this? Here is a code snippet too
void Init() { RenderTargetInfo info = {}; info.pDeviceIndices = { 0, 0 }; CreateRenderTarget(&info, &pTextureLeft); // Need to share this on both GPUs info.pDeviceIndices = { 0, 1 }; CreateRenderTarget(&info, &pTextureRight); } void DrawEye(CommandBuffer* pCmd, uint32_t eye) { // Do the draw // Begin with device mask depending on eye pCmd->Open((1 << eye)); // If eye is 0, we need to do some extra work to composite pTextureRight and pTextureLeft if (eye == 0) { DrawTexture(0, 0, width * 0.5, height, pTextureLeft); DrawTexture(width * 0.5, 0, width * 0.5, height, pTextureRight); } // Submit to the correct GPU pQueue->Submit(pCmd, (1 << eye)); } void Draw() { DrawEye(pRightCmd, 1); DrawEye(pLeftCmd, 0); }

• Hi,
I finally managed to get the DX11 emulating Vulkan device working but everything is flipped vertically now because Vulkan has a different clipping space. What are the best practices out there to keep these implementation consistent? I tried using a vertically flipped viewport, and while it works on Nvidia 1050, the Vulkan debug layer is throwing error messages that this is not supported in the spec so it might not work on others. There is also the possibility to flip the clip scpace position Y coordinate before writing out with vertex shader, but that requires changing and recompiling every shader. I could also bake it into the camera projection matrices, though I want to avoid that because then I need to track down for the whole engine where I upload matrices... Any chance of an easy extension or something? If not, I will probably go with changing the vertex shaders.

• I publishing for manufacturing our ray tracing engines and products on graphics API (C++, Vulkan API, GLSL460, SPIR-V): https://github.com/world8th/satellite-oem
For end users I have no more products or test products. Also, have one simple gltf viewer example (only source code).
In 2016 year had idea for replacement of screen space reflections, but in 2018 we resolved to finally re-profile project as "basis of render engine". In Q3 of 2017 year finally merged to Vulkan API.

• vkQueuePresentKHR is busy waiting - ie. wasting all the CPU cycles while waiting for vsync. Expected, sane, behavior would of course be akin to Sleep(0) till it can finish.
Windows 7, GeForce GTX 660.
Is this a common problem? Is there anything i can do to make it behave properly?

• I am working on reusing as many command buffers as I can by pre-recording them at load time. This gives a significant boost on CPU although now I cannot get the GPU timestamps since there is no way to read back. I Map the readback buffer before and Unmap it after reading is done. Does this mean I need a persistently mapped readback buffer?
void Init() { beginCmd(cmd); cmdBeginQuery(cmd); // Do a bunch of stuff cmdEndQuery(cmd); endCmd(cmd); } void Draw() { CommandBuffer* cmd = commands[frameIdx]; submit(cmd); } The begin and end query do exactly what the names say.

# Vulkan Vulkan Swapchain Unable To Create

This topic is 643 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi guys,

I'm currently having a problem with creating a swapchain. I've followed the 101 tutorial by jhenriques (it's posted in this forum), and apparently the swapchain is created just fine. Then I tried to redo the tutorial by Intel, and it triggers me an error when creating a swapchain. The app closes right away with validation layer enabled. I assume it's validation layer problem or whatev, so I tried to disable it. Now it throws an access violation error if I turned it off. It doesn't even have a chance to return a result for both situations. The only feedback I have from debugreportcallback is, it only says "Swapchain" given from pLayerPrefix, lol. So I assume it's related to one of the properties in the swapchainCreateInfo.

I have also visited Reddit for the almost same case. His case was he did not enable the VK_KHR_swapchain  in device extensions (he did it on instance extensions instead), and therefore throws the same problem as I am. I checked mine, but I have the swapchain extension enabled during device creation. I've checked the format, the image usage, surface formats, everything is there, nothing seems to be missing.

So I really have no idea what to look anymore. Does any of you have any case with swapchain that I may need to look for?

Thanks!

---

Swapchain creation:

	void _createSwapchain()
{
VkResult result;

if (_device != VK_NULL_HANDLE)
{
vkDeviceWaitIdle(_device);
}

// Get surface capabilities.
VkSurfaceCapabilitiesKHR surfaceCapabilities;

result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(_physicalDevice, _surface, &surfaceCapabilities);
KMA_VULKAN_CHECK_RESULT(result, "Unable to get physical device capabilities.");

// Get surface formats.
uint32_t surfaceFormatCount;

result = vkGetPhysicalDeviceSurfaceFormatsKHR(_physicalDevice, _surface, &surfaceFormatCount, nullptr);
KMA_VULKAN_CHECK_RESULT(result, "Unable to get physical device surface formats.");

std::vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount);

result = vkGetPhysicalDeviceSurfaceFormatsKHR(_physicalDevice, _surface, &surfaceFormatCount, surfaceFormats.data());
KMA_VULKAN_CHECK_RESULT(result, "Unable to get physical device surface formats.");

// Get present modes.
uint32_t presentModeCount;

result = vkGetPhysicalDeviceSurfacePresentModesKHR(_physicalDevice, _surface, &presentModeCount, nullptr);
KMA_VULKAN_CHECK_RESULT(result, "Unable to get physical device present modes.");

std::vector<VkPresentModeKHR> presentModes(presentModeCount);

result = vkGetPhysicalDeviceSurfacePresentModesKHR(_physicalDevice, _surface, &presentModeCount, presentModes.data());
KMA_VULKAN_CHECK_RESULT(result, "Unable to get physical device present modes.");

// Get image count. 2 = double buffering, 3 triple buffering.
uint32_t imageCount = 2;

// Check if the surface is able to handle the image count we desire.
if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount)
{
imageCount = surfaceCapabilities.maxImageCount;
}

// Get surface format.
VkSurfaceFormatKHR surfaceFormat = surfaceFormats[0];

// If there is no preferred format, we can put anything.
if (surfaceFormats.size() == 1 && surfaceFormat.format == VK_FORMAT_UNDEFINED)
{
surfaceFormat.format = VK_FORMAT_R8G8B8A8_UNORM;
surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
}

// Get our preferred format.
for (int i = 0, size = surfaceFormats.size(); i < size; ++i)
{
if (surfaceFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM)
{
surfaceFormat = surfaceFormats[i];
}
}

// Set swapchain extent. If surface capabilities has no width,
// just set it like our window size, as long as it fits the surface capabilities.
Window* window = Global::stage->getWindow();

VkExtent2D extent = {};

extent.width = window->width;
extent.height = window->height;

if (surfaceCapabilities.currentExtent.width == -1)
{
if (extent.width < surfaceCapabilities.minImageExtent.width)
{
extent.width = surfaceCapabilities.minImageExtent.width;
}

if (extent.height < surfaceCapabilities.minImageExtent.height)
{
extent.height = surfaceCapabilities.minImageExtent.height;
}

if (extent.width > surfaceCapabilities.maxImageExtent.width)
{
extent.width = surfaceCapabilities.maxImageExtent.width;
}

if (extent.height > surfaceCapabilities.maxImageExtent.height)
{
extent.height = surfaceCapabilities.maxImageExtent.height;
}
}

// Set image usage; how the image is used by Vulkan.
VkImageUsageFlags imageUsage;

// Just checking a bit, but color attachment is always supported.
if (surfaceCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
{
imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
else
{
KMA_ERROR("No image usage supported by the surface.");
}

// Select the pre-transformations. This is useful on phones/tablets to determine the default orientation.
VkSurfaceTransformFlagBitsKHR preTransform;

if (surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
{
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
}
else
{
preTransform = surfaceCapabilities.currentTransform;
}

// Select the present modes. By default we use FIFO method, but we prefer mailbox if it's supported.
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;

for (int i = 0, size = presentModes.size(); i < size; ++i)
{
if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
{
presentMode = presentModes[i];
}
}

// If the window is minimized, we may want not want to recreate swapchain as there's nothing to render.
// Desktop only case.
if ((extent.width == 0) || (extent.height == 0))
{
return;
}

// Refer the current swapchain as old swapchain.
VkSwapchainKHR oldSwapchain = _swapchain;

// Finally create the swapchain.
VkSwapchainCreateInfoKHR swapchainCreateInfo = {};

swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchainCreateInfo.pNext = nullptr;
swapchainCreateInfo.flags = 0;
swapchainCreateInfo.surface = _surface;
swapchainCreateInfo.minImageCount = imageCount;
swapchainCreateInfo.imageFormat = surfaceFormat.format;
swapchainCreateInfo.imageColorSpace = surfaceFormat.colorSpace;
swapchainCreateInfo.imageExtent = extent;
swapchainCreateInfo.imageArrayLayers = 1;
swapchainCreateInfo.imageUsage = imageUsage;

swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapchainCreateInfo.queueFamilyIndexCount = 0;
swapchainCreateInfo.pQueueFamilyIndices = nullptr;

swapchainCreateInfo.preTransform = preTransform;
swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
swapchainCreateInfo.presentMode = presentMode;
swapchainCreateInfo.clipped = VK_TRUE;
swapchainCreateInfo.oldSwapchain = oldSwapchain;

result = vkCreateSwapchainKHR(_device, &swapchainCreateInfo, nullptr, &_swapchain); // <-- WHERE THE ERROR HAPPENS.
KMA_VULKAN_CHECK_RESULT(result, "Unable to create swapchain.");

// Destroy the old swapchain.
if (oldSwapchain != VK_NULL_HANDLE)
{
vkDestroySwapchainKHR(_device, oldSwapchain, nullptr);
}
}

Edited by Alectora

##### Share on other sites

Oh geez. Apparently I made a mistake on matching the image extent. Since currentExtent already exists, I just need to refer it to the currentExtent by default and it solves the problem.

I can only define the extent when the currentExtent dimension is -1. If I define the dimension myself while the current extent exists (or not -1), it throws that error because they don't match! (Well, as jhenriques' tutorial said)

So this one:

Window* window = Global::stage->getWindow();

VkExtent2D extent = {};

extent.width = window->width;
extent.height = window->height;

if (surfaceCapabilities.currentExtent.width == -1)
{
... 

Should be roughly like this:

VkExtent2D extent = surfaceCapabilities.currentExtent;

if (extent.width == -1)
{
Window* window = Global::stage->getWindow();

extent.width = window->width;
extent.height = window->height;
...
Edited by Alectora