Renderdoc can finally capture a frame rendered with Vulkan

This commit is contained in:
Robert Beckebans 2018-11-02 16:53:36 +01:00
parent 8cdc4aa99c
commit 33c7d06871
9 changed files with 161 additions and 49 deletions

View file

@ -0,0 +1,6 @@
cd ..
del /s /q build
mkdir build
cd build
cmake -G "Visual Studio 14 Win64" -DCMAKE_INSTALL_PREFIX=../bin/windows10-64 -DWINDOWS10=ON -DUSE_VULKAN=ON ../neo
pause

View file

@ -560,6 +560,12 @@ void idRenderBackend::BindVariableStageImage( const textureStage_t* texture, con
{
if( texture->cinematic )
{
#if defined(USE_VULKAN)
// FIXME upload of video image sub resources
GL_SelectTexture( 0 );
globalImages->defaultImage->Bind();
#else
cinData_t cin;
if( r_skipDynamicTextures.GetBool() )
@ -576,13 +582,13 @@ void idRenderBackend::BindVariableStageImage( const textureStage_t* texture, con
{
GL_SelectTexture( 0 );
cin.imageY->Bind();
GL_SelectTexture( 1 );
cin.imageCr->Bind();
GL_SelectTexture( 2 );
cin.imageCb->Bind();
// DG: imageY is only used for bink videos (with libbinkdec), so the bink shader must be used
if( viewDef->is2Dgui )
{
@ -598,7 +604,7 @@ void idRenderBackend::BindVariableStageImage( const textureStage_t* texture, con
// Carl: A single RGB image works better with the FFMPEG BINK codec.
GL_SelectTexture( 0 );
cin.image->Bind();
/*
if( backEnd.viewDef->is2Dgui )
{
@ -618,6 +624,7 @@ void idRenderBackend::BindVariableStageImage( const textureStage_t* texture, con
// SWF GUI case is handled better, too
renderProgManager.BindShader_TextureVertexColor();
}
#endif
}
else
{
@ -5166,6 +5173,8 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds )
resolutionScale.SetCurrentGPUFrameTime( commonLocal.GetRendererGPUMicroseconds() );
ResizeImages();
renderLog.StartFrame();
GL_StartFrame();
@ -5207,7 +5216,7 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds )
break;
case RC_SET_BUFFER:
SetBuffer( cmds );
//SetBuffer( cmds );
c_setBuffers++;
break;

View file

@ -146,8 +146,8 @@ struct gpuInfo_t
struct vulkanContext_t
{
uint64 counter;
uint32 currentFrameData;
uint64 frameCounter;
uint32 frameParity;
vertCacheHandle_t jointCacheHandle;
uint64 stencilOperations[ STENCIL_FACE_NUM ];

View file

@ -298,25 +298,52 @@ void idRenderProgManager::KillAllShaders()
{
Unbind();
#if !defined(USE_VULKAN)
for( int i = 0; i < shaders.Num(); i++ )
// destroy shaders
for( int i = 0; i < shaders.Num(); ++i )
{
if( shaders[i].progId != INVALID_PROGID )
{
glDeleteShader( shaders[i].progId );
shaders[i].progId = INVALID_PROGID;
}
shader_t& shader = shaders[ i ];
vkDestroyShaderModule( vkcontext.device, shader.module, NULL );
shader.module = VK_NULL_HANDLE;
}
// destroy pipelines
for( int i = 0; i < renderProgs.Num(); ++i )
{
if( renderProgs[i].progId != INVALID_PROGID )
renderProg_t& prog = renderProgs[ i ];
for( int j = 0; j < prog.pipelines.Num(); ++j )
{
glDeleteProgram( renderProgs[i].progId );
renderProgs[i].progId = INVALID_PROGID;
vkDestroyPipeline( vkcontext.device, prog.pipelines[ j ].pipeline, NULL );
}
prog.pipelines.Clear();
vkDestroyDescriptorSetLayout( vkcontext.device, prog.descriptorSetLayout, NULL );
vkDestroyPipelineLayout( vkcontext.device, prog.pipelineLayout, NULL );
}
#endif
renderProgs.Clear();
for( int i = 0; i < NUM_FRAME_DATA; ++i )
{
parmBuffers[ i ]->FreeBufferObject();
delete parmBuffers[ i ];
parmBuffers[ i ] = NULL;
}
emptyUBO.FreeBufferObject();
for( int i = 0; i < NUM_FRAME_DATA; ++i )
{
//vkFreeDescriptorSets( vkcontext.device, descriptorPools[ i ], MAX_DESC_SETS, descriptorSets[ i ] );
vkResetDescriptorPool( vkcontext.device, descriptorPools[ i ], 0 );
vkDestroyDescriptorPool( vkcontext.device, descriptorPools[ i ], NULL );
}
memset( descriptorSets, 0, sizeof( descriptorSets ) );
memset( descriptorPools, 0, sizeof( descriptorPools ) );
counter = 0;
currentData = 0;
currentDescSet = 0;
}
/*

View file

@ -33,7 +33,7 @@ If you have questions concerning this license or the applicable additional terms
#include "../RenderBackend.h"
#include "Allocator_VK.h"
idCVar r_vkDeviceLocalMemoryMB( "r_vkDeviceLocalMemoryMB", "128", CVAR_INTEGER | CVAR_INIT, "" );
idCVar r_vkDeviceLocalMemoryMB( "r_vkDeviceLocalMemoryMB", "256", CVAR_INTEGER | CVAR_INIT, "" );
idCVar r_vkHostVisibleMemoryMB( "r_vkHostVisibleMemoryMB", "64", CVAR_INTEGER | CVAR_INIT, "" );
/*

View file

@ -482,6 +482,8 @@ void idImage::AllocImage()
ID_VK_CHECK( vkBindImageMemory( vkcontext.device, image, allocation.deviceMemory, allocation.offset ) );
#endif
idLib::Printf( "Vulkan Image alloc '%s': %p\n", GetName(), image );
// Create Image View
VkImageViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;

View file

@ -45,7 +45,7 @@ idCVar r_syncEveryFrame( "r_syncEveryFrame", "1", CVAR_BOOL, "Don't let the GPU
// NEW VULKAN STUFF
idCVar r_vkEnableValidationLayers( "r_vkEnableValidationLayers", "0", CVAR_BOOL, "" );
idCVar r_vkEnableValidationLayers( "r_vkEnableValidationLayers", "1", CVAR_BOOL, "" );
vulkanContext_t vkcontext;
@ -1064,6 +1064,10 @@ static void CreateRenderPass()
depthAttachment.samples = vkcontext.sampleCount;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
// RB
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
@ -1183,8 +1187,8 @@ ClearContext
*/
static void ClearContext()
{
vkcontext.counter = 0;
vkcontext.currentFrameData = 0;
vkcontext.frameCounter = 0;
vkcontext.frameParity = 0;
vkcontext.jointCacheHandle = 0;
memset( vkcontext.stencilOperations, 0, sizeof( vkcontext.stencilOperations ) );
vkcontext.instance = VK_NULL_HANDLE;
@ -1349,6 +1353,9 @@ void idRenderBackend::Shutdown()
// RB: release input before anything goes wrong
Sys_ShutdownInput();
// Destroy Shaders
renderProgManager.Shutdown();
for( int i = 0; i < NUM_FRAME_DATA; ++i )
{
idImage::EmptyGarbage();
@ -1527,7 +1534,7 @@ void idRenderBackend::DrawElementsWithCounters( const drawSurf_t* surf )
{
const VkBuffer buffer = indexBuffer->GetAPIObject();
const VkDeviceSize offset = indexBuffer->GetOffset();
vkCmdBindIndexBuffer( vkcontext.commandBuffer[ vkcontext.currentFrameData ], buffer, offset, VK_INDEX_TYPE_UINT16 );
vkCmdBindIndexBuffer( vkcontext.commandBuffer[ vkcontext.frameParity ], buffer, offset, VK_INDEX_TYPE_UINT16 );
}
/*
@ -1557,7 +1564,7 @@ void idRenderBackend::DrawElementsWithCounters( const drawSurf_t* surf )
{
const VkBuffer buffer = vertexBuffer->GetAPIObject();
const VkDeviceSize offset = vertexBuffer->GetOffset();
vkCmdBindVertexBuffers( vkcontext.commandBuffer[ vkcontext.currentFrameData ], 0, 1, &buffer, &offset );
vkCmdBindVertexBuffers( vkcontext.commandBuffer[ vkcontext.frameParity ], 0, 1, &buffer, &offset );
}
/*
@ -1569,7 +1576,7 @@ void idRenderBackend::DrawElementsWithCounters( const drawSurf_t* surf )
*/
vkCmdDrawIndexed(
vkcontext.commandBuffer[ vkcontext.currentFrameData ],
vkcontext.commandBuffer[ vkcontext.frameParity ],
surf->numIndexes, 1, ( indexOffset >> 1 ), vertOffset / sizeof( idDrawVert ), 0 );
// RB: added stats
@ -1578,6 +1585,67 @@ void idRenderBackend::DrawElementsWithCounters( const drawSurf_t* surf )
}
/*
====================
idRenderBackend::ResizeImages
====================
*/
void idRenderBackend::ResizeImages()
{
if( vkcontext.swapchainExtent.width == glConfig.nativeScreenWidth &&
vkcontext.swapchainExtent.height == glConfig.nativeScreenHeight &&
vkcontext.fullscreen == glConfig.isFullscreen )
{
return;
}
stagingManager.Flush();
vkDeviceWaitIdle( vkcontext.device );
idImage::EmptyGarbage();
// Destroy Frame Buffers
DestroyFrameBuffers();
// Destroy Render Targets
DestroyRenderTargets();
// Destroy Current Swap Chain
DestroySwapChain();
// Destroy Current Surface
vkDestroySurfaceKHR( vkcontext.instance, vkcontext.surface, NULL );
#if !defined( USE_AMD_ALLOCATOR )
vulkanAllocator.EmptyGarbage();
#endif
// Create New Surface
CreateSurface();
// Refresh Surface Capabilities
ID_VK_CHECK( vkGetPhysicalDeviceSurfaceCapabilitiesKHR( vkcontext.physicalDevice, vkcontext.surface, &vkcontext.gpu->surfaceCaps ) );
// Recheck presentation support
VkBool32 supportsPresent = VK_FALSE;
ID_VK_CHECK( vkGetPhysicalDeviceSurfaceSupportKHR( vkcontext.physicalDevice, vkcontext.presentFamilyIdx, vkcontext.surface, &supportsPresent ) );
if( supportsPresent == VK_FALSE )
{
idLib::FatalError( "idRenderBackend::ResizeImages: New surface does not support present?" );
}
// Create New Swap Chain
CreateSwapChain();
// Create New Render Targets
CreateRenderTargets();
// Create New Frame Buffers
CreateFrameBuffers();
}
/*
=========================================================================================================
@ -1623,7 +1691,7 @@ idRenderBackend::GL_StartFrame
*/
void idRenderBackend::GL_StartFrame()
{
ID_VK_CHECK( vkAcquireNextImageKHR( vkcontext.device, vkcontext.swapchain, UINT64_MAX, vkcontext.acquireSemaphores[ vkcontext.currentFrameData ], VK_NULL_HANDLE, &vkcontext.currentSwapIndex ) );
ID_VK_CHECK( vkAcquireNextImageKHR( vkcontext.device, vkcontext.swapchain, UINT64_MAX, vkcontext.acquireSemaphores[ vkcontext.frameParity ], VK_NULL_HANDLE, &vkcontext.currentSwapIndex ) );
idImage::EmptyGarbage();
@ -1637,7 +1705,7 @@ void idRenderBackend::GL_StartFrame()
VkCommandBufferBeginInfo commandBufferBeginInfo = {};
commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
ID_VK_CHECK( vkBeginCommandBuffer( vkcontext.commandBuffer[ vkcontext.currentFrameData ], &commandBufferBeginInfo ) );
ID_VK_CHECK( vkBeginCommandBuffer( vkcontext.commandBuffer[ vkcontext.frameParity ], &commandBufferBeginInfo ) );
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
@ -1645,7 +1713,7 @@ void idRenderBackend::GL_StartFrame()
renderPassBeginInfo.framebuffer = vkcontext.frameBuffers[ vkcontext.currentSwapIndex ];
renderPassBeginInfo.renderArea.extent = vkcontext.swapchainExtent;
vkCmdBeginRenderPass( vkcontext.commandBuffer[ vkcontext.currentFrameData ], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE );
vkCmdBeginRenderPass( vkcontext.commandBuffer[ vkcontext.frameParity ], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE );
}
/*
@ -1655,7 +1723,7 @@ idRenderBackend::GL_EndFrame
*/
void idRenderBackend::GL_EndFrame()
{
VkCommandBuffer commandBuffer = vkcontext.commandBuffer[ vkcontext.currentFrameData ];
VkCommandBuffer commandBuffer = vkcontext.commandBuffer[ vkcontext.frameParity ];
vkCmdEndRenderPass( commandBuffer );
@ -1692,24 +1760,24 @@ void idRenderBackend::GL_EndFrame()
0, 0, NULL, 0, NULL, 1, &barrier );
ID_VK_CHECK( vkEndCommandBuffer( commandBuffer ) )
vkcontext.commandBufferRecorded[ vkcontext.currentFrameData ] = true;
vkcontext.commandBufferRecorded[ vkcontext.frameParity ] = true;
VkSemaphore* acquire = &vkcontext.acquireSemaphores[ vkcontext.currentFrameData ];
VkSemaphore* finished = &vkcontext.renderCompleteSemaphores[ vkcontext.currentFrameData ];
VkSemaphore* acquire = &vkcontext.acquireSemaphores[ vkcontext.frameParity ];
VkSemaphore* finished = &vkcontext.renderCompleteSemaphores[ vkcontext.frameParity ];
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &vkcontext.commandBuffer[ vkcontext.currentFrameData ];
submitInfo.pCommandBuffers = &vkcontext.commandBuffer[ vkcontext.frameParity ];
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = acquire;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = finished;
submitInfo.pWaitDstStageMask = &dstStageMask;
ID_VK_CHECK( vkQueueSubmit( vkcontext.graphicsQueue, 1, &submitInfo, vkcontext.commandBufferFences[ vkcontext.currentFrameData ] ) );
ID_VK_CHECK( vkQueueSubmit( vkcontext.graphicsQueue, 1, &submitInfo, vkcontext.commandBufferFences[ vkcontext.frameParity ] ) );
}
/*
@ -1723,18 +1791,18 @@ void idRenderBackend::GL_BlockingSwapBuffers()
{
RENDERLOG_PRINTF( "***************** BlockingSwapBuffers *****************\n\n\n" );
if( vkcontext.commandBufferRecorded[ vkcontext.currentFrameData ] == false )
if( vkcontext.commandBufferRecorded[ vkcontext.frameParity ] == false )
{
// RB: no need to present anything if no command buffers where recorded in this frame
return;
}
ID_VK_CHECK( vkWaitForFences( vkcontext.device, 1, &vkcontext.commandBufferFences[ vkcontext.currentFrameData ], VK_TRUE, UINT64_MAX ) );
ID_VK_CHECK( vkWaitForFences( vkcontext.device, 1, &vkcontext.commandBufferFences[ vkcontext.frameParity ], VK_TRUE, UINT64_MAX ) );
ID_VK_CHECK( vkResetFences( vkcontext.device, 1, &vkcontext.commandBufferFences[ vkcontext.currentFrameData ] ) );
vkcontext.commandBufferRecorded[ vkcontext.currentFrameData ] = false;
ID_VK_CHECK( vkResetFences( vkcontext.device, 1, &vkcontext.commandBufferFences[ vkcontext.frameParity ] ) );
vkcontext.commandBufferRecorded[ vkcontext.frameParity ] = false;
VkSemaphore* finished = &vkcontext.renderCompleteSemaphores[ vkcontext.currentFrameData ];
VkSemaphore* finished = &vkcontext.renderCompleteSemaphores[ vkcontext.frameParity ];
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
@ -1748,8 +1816,8 @@ void idRenderBackend::GL_BlockingSwapBuffers()
// RB: at this time the image is presented on the screen
vkcontext.counter++;
vkcontext.currentFrameData = vkcontext.counter % NUM_FRAME_DATA;
vkcontext.frameCounter++;
vkcontext.frameParity = vkcontext.frameCounter % NUM_FRAME_DATA;
}
/*
@ -1829,7 +1897,7 @@ void idRenderBackend::GL_Scissor( int x /* left*/, int y /* bottom */, int w, in
scissor.extent.width = w;
scissor.extent.height = h;
vkCmdSetScissor( vkcontext.commandBuffer[ vkcontext.currentFrameData ], 0, 1, &scissor );
vkCmdSetScissor( vkcontext.commandBuffer[ vkcontext.frameParity ], 0, 1, &scissor );
}
/*
@ -1847,7 +1915,7 @@ void idRenderBackend::GL_Viewport( int x /* left */, int y /* bottom */, int w,
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport( vkcontext.commandBuffer[ vkcontext.currentFrameData ], 0, 1, &viewport );
vkCmdSetViewport( vkcontext.commandBuffer[ vkcontext.frameParity ], 0, 1, &viewport );
}
/*
@ -1935,7 +2003,7 @@ void idRenderBackend::GL_Clear( bool color, bool depth, bool stencil, byte stenc
clearRect.layerCount = 1;
clearRect.rect.extent = vkcontext.swapchainExtent;
vkCmdClearAttachments( vkcontext.commandBuffer[ vkcontext.currentFrameData ], numAttachments, attachments, 1, &clearRect );
vkCmdClearAttachments( vkcontext.commandBuffer[ vkcontext.frameParity ], numAttachments, attachments, 1, &clearRect );
/*
int clearFlags = 0;
@ -2121,7 +2189,7 @@ void idRenderBackend::DrawFlickerBox()
VkClearColorValue& color = attachment.clearValue.color;
if( vkcontext.currentFrameData & 1 )
if( vkcontext.frameParity & 1 )
{
color.float32[ 0 ] = 1;
color.float32[ 1 ] = 0;
@ -2145,7 +2213,7 @@ void idRenderBackend::DrawFlickerBox()
clearRect.layerCount = 1;
clearRect.rect.extent = extent;
vkCmdClearAttachments( vkcontext.commandBuffer[ vkcontext.currentFrameData ], 1, &attachment, 1, &clearRect );
vkCmdClearAttachments( vkcontext.commandBuffer[ vkcontext.frameParity ], 1, &attachment, 1, &clearRect );
/*
if( tr.frameCount & 1 )

View file

@ -1438,13 +1438,13 @@ void idRenderProgManager::CommitUniforms( uint64 stateBits )
vkUpdateDescriptorSets( vkcontext.device, writeIndex, writes, 0, NULL );
vkCmdBindDescriptorSets(
vkcontext.commandBuffer[ vkcontext.currentFrameData ],
vkcontext.commandBuffer[ vkcontext.frameParity ],
VK_PIPELINE_BIND_POINT_GRAPHICS,
prog.pipelineLayout, 0, 1, &descSet,
0, NULL );
vkCmdBindPipeline(
vkcontext.commandBuffer[ vkcontext.currentFrameData ],
vkcontext.commandBuffer[ vkcontext.frameParity ],
VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline );
}

View file

@ -33,7 +33,7 @@ If you have questions concerning this license or the applicable additional terms
#if defined( USE_VULKAN )
#define VK_USE_PLATFORM_WIN32_KHR
//#define USE_AMD_ALLOCATOR
#define USE_AMD_ALLOCATOR
#include <vulkan/vulkan.h>