Merged more Vulkan code from vkneo

This commit is contained in:
Robert Beckebans 2018-10-05 21:43:55 +02:00
parent af02ccb9dc
commit f180da6f63
15 changed files with 1068 additions and 72 deletions

View file

@ -307,12 +307,16 @@ public:
levelLoadReferenced = true;
}
void ActuallyLoadImage( bool fromBackEnd );
//---------------------------------------------
// Platform specific implementations
//---------------------------------------------
#if defined( ID_VULKAN )
#if defined( USE_VULKAN )
void CreateFromSwapImage( VkImage image, VkImageView imageView, VkFormat format, const VkExtent2D& extent );
static void EmptyGarbage();
VkImage GetImage() const
{
return image;
@ -345,7 +349,7 @@ public:
// they must be a multiple of four for dxt data.
void SubImageUpload( int mipLevel, int destX, int destY, int destZ,
int width, int height, const void* data,
int pixelPitch = 0 ) const;
int pixelPitch = 0 );
// SetPixel is assumed to be a fast memory write on consoles, degenerating to a
// SubImageUpload on PCs. Used to update the page mapping images.
@ -412,6 +416,8 @@ private:
static const uint32 TEXTURE_NOT_LOADED = 0xFFFFFFFF;
#if defined( USE_VULKAN )
void CreateSampler();
bool bIsSwapChainImage;
VkFormat internalFormat;
VkImage image;

View file

@ -248,7 +248,7 @@ On exit, the idImage will have a valid OpenGL texture number that can be bound
void idImage::ActuallyLoadImage( bool fromBackEnd )
{
// if we don't have a rendering context yet, just return
if( !R_IsInitialized() )
if( !tr.IsInitialized() )
{
return;
}
@ -692,7 +692,7 @@ void idImage::GenerateImage( const byte* pic, int width, int height, textureFilt
// have filled in the parms. We must have the values set, or
// an image match from a shader before the render starts would miss
// the generated texture
if( !R_IsInitialized() )
if( !tr.IsInitialized() )
{
return;
}
@ -760,7 +760,7 @@ void idImage::GenerateCubeImage( const byte* pic[6], int size, textureFilter_t f
// have filled in the parms. We must have the values set, or
// an image match from a shader before the render starts would miss
// the generated texture
if( !R_IsInitialized() )
if( !tr.IsInitialized() )
{
return;
}
@ -812,7 +812,7 @@ void idImage::GenerateShadowArray( int width, int height, textureFilter_t filter
// have filled in the parms. We must have the values set, or
// an image match from a shader before the render starts would miss
// the generated texture
if( !R_IsInitialized() )
if( !tr.IsInitialized() )
{
return;
}

View file

@ -290,7 +290,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 ) const
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 );
@ -763,7 +763,7 @@ void idImage::AllocImage()
// have filled in the parms. We must have the values set, or
// an image match from a shader before OpenGL starts would miss
// the generated texture
if( !R_IsInitialized() )
if( !tr.IsInitialized() )
{
return;
}

View file

@ -118,17 +118,7 @@ bool GL_CheckErrors_( const char* filename, int line )
}
static bool r_initialized = false;
/*
=============================
R_IsInitialized
=============================
*/
bool R_IsInitialized()
{
return r_initialized;
}
@ -470,7 +460,7 @@ void idRenderBackend::Init()
{
common->Printf( "----- R_InitOpenGL -----\n" );
if( R_IsInitialized() )
if( tr.IsInitialized() )
{
common->FatalError( "R_InitOpenGL called while active" );
}
@ -532,14 +522,12 @@ void idRenderBackend::Init()
glConfig.maxTextureSize = 256;
}
r_initialized = true;
// recheck all the extensions (FIXME: this might be dangerous)
R_CheckPortableExtensions();
renderProgManager.Init();
r_initialized = true;
tr.SetInitialized();
// allocate the vertex array range or vertex objects
vertexCache.Init( glConfig.uniformBufferOffsetAlignment );
@ -554,7 +542,6 @@ void idRenderBackend::Init()
void idRenderBackend::Shutdown()
{
GLimp_Shutdown();
r_initialized = false;
}
/*

View file

@ -154,9 +154,14 @@ struct vulkanContext_t
uint64 stencilOperations[ STENCIL_FACE_NUM ];
VkInstance instance;
// selected physical device
VkPhysicalDevice physicalDevice;
VkPhysicalDeviceFeatures physicalDeviceFeatures;
// logical device
VkDevice device;
VkQueue graphicsQueue;
VkQueue presentQueue;
int graphicsFamilyIdx;
@ -167,7 +172,10 @@ struct vulkanContext_t
idList< const char* > deviceExtensions;
idList< const char* > validationLayers;
// selected GPU
gpuInfo_t* gpu;
// all GPUs found on the system
idList< gpuInfo_t > gpus;
VkCommandPool commandPool;

View file

@ -704,6 +704,10 @@ public:
// external functions
virtual void Init();
virtual void Shutdown();
virtual bool IsInitialized() const
{
return bInitialized;
}
virtual void ResetGuiModels();
virtual void InitOpenGL();
virtual void ShutdownOpenGL();
@ -765,6 +769,10 @@ public:
void PrintPerformanceCounters();
void SetInitialized()
{
bInitialized = true;
}
public:
// internal functions
@ -850,6 +858,9 @@ public:
idRenderBackend backend;
unsigned timerQueryId; // for GL_TIME_ELAPSED_EXT queries
private:
bool bInitialized;
};
extern idRenderSystemLocal tr;

View file

@ -1968,10 +1968,12 @@ idRenderProgManager::SetUniformValue
*/
void idRenderProgManager::SetUniformValue( const renderParm_t rp, const float* value )
{
#if !defined(USE_VULKAN)
for( int i = 0; i < 4; i++ )
{
glslUniforms[rp][i] = value[i];
}
#endif
}
/*

View file

@ -238,7 +238,8 @@ idRenderSystemLocal::idRenderSystemLocal
idRenderSystemLocal::idRenderSystemLocal() :
unitSquareTriangles( NULL ),
zeroOneCubeTriangles( NULL ),
testImageTriangles( NULL )
testImageTriangles( NULL ),
bInitialized( false )
{
Clear();
}
@ -311,7 +312,7 @@ idRenderSystemLocal::DrawStretchPic
static triIndex_t quadPicIndexes[6] = { 3, 0, 2, 2, 0, 1 };
void idRenderSystemLocal::DrawStretchPic( const idVec4& topLeft, const idVec4& topRight, const idVec4& bottomRight, const idVec4& bottomLeft, const idMaterial* material )
{
if( !R_IsInitialized() )
if( !IsInitialized() )
{
return;
}
@ -366,7 +367,7 @@ idRenderSystemLocal::DrawStretchTri
*/
void idRenderSystemLocal::DrawStretchTri( const idVec2& p1, const idVec2& p2, const idVec2& p3, const idVec2& t1, const idVec2& t2, const idVec2& t3, const idMaterial* material )
{
if( !R_IsInitialized() )
if( !IsInitialized() )
{
return;
}
@ -635,14 +636,14 @@ void idRenderSystemLocal::SwapCommandBuffers_FinishRendering(
*gpuMicroSec = 0; // until shown otherwise
}
if( !R_IsInitialized() )
if( !IsInitialized() )
{
return;
}
// After coming back from an autoswap, we won't have anything to render
if( frameData->cmdHead->next != NULL )
if( frameData && frameData->cmdHead->next != NULL )
{
// wait for our fence to hit, which means the swap has actually happened
// We must do this before clearing any resources the GPU may be using
@ -705,7 +706,7 @@ idRenderSystemLocal::SwapCommandBuffers_FinishCommandBuffers
*/
const emptyCommand_t* idRenderSystemLocal::SwapCommandBuffers_FinishCommandBuffers()
{
if( !R_IsInitialized() )
if( !IsInitialized() )
{
return NULL;
}
@ -854,7 +855,7 @@ idRenderSystemLocal::CropRenderSize
*/
void idRenderSystemLocal::CropRenderSize( int width, int height )
{
if( !R_IsInitialized() )
if( !IsInitialized() )
{
return;
}
@ -901,7 +902,7 @@ idRenderSystemLocal::UnCrop
*/
void idRenderSystemLocal::UnCrop()
{
if( !R_IsInitialized() )
if( !IsInitialized() )
{
return;
}
@ -936,7 +937,7 @@ idRenderSystemLocal::CaptureRenderToImage
*/
void idRenderSystemLocal::CaptureRenderToImage( const char* imageName, bool clearColorAfterCopy )
{
if( !R_IsInitialized() )
if( !IsInitialized() )
{
return;
}
@ -981,7 +982,7 @@ idRenderSystemLocal::CaptureRenderToFile
*/
void idRenderSystemLocal::CaptureRenderToFile( const char* fileName, bool fixAlpha )
{
if( !R_IsInitialized() )
if( !IsInitialized() )
{
return;
}

View file

@ -199,8 +199,6 @@ struct glconfig_t
struct emptyCommand_t;
bool R_IsInitialized();
const int SMALLCHAR_WIDTH = 8;
const int SMALLCHAR_HEIGHT = 16;
const int BIGCHAR_WIDTH = 16;
@ -229,6 +227,8 @@ public:
// only called before quitting
virtual void Shutdown() = 0;
virtual bool IsInitialized() const = 0;
virtual void ResetGuiModels() = 0;
virtual void InitOpenGL() = 0;

View file

@ -1816,7 +1816,7 @@ R_VidRestart_f
void R_VidRestart_f( const idCmdArgs& args )
{
// if OpenGL isn't started, do nothing
if( !R_IsInitialized() )
if( !tr.IsInitialized() )
{
return;
}
@ -2209,6 +2209,9 @@ void idRenderSystemLocal::Init()
R_InitCommands();
// allocate the frame data, which may be more if smp is enabled
R_InitFrameData();
guiModel = new( TAG_RENDER ) idGuiModel;
guiModel->Clear();
tr_guiModel = guiModel; // for DeviceContext fast path
@ -2253,6 +2256,8 @@ void idRenderSystemLocal::Init()
frontEndJobList = parallelJobManager->AllocJobList( JOBLIST_RENDERER_FRONTEND, JOBLIST_PRIORITY_MEDIUM, 2048, 0, NULL );
bInitialized = true;
// make sure the command buffers are ready to accept the first screen update
SwapCommandBuffers( NULL, NULL, NULL, NULL );
@ -2271,7 +2276,7 @@ void idRenderSystemLocal::Shutdown()
fonts.DeleteContents();
if( R_IsInitialized() )
if( IsInitialized() )
{
globalImages->PurgeAllImages();
}
@ -2303,6 +2308,8 @@ void idRenderSystemLocal::Shutdown()
Clear();
ShutdownOpenGL();
bInitialized = false;
}
/*
@ -2434,7 +2441,7 @@ idRenderSystemLocal::InitOpenGL
void idRenderSystemLocal::InitOpenGL()
{
// if OpenGL isn't started, start it now
if( !R_IsInitialized() )
if( !IsInitialized() )
{
backend.Init();
@ -2471,7 +2478,7 @@ idRenderSystemLocal::IsOpenGLRunning
*/
bool idRenderSystemLocal::IsOpenGLRunning() const
{
return R_IsInitialized();
return IsInitialized();
}
/*

View file

@ -895,7 +895,7 @@ to handle mirrors,
*/
void idRenderWorldLocal::RenderScene( const renderView_t* renderView )
{
if( !R_IsInitialized() )
if( !tr.IsInitialized() )
{
return;
}
@ -1749,7 +1749,7 @@ If this isn't called, they will all be dynamically generated
*/
void idRenderWorldLocal::GenerateAllInteractions()
{
if( !R_IsInitialized() )
if( !tr.IsInitialized() )
{
return;
}

View file

@ -3,7 +3,8 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2016 Robert Beckebans
Copyright (C) 2013-2018 Robert Beckebans
Copyright (C) 2016-2017 Dustin Land
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -31,11 +32,122 @@ If you have questions concerning this license or the applicable additional terms
/*
================================================================================================
Contains the Image implementation for OpenGL.
Contains the Image implementation for Vulkan
================================================================================================
*/
#include "../RenderCommon.h"
#include "Staging_VK.h"
int idImage::garbageIndex = 0;
#if defined( ID_USE_AMD_ALLOCATOR )
idList< VmaAllocation > idImage::m_allocationGarbage[ NUM_FRAME_DATA ];
#else
idList< vulkanAllocation_t > idImage::allocationGarbage[ NUM_FRAME_DATA ];
#endif
idList< VkImage > idImage::imageGarbage[ NUM_FRAME_DATA ];
idList< VkImageView > idImage::viewGarbage[ NUM_FRAME_DATA ];
idList< VkSampler > idImage::samplerGarbage[ NUM_FRAME_DATA ];
/*
====================
VK_GetFormatFromTextureFormat
====================
*/
static VkFormat VK_GetFormatFromTextureFormat( const textureFormat_t format )
{
switch( format )
{
case FMT_RGBA8:
return VK_FORMAT_R8G8B8A8_UNORM;
case FMT_XRGB8:
return VK_FORMAT_R8G8B8_UNORM;
case FMT_ALPHA:
return VK_FORMAT_R8_UNORM;
case FMT_L8A8:
return VK_FORMAT_R8G8_UNORM;
case FMT_LUM8:
return VK_FORMAT_R8_UNORM;
case FMT_INT8:
return VK_FORMAT_R8_UNORM;
case FMT_DXT1:
return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
case FMT_DXT5:
return VK_FORMAT_BC3_UNORM_BLOCK;
case FMT_DEPTH:
return vkcontext.depthFormat;
case FMT_X16:
return VK_FORMAT_R16_UNORM;
case FMT_Y16_X16:
return VK_FORMAT_R16G16_UNORM;
case FMT_RGB565:
return VK_FORMAT_R5G6B5_UNORM_PACK16;
default:
return VK_FORMAT_UNDEFINED;
}
}
/*
====================
VK_GetComponentMappingFromTextureFormat
====================
*/
static VkComponentMapping VK_GetComponentMappingFromTextureFormat( const textureFormat_t format, textureColor_t color )
{
VkComponentMapping componentMapping =
{
VK_COMPONENT_SWIZZLE_ZERO,
VK_COMPONENT_SWIZZLE_ZERO,
VK_COMPONENT_SWIZZLE_ZERO,
VK_COMPONENT_SWIZZLE_ZERO
};
if( color == CFM_GREEN_ALPHA )
{
componentMapping.r = VK_COMPONENT_SWIZZLE_ONE;
componentMapping.g = VK_COMPONENT_SWIZZLE_ONE;
componentMapping.b = VK_COMPONENT_SWIZZLE_ONE;
componentMapping.a = VK_COMPONENT_SWIZZLE_G;
return componentMapping;
}
switch( format )
{
case FMT_LUM8:
componentMapping.r = VK_COMPONENT_SWIZZLE_R;
componentMapping.g = VK_COMPONENT_SWIZZLE_R;
componentMapping.b = VK_COMPONENT_SWIZZLE_R;
componentMapping.a = VK_COMPONENT_SWIZZLE_ONE;
break;
case FMT_L8A8:
componentMapping.r = VK_COMPONENT_SWIZZLE_R;
componentMapping.g = VK_COMPONENT_SWIZZLE_R;
componentMapping.b = VK_COMPONENT_SWIZZLE_R;
componentMapping.a = VK_COMPONENT_SWIZZLE_G;
break;
case FMT_ALPHA:
componentMapping.r = VK_COMPONENT_SWIZZLE_ONE;
componentMapping.g = VK_COMPONENT_SWIZZLE_ONE;
componentMapping.b = VK_COMPONENT_SWIZZLE_ONE;
componentMapping.a = VK_COMPONENT_SWIZZLE_R;
break;
case FMT_INT8:
componentMapping.r = VK_COMPONENT_SWIZZLE_R;
componentMapping.g = VK_COMPONENT_SWIZZLE_R;
componentMapping.b = VK_COMPONENT_SWIZZLE_R;
componentMapping.a = VK_COMPONENT_SWIZZLE_R;
break;
default:
componentMapping.r = VK_COMPONENT_SWIZZLE_R;
componentMapping.g = VK_COMPONENT_SWIZZLE_G;
componentMapping.b = VK_COMPONENT_SWIZZLE_B;
componentMapping.a = VK_COMPONENT_SWIZZLE_A;
break;
}
return componentMapping;
}
/*
====================
@ -44,10 +156,14 @@ idImage::idImage
*/
idImage::idImage( const char* name ) : imgName( name )
{
//texnum = TEXTURE_NOT_LOADED;
//internalFormat = 0;
//dataFormat = 0;
//dataType = 0;
// Vulkan specific
bIsSwapChainImage = false;
internalFormat = VK_FORMAT_UNDEFINED;
image = VK_NULL_HANDLE;
view = VK_NULL_HANDLE;
layout = VK_IMAGE_LAYOUT_GENERAL;
sampler = VK_NULL_HANDLE;
generatorFunction = NULL;
filter = TF_DEFAULT;
repeat = TR_REPEAT;
@ -69,7 +185,10 @@ idImage::~idImage
*/
idImage::~idImage()
{
PurgeImage();
if( !bIsSwapChainImage )
{
PurgeImage();
}
}
/*
@ -82,6 +201,156 @@ 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
====================
*/
void idImage::CreateSampler()
{
VkSamplerCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
createInfo.maxAnisotropy = 1.0f;
createInfo.anisotropyEnable = VK_FALSE;
createInfo.compareEnable = ( opts.format == FMT_DEPTH );
createInfo.compareOp = ( opts.format == FMT_DEPTH ) ? VK_COMPARE_OP_LESS_OR_EQUAL : VK_COMPARE_OP_NEVER;
switch( filter )
{
case TF_DEFAULT:
case TF_LINEAR:
createInfo.minFilter = VK_FILTER_LINEAR;
createInfo.magFilter = VK_FILTER_LINEAR;
createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
break;
case TF_NEAREST:
createInfo.minFilter = VK_FILTER_NEAREST;
createInfo.magFilter = VK_FILTER_NEAREST;
createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
break;
// RB:
case TF_NEAREST_MIPMAP:
createInfo.minFilter = VK_FILTER_NEAREST;
createInfo.magFilter = VK_FILTER_NEAREST;
createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
break;
default:
idLib::FatalError( "idImage::CreateSampler: unrecognized texture filter %d", filter );
}
switch( repeat )
{
case TR_REPEAT:
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
break;
case TR_CLAMP:
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
break;
case TR_CLAMP_TO_ZERO_ALPHA:
createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
break;
case TR_CLAMP_TO_ZERO:
createInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
break;
default:
idLib::FatalError( "idImage::CreateSampler: unrecognized texture repeat mode %d", repeat );
}
ID_VK_CHECK( vkCreateSampler( vkcontext.device, &createInfo, NULL, &sampler ) );
}
/*
====================
idImage::EmptyGarbage
====================
*/
void idImage::EmptyGarbage()
{
garbageIndex = ( garbageIndex + 1 ) % NUM_FRAME_DATA;
#if defined( ID_USE_AMD_ALLOCATOR )
idList< VmaAllocation >& allocationsToFree = allocationGarbage[ garbageIndex ];
#else
idList< vulkanAllocation_t >& allocationsToFree = allocationGarbage[ garbageIndex ];
#endif
idList< VkImage >& imagesToFree = imageGarbage[ garbageIndex ];
idList< VkImageView >& viewsToFree = viewGarbage[ garbageIndex ];
idList< VkSampler >& samplersToFree = samplerGarbage[ garbageIndex ];
#if defined( ID_USE_AMD_ALLOCATOR )
const int numAllocations = allocationsToFree.Num();
for( int i = 0; i < numAllocations; ++i )
{
vmaDestroyImage( vmaAllocator, imagesToFree[ i ], allocationsToFree[ i ] );
}
#else
const int numAllocations = allocationsToFree.Num();
for( int i = 0; i < numAllocations; ++i )
{
vulkanAllocator.Free( allocationsToFree[ i ] );
}
const int numImages = imagesToFree.Num();
for( int i = 0; i < numImages; ++i )
{
vkDestroyImage( vkcontext.device, imagesToFree[ i ], NULL );
}
#endif
const int numViews = viewsToFree.Num();
for( int i = 0; i < numViews; ++i )
{
vkDestroyImageView( vkcontext.device, viewsToFree[ i ], NULL );
}
const int numSamplers = samplersToFree.Num();
for( int i = 0; i < numSamplers; ++i )
{
vkDestroySampler( vkcontext.device, samplersToFree[ i ], NULL );
}
allocationsToFree.Clear();
imagesToFree.Clear();
viewsToFree.Clear();
samplersToFree.Clear();
}
/*
==============
Bind
@ -119,9 +388,77 @@ 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 ) const
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;
}
/*
@ -166,7 +503,74 @@ This should not be done during normal game-play, if you can avoid it.
*/
void idImage::AllocImage()
{
PurgeImage();
internalFormat = VK_GetFormatFromTextureFormat( opts.format );
// Create Sampler
CreateSampler();
VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
if( opts.format == FMT_DEPTH )
{
usageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
else
{
usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
// Create Image
VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.flags = ( opts.textureType == TT_CUBIC ) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = internalFormat;
imageCreateInfo.extent.width = opts.width;
imageCreateInfo.extent.height = opts.height;
imageCreateInfo.extent.depth = 1;
imageCreateInfo.mipLevels = opts.numLevels;
imageCreateInfo.arrayLayers = ( opts.textureType == TT_CUBIC ) ? 6 : 1;
imageCreateInfo.samples = static_cast< VkSampleCountFlagBits >( opts.samples );
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = usageFlags;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
#if defined( ID_USE_AMD_ALLOCATOR )
VmaMemoryRequirements vmaReq = {};
vmaReq.usage = VMA_MEMORY_USAGE_GPU_ONLY;
ID_VK_CHECK( vmaCreateImage( vmaAllocator, &imageCreateInfo, &vmaReq, &image, &allocation, NULL ) );
#else
ID_VK_CHECK( vkCreateImage( vkcontext.device, &imageCreateInfo, NULL, &image ) );
VkMemoryRequirements memoryRequirements;
vkGetImageMemoryRequirements( vkcontext.device, image, &memoryRequirements );
allocation = vulkanAllocator.Allocate(
memoryRequirements.size,
memoryRequirements.alignment,
memoryRequirements.memoryTypeBits,
VULKAN_MEMORY_USAGE_GPU_ONLY,
VULKAN_ALLOCATION_TYPE_IMAGE_OPTIMAL );
ID_VK_CHECK( vkBindImageMemory( vkcontext.device, image, allocation.deviceMemory, allocation.offset ) );
#endif
// Create Image View
VkImageViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCreateInfo.image = image;
viewCreateInfo.viewType = ( opts.textureType == TT_CUBIC ) ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D;
viewCreateInfo.format = internalFormat;
viewCreateInfo.components = VK_GetComponentMappingFromTextureFormat( opts.format, opts.colorFormat );
viewCreateInfo.subresourceRange.aspectMask = ( opts.format == FMT_DEPTH ) ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
viewCreateInfo.subresourceRange.levelCount = opts.numLevels;
viewCreateInfo.subresourceRange.layerCount = ( opts.textureType == TT_CUBIC ) ? 6 : 1;
viewCreateInfo.subresourceRange.baseMipLevel = 0;
ID_VK_CHECK( vkCreateImageView( vkcontext.device, &viewCreateInfo, NULL, &view ) );
}
/*
@ -176,7 +580,27 @@ idImage::PurgeImage
*/
void idImage::PurgeImage()
{
if( sampler != VK_NULL_HANDLE )
{
samplerGarbage[ garbageIndex ].Append( sampler );
sampler = VK_NULL_HANDLE;
}
if( image != VK_NULL_HANDLE )
{
allocationGarbage[ garbageIndex ].Append( allocation );
viewGarbage[ garbageIndex ].Append( view );
imageGarbage[ garbageIndex ].Append( image );
#if defined( ID_USE_AMD_ALLOCATOR )
allocation = NULL;
#else
allocation = vulkanAllocation_t();
#endif
view = VK_NULL_HANDLE;
image = VK_NULL_HANDLE;
}
}
/*

View file

@ -33,6 +33,7 @@ If you have questions concerning this license or the applicable additional terms
#include "../RenderCommon.h"
#include "../RenderBackend.h"
#include "Staging_VK.h"
#include "../../framework/Common_local.h"
idCVar r_drawFlickerBox( "r_drawFlickerBox", "0", CVAR_RENDERER | CVAR_BOOL, "visual test for dropping frames" );
@ -152,23 +153,23 @@ VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback( VkDebugReportFlagsEXT msgFlags, Vk
{
if( msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT )
{
idLib::Printf( "Vulkan ERROR: [ %s ] Code %d : '%s'\n", layerPrefix, msgCode, msg );
idLib::Printf( "[Vulkan] ERROR: [ %s ] Code %d : '%s'\n", layerPrefix, msgCode, msg );
}
else if( msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT )
{
idLib::Printf( "Vulkan WARNING: [ %s ] Code %d : '%s'\n", layerPrefix, msgCode, msg );
idLib::Printf( "[Vulkan] WARNING: [ %s ] Code %d : '%s'\n", layerPrefix, msgCode, msg );
}
else if( msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT )
{
idLib::Printf( "Vulkan PERFORMANCE WARNING: [ %s ] Code %d : '%s'\n", layerPrefix, msgCode, msg );
idLib::Printf( "[Vulkan] PERFORMANCE WARNING: [ %s ] Code %d : '%s'\n", layerPrefix, msgCode, msg );
}
else if( msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT )
{
idLib::Printf( "Vulkan INFO: [ %s ] Code %d : '%s'\n", layerPrefix, msgCode, msg );
idLib::Printf( "[Vulkan] INFO: [ %s ] Code %d : '%s'\n", layerPrefix, msgCode, msg );
}
else if( msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT )
{
idLib::Printf( "Vulkan DEBUG: [ %s ] Code %d : '%s'\n", layerPrefix, msgCode, msg );
idLib::Printf( "[Vulkan] DEBUG: [ %s ] Code %d : '%s'\n", layerPrefix, msgCode, msg );
}
/*
@ -375,6 +376,7 @@ static void EnumeratePhysicalDevices()
gpuInfo_t& gpu = vkcontext.gpus[ i ];
gpu.device = devices[ i ];
// get Queue family properties
{
uint32 numQueues = 0;
vkGetPhysicalDeviceQueueFamilyProperties( gpu.device, &numQueues, NULL );
@ -385,6 +387,7 @@ static void EnumeratePhysicalDevices()
ID_VK_VALIDATE( numQueues > 0, "vkGetPhysicalDeviceQueueFamilyProperties returned zero queues." );
}
// grab available Vulkan extensions
{
uint32 numExtension;
ID_VK_CHECK( vkEnumerateDeviceExtensionProperties( gpu.device, NULL, &numExtension, NULL ) );
@ -402,6 +405,7 @@ static void EnumeratePhysicalDevices()
#endif
}
// grab surface specific information
ID_VK_CHECK( vkGetPhysicalDeviceSurfaceCapabilitiesKHR( gpu.device, vkcontext.surface, &gpu.surfaceCaps ) );
{
@ -426,9 +430,465 @@ static void EnumeratePhysicalDevices()
vkGetPhysicalDeviceMemoryProperties( gpu.device, &gpu.memProps );
vkGetPhysicalDeviceProperties( gpu.device, &gpu.props );
switch( gpu.props.vendorID )
{
case 0x8086:
idLib::Printf( "Found device[%i] Vendor: Intel\n", i );
break;
case 0x10DE:
idLib::Printf( "Found device[%i] Vendor: NVIDIA\n", i );
break;
case 0x1002:
idLib::Printf( "Found device[%i] Vendor: AMD\n", i );
break;
default:
idLib::Printf( "Found device[%i] Vendor: Unknown (0x%x)\n", i, gpu.props.vendorID );
}
}
}
/*
=============
CheckPhysicalDeviceExtensionSupport
=============
*/
static bool CheckPhysicalDeviceExtensionSupport( gpuInfo_t& gpu, idList< const char* >& requiredExt )
{
int required = requiredExt.Num();
int available = 0;
for( int i = 0; i < requiredExt.Num(); ++i )
{
for( int j = 0; j < gpu.extensionProps.Num(); ++j )
{
if( idStr::Icmp( requiredExt[ i ], gpu.extensionProps[ j ].extensionName ) == 0 )
{
available++;
break;
}
}
}
return available == required;
}
/*
=============
SelectPhysicalDevice
=============
*/
static void SelectPhysicalDevice()
{
//idLib::Printf( "Selecting physical device:\n" );
for( int i = 0; i < vkcontext.gpus.Num(); ++i )
{
gpuInfo_t& gpu = vkcontext.gpus[ i ];
int graphicsIdx = -1;
int presentIdx = -1;
if( !CheckPhysicalDeviceExtensionSupport( gpu, vkcontext.deviceExtensions ) )
{
continue;
}
if( gpu.surfaceFormats.Num() == 0 )
{
continue;
}
if( gpu.presentModes.Num() == 0 )
{
continue;
}
// Find graphics queue family
for( int j = 0; j < gpu.queueFamilyProps.Num(); ++j )
{
VkQueueFamilyProperties& props = gpu.queueFamilyProps[ j ];
if( props.queueCount == 0 )
{
continue;
}
if( props.queueFlags & VK_QUEUE_GRAPHICS_BIT )
{
graphicsIdx = j;
break;
}
}
// Find present queue family
for( int j = 0; j < gpu.queueFamilyProps.Num(); ++j )
{
VkQueueFamilyProperties& props = gpu.queueFamilyProps[ j ];
if( props.queueCount == 0 )
{
continue;
}
VkBool32 supportsPresent = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR( gpu.device, j, vkcontext.surface, &supportsPresent );
if( supportsPresent )
{
presentIdx = j;
break;
}
}
// Did we find a device supporting both graphics and present.
if( graphicsIdx >= 0 && presentIdx >= 0 )
{
vkcontext.graphicsFamilyIdx = graphicsIdx;
vkcontext.presentFamilyIdx = presentIdx;
vkcontext.physicalDevice = gpu.device;
vkcontext.gpu = &gpu;
vkGetPhysicalDeviceFeatures( vkcontext.physicalDevice, &vkcontext.physicalDeviceFeatures );
idLib::Printf( "Selected device '%s'\n", gpu.props.deviceName );
// RB: found vendor IDs in nvQuake
switch( gpu.props.vendorID )
{
case 0x8086:
idLib::Printf( "Vendor: Intel\n", i );
glConfig.vendor = VENDOR_INTEL;
break;
case 0x10DE:
idLib::Printf( "Vendor: NVIDIA\n", i );
glConfig.vendor = VENDOR_NVIDIA;
break;
case 0x1002:
idLib::Printf( "Vendor: AMD\n", i );
glConfig.vendor = VENDOR_AMD;
break;
default:
idLib::Printf( "Vendor: Unknown (0x%x)\n", i, gpu.props.vendorID );
}
return;
}
}
// If we can't render or present, just bail.
idLib::FatalError( "Could not find a physical device which fits our desired profile" );
}
/*
=============
CreateLogicalDeviceAndQueues
=============
*/
static void CreateLogicalDeviceAndQueues()
{
idList< int > uniqueIdx;
uniqueIdx.AddUnique( vkcontext.graphicsFamilyIdx );
uniqueIdx.AddUnique( vkcontext.presentFamilyIdx );
idList< VkDeviceQueueCreateInfo > devqInfo;
const float priority = 1.0f;
for( int i = 0; i < uniqueIdx.Num(); ++i )
{
VkDeviceQueueCreateInfo qinfo = {};
qinfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
qinfo.queueFamilyIndex = uniqueIdx[ i ];
qinfo.queueCount = 1;
qinfo.pQueuePriorities = &priority;
devqInfo.Append( qinfo );
}
VkPhysicalDeviceFeatures deviceFeatures = {};
deviceFeatures.textureCompressionBC = VK_TRUE;
deviceFeatures.imageCubeArray = VK_TRUE;
deviceFeatures.depthClamp = VK_TRUE;
deviceFeatures.depthBiasClamp = VK_TRUE;
deviceFeatures.depthBounds = VK_TRUE;
deviceFeatures.fillModeNonSolid = VK_TRUE;
deviceFeatures.samplerAnisotropy = vkcontext.physicalDeviceFeatures.samplerAnisotropy; // RB
VkDeviceCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
info.queueCreateInfoCount = devqInfo.Num();
info.pQueueCreateInfos = devqInfo.Ptr();
info.pEnabledFeatures = &deviceFeatures;
info.enabledExtensionCount = vkcontext.deviceExtensions.Num();
info.ppEnabledExtensionNames = vkcontext.deviceExtensions.Ptr();
if( r_vkEnableValidationLayers.GetBool() )
{
info.enabledLayerCount = vkcontext.validationLayers.Num();
info.ppEnabledLayerNames = vkcontext.validationLayers.Ptr();
}
else
{
info.enabledLayerCount = 0;
}
ID_VK_CHECK( vkCreateDevice( vkcontext.physicalDevice, &info, NULL, &vkcontext.device ) );
vkGetDeviceQueue( vkcontext.device, vkcontext.graphicsFamilyIdx, 0, &vkcontext.graphicsQueue );
vkGetDeviceQueue( vkcontext.device, vkcontext.presentFamilyIdx, 0, &vkcontext.presentQueue );
}
/*
=============
ChooseSurfaceFormat
=============
*/
static VkSurfaceFormatKHR ChooseSurfaceFormat( idList< VkSurfaceFormatKHR >& formats )
{
VkSurfaceFormatKHR result;
if( formats.Num() == 1 && formats[ 0 ].format == VK_FORMAT_UNDEFINED )
{
result.format = VK_FORMAT_B8G8R8A8_UNORM;
result.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
return result;
}
for( int i = 0; i < formats.Num(); ++i )
{
VkSurfaceFormatKHR& fmt = formats[ i ];
if( fmt.format == VK_FORMAT_B8G8R8A8_UNORM && fmt.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR )
{
return fmt;
}
}
return formats[ 0 ];
}
/*
=============
ChoosePresentMode
=============
*/
static VkPresentModeKHR ChoosePresentMode( idList< VkPresentModeKHR >& modes )
{
VkPresentModeKHR desiredMode = VK_PRESENT_MODE_FIFO_KHR;
if( r_swapInterval.GetInteger() < 1 )
{
for( int i = 0; i < modes.Num(); i++ )
{
if( modes[i] == VK_PRESENT_MODE_MAILBOX_KHR )
{
return VK_PRESENT_MODE_MAILBOX_KHR;
}
if( ( modes[i] != VK_PRESENT_MODE_MAILBOX_KHR ) && ( modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR ) )
{
return VK_PRESENT_MODE_IMMEDIATE_KHR;
}
}
}
for( int i = 0; i < modes.Num(); ++i )
{
if( modes[i] == desiredMode )
{
return desiredMode;
}
}
return VK_PRESENT_MODE_FIFO_KHR;
}
/*
=============
ChooseSurfaceExtent
=============
*/
static VkExtent2D ChooseSurfaceExtent( VkSurfaceCapabilitiesKHR& caps )
{
VkExtent2D extent;
if( caps.currentExtent.width == -1 )
{
extent.width = glConfig.nativeScreenWidth;
extent.height = glConfig.nativeScreenHeight;
}
else
{
extent = caps.currentExtent;
}
return extent;
}
/*
=============
CreateSwapChain
=============
*/
static void CreateSwapChain()
{
gpuInfo_t& gpu = *vkcontext.gpu;
VkSurfaceFormatKHR surfaceFormat = ChooseSurfaceFormat( gpu.surfaceFormats );
VkPresentModeKHR presentMode = ChoosePresentMode( gpu.presentModes );
VkExtent2D extent = ChooseSurfaceExtent( gpu.surfaceCaps );
VkSwapchainCreateInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
info.surface = vkcontext.surface;
info.minImageCount = NUM_FRAME_DATA;
info.imageFormat = surfaceFormat.format;
info.imageColorSpace = surfaceFormat.colorSpace;
info.imageExtent = extent;
info.imageArrayLayers = 1;
info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
if( vkcontext.graphicsFamilyIdx != vkcontext.presentFamilyIdx )
{
uint32 indices[] = { ( uint32 )vkcontext.graphicsFamilyIdx, ( uint32 )vkcontext.presentFamilyIdx };
info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
info.queueFamilyIndexCount = 2;
info.pQueueFamilyIndices = indices;
}
else
{
info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
}
info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
info.presentMode = presentMode;
info.clipped = VK_TRUE;
ID_VK_CHECK( vkCreateSwapchainKHR( vkcontext.device, &info, NULL, &vkcontext.swapchain ) );
vkcontext.swapchainFormat = surfaceFormat.format;
vkcontext.presentMode = presentMode;
vkcontext.swapchainExtent = extent;
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_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.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewCreateInfo.format = vkcontext.swapchainFormat;
imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R;
imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G;
imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B;
imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A;
imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
imageViewCreateInfo.subresourceRange.levelCount = 1;
imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
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;
}
}
/*
=============
CreateCommandPool
=============
*/
static void CreateCommandPool()
{
VkCommandPoolCreateInfo commandPoolCreateInfo = {};
commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
commandPoolCreateInfo.queueFamilyIndex = vkcontext.graphicsFamilyIdx;
ID_VK_CHECK( vkCreateCommandPool( vkcontext.device, &commandPoolCreateInfo, NULL, &vkcontext.commandPool ) );
}
/*
=============
CreateCommandBuffer
=============
*/
static void CreateCommandBuffer()
{
VkCommandBufferAllocateInfo commandBufferAllocateInfo = {};
commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandBufferAllocateInfo.commandPool = vkcontext.commandPool;
commandBufferAllocateInfo.commandBufferCount = NUM_FRAME_DATA;
ID_VK_CHECK( vkAllocateCommandBuffers( vkcontext.device, &commandBufferAllocateInfo, vkcontext.commandBuffer.Ptr() ) );
VkFenceCreateInfo fenceCreateInfo = {};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
for( int i = 0; i < NUM_FRAME_DATA; ++i )
{
ID_VK_CHECK( vkCreateFence( vkcontext.device, &fenceCreateInfo, NULL, &vkcontext.commandBufferFences[ i ] ) );
}
}
/*
=============
CreateSemaphores
=============
*/
static void CreateSemaphores()
{
VkSemaphoreCreateInfo semaphoreCreateInfo = {};
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
for( int i = 0; i < NUM_FRAME_DATA; ++i )
{
ID_VK_CHECK( vkCreateSemaphore( vkcontext.device, &semaphoreCreateInfo, NULL, &vkcontext.acquireSemaphores[ i ] ) );
ID_VK_CHECK( vkCreateSemaphore( vkcontext.device, &semaphoreCreateInfo, NULL, &vkcontext.renderCompleteSemaphores[ i ] ) );
}
}
/*
=============
DestroySwapChain
=============
*/
static void DestroySwapChain()
{
for( uint32 i = 0; i < NUM_FRAME_DATA; ++i )
{
vkDestroyImageView( vkcontext.device, vkcontext.swapchainImages[ i ]->GetView(), NULL );
delete vkcontext.swapchainImages[ i ];
}
vkcontext.swapchainImages.Zero();
vkDestroySwapchainKHR( vkcontext.device, vkcontext.swapchain, NULL );
}
/*
=============
ClearContext
@ -498,17 +958,6 @@ idRenderBackend::~idRenderBackend()
}
/*
=============================
R_IsInitialized
=============================
*/
static bool r_initialized = false;
bool R_IsInitialized()
{
return r_initialized;
}
/*
=============
idRenderBackend::Init
@ -516,7 +965,7 @@ idRenderBackend::Init
*/
void idRenderBackend::Init()
{
if( R_IsInitialized() )
if( tr.IsInitialized() )
{
idLib::FatalError( "R_InitVulkan called while active" );
}
@ -542,6 +991,64 @@ void idRenderBackend::Init()
// grab detailed information of available GPUs
EnumeratePhysicalDevices();
// find queue family/families supporting graphics and present.
SelectPhysicalDevice();
// create logical device and queues
CreateLogicalDeviceAndQueues();
// create semaphores for image acquisition and rendering completion
CreateSemaphores();
// create Command Pool
CreateCommandPool();
// create Command Buffer
CreateCommandBuffer();
// setup the allocator
#if defined( USE_AMD_ALLOCATOR )
extern idCVar r_vkHostVisibleMemoryMB;
extern idCVar r_vkDeviceLocalMemoryMB;
VmaAllocatorCreateInfo createInfo = {};
createInfo.physicalDevice = vkcontext.physicalDevice;
createInfo.device = vkcontext.device;
createInfo.preferredSmallHeapBlockSize = r_vkHostVisibleMemoryMB.GetInteger() * 1024 * 1024;
createInfo.preferredLargeHeapBlockSize = r_vkDeviceLocalMemoryMB.GetInteger() * 1024 * 1024;
vmaCreateAllocator( &createInfo, &vmaAllocator );
#else
vulkanAllocator.Init();
#endif
// start the Staging Manager
stagingManager.Init();
// create Swap Chain
CreateSwapChain();
#if 0
// create Render Targets
CreateRenderTargets();
// create Render Pass
CreateRenderPass();
// create Pipeline Cache
CreatePipelineCache();
// create Frame Buffers
CreateFrameBuffers();
// init RenderProg Manager
renderProgManager.Init();
#endif
// init Vertex Cache
vertexCache.Init( vkcontext.gpu->props.limits.minUniformBufferOffsetAlignment );
}
/*
@ -551,18 +1058,60 @@ idRenderBackend::Shutdown
*/
void idRenderBackend::Shutdown()
{
for( int i = 0; i < NUM_FRAME_DATA; ++i )
{
idImage::EmptyGarbage();
}
// destroy Swap Chain
DestroySwapChain();
// stop the Staging Manager
stagingManager.Shutdown();
// 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
vkDestroyCommandPool( vkcontext.device, vkcontext.commandPool, NULL );
// 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
if( r_vkEnableValidationLayers.GetBool() )
{
DestroyDebugReportCallback();
}
// dump all our memory
#if defined( USE_AMD_ALLOCATOR )
vmaDestroyAllocator( vmaAllocator );
#else
vulkanAllocator.Shutdown();
#endif
// destroy Logical Device
vkDestroyDevice( vkcontext.device, NULL );
// destroy Surface
vkDestroySurfaceKHR( vkcontext.instance, vkcontext.surface, NULL );
// destroy the Instance
vkDestroyInstance( vkcontext.instance, NULL );
ClearContext();
// destroy main window
GLimp_Shutdown();
r_initialized = false;
}

View file

@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2016-2017 Dustin Land
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").

View file

@ -97,7 +97,7 @@ static void WIN_EnableAltTab()
void WIN_Sizing( WORD side, RECT* rect )
{
if( !R_IsInitialized() || renderSystem->GetWidth() <= 0 || renderSystem->GetHeight() <= 0 )
if( !renderSystem->IsInitialized() || renderSystem->GetWidth() <= 0 || renderSystem->GetHeight() <= 0 )
{
return;
}
@ -176,7 +176,7 @@ LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
switch( uMsg )
{
case WM_WINDOWPOSCHANGED:
if( R_IsInitialized() )
if( renderSystem->IsInitialized() )
{
RECT rect;
if( ::GetClientRect( win32.hWnd, &rect ) )