屏幕截图功能可以工作,但会导致 Vulkan 应用程序尝试重新创建 swapchian 并崩溃

问题描述 投票:0回答:1

我一直在尝试通过密切关注 Sascha Willems exmaple 在我的 Vulkan 应用程序中添加创建屏幕截图的功能。此时,该函数完全按照预期工作,但在该函数运行后,我的程序尝试重新创建交换链并返回以下输出:

Image successfully saved! 
Present mode: Mailbox
validation layer: Validation Error: [ VUID-VkSwapchainCreateInfoKHR-preTransform-parameter ] Object 0: handle = 0x26dba352cf0, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xaf5f3828 | vkCreateSwapchainKHR: value of pCreateInfo->preTransform contains flag bits that are not recognized members of VkSurfaceTransformFlagBitsKHR The Vulkan spec states: preTransform must be a valid VkSurfaceTransformFlagBitsKHR value (https://vulkan.lunarg.com/doc/view/1.3.250.1/windows/1.3-extensions/vkspec.html#VUID-VkSwapchainCreateInfoKHR-preTransform-parameter)
validation layer: Validation Error: [ VUID-VkSwapchainCreateInfoKHR-preTransform-parameter ] Object 0: handle = 0x26dba352cf0, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xaf5f3828 | vkCreateSwapchainKHR: value of pCreateInfo->preTransform contains multiple members of VkSurfaceTransformFlagBitsKHR when only a single value is allowed The Vulkan spec states: preTransform must be a valid VkSurfaceTransformFlagBitsKHR value (https://vulkan.lunarg.com/doc/view/1.3.250.1/windows/1.3-extensions/vkspec.html#VUID-VkSwapchainCreateInfoKHR-preTransform-parameter)
validation layer: Validation Performance Warning: [ UNASSIGNED-CoreValidation-SwapchainPreTransform ] Object 0: handle = 0x26dba0ca580, type = VK_OBJECT_TYPE_PHYSICAL_DEVICE; | MessageID = 0x214b6dd0 | vkCreateSwapchainKHR(): pCreateInfo->preTransform (Unhandled VkSurfaceTransformFlagBitsKHR) doesn't match the currentTransform (VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR, the presentation engine will transform the image content as part of the presentation operation.
validation layer: Validation Error: [ VUID-VkSwapchainCreateInfoKHR-minImageCount-01272 ] Object 0: handle = 0x26dba352cf0, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x7400c58b | vkCreateSwapchainKHR() called with minImageCount = -858993460, which is outside the bounds returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = 2, maxImageCount = 8). The Vulkan spec states: minImageCount must be less than or equal to the value returned in the maxImageCount member of the VkSurfaceCapabilitiesKHR structure returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the surface if the returned maxImageCount is not zero (https://vulkan.lunarg.com/doc/view/1.3.250.1/windows/1.3-extensions/vkspec.html#VUID-VkSwapchainCreateInfoKHR-minImageCount-01272)
validation layer: Validation Error: [ VUID-VkSwapchainCreateInfoKHR-preTransform-01279 ] Object 0: handle = 0x26dba352cf0, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x987713ee | vkCreateSwapchainKHR() called with a non-supported pCreateInfo->preTransform (i.e. Unhandled VkSurfaceTransformFlagBitsKHR).  Supported values are:
    VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
. The Vulkan spec states: preTransform must be one of the bits present in the supportedTransforms member of the VkSurfaceCapabilitiesKHR structure returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the surface (https://vulkan.lunarg.com/doc/view/1.3.250.1/windows/1.3-extensions/vkspec.html#VUID-VkSwapchainCreateInfoKHR-preTransform-01279)
validation layer: Validation Error: [ VUID-VkSwapchainCreateInfoKHR-imageExtent-01274 ] Object 0: handle = 0x26dba352cf0, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x7cd0911d | vkCreateSwapchainKHR() called with imageExtent = (3435973836,3435973836), which is outside the bounds returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (800,600), minImageExtent = (800,600), maxImageExtent = (800,600). The Vulkan spec states: imageExtent must be between minImageExtent and maxImageExtent, inclusive, where minImageExtent and maxImageExtent are members of the VkSurfaceCapabilitiesKHR structure returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the surface (https://vulkan.lunarg.com/doc/view/1.3.250.1/windows/1.3-extensions/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageExtent-01274)
validation layer: Validation Error: [ VUID-VkSwapchainCreateInfoKHR-imageFormat-01778 ] Object 0: handle = 0x26dba352cf0, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xc036022f | vkCreateSwapchainKHR() called with imageExtent = (-858993460,-858993460), which is bigger than max extent (32768,32768)returned by vkGetPhysicalDeviceImageFormatProperties(): for imageFormat VK_FORMAT_B8G8R8A8_SRGB with tiling VK_IMAGE_TILING_OPTIMAL The Vulkan spec states: The implied image creation parameters of the swapchain must be supported as reported by vkGetPhysicalDeviceImageFormatProperties (https://vulkan.lunarg.com/doc/view/1.3.250.1/windows/1.3-extensions/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageFormat-01778)
failed to create swap chain!

到目前为止,重新创建交换链的唯一条件是调整窗口大小(这是有道理的)。我不知道是什么触发了重新创建交换链的调用。现在,屏幕截图函数在帧完全完成后调用,但我也在渲染帧内容后立即调用它,但输出没有变化。这是截图功能:

    class ScreenshotTool {
        public:
            
            //assumes blitting is supported
            //Turns out that was a bad idea my 1060 does not in fact support blitting 
            //this is only for linear tiling, it is supprted for optimal tiling but i dont want to dive into something new right now
            //and no, I am not execty sure what it does (a boolean based combining or seperating function)
            
            void ScreenshotTool::takeScreenshot(VkImage srcImage, char* fileName, Device &device, Window window){
                bool supportsblit = false;
                //check for blit support later

                std::cout << "attempting to take screenshot \n";
                VkImageCreateInfo captureImageInfo{};
                VkExtent2D extent = window.getExtent();

                captureImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
                captureImageInfo.imageType = VK_IMAGE_TYPE_2D;
                // Note that vkCmdBlitImage (if supported) will also do format conversions if the swapchain color format would differ
                captureImageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
                captureImageInfo.extent.width = extent.width;
                captureImageInfo.extent.height = extent.height;
                captureImageInfo.extent.depth = 1;
                captureImageInfo.arrayLayers = 1;
                captureImageInfo.mipLevels = 1;
                captureImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
                captureImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
                captureImageInfo.tiling = VK_IMAGE_TILING_LINEAR;
                captureImageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;

                VkImage cptImage;

                std::cout << "creating image \n";
                vkCreateImage(device.device(), &captureImageInfo, nullptr, &cptImage);

                std::cout << "creating image memory \n";
                //create memory ???
                VkMemoryRequirements memRequirements;
                VkMemoryAllocateInfo memAllocInfo{};
                VkDeviceMemory cptImageMemory;
                vkGetImageMemoryRequirements(device.device(), cptImage, &memRequirements);
                memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
                memAllocInfo.allocationSize = memRequirements.size;

                memAllocInfo.memoryTypeIndex = device.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
                vkAllocateMemory(device.device(), &memAllocInfo, nullptr, &cptImageMemory);
                vkBindImageMemory(device.device(), cptImage, cptImageMemory, 0);

                std::cout << "chanigng image layouts \n";
                //changing image layouts 
                device.insertImageMemoryBarrier(
                cptImage,
                0,
                VK_ACCESS_TRANSFER_WRITE_BIT,
                VK_IMAGE_LAYOUT_UNDEFINED,
                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                VK_PIPELINE_STAGE_TRANSFER_BIT,
                VK_PIPELINE_STAGE_TRANSFER_BIT,
                VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
                
                device.insertImageMemoryBarrier(
                srcImage,
                VK_ACCESS_MEMORY_READ_BIT,
                VK_ACCESS_TRANSFER_READ_BIT,
                VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                VK_PIPELINE_STAGE_TRANSFER_BIT,
                VK_PIPELINE_STAGE_TRANSFER_BIT,
                VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });

                VkCommandBuffer commandBuffer = device.beginSingleTimeCommands();
                //where blit becomes required, blit can do format conversions
                if(supportsblit){
                    VkOffset3D blitSize;
                    blitSize.x = extent.width;
                    blitSize.y = extent.height;
                    blitSize.z = 1;
                    VkImageBlit imageBlitRegion{};
                    imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
                    imageBlitRegion.srcSubresource.layerCount = 1;
                    imageBlitRegion.srcOffsets[1] = blitSize;
                    imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
                    imageBlitRegion.dstSubresource.layerCount = 1;
                    imageBlitRegion.dstOffsets[1] = blitSize;

                    vkCmdBlitImage(
                    commandBuffer,
                    srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                    cptImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                    1,
                    &imageBlitRegion,
                    VK_FILTER_NEAREST);
                }
                //will need to manually convert to rgb, eventually
                if(!supportsblit) {
                    VkImageCopy imageCopyRegion{};
                    imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
                    imageCopyRegion.srcSubresource.layerCount = 1;
                    imageCopyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
                    imageCopyRegion.dstSubresource.layerCount = 1;
                    imageCopyRegion.extent.width = extent.width;
                    imageCopyRegion.extent.height = extent.height;
                    imageCopyRegion.extent.depth = 1;

                    // Issue the copy command
                    vkCmdCopyImage(
                        commandBuffer,
                        srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                        cptImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                        1,
                        &imageCopyRegion);
                }

                device.endSingleTimeCommands(commandBuffer);

                //change image format again to write to file
                device.insertImageMemoryBarrier(
                cptImage,
                VK_ACCESS_TRANSFER_WRITE_BIT,
                VK_ACCESS_MEMORY_READ_BIT,
                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                VK_IMAGE_LAYOUT_GENERAL,
                VK_PIPELINE_STAGE_TRANSFER_BIT,
                VK_PIPELINE_STAGE_TRANSFER_BIT,
                VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });

                device.insertImageMemoryBarrier(
                srcImage,
                VK_ACCESS_TRANSFER_READ_BIT,
                VK_ACCESS_MEMORY_READ_BIT,
                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
                VK_PIPELINE_STAGE_TRANSFER_BIT,
                VK_PIPELINE_STAGE_TRANSFER_BIT,
                VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });


                std::cout << "extracting image data \n";
                //get image layout
                VkImageSubresource subResource { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
                VkSubresourceLayout subResourceLayout;
                vkGetImageSubresourceLayout(device.device(), cptImage, &subResource, &subResourceLayout);

                const char* data;
                vkMapMemory(device.device(), cptImageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&data);
                //data += subResourceLayout.offset;

                //using stb to save as jpg not ppm because I can

                std::cout << "writing to jpg \n";
                if(stbi_write_jpg(fileName, extent.width, extent.height, 4, (void*)data, 100) == 0) {
                    std::cout << "bad doo doo \n";
                }
                std::cout << "Image successfully saved! \n";

                vkUnmapMemory(device.device(), cptImageMemory);
                vkFreeMemory(device.device(), cptImageMemory, nullptr);
                vkDestroyImage(device.device(), cptImage, nullptr);
            }

其他所有内容都在我的repo

c++ graphics vulkan
1个回答
0
投票

问题我已经解决了,与Vulkan无关。我正在传递我的窗口对象,它是一个唯一的指针。我应该传递一个指针或简单地传递范围,这就是我最终所做的。它有效!

© www.soinside.com 2019 - 2024. All rights reserved.