Fixed a bug in the Vulkan Swapchain

This commit is contained in:
Robert Beckebans 2018-10-07 17:58:32 +02:00
parent 98a13a2424
commit 0ef3fcfe92
5 changed files with 143 additions and 169 deletions

View file

@ -313,8 +313,6 @@ public:
//---------------------------------------------
#if defined( USE_VULKAN )
void CreateFromSwapImage( VkImage image, VkImageView imageView, VkFormat format, const VkExtent2D& extent );
static void EmptyGarbage();
VkImage GetImage() const

View file

@ -204,7 +204,9 @@ struct vulkanContext_t
#else
vulkanAllocation_t msaaAllocation;
#endif
idArray< idImage*, NUM_FRAME_DATA > swapchainImages;
idArray< VkImage, NUM_FRAME_DATA > swapchainImages;
idArray< VkImageView, NUM_FRAME_DATA > swapchainViews;
idArray< VkFramebuffer, NUM_FRAME_DATA > frameBuffers;
idArray< VkSemaphore, NUM_FRAME_DATA > acquireSemaphores;
idArray< VkSemaphore, NUM_FRAME_DATA > renderCompleteSemaphores;

View file

@ -2446,7 +2446,7 @@ void idRenderSystemLocal::InitOpenGL()
backend.Init();
// Reloading images here causes the rendertargets to get deleted. Figure out how to handle this properly on 360
globalImages->ReloadImages( true );
//globalImages->ReloadImages( true );
#if !defined(USE_VULKAN)
int err = glGetError();

View file

@ -201,26 +201,6 @@ bool idImage::IsLoaded() const
return image != VK_NULL_HANDLE; // TODO_VK maybe do something better than this.
}
/*
====================
idImage::CreateFromSwapImage
====================
*/
void idImage::CreateFromSwapImage( VkImage image, VkImageView imageView, VkFormat format, const VkExtent2D& extent )
{
image = image;
view = imageView;
internalFormat = format;
opts.textureType = TT_2D;
opts.format = FMT_RGBA8;
opts.numLevels = 1;
opts.width = extent.width;
opts.height = extent.height;
bIsSwapChainImage = true;
// TODO_VK may need to setup more state here.
}
/*
====================
idImage::CreateSampler
@ -383,83 +363,7 @@ void idImage::CopyDepthbuffer( int x, int y, int imageWidth, int imageHeight )
}
/*
========================
idImage::SubImageUpload
========================
*/
void idImage::SubImageUpload( int mipLevel, int x, int y, int z, int width, int height, const void* pic, int pixelPitch )
{
assert( x >= 0 && y >= 0 && mipLevel >= 0 && width >= 0 && height >= 0 && mipLevel < opts.numLevels );
if( IsCompressed() )
{
width = ( width + 3 ) & ~3;
height = ( height + 3 ) & ~3;
}
int size = width * height * BitsForFormat( opts.format ) / 8;
VkBuffer buffer;
VkCommandBuffer commandBuffer;
int offset = 0;
byte* data = stagingManager.Stage( size, 16, commandBuffer, buffer, offset );
if( opts.format == FMT_RGB565 )
{
byte* imgData = ( byte* )pic;
for( int i = 0; i < size; i += 2 )
{
data[ i ] = imgData[ i + 1 ];
data[ i + 1 ] = imgData[ i ];
}
}
else
{
memcpy( data, pic, size );
}
VkBufferImageCopy imgCopy = {};
imgCopy.bufferOffset = offset;
imgCopy.bufferRowLength = pixelPitch;
imgCopy.bufferImageHeight = height;
imgCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imgCopy.imageSubresource.layerCount = 1;
imgCopy.imageSubresource.mipLevel = mipLevel;
imgCopy.imageSubresource.baseArrayLayer = z;
imgCopy.imageOffset.x = x;
imgCopy.imageOffset.y = y;
imgCopy.imageOffset.z = 0;
imgCopy.imageExtent.width = width;
imgCopy.imageExtent.height = height;
imgCopy.imageExtent.depth = 1;
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = opts.numLevels;
barrier.subresourceRange.baseArrayLayer = z;
barrier.subresourceRange.layerCount = 1;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier );
vkCmdCopyBufferToImage( commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imgCopy );
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, 0, NULL, 0, NULL, 1, &barrier );
layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
/*
========================
@ -574,9 +478,9 @@ void idImage::AllocImage()
}
/*
========================
====================
idImage::PurgeImage
========================
====================
*/
void idImage::PurgeImage()
{
@ -612,3 +516,81 @@ void idImage::Resize( int width, int height )
{
}
/*
====================
idImage::SubImageUpload
====================
*/
void idImage::SubImageUpload( int mipLevel, int x, int y, int z, int width, int height, const void* pic, int pixelPitch )
{
assert( x >= 0 && y >= 0 && mipLevel >= 0 && width >= 0 && height >= 0 && mipLevel < opts.numLevels );
if( IsCompressed() )
{
width = ( width + 3 ) & ~3;
height = ( height + 3 ) & ~3;
}
int size = width * height * BitsForFormat( opts.format ) / 8;
VkBuffer buffer;
VkCommandBuffer commandBuffer;
int offset = 0;
byte* data = stagingManager.Stage( size, 16, commandBuffer, buffer, offset );
if( opts.format == FMT_RGB565 )
{
byte* imgData = ( byte* )pic;
for( int i = 0; i < size; i += 2 )
{
data[ i ] = imgData[ i + 1 ];
data[ i + 1 ] = imgData[ i ];
}
}
else
{
memcpy( data, pic, size );
}
VkBufferImageCopy imgCopy = {};
imgCopy.bufferOffset = offset;
imgCopy.bufferRowLength = pixelPitch;
imgCopy.bufferImageHeight = height;
imgCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imgCopy.imageSubresource.layerCount = 1;
imgCopy.imageSubresource.mipLevel = mipLevel;
imgCopy.imageSubresource.baseArrayLayer = z;
imgCopy.imageOffset.x = x;
imgCopy.imageOffset.y = y;
imgCopy.imageOffset.z = 0;
imgCopy.imageExtent.width = width;
imgCopy.imageExtent.height = height;
imgCopy.imageExtent.depth = 1;
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = opts.numLevels;
barrier.subresourceRange.baseArrayLayer = z;
barrier.subresourceRange.layerCount = 1;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier );
vkCmdCopyBufferToImage( commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imgCopy );
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, 0, NULL, 0, NULL, 1, &barrier );
layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}

View file

@ -49,6 +49,31 @@ idCVar r_vkEnableValidationLayers( "r_vkEnableValidationLayers", "1", CVAR_BOOL,
vulkanContext_t vkcontext;
static const int g_numInstanceExtensions = 2;
static const char* g_instanceExtensions[ g_numInstanceExtensions ] =
{
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
};
static const int g_numDebugInstanceExtensions = 1;
static const char* g_debugInstanceExtensions[ g_numDebugInstanceExtensions ] =
{
VK_EXT_DEBUG_REPORT_EXTENSION_NAME
};
static const int g_numDeviceExtensions = 1;
static const char* g_deviceExtensions[ g_numDeviceExtensions ] =
{
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
static const int g_numValidationLayers = 1;
static const char* g_validationLayers[ g_numValidationLayers ] =
{
"VK_LAYER_LUNARG_standard_validation"
};
#define ID_VK_ERROR_STRING( x ) case static_cast< int >( x ): return #x
/*
@ -91,30 +116,7 @@ const char* VK_ErrorToString( VkResult result )
};
}
static const int g_numInstanceExtensions = 2;
static const char* g_instanceExtensions[ g_numInstanceExtensions ] =
{
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
};
static const int g_numDebugInstanceExtensions = 1;
static const char* g_debugInstanceExtensions[ g_numDebugInstanceExtensions ] =
{
VK_EXT_DEBUG_REPORT_EXTENSION_NAME
};
static const int g_numDeviceExtensions = 1;
static const char* g_deviceExtensions[ g_numDeviceExtensions ] =
{
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
static const int g_numValidationLayers = 1;
static const char* g_validationLayers[ g_numValidationLayers ] =
{
"VK_LAYER_LUNARG_standard_validation"
};
/*
@ -756,18 +758,17 @@ static void CreateSwapChain()
vkcontext.fullscreen = glConfig.isFullscreen;
uint32 numImages = 0;
idArray< VkImage, NUM_FRAME_DATA > swapchainImages;
ID_VK_CHECK( vkGetSwapchainImagesKHR( vkcontext.device, vkcontext.swapchain, &numImages, NULL ) );
ID_VK_VALIDATE( numImages > 0, "vkGetSwapchainImagesKHR returned a zero image count." );
ID_VK_CHECK( vkGetSwapchainImagesKHR( vkcontext.device, vkcontext.swapchain, &numImages, swapchainImages.Ptr() ) );
ID_VK_CHECK( vkGetSwapchainImagesKHR( vkcontext.device, vkcontext.swapchain, &numImages, vkcontext.swapchainImages.Ptr() ) );
ID_VK_VALIDATE( numImages > 0, "vkGetSwapchainImagesKHR returned a zero image count." );
for( uint32 i = 0; i < NUM_FRAME_DATA; ++i )
{
VkImageViewCreateInfo imageViewCreateInfo = {};
imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewCreateInfo.image = swapchainImages[ i ];
imageViewCreateInfo.image = vkcontext.swapchainImages[ i ];
imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewCreateInfo.format = vkcontext.swapchainFormat;
imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R;
@ -781,16 +782,7 @@ static void CreateSwapChain()
imageViewCreateInfo.subresourceRange.layerCount = 1;
imageViewCreateInfo.flags = 0;
VkImageView imageView;
ID_VK_CHECK( vkCreateImageView( vkcontext.device, &imageViewCreateInfo, NULL, &imageView ) );
idImage* image = new idImage( va( "_swapchain%d", i ) );
image->CreateFromSwapImage(
swapchainImages[ i ],
imageView,
vkcontext.swapchainFormat,
vkcontext.swapchainExtent );
vkcontext.swapchainImages[ i ] = image;
ID_VK_CHECK( vkCreateImageView( vkcontext.device, &imageViewCreateInfo, NULL, &vkcontext.swapchainViews[ i ] ) );
}
}
@ -803,10 +795,10 @@ static void DestroySwapChain()
{
for( uint32 i = 0; i < NUM_FRAME_DATA; ++i )
{
vkDestroyImageView( vkcontext.device, vkcontext.swapchainImages[ i ]->GetView(), NULL );
delete vkcontext.swapchainImages[ i ];
vkDestroyImageView( vkcontext.device, vkcontext.swapchainViews[ i ], NULL );
}
vkcontext.swapchainImages.Zero();
vkcontext.swapchainViews.Zero();
vkDestroySwapchainKHR( vkcontext.device, vkcontext.swapchain, NULL );
}
@ -1165,7 +1157,7 @@ static void CreateFrameBuffers()
for( int i = 0; i < NUM_FRAME_DATA; ++i )
{
attachments[ 0 ] = vkcontext.swapchainImages[ i ]->GetView();
attachments[ 0 ] = vkcontext.swapchainViews[ i ];
ID_VK_CHECK( vkCreateFramebuffer( vkcontext.device, &frameBufferCreateInfo, NULL, &vkcontext.frameBuffers[ i ] ) );
}
}
@ -1184,7 +1176,6 @@ static void DestroyFrameBuffers()
vkcontext.frameBuffers.Zero();
}
/*
=============
ClearContext
@ -1227,6 +1218,7 @@ static void ClearContext()
vkcontext.msaaImage = VK_NULL_HANDLE;
vkcontext.msaaImageView = VK_NULL_HANDLE;
vkcontext.swapchainImages.Zero();
vkcontext.swapchainViews.Zero();
vkcontext.frameBuffers.Zero();
vkcontext.acquireSemaphores.Zero();
vkcontext.renderCompleteSemaphores.Zero();
@ -1285,22 +1277,22 @@ void idRenderBackend::Init()
CreateSurface();
#endif
// grab detailed information of available GPUs
// Enumerate physical devices and get their properties
EnumeratePhysicalDevices();
// find queue family/families supporting graphics and present.
// Find queue family/families supporting graphics and present.
SelectPhysicalDevice();
// create logical device and queues
// Create logical device and queues
CreateLogicalDeviceAndQueues();
// create semaphores for image acquisition and rendering completion
// Create semaphores for image acquisition and rendering completion
CreateSemaphores();
// create Command Pool
// Create Command Pool
CreateCommandPool();
// create Command Buffer
// Create Command Buffer
CreateCommandBuffer();
// setup the allocator
@ -1319,22 +1311,22 @@ void idRenderBackend::Init()
vulkanAllocator.Init();
#endif
// start the Staging Manager
// Start the Staging Manager
stagingManager.Init();
// create Swap Chain
// Create Swap Chain
CreateSwapChain();
// create Render Targets
// Create Render Targets
CreateRenderTargets();
// create Render Pass
// Create Render Pass
CreateRenderPass();
// create Pipeline Cache
// Create Pipeline Cache
CreatePipelineCache();
// create Frame Buffers
// Create Frame Buffers
CreateFrameBuffers();
#if 0
@ -1361,42 +1353,42 @@ void idRenderBackend::Shutdown()
idImage::EmptyGarbage();
}
// detroy Frame Buffers
// Detroy Frame Buffers
DestroyFrameBuffers();
// destroy Pipeline Cache
// Destroy Pipeline Cache
vkDestroyPipelineCache( vkcontext.device, vkcontext.pipelineCache, NULL );
// destroy Render Pass
// Destroy Render Pass
vkDestroyRenderPass( vkcontext.device, vkcontext.renderPass, NULL );
// destroy Render Targets
// Destroy Render Targets
DestroyRenderTargets();
// destroy Swap Chain
// Destroy Swap Chain
DestroySwapChain();
// stop the Staging Manager
// Stop the Staging Manager
stagingManager.Shutdown();
// destroy Command Buffer
// Destroy Command Buffer
vkFreeCommandBuffers( vkcontext.device, vkcontext.commandPool, NUM_FRAME_DATA, vkcontext.commandBuffer.Ptr() );
for( int i = 0; i < NUM_FRAME_DATA; ++i )
{
vkDestroyFence( vkcontext.device, vkcontext.commandBufferFences[ i ], NULL );
}
// destroy Command Pool
// Destroy Command Pool
vkDestroyCommandPool( vkcontext.device, vkcontext.commandPool, NULL );
// destroy Semaphores
// Destroy Semaphores
for( int i = 0; i < NUM_FRAME_DATA; ++i )
{
vkDestroySemaphore( vkcontext.device, vkcontext.acquireSemaphores[ i ], NULL );
vkDestroySemaphore( vkcontext.device, vkcontext.renderCompleteSemaphores[ i ], NULL );
}
// destroy Debug Callback
// Destroy Debug Callback
if( r_vkEnableValidationLayers.GetBool() )
{
DestroyDebugReportCallback();
@ -1409,13 +1401,13 @@ void idRenderBackend::Shutdown()
vulkanAllocator.Shutdown();
#endif
// destroy Logical Device
// Destroy Logical Device
vkDestroyDevice( vkcontext.device, NULL );
// destroy Surface
// Destroy Surface
vkDestroySurfaceKHR( vkcontext.instance, vkcontext.surface, NULL );
// destroy the Instance
// Destroy the Instance
vkDestroyInstance( vkcontext.instance, NULL );
ClearContext();
@ -1534,7 +1526,7 @@ void idRenderBackend::GL_EndFrame()
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = vkcontext.swapchainImages[ vkcontext.currentSwapIndex ]->GetImage();
barrier.image = vkcontext.swapchainImages[ vkcontext.currentSwapIndex ];
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;