mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-17 08:00:49 +00:00
1617 lines
48 KiB
C++
1617 lines
48 KiB
C++
/*
|
||
===========================================================================
|
||
|
||
Doom 3 BFG Edition GPL Source Code
|
||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||
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").
|
||
|
||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation, either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||
|
||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||
|
||
===========================================================================
|
||
*/
|
||
|
||
#pragma hdrstop
|
||
#include "precompiled.h"
|
||
|
||
#include "../RenderCommon.h"
|
||
#include "../RenderProgs.h"
|
||
|
||
|
||
void RpPrintState( uint64 stateBits );
|
||
|
||
struct vertexLayout_t
|
||
{
|
||
VkPipelineVertexInputStateCreateInfo inputState;
|
||
idList< VkVertexInputBindingDescription > bindingDesc;
|
||
idList< VkVertexInputAttributeDescription > attributeDesc;
|
||
};
|
||
|
||
idUniformBuffer emptyUBO;
|
||
|
||
static vertexLayout_t vertexLayouts[ NUM_VERTEX_LAYOUTS ];
|
||
|
||
static const char* renderProgBindingStrings[ BINDING_TYPE_MAX ] =
|
||
{
|
||
"ubo",
|
||
"sampler"
|
||
};
|
||
|
||
/*
|
||
=============
|
||
CreateVertexDescriptions
|
||
=============
|
||
*/
|
||
void CreateVertexDescriptions()
|
||
{
|
||
VkPipelineVertexInputStateCreateInfo createInfo = {};
|
||
createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||
createInfo.pNext = NULL;
|
||
createInfo.flags = 0;
|
||
|
||
VkVertexInputBindingDescription binding = {};
|
||
VkVertexInputAttributeDescription attribute = {};
|
||
|
||
{
|
||
vertexLayout_t& layout = vertexLayouts[ LAYOUT_DRAW_VERT ];
|
||
layout.inputState = createInfo;
|
||
|
||
uint32 locationNo = 0;
|
||
uint32 offset = 0;
|
||
|
||
binding.stride = sizeof( idDrawVert );
|
||
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||
layout.bindingDesc.Append( binding );
|
||
|
||
// Position
|
||
attribute.format = VK_FORMAT_R32G32B32_SFLOAT;
|
||
attribute.location = locationNo++;
|
||
attribute.offset = offset;
|
||
layout.attributeDesc.Append( attribute );
|
||
offset += sizeof( idDrawVert::xyz );
|
||
|
||
// TexCoord
|
||
attribute.format = VK_FORMAT_R16G16_SFLOAT;
|
||
attribute.location = locationNo++;
|
||
attribute.offset = offset;
|
||
layout.attributeDesc.Append( attribute );
|
||
offset += sizeof( idDrawVert::st );
|
||
|
||
// Normal
|
||
attribute.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||
attribute.location = locationNo++;
|
||
attribute.offset = offset;
|
||
layout.attributeDesc.Append( attribute );
|
||
offset += sizeof( idDrawVert::normal );
|
||
|
||
// Tangent
|
||
attribute.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||
attribute.location = locationNo++;
|
||
attribute.offset = offset;
|
||
layout.attributeDesc.Append( attribute );
|
||
offset += sizeof( idDrawVert::tangent );
|
||
|
||
// Color1
|
||
attribute.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||
attribute.location = locationNo++;
|
||
attribute.offset = offset;
|
||
layout.attributeDesc.Append( attribute );
|
||
offset += sizeof( idDrawVert::color );
|
||
|
||
// Color2
|
||
attribute.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||
attribute.location = locationNo++;
|
||
attribute.offset = offset;
|
||
layout.attributeDesc.Append( attribute );
|
||
}
|
||
|
||
{
|
||
vertexLayout_t& layout = vertexLayouts[ LAYOUT_DRAW_SHADOW_VERT_SKINNED ];
|
||
layout.inputState = createInfo;
|
||
|
||
uint32 locationNo = 0;
|
||
uint32 offset = 0;
|
||
|
||
binding.stride = sizeof( idShadowVertSkinned );
|
||
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||
layout.bindingDesc.Append( binding );
|
||
|
||
// Position
|
||
attribute.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||
attribute.location = locationNo++;
|
||
attribute.offset = offset;
|
||
layout.attributeDesc.Append( attribute );
|
||
offset += sizeof( idShadowVertSkinned::xyzw );
|
||
|
||
// Color1
|
||
attribute.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||
attribute.location = locationNo++;
|
||
attribute.offset = offset;
|
||
layout.attributeDesc.Append( attribute );
|
||
offset += sizeof( idShadowVertSkinned::color );
|
||
|
||
// Color2
|
||
attribute.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||
attribute.location = locationNo++;
|
||
attribute.offset = offset;
|
||
layout.attributeDesc.Append( attribute );
|
||
}
|
||
|
||
{
|
||
vertexLayout_t& layout = vertexLayouts[ LAYOUT_DRAW_SHADOW_VERT ];
|
||
layout.inputState = createInfo;
|
||
|
||
binding.stride = sizeof( idShadowVert );
|
||
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||
layout.bindingDesc.Append( binding );
|
||
|
||
// Position
|
||
attribute.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||
attribute.location = 0;
|
||
attribute.offset = 0;
|
||
layout.attributeDesc.Append( attribute );
|
||
}
|
||
}
|
||
|
||
/*
|
||
========================
|
||
CreateDescriptorPools
|
||
========================
|
||
*/
|
||
void CreateDescriptorPools( VkDescriptorPool( &pools )[ NUM_FRAME_DATA ] )
|
||
{
|
||
const int numPools = 2;
|
||
VkDescriptorPoolSize poolSizes[ numPools ];
|
||
poolSizes[ 0 ].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||
poolSizes[ 0 ].descriptorCount = MAX_DESC_UNIFORM_BUFFERS;
|
||
|
||
poolSizes[ 1 ].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||
poolSizes[ 1 ].descriptorCount = MAX_DESC_IMAGE_SAMPLERS;
|
||
|
||
VkDescriptorPoolCreateInfo poolCreateInfo = {};
|
||
poolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||
poolCreateInfo.pNext = NULL;
|
||
poolCreateInfo.maxSets = MAX_DESC_SETS;
|
||
poolCreateInfo.poolSizeCount = numPools;
|
||
poolCreateInfo.pPoolSizes = poolSizes;
|
||
|
||
for( int i = 0; i < NUM_FRAME_DATA; ++i )
|
||
{
|
||
ID_VK_CHECK( vkCreateDescriptorPool( vkcontext.device, &poolCreateInfo, NULL, &pools[ i ] ) );
|
||
}
|
||
}
|
||
|
||
/*
|
||
========================
|
||
GetDescriptorType
|
||
========================
|
||
*/
|
||
static VkDescriptorType GetDescriptorType( rpBinding_t type )
|
||
{
|
||
switch( type )
|
||
{
|
||
case BINDING_TYPE_UNIFORM_BUFFER:
|
||
return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||
|
||
case BINDING_TYPE_SAMPLER:
|
||
return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||
|
||
default:
|
||
idLib::Error( "Unknown rpBinding_t %d", static_cast< int >( type ) );
|
||
return VK_DESCRIPTOR_TYPE_MAX_ENUM;
|
||
}
|
||
}
|
||
|
||
/*
|
||
========================
|
||
CreateDescriptorSetLayout
|
||
========================
|
||
*/
|
||
void idRenderProgManager::CreateDescriptorSetLayout( const shader_t& vertexShader, const shader_t& fragmentShader, renderProg_t& renderProg )
|
||
{
|
||
// Descriptor Set Layout
|
||
{
|
||
idList< VkDescriptorSetLayoutBinding > layoutBindings;
|
||
VkDescriptorSetLayoutBinding binding = {};
|
||
binding.descriptorCount = 1;
|
||
|
||
uint32 bindingId = 0;
|
||
|
||
binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||
for( int i = 0; i < vertexShader.bindings.Num(); ++i )
|
||
{
|
||
binding.binding = bindingId++;
|
||
binding.descriptorType = GetDescriptorType( vertexShader.bindings[ i ] );
|
||
renderProg.bindings.Append( vertexShader.bindings[ i ] );
|
||
|
||
layoutBindings.Append( binding );
|
||
}
|
||
|
||
binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||
for( int i = 0; i < fragmentShader.bindings.Num(); ++i )
|
||
{
|
||
binding.binding = bindingId++;
|
||
binding.descriptorType = GetDescriptorType( fragmentShader.bindings[ i ] );
|
||
renderProg.bindings.Append( fragmentShader.bindings[ i ] );
|
||
|
||
layoutBindings.Append( binding );
|
||
}
|
||
|
||
VkDescriptorSetLayoutCreateInfo createInfo = {};
|
||
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||
createInfo.bindingCount = layoutBindings.Num();
|
||
createInfo.pBindings = layoutBindings.Ptr();
|
||
|
||
vkCreateDescriptorSetLayout( vkcontext.device, &createInfo, NULL, &renderProg.descriptorSetLayout );
|
||
}
|
||
|
||
// Pipeline Layout
|
||
{
|
||
VkPipelineLayoutCreateInfo createInfo = {};
|
||
createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||
createInfo.setLayoutCount = 1;
|
||
createInfo.pSetLayouts = &renderProg.descriptorSetLayout;
|
||
|
||
vkCreatePipelineLayout( vkcontext.device, &createInfo, NULL, &renderProg.pipelineLayout );
|
||
}
|
||
}
|
||
|
||
/*
|
||
========================
|
||
idRenderProgManager::StartFrame
|
||
========================
|
||
*/
|
||
void idRenderProgManager::StartFrame()
|
||
{
|
||
counter++;
|
||
currentData = counter % NUM_FRAME_DATA;
|
||
currentDescSet = 0;
|
||
currentParmBufferOffset = 0;
|
||
|
||
vkResetDescriptorPool( vkcontext.device, descriptorPools[ currentData ], 0 );
|
||
}
|
||
|
||
/*
|
||
================================================================================================
|
||
idRenderProgManager::BindProgram
|
||
================================================================================================
|
||
*/
|
||
void idRenderProgManager::BindProgram( int index )
|
||
{
|
||
if( current == index )
|
||
{
|
||
return;
|
||
}
|
||
|
||
current = index;
|
||
|
||
RENDERLOG_PRINTF( "Binding SPIR-V Program %s\n", renderProgs[ index ].name.c_str() );
|
||
}
|
||
|
||
/*
|
||
================================================================================================
|
||
idRenderProgManager::Unbind
|
||
================================================================================================
|
||
*/
|
||
void idRenderProgManager::Unbind()
|
||
{
|
||
current = -1;
|
||
}
|
||
|
||
/*
|
||
================================================================================================
|
||
idRenderProgManager::LoadShader
|
||
================================================================================================
|
||
*/
|
||
void idRenderProgManager::LoadShader( int index, rpStage_t stage )
|
||
{
|
||
if( shaders[ index ].module != VK_NULL_HANDLE )
|
||
{
|
||
return; // Already loaded
|
||
}
|
||
|
||
LoadShader( shaders[index] );
|
||
}
|
||
|
||
|
||
/*
|
||
================================================================================================
|
||
CompileGLSLtoSPIRV
|
||
================================================================================================
|
||
*/
|
||
|
||
|
||
#if defined(SPIRV_SHADERC)
|
||
|
||
#include <shaderc/shaderc.hpp>
|
||
|
||
static int CompileGLSLtoSPIRV( const char* filename, const idStr& dataGLSL, const rpStage_t stage, uint32** spirvBuffer )
|
||
{
|
||
shaderc::Compiler compiler;
|
||
shaderc::CompileOptions options;
|
||
|
||
// Like -DMY_DEFINE=1
|
||
//options.AddMacroDefinition("MY_DEFINE", "1");
|
||
|
||
//if (optimize)
|
||
{
|
||
options.SetOptimizationLevel( shaderc_optimization_level_size );
|
||
}
|
||
|
||
shaderc_shader_kind shaderKind;
|
||
if( stage == SHADER_STAGE_VERTEX )
|
||
{
|
||
shaderKind = shaderc_glsl_vertex_shader;
|
||
}
|
||
else if( stage == SHADER_STAGE_COMPUTE )
|
||
{
|
||
shaderKind = shaderc_glsl_compute_shader;
|
||
}
|
||
else
|
||
{
|
||
shaderKind = shaderc_glsl_fragment_shader;
|
||
}
|
||
|
||
std::string source = dataGLSL.c_str();
|
||
|
||
shaderc::SpvCompilationResult module = compiler.CompileGlslToSpv( source, shaderKind, filename, options );
|
||
|
||
if( module.GetCompilationStatus() != shaderc_compilation_status_success )
|
||
{
|
||
idLib::Printf( "Comping GLSL to SPIR-V using shaderc failed for: %s\n", filename );
|
||
idLib::Printf( "%s\n", module.GetErrorMessage().c_str() );
|
||
return 0;
|
||
}
|
||
|
||
std::vector<uint32_t> spirV = { module.cbegin(), module.cend() };
|
||
|
||
// copy to spirvBuffer
|
||
int32 spirvLen = spirV.size() * sizeof( uint32_t );
|
||
|
||
void* buffer = Mem_Alloc( spirvLen, TAG_RENDERPROG );
|
||
memcpy( buffer, spirV.data(), spirvLen );
|
||
|
||
*spirvBuffer = ( uint32_t* ) buffer;
|
||
return spirvLen;
|
||
|
||
|
||
}
|
||
#else
|
||
|
||
#include <glslang/Public/ShaderLang.h>
|
||
#include <glslang/Include/ResourceLimits.h>
|
||
#include <SPIRV/GlslangToSpv.h>
|
||
|
||
//#include <glslang/StandAlone/DirStackFileIncluder.h>
|
||
|
||
namespace glslang
|
||
{
|
||
|
||
// These are the default resources for TBuiltInResources, used for both
|
||
// - parsing this string for the case where the user didn't supply one,
|
||
// - dumping out a template for user construction of a config file.
|
||
#if 0
|
||
// RB: if you want to use this then you need to compile GLSLANG with ENABLE_GLSLANG_BINARIES ON
|
||
extern const TBuiltInResource DefaultTBuiltInResource;
|
||
#else
|
||
|
||
// RB: see RBDOOM-3-BFG\neo\extern\glslang\StandAlone\ResourceLimits.cpp
|
||
const TBuiltInResource DefaultTBuiltInResource =
|
||
{
|
||
/* .MaxLights = */ 32,
|
||
/* .MaxClipPlanes = */ 6,
|
||
/* .MaxTextureUnits = */ 32,
|
||
/* .MaxTextureCoords = */ 32,
|
||
/* .MaxVertexAttribs = */ 64,
|
||
/* .MaxVertexUniformComponents = */ 4096,
|
||
/* .MaxVaryingFloats = */ 64,
|
||
/* .MaxVertexTextureImageUnits = */ 32,
|
||
/* .MaxCombinedTextureImageUnits = */ 80,
|
||
/* .MaxTextureImageUnits = */ 32,
|
||
/* .MaxFragmentUniformComponents = */ 4096,
|
||
/* .MaxDrawBuffers = */ 32,
|
||
/* .MaxVertexUniformVectors = */ 128,
|
||
/* .MaxVaryingVectors = */ 8,
|
||
/* .MaxFragmentUniformVectors = */ 16,
|
||
/* .MaxVertexOutputVectors = */ 16,
|
||
/* .MaxFragmentInputVectors = */ 15,
|
||
/* .MinProgramTexelOffset = */ -8,
|
||
/* .MaxProgramTexelOffset = */ 7,
|
||
/* .MaxClipDistances = */ 8,
|
||
/* .MaxComputeWorkGroupCountX = */ 65535,
|
||
/* .MaxComputeWorkGroupCountY = */ 65535,
|
||
/* .MaxComputeWorkGroupCountZ = */ 65535,
|
||
/* .MaxComputeWorkGroupSizeX = */ 1024,
|
||
/* .MaxComputeWorkGroupSizeY = */ 1024,
|
||
/* .MaxComputeWorkGroupSizeZ = */ 64,
|
||
/* .MaxComputeUniformComponents = */ 1024,
|
||
/* .MaxComputeTextureImageUnits = */ 16,
|
||
/* .MaxComputeImageUniforms = */ 8,
|
||
/* .MaxComputeAtomicCounters = */ 8,
|
||
/* .MaxComputeAtomicCounterBuffers = */ 1,
|
||
/* .MaxVaryingComponents = */ 60,
|
||
/* .MaxVertexOutputComponents = */ 64,
|
||
/* .MaxGeometryInputComponents = */ 64,
|
||
/* .MaxGeometryOutputComponents = */ 128,
|
||
/* .MaxFragmentInputComponents = */ 128,
|
||
/* .MaxImageUnits = */ 8,
|
||
/* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8,
|
||
/* .MaxCombinedShaderOutputResources = */ 8,
|
||
/* .MaxImageSamples = */ 0,
|
||
/* .MaxVertexImageUniforms = */ 0,
|
||
/* .MaxTessControlImageUniforms = */ 0,
|
||
/* .MaxTessEvaluationImageUniforms = */ 0,
|
||
/* .MaxGeometryImageUniforms = */ 0,
|
||
/* .MaxFragmentImageUniforms = */ 8,
|
||
/* .MaxCombinedImageUniforms = */ 8,
|
||
/* .MaxGeometryTextureImageUnits = */ 16,
|
||
/* .MaxGeometryOutputVertices = */ 256,
|
||
/* .MaxGeometryTotalOutputComponents = */ 1024,
|
||
/* .MaxGeometryUniformComponents = */ 1024,
|
||
/* .MaxGeometryVaryingComponents = */ 64,
|
||
/* .MaxTessControlInputComponents = */ 128,
|
||
/* .MaxTessControlOutputComponents = */ 128,
|
||
/* .MaxTessControlTextureImageUnits = */ 16,
|
||
/* .MaxTessControlUniformComponents = */ 1024,
|
||
/* .MaxTessControlTotalOutputComponents = */ 4096,
|
||
/* .MaxTessEvaluationInputComponents = */ 128,
|
||
/* .MaxTessEvaluationOutputComponents = */ 128,
|
||
/* .MaxTessEvaluationTextureImageUnits = */ 16,
|
||
/* .MaxTessEvaluationUniformComponents = */ 1024,
|
||
/* .MaxTessPatchComponents = */ 120,
|
||
/* .MaxPatchVertices = */ 32,
|
||
/* .MaxTessGenLevel = */ 64,
|
||
/* .MaxViewports = */ 16,
|
||
/* .MaxVertexAtomicCounters = */ 0,
|
||
/* .MaxTessControlAtomicCounters = */ 0,
|
||
/* .MaxTessEvaluationAtomicCounters = */ 0,
|
||
/* .MaxGeometryAtomicCounters = */ 0,
|
||
/* .MaxFragmentAtomicCounters = */ 8,
|
||
/* .MaxCombinedAtomicCounters = */ 8,
|
||
/* .MaxAtomicCounterBindings = */ 1,
|
||
/* .MaxVertexAtomicCounterBuffers = */ 0,
|
||
/* .MaxTessControlAtomicCounterBuffers = */ 0,
|
||
/* .MaxTessEvaluationAtomicCounterBuffers = */ 0,
|
||
/* .MaxGeometryAtomicCounterBuffers = */ 0,
|
||
/* .MaxFragmentAtomicCounterBuffers = */ 1,
|
||
/* .MaxCombinedAtomicCounterBuffers = */ 1,
|
||
/* .MaxAtomicCounterBufferSize = */ 16384,
|
||
/* .MaxTransformFeedbackBuffers = */ 4,
|
||
/* .MaxTransformFeedbackInterleavedComponents = */ 64,
|
||
/* .MaxCullDistances = */ 8,
|
||
/* .MaxCombinedClipAndCullDistances = */ 8,
|
||
/* .MaxSamples = */ 4,
|
||
/* .maxMeshOutputVerticesNV = */ 256,
|
||
/* .maxMeshOutputPrimitivesNV = */ 512,
|
||
/* .maxMeshWorkGroupSizeX_NV = */ 32,
|
||
/* .maxMeshWorkGroupSizeY_NV = */ 1,
|
||
/* .maxMeshWorkGroupSizeZ_NV = */ 1,
|
||
/* .maxTaskWorkGroupSizeX_NV = */ 32,
|
||
/* .maxTaskWorkGroupSizeY_NV = */ 1,
|
||
/* .maxTaskWorkGroupSizeZ_NV = */ 1,
|
||
/* .maxMeshViewCountNV = */ 4,
|
||
|
||
/* .limits = */ {
|
||
/* .nonInductiveForLoops = */ 1,
|
||
/* .whileLoops = */ 1,
|
||
/* .doWhileLoops = */ 1,
|
||
/* .generalUniformIndexing = */ 1,
|
||
/* .generalAttributeMatrixVectorIndexing = */ 1,
|
||
/* .generalVaryingIndexing = */ 1,
|
||
/* .generalSamplerIndexing = */ 1,
|
||
/* .generalVariableIndexing = */ 1,
|
||
/* .generalConstantMatrixVectorIndexing = */ 1,
|
||
}
|
||
};
|
||
#endif
|
||
}
|
||
|
||
static bool glslangInitialized = false;
|
||
|
||
static int CompileGLSLtoSPIRV( const char* filename, const idStr& dataGLSL, const rpStage_t stage, uint32** spirvBuffer )
|
||
{
|
||
if( !glslangInitialized )
|
||
{
|
||
glslang::InitializeProcess();
|
||
glslangInitialized = true;
|
||
}
|
||
|
||
const char* inputCString = dataGLSL.c_str();
|
||
|
||
EShLanguage shaderType;
|
||
if( stage == SHADER_STAGE_VERTEX )
|
||
{
|
||
shaderType = EShLangVertex;
|
||
}
|
||
else if( stage == SHADER_STAGE_COMPUTE )
|
||
{
|
||
shaderType = EShLangCompute;
|
||
}
|
||
else
|
||
{
|
||
shaderType = EShLangFragment;
|
||
}
|
||
|
||
glslang::TShader shader( shaderType );
|
||
shader.setStrings( &inputCString, 1 );
|
||
|
||
int clientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
|
||
glslang::EShTargetClientVersion vulkanClientVersion = glslang::EShTargetVulkan_1_0;
|
||
glslang::EShTargetLanguageVersion targetVersion = glslang::EShTargetSpv_1_0;
|
||
|
||
shader.setEnvInput( glslang::EShSourceGlsl, shaderType, glslang::EShClientVulkan, clientInputSemanticsVersion );
|
||
shader.setEnvClient( glslang::EShClientVulkan, vulkanClientVersion );
|
||
shader.setEnvTarget( glslang::EShTargetSpv, targetVersion );
|
||
|
||
TBuiltInResource resources;
|
||
resources = glslang::DefaultTBuiltInResource;
|
||
EShMessages messages = ( EShMessages )( EShMsgSpvRules | EShMsgVulkanRules );
|
||
|
||
const int defaultVersion = 100;
|
||
|
||
if( !shader.parse( &resources, 100, false, messages ) )
|
||
{
|
||
idLib::Printf( "GLSL parsing failed for: %s\n", filename );
|
||
idLib::Printf( "%s\n", shader.getInfoLog() );
|
||
idLib::Printf( "%s\n", shader.getInfoDebugLog() );
|
||
}
|
||
|
||
glslang::TProgram program;
|
||
program.addShader( &shader );
|
||
|
||
if( !program.link( messages ) )
|
||
{
|
||
idLib::Printf( "GLSL linking failed for: %s\n", filename );
|
||
idLib::Printf( "%s\n", shader.getInfoLog() );
|
||
idLib::Printf( "%s\n", shader.getInfoDebugLog() );
|
||
}
|
||
|
||
// All that<61>s left to do now is to convert the program<61>s intermediate representation into SpirV:
|
||
std::vector<unsigned int> spirV;
|
||
spv::SpvBuildLogger logger;
|
||
glslang::SpvOptions spvOptions;
|
||
|
||
glslang::GlslangToSpv( *program.getIntermediate( shaderType ), spirV, &logger, &spvOptions );
|
||
|
||
int32 spirvLen = spirV.size() * sizeof( unsigned int );
|
||
|
||
void* buffer = Mem_Alloc( spirvLen, TAG_RENDERPROG );
|
||
memcpy( buffer, spirV.data(), spirvLen );
|
||
|
||
*spirvBuffer = ( uint32* ) buffer;
|
||
return spirvLen;
|
||
|
||
|
||
}
|
||
#endif
|
||
|
||
/*
|
||
================================================================================================
|
||
idRenderProgManager::LoadGLSLShader
|
||
================================================================================================
|
||
*/
|
||
void idRenderProgManager::LoadShader( shader_t& shader )
|
||
{
|
||
idStr inFile;
|
||
idStr outFileHLSL;
|
||
idStr outFileGLSL;
|
||
idStr outFileSPIRV;
|
||
idStr outFileLayout;
|
||
|
||
// RB: replaced backslashes
|
||
inFile.Format( "renderprogs/%s", shader.name.c_str() );
|
||
inFile.StripFileExtension();
|
||
outFileHLSL.Format( "renderprogs/hlsl/%s%s", shader.name.c_str(), shader.nameOutSuffix.c_str() );
|
||
outFileHLSL.StripFileExtension();
|
||
|
||
outFileGLSL.Format( "renderprogs/vkglsl/%s%s", shader.name.c_str(), shader.nameOutSuffix.c_str() );
|
||
outFileLayout.Format( "renderprogs/vkglsl/%s%s", shader.name.c_str(), shader.nameOutSuffix.c_str() );
|
||
|
||
outFileGLSL.StripFileExtension();
|
||
outFileLayout.StripFileExtension();
|
||
|
||
if( shader.stage == SHADER_STAGE_FRAGMENT )
|
||
{
|
||
inFile += ".ps.hlsl";
|
||
outFileHLSL += ".ps.hlsl";
|
||
outFileGLSL += ".frag";
|
||
outFileLayout += ".frag.layout";
|
||
outFileSPIRV += ".fspv";
|
||
}
|
||
else
|
||
{
|
||
inFile += ".vs.hlsl";
|
||
outFileHLSL += ".vs.hlsl";
|
||
outFileGLSL += ".vert";
|
||
outFileLayout += ".vert.layout";
|
||
outFileSPIRV += ".vspv";
|
||
}
|
||
|
||
// first check whether we already have a valid GLSL file and compare it to the hlsl timestamp;
|
||
ID_TIME_T hlslTimeStamp;
|
||
int hlslFileLength = fileSystem->ReadFile( inFile.c_str(), NULL, &hlslTimeStamp );
|
||
|
||
ID_TIME_T glslTimeStamp;
|
||
int glslFileLength = fileSystem->ReadFile( outFileGLSL.c_str(), NULL, &glslTimeStamp );
|
||
|
||
// if the glsl file doesn't exist or we have a newer HLSL file we need to recreate the glsl file.
|
||
idStr programGLSL;
|
||
idStr programLayout;
|
||
//if( ( glslFileLength <= 0 ) || ( hlslTimeStamp != FILE_NOT_FOUND_TIMESTAMP && hlslTimeStamp > glslTimeStamp ) || r_alwaysExportGLSL.GetBool() )
|
||
{
|
||
const char* hlslFileBuffer = NULL;
|
||
int len = 0;
|
||
|
||
if( hlslFileLength <= 0 )
|
||
{
|
||
hlslFileBuffer = FindEmbeddedSourceShader( inFile.c_str() );
|
||
if( hlslFileBuffer == NULL )
|
||
{
|
||
// hlsl file doesn't even exist bail out
|
||
idLib::Error( "HLSL file %s could not be loaded and may be corrupt", inFile.c_str() );
|
||
return;
|
||
}
|
||
|
||
len = strlen( hlslFileBuffer );
|
||
}
|
||
else
|
||
{
|
||
len = fileSystem->ReadFile( inFile.c_str(), ( void** ) &hlslFileBuffer );
|
||
}
|
||
|
||
if( len <= 0 )
|
||
{
|
||
return;
|
||
}
|
||
|
||
idStrList compileMacros;
|
||
for( int j = 0; j < MAX_SHADER_MACRO_NAMES; j++ )
|
||
{
|
||
if( BIT( j ) & shader.shaderFeatures )
|
||
{
|
||
const char* macroName = GetGLSLMacroName( ( shaderFeature_t ) j );
|
||
compileMacros.Append( idStr( macroName ) );
|
||
}
|
||
}
|
||
|
||
// FIXME: we should really scan the program source code for using rpEnableSkinning but at this
|
||
// point we directly load a binary and the program source code is not available on the consoles
|
||
bool hasGPUSkinning = false;
|
||
|
||
if( idStr::Icmp( shader.name.c_str(), "heatHaze" ) == 0 ||
|
||
idStr::Icmp( shader.name.c_str(), "heatHazeWithMask" ) == 0 ||
|
||
idStr::Icmp( shader.name.c_str(), "heatHazeWithMaskAndVertex" ) == 0 ||
|
||
( BIT( USE_GPU_SKINNING ) & shader.shaderFeatures ) )
|
||
{
|
||
hasGPUSkinning = true;
|
||
}
|
||
|
||
idStr hlslCode( hlslFileBuffer );
|
||
idStr programHLSL = StripDeadCode( hlslCode, inFile, compileMacros, shader.builtin );
|
||
programGLSL = ConvertCG2GLSL( programHLSL, inFile, shader.stage, programLayout, true, hasGPUSkinning, shader.vertexLayout );
|
||
|
||
fileSystem->WriteFile( outFileHLSL, programHLSL.c_str(), programHLSL.Length(), "fs_savepath" );
|
||
fileSystem->WriteFile( outFileGLSL, programGLSL.c_str(), programGLSL.Length(), "fs_savepath" );
|
||
fileSystem->WriteFile( outFileLayout, programLayout.c_str(), programLayout.Length(), "fs_savepath" );
|
||
}
|
||
/*
|
||
else
|
||
{
|
||
// read in the glsl file
|
||
void* fileBufferGLSL = NULL;
|
||
int lengthGLSL = fileSystem->ReadFile( outFileGLSL.c_str(), &fileBufferGLSL );
|
||
if( lengthGLSL <= 0 )
|
||
{
|
||
idLib::Error( "GLSL file %s could not be loaded and may be corrupt", outFileGLSL.c_str() );
|
||
}
|
||
programGLSL = ( const char* ) fileBufferGLSL;
|
||
Mem_Free( fileBufferGLSL );
|
||
|
||
|
||
{
|
||
// read in the uniform file
|
||
void* fileBufferUniforms = NULL;
|
||
int lengthUniforms = fileSystem->ReadFile( outFileUniforms.c_str(), &fileBufferUniforms );
|
||
if( lengthUniforms <= 0 )
|
||
{
|
||
idLib::Error( "uniform file %s could not be loaded and may be corrupt", outFileUniforms.c_str() );
|
||
}
|
||
programUniforms = ( const char* ) fileBufferUniforms;
|
||
Mem_Free( fileBufferUniforms );
|
||
}
|
||
}
|
||
*/
|
||
|
||
// RB: find the uniforms locations in either the vertex or fragment uniform array
|
||
// this uses the new layout structure
|
||
{
|
||
idLexer src( programLayout, programLayout.Length(), "layout" );
|
||
idToken token;
|
||
if( src.ExpectTokenString( "uniforms" ) )
|
||
{
|
||
src.ExpectTokenString( "[" );
|
||
|
||
while( !src.CheckTokenString( "]" ) )
|
||
{
|
||
src.ReadToken( &token );
|
||
|
||
int index = -1;
|
||
for( int i = 0; i < RENDERPARM_TOTAL && index == -1; i++ )
|
||
{
|
||
const char* parmName = GetGLSLParmName( i );
|
||
if( token == parmName )
|
||
{
|
||
index = i;
|
||
}
|
||
}
|
||
|
||
if( index == -1 )
|
||
{
|
||
idLib::Error( "couldn't find uniform %s for %s", token.c_str(), outFileGLSL.c_str() );
|
||
}
|
||
shader.parmIndices.Append( index );
|
||
}
|
||
}
|
||
|
||
if( src.ExpectTokenString( "bindings" ) )
|
||
{
|
||
src.ExpectTokenString( "[" );
|
||
|
||
while( !src.CheckTokenString( "]" ) )
|
||
{
|
||
src.ReadToken( &token );
|
||
|
||
int index = -1;
|
||
for( int i = 0; i < BINDING_TYPE_MAX; ++i )
|
||
{
|
||
if( token == renderProgBindingStrings[ i ] )
|
||
{
|
||
index = i;
|
||
}
|
||
}
|
||
|
||
if( index == -1 )
|
||
{
|
||
idLib::Error( "Invalid binding %s", token.c_str() );
|
||
}
|
||
|
||
shader.bindings.Append( static_cast< rpBinding_t >( index ) );
|
||
}
|
||
}
|
||
}
|
||
|
||
// TODO GLSL to SPIR-V compilation
|
||
uint32* spirvBuffer = NULL;
|
||
int spirvLen = CompileGLSLtoSPIRV( outFileGLSL.c_str(), programGLSL, shader.stage, &spirvBuffer );
|
||
|
||
VkShaderModuleCreateInfo shaderModuleCreateInfo = {};
|
||
shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||
shaderModuleCreateInfo.codeSize = spirvLen;
|
||
shaderModuleCreateInfo.pCode = ( uint32* )spirvBuffer;
|
||
|
||
ID_VK_CHECK( vkCreateShaderModule( vkcontext.device, &shaderModuleCreateInfo, NULL, &shader.module ) );
|
||
|
||
Mem_Free( spirvBuffer );
|
||
}
|
||
|
||
/*
|
||
================================================================================================
|
||
idRenderProgManager::LoadGLSLProgram
|
||
================================================================================================
|
||
*/
|
||
void idRenderProgManager::LoadGLSLProgram( const int programIndex, const int vertexShaderIndex, const int fragmentShaderIndex )
|
||
{
|
||
renderProg_t& prog = renderProgs[programIndex];
|
||
|
||
if( prog.progId != INVALID_PROGID )
|
||
{
|
||
return; // Already loaded
|
||
}
|
||
|
||
idStr programName = shaders[ vertexShaderIndex ].name;
|
||
programName.StripFileExtension();
|
||
prog.name = programName;
|
||
//prog.progId = programIndex;
|
||
prog.fragmentShaderIndex = fragmentShaderIndex;
|
||
prog.vertexShaderIndex = vertexShaderIndex;
|
||
|
||
CreateDescriptorSetLayout( shaders[ vertexShaderIndex ], shaders[ fragmentShaderIndex ], prog );
|
||
|
||
|
||
// TODO
|
||
|
||
#if 1
|
||
// RB: removed idStr::Icmp( name, "heatHaze.vfp" ) == 0 hack
|
||
for( int i = 0; i < shaders[vertexShaderIndex].parmIndices.Num(); i++ )
|
||
{
|
||
if( shaders[vertexShaderIndex].parmIndices[i] == RENDERPARM_ENABLE_SKINNING )
|
||
{
|
||
prog.usesJoints = true;
|
||
prog.optionalSkinning = true;
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
================================================================================================
|
||
idRenderProgManager::KillAllShaders()
|
||
================================================================================================
|
||
*/
|
||
void idRenderProgManager::KillAllShaders()
|
||
{
|
||
Unbind();
|
||
|
||
// destroy shaders
|
||
for( int i = 0; i < shaders.Num(); ++i )
|
||
{
|
||
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 )
|
||
{
|
||
renderProg_t& prog = renderProgs[ i ];
|
||
|
||
for( int j = 0; j < prog.pipelines.Num(); ++j )
|
||
{
|
||
vkDestroyPipeline( vkcontext.device, prog.pipelines[ j ].pipeline, NULL );
|
||
}
|
||
prog.pipelines.Clear();
|
||
|
||
vkDestroyDescriptorSetLayout( vkcontext.device, prog.descriptorSetLayout, NULL );
|
||
vkDestroyPipelineLayout( vkcontext.device, prog.pipelineLayout, NULL );
|
||
}
|
||
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;
|
||
}
|
||
|
||
/*
|
||
========================
|
||
idRenderProgManager::AllocParmBlockBuffer
|
||
========================
|
||
*/
|
||
void idRenderProgManager::AllocParmBlockBuffer( const idList<int>& parmIndices, idUniformBuffer& ubo )
|
||
{
|
||
// TODO support shadow matrices + 23 float4
|
||
|
||
const int numParms = parmIndices.Num();
|
||
const int bytes = ALIGN( numParms * sizeof( idVec4 ), vkcontext.gpu->props.limits.minUniformBufferOffsetAlignment );
|
||
|
||
ubo.Reference( *parmBuffers[ currentData ], currentParmBufferOffset, bytes );
|
||
|
||
idVec4* gpuUniforms = ( idVec4* )ubo.MapBuffer( BM_WRITE );
|
||
|
||
for( int i = 0; i < numParms; ++i )
|
||
{
|
||
gpuUniforms[ i ] = uniforms[ static_cast< renderParm_t >( parmIndices[ i ] ) ];
|
||
}
|
||
|
||
ubo.UnmapBuffer();
|
||
|
||
currentParmBufferOffset += bytes;
|
||
}
|
||
|
||
/*
|
||
========================
|
||
GetStencilOpState
|
||
========================
|
||
*/
|
||
static VkStencilOpState GetStencilOpState( uint64 stencilBits )
|
||
{
|
||
VkStencilOpState state = {};
|
||
|
||
switch( stencilBits & GLS_STENCIL_OP_FAIL_BITS )
|
||
{
|
||
case GLS_STENCIL_OP_FAIL_KEEP:
|
||
state.failOp = VK_STENCIL_OP_KEEP;
|
||
break;
|
||
case GLS_STENCIL_OP_FAIL_ZERO:
|
||
state.failOp = VK_STENCIL_OP_ZERO;
|
||
break;
|
||
case GLS_STENCIL_OP_FAIL_REPLACE:
|
||
state.failOp = VK_STENCIL_OP_REPLACE;
|
||
break;
|
||
case GLS_STENCIL_OP_FAIL_INCR:
|
||
state.failOp = VK_STENCIL_OP_INCREMENT_AND_CLAMP;
|
||
break;
|
||
case GLS_STENCIL_OP_FAIL_DECR:
|
||
state.failOp = VK_STENCIL_OP_DECREMENT_AND_CLAMP;
|
||
break;
|
||
case GLS_STENCIL_OP_FAIL_INVERT:
|
||
state.failOp = VK_STENCIL_OP_INVERT;
|
||
break;
|
||
case GLS_STENCIL_OP_FAIL_INCR_WRAP:
|
||
state.failOp = VK_STENCIL_OP_INCREMENT_AND_WRAP;
|
||
break;
|
||
case GLS_STENCIL_OP_FAIL_DECR_WRAP:
|
||
state.failOp = VK_STENCIL_OP_DECREMENT_AND_WRAP;
|
||
break;
|
||
}
|
||
switch( stencilBits & GLS_STENCIL_OP_ZFAIL_BITS )
|
||
{
|
||
case GLS_STENCIL_OP_ZFAIL_KEEP:
|
||
state.depthFailOp = VK_STENCIL_OP_KEEP;
|
||
break;
|
||
case GLS_STENCIL_OP_ZFAIL_ZERO:
|
||
state.depthFailOp = VK_STENCIL_OP_ZERO;
|
||
break;
|
||
case GLS_STENCIL_OP_ZFAIL_REPLACE:
|
||
state.depthFailOp = VK_STENCIL_OP_REPLACE;
|
||
break;
|
||
case GLS_STENCIL_OP_ZFAIL_INCR:
|
||
state.depthFailOp = VK_STENCIL_OP_INCREMENT_AND_CLAMP;
|
||
break;
|
||
case GLS_STENCIL_OP_ZFAIL_DECR:
|
||
state.depthFailOp = VK_STENCIL_OP_DECREMENT_AND_CLAMP;
|
||
break;
|
||
case GLS_STENCIL_OP_ZFAIL_INVERT:
|
||
state.depthFailOp = VK_STENCIL_OP_INVERT;
|
||
break;
|
||
case GLS_STENCIL_OP_ZFAIL_INCR_WRAP:
|
||
state.depthFailOp = VK_STENCIL_OP_INCREMENT_AND_WRAP;
|
||
break;
|
||
case GLS_STENCIL_OP_ZFAIL_DECR_WRAP:
|
||
state.depthFailOp = VK_STENCIL_OP_DECREMENT_AND_WRAP;
|
||
break;
|
||
}
|
||
switch( stencilBits & GLS_STENCIL_OP_PASS_BITS )
|
||
{
|
||
case GLS_STENCIL_OP_PASS_KEEP:
|
||
state.passOp = VK_STENCIL_OP_KEEP;
|
||
break;
|
||
case GLS_STENCIL_OP_PASS_ZERO:
|
||
state.passOp = VK_STENCIL_OP_ZERO;
|
||
break;
|
||
case GLS_STENCIL_OP_PASS_REPLACE:
|
||
state.passOp = VK_STENCIL_OP_REPLACE;
|
||
break;
|
||
case GLS_STENCIL_OP_PASS_INCR:
|
||
state.passOp = VK_STENCIL_OP_INCREMENT_AND_CLAMP;
|
||
break;
|
||
case GLS_STENCIL_OP_PASS_DECR:
|
||
state.passOp = VK_STENCIL_OP_DECREMENT_AND_CLAMP;
|
||
break;
|
||
case GLS_STENCIL_OP_PASS_INVERT:
|
||
state.passOp = VK_STENCIL_OP_INVERT;
|
||
break;
|
||
case GLS_STENCIL_OP_PASS_INCR_WRAP:
|
||
state.passOp = VK_STENCIL_OP_INCREMENT_AND_WRAP;
|
||
break;
|
||
case GLS_STENCIL_OP_PASS_DECR_WRAP:
|
||
state.passOp = VK_STENCIL_OP_DECREMENT_AND_WRAP;
|
||
break;
|
||
}
|
||
|
||
return state;
|
||
}
|
||
|
||
/*
|
||
========================
|
||
CreateGraphicsPipeline
|
||
========================
|
||
*/
|
||
static VkPipeline CreateGraphicsPipeline(
|
||
vertexLayoutType_t vertexLayoutType,
|
||
VkShaderModule vertexShader,
|
||
VkShaderModule fragmentShader,
|
||
VkPipelineLayout pipelineLayout,
|
||
uint64 stateBits )
|
||
{
|
||
|
||
// Pipeline
|
||
vertexLayout_t& vertexLayout = vertexLayouts[ vertexLayoutType ];
|
||
|
||
// Vertex Input
|
||
VkPipelineVertexInputStateCreateInfo vertexInputState = vertexLayout.inputState;
|
||
vertexInputState.vertexBindingDescriptionCount = vertexLayout.bindingDesc.Num();
|
||
vertexInputState.pVertexBindingDescriptions = vertexLayout.bindingDesc.Ptr();
|
||
vertexInputState.vertexAttributeDescriptionCount = vertexLayout.attributeDesc.Num();
|
||
vertexInputState.pVertexAttributeDescriptions = vertexLayout.attributeDesc.Ptr();
|
||
|
||
// Input Assembly
|
||
VkPipelineInputAssemblyStateCreateInfo assemblyInputState = {};
|
||
assemblyInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||
assemblyInputState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||
|
||
// Rasterization
|
||
VkPipelineRasterizationStateCreateInfo rasterizationState = {};
|
||
rasterizationState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||
rasterizationState.rasterizerDiscardEnable = VK_FALSE;
|
||
rasterizationState.depthBiasEnable = ( stateBits & GLS_POLYGON_OFFSET ) != 0;
|
||
rasterizationState.depthClampEnable = VK_FALSE;
|
||
rasterizationState.frontFace = ( stateBits & GLS_CLOCKWISE ) ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||
rasterizationState.lineWidth = 1.0f;
|
||
rasterizationState.polygonMode = ( stateBits & GLS_POLYMODE_LINE ) ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;
|
||
|
||
switch( stateBits & GLS_CULL_BITS )
|
||
{
|
||
case GLS_CULL_TWOSIDED:
|
||
rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
||
break;
|
||
|
||
case GLS_CULL_BACKSIDED:
|
||
if( stateBits & GLS_MIRROR_VIEW )
|
||
{
|
||
rasterizationState.cullMode = VK_CULL_MODE_FRONT_BIT;
|
||
}
|
||
else
|
||
{
|
||
rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT;
|
||
}
|
||
break;
|
||
|
||
case GLS_CULL_FRONTSIDED:
|
||
default:
|
||
if( stateBits & GLS_MIRROR_VIEW )
|
||
{
|
||
rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT;
|
||
}
|
||
else
|
||
{
|
||
rasterizationState.cullMode = VK_CULL_MODE_FRONT_BIT;
|
||
}
|
||
break;
|
||
}
|
||
|
||
// Color Blend Attachment
|
||
VkPipelineColorBlendAttachmentState attachmentState = {};
|
||
{
|
||
VkBlendFactor srcFactor = VK_BLEND_FACTOR_ONE;
|
||
switch( stateBits & GLS_SRCBLEND_BITS )
|
||
{
|
||
case GLS_SRCBLEND_ZERO:
|
||
srcFactor = VK_BLEND_FACTOR_ZERO;
|
||
break;
|
||
case GLS_SRCBLEND_ONE:
|
||
srcFactor = VK_BLEND_FACTOR_ONE;
|
||
break;
|
||
case GLS_SRCBLEND_DST_COLOR:
|
||
srcFactor = VK_BLEND_FACTOR_DST_COLOR;
|
||
break;
|
||
case GLS_SRCBLEND_ONE_MINUS_DST_COLOR:
|
||
srcFactor = VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
|
||
break;
|
||
case GLS_SRCBLEND_SRC_ALPHA:
|
||
srcFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||
break;
|
||
case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:
|
||
srcFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||
break;
|
||
case GLS_SRCBLEND_DST_ALPHA:
|
||
srcFactor = VK_BLEND_FACTOR_DST_ALPHA;
|
||
break;
|
||
case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:
|
||
srcFactor = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
|
||
break;
|
||
}
|
||
|
||
VkBlendFactor dstFactor = VK_BLEND_FACTOR_ZERO;
|
||
switch( stateBits & GLS_DSTBLEND_BITS )
|
||
{
|
||
case GLS_DSTBLEND_ZERO:
|
||
dstFactor = VK_BLEND_FACTOR_ZERO;
|
||
break;
|
||
case GLS_DSTBLEND_ONE:
|
||
dstFactor = VK_BLEND_FACTOR_ONE;
|
||
break;
|
||
case GLS_DSTBLEND_SRC_COLOR:
|
||
dstFactor = VK_BLEND_FACTOR_SRC_COLOR;
|
||
break;
|
||
case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:
|
||
dstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
|
||
break;
|
||
case GLS_DSTBLEND_SRC_ALPHA:
|
||
dstFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||
break;
|
||
case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:
|
||
dstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||
break;
|
||
case GLS_DSTBLEND_DST_ALPHA:
|
||
dstFactor = VK_BLEND_FACTOR_DST_ALPHA;
|
||
break;
|
||
case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:
|
||
dstFactor = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
|
||
break;
|
||
}
|
||
|
||
VkBlendOp blendOp = VK_BLEND_OP_ADD;
|
||
switch( stateBits & GLS_BLENDOP_BITS )
|
||
{
|
||
case GLS_BLENDOP_MIN:
|
||
blendOp = VK_BLEND_OP_MIN;
|
||
break;
|
||
case GLS_BLENDOP_MAX:
|
||
blendOp = VK_BLEND_OP_MAX;
|
||
break;
|
||
case GLS_BLENDOP_ADD:
|
||
blendOp = VK_BLEND_OP_ADD;
|
||
break;
|
||
case GLS_BLENDOP_SUB:
|
||
blendOp = VK_BLEND_OP_SUBTRACT;
|
||
break;
|
||
}
|
||
|
||
attachmentState.blendEnable = ( srcFactor != VK_BLEND_FACTOR_ONE || dstFactor != VK_BLEND_FACTOR_ZERO );
|
||
attachmentState.colorBlendOp = blendOp;
|
||
attachmentState.srcColorBlendFactor = srcFactor;
|
||
attachmentState.dstColorBlendFactor = dstFactor;
|
||
attachmentState.alphaBlendOp = blendOp;
|
||
attachmentState.srcAlphaBlendFactor = srcFactor;
|
||
attachmentState.dstAlphaBlendFactor = dstFactor;
|
||
|
||
// Color Mask
|
||
attachmentState.colorWriteMask = 0;
|
||
attachmentState.colorWriteMask |= ( stateBits & GLS_REDMASK ) ? 0 : VK_COLOR_COMPONENT_R_BIT;
|
||
attachmentState.colorWriteMask |= ( stateBits & GLS_GREENMASK ) ? 0 : VK_COLOR_COMPONENT_G_BIT;
|
||
attachmentState.colorWriteMask |= ( stateBits & GLS_BLUEMASK ) ? 0 : VK_COLOR_COMPONENT_B_BIT;
|
||
attachmentState.colorWriteMask |= ( stateBits & GLS_ALPHAMASK ) ? 0 : VK_COLOR_COMPONENT_A_BIT;
|
||
}
|
||
|
||
// Color Blend
|
||
VkPipelineColorBlendStateCreateInfo colorBlendState = {};
|
||
colorBlendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||
colorBlendState.attachmentCount = 1;
|
||
colorBlendState.pAttachments = &attachmentState;
|
||
|
||
// Depth / Stencil
|
||
VkPipelineDepthStencilStateCreateInfo depthStencilState = {};
|
||
{
|
||
VkCompareOp depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||
switch( stateBits & GLS_DEPTHFUNC_BITS )
|
||
{
|
||
case GLS_DEPTHFUNC_EQUAL:
|
||
depthCompareOp = VK_COMPARE_OP_EQUAL;
|
||
break;
|
||
case GLS_DEPTHFUNC_ALWAYS:
|
||
depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||
break;
|
||
case GLS_DEPTHFUNC_LESS:
|
||
depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
||
break;
|
||
case GLS_DEPTHFUNC_GREATER:
|
||
depthCompareOp = VK_COMPARE_OP_GREATER_OR_EQUAL;
|
||
break;
|
||
}
|
||
|
||
VkCompareOp stencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||
switch( stateBits & GLS_STENCIL_FUNC_BITS )
|
||
{
|
||
case GLS_STENCIL_FUNC_NEVER:
|
||
stencilCompareOp = VK_COMPARE_OP_NEVER;
|
||
break;
|
||
case GLS_STENCIL_FUNC_LESS:
|
||
stencilCompareOp = VK_COMPARE_OP_LESS;
|
||
break;
|
||
case GLS_STENCIL_FUNC_EQUAL:
|
||
stencilCompareOp = VK_COMPARE_OP_EQUAL;
|
||
break;
|
||
case GLS_STENCIL_FUNC_LEQUAL:
|
||
stencilCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
||
break;
|
||
case GLS_STENCIL_FUNC_GREATER:
|
||
stencilCompareOp = VK_COMPARE_OP_GREATER;
|
||
break;
|
||
case GLS_STENCIL_FUNC_NOTEQUAL:
|
||
stencilCompareOp = VK_COMPARE_OP_NOT_EQUAL;
|
||
break;
|
||
case GLS_STENCIL_FUNC_GEQUAL:
|
||
stencilCompareOp = VK_COMPARE_OP_GREATER_OR_EQUAL;
|
||
break;
|
||
case GLS_STENCIL_FUNC_ALWAYS:
|
||
stencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||
break;
|
||
}
|
||
|
||
depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||
depthStencilState.depthTestEnable = VK_TRUE;
|
||
depthStencilState.depthWriteEnable = ( stateBits & GLS_DEPTHMASK ) == 0;
|
||
depthStencilState.depthCompareOp = depthCompareOp;
|
||
depthStencilState.depthBoundsTestEnable = ( stateBits & GLS_DEPTH_TEST_MASK ) != 0;
|
||
depthStencilState.minDepthBounds = 0.0f;
|
||
depthStencilState.maxDepthBounds = 1.0f;
|
||
depthStencilState.stencilTestEnable = ( stateBits & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS | GLS_SEPARATE_STENCIL ) ) != 0;
|
||
|
||
uint32 ref = uint32( ( stateBits & GLS_STENCIL_FUNC_REF_BITS ) >> GLS_STENCIL_FUNC_REF_SHIFT );
|
||
uint32 mask = uint32( ( stateBits & GLS_STENCIL_FUNC_MASK_BITS ) >> GLS_STENCIL_FUNC_MASK_SHIFT );
|
||
|
||
if( stateBits & GLS_SEPARATE_STENCIL )
|
||
{
|
||
depthStencilState.front = GetStencilOpState( stateBits & GLS_STENCIL_FRONT_OPS );
|
||
depthStencilState.front.writeMask = 0xFFFFFFFF;
|
||
depthStencilState.front.compareOp = stencilCompareOp;
|
||
depthStencilState.front.compareMask = mask;
|
||
depthStencilState.front.reference = ref;
|
||
|
||
depthStencilState.back = GetStencilOpState( ( stateBits & GLS_STENCIL_BACK_OPS ) >> 12 );
|
||
depthStencilState.back.writeMask = 0xFFFFFFFF;
|
||
depthStencilState.back.compareOp = stencilCompareOp;
|
||
depthStencilState.back.compareMask = mask;
|
||
depthStencilState.back.reference = ref;
|
||
}
|
||
else
|
||
{
|
||
depthStencilState.front = GetStencilOpState( stateBits );
|
||
depthStencilState.front.writeMask = 0xFFFFFFFF;
|
||
depthStencilState.front.compareOp = stencilCompareOp;
|
||
depthStencilState.front.compareMask = mask;
|
||
depthStencilState.front.reference = ref;
|
||
depthStencilState.back = depthStencilState.front;
|
||
}
|
||
}
|
||
|
||
// Multisample
|
||
VkPipelineMultisampleStateCreateInfo multisampleState = {};
|
||
multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||
multisampleState.rasterizationSamples = vkcontext.sampleCount;
|
||
if( vkcontext.supersampling )
|
||
{
|
||
multisampleState.sampleShadingEnable = VK_TRUE;
|
||
multisampleState.minSampleShading = 1.0f;
|
||
}
|
||
|
||
// Shader Stages
|
||
idList< VkPipelineShaderStageCreateInfo > stages;
|
||
VkPipelineShaderStageCreateInfo stage = {};
|
||
stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||
stage.pName = "main";
|
||
|
||
{
|
||
stage.module = vertexShader;
|
||
stage.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||
stages.Append( stage );
|
||
}
|
||
|
||
if( fragmentShader != VK_NULL_HANDLE )
|
||
{
|
||
stage.module = fragmentShader;
|
||
stage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||
stages.Append( stage );
|
||
}
|
||
|
||
// Dynamic
|
||
idList< VkDynamicState > dynamic;
|
||
dynamic.Append( VK_DYNAMIC_STATE_SCISSOR );
|
||
dynamic.Append( VK_DYNAMIC_STATE_VIEWPORT );
|
||
|
||
//if( stateBits & GLS_POLYGON_OFFSET )
|
||
{
|
||
dynamic.Append( VK_DYNAMIC_STATE_DEPTH_BIAS );
|
||
}
|
||
|
||
//if( stateBits & GLS_DEPTH_TEST_MASK )
|
||
{
|
||
dynamic.Append( VK_DYNAMIC_STATE_DEPTH_BOUNDS );
|
||
}
|
||
|
||
VkPipelineDynamicStateCreateInfo dynamicState = {};
|
||
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||
dynamicState.dynamicStateCount = dynamic.Num();
|
||
dynamicState.pDynamicStates = dynamic.Ptr();
|
||
|
||
// Viewport / Scissor
|
||
VkPipelineViewportStateCreateInfo viewportState = {};
|
||
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||
viewportState.viewportCount = 1;
|
||
viewportState.scissorCount = 1;
|
||
|
||
// Pipeline Create
|
||
VkGraphicsPipelineCreateInfo createInfo = {};
|
||
createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||
createInfo.layout = pipelineLayout;
|
||
createInfo.renderPass = vkcontext.renderPass;
|
||
createInfo.pVertexInputState = &vertexInputState;
|
||
createInfo.pInputAssemblyState = &assemblyInputState;
|
||
createInfo.pRasterizationState = &rasterizationState;
|
||
createInfo.pColorBlendState = &colorBlendState;
|
||
createInfo.pDepthStencilState = &depthStencilState;
|
||
createInfo.pMultisampleState = &multisampleState;
|
||
createInfo.pDynamicState = &dynamicState;
|
||
createInfo.pViewportState = &viewportState;
|
||
createInfo.stageCount = stages.Num();
|
||
createInfo.pStages = stages.Ptr();
|
||
|
||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||
|
||
ID_VK_CHECK( vkCreateGraphicsPipelines( vkcontext.device, vkcontext.pipelineCache, 1, &createInfo, NULL, &pipeline ) );
|
||
|
||
return pipeline;
|
||
}
|
||
|
||
/*
|
||
========================
|
||
renderProg_t::GetPipeline
|
||
========================
|
||
*/
|
||
VkPipeline idRenderProgManager::renderProg_t::GetPipeline( uint64 stateBits, VkShaderModule vertexShader, VkShaderModule fragmentShader )
|
||
{
|
||
for( int i = 0; i < pipelines.Num(); ++i )
|
||
{
|
||
if( stateBits == pipelines[ i ].stateBits )
|
||
{
|
||
return pipelines[ i ].pipeline;
|
||
}
|
||
}
|
||
|
||
VkPipeline pipeline = CreateGraphicsPipeline( vertexLayout, vertexShader, fragmentShader, pipelineLayout, stateBits );
|
||
|
||
pipelineState_t pipelineState;
|
||
pipelineState.pipeline = pipeline;
|
||
pipelineState.stateBits = stateBits;
|
||
pipelines.Append( pipelineState );
|
||
|
||
return pipeline;
|
||
}
|
||
|
||
/*
|
||
================================================================================================
|
||
idRenderProgManager::CommitUnforms
|
||
================================================================================================
|
||
*/
|
||
void idRenderProgManager::CommitUniforms( uint64 stateBits )
|
||
{
|
||
#if 0
|
||
const int progID = current;
|
||
const renderProg_t& prog = renderProgs[progID];
|
||
|
||
//GL_CheckErrors();
|
||
|
||
ALIGNTYPE16 idVec4 localVectors[RENDERPARM_TOTAL];
|
||
|
||
auto commitarray = [&]( idVec4( &vectors )[ RENDERPARM_TOTAL ] , shader_t& shader )
|
||
{
|
||
const int numUniforms = shader.uniforms.Num();
|
||
if( shader.uniformArray != -1 && numUniforms > 0 )
|
||
{
|
||
int totalUniforms = 0;
|
||
for( int i = 0; i < numUniforms; ++i )
|
||
{
|
||
// RB: HACK rpShadowMatrices[6 * 4]
|
||
if( shader.uniforms[i] == RENDERPARM_SHADOW_MATRIX_0_X )
|
||
{
|
||
for( int j = 0; j < ( 6 * 4 ); j++ )
|
||
{
|
||
vectors[i + j] = uniforms[ shader.uniforms[i] + j];
|
||
totalUniforms++;
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
vectors[i] = uniforms[ shader.uniforms[i] ];
|
||
totalUniforms++;
|
||
}
|
||
}
|
||
glUniform4fv( shader.uniformArray, totalUniforms, localVectors->ToFloatPtr() );
|
||
}
|
||
};
|
||
|
||
if( prog.vertexShaderIndex >= 0 )
|
||
{
|
||
commitarray( localVectors, shaders[ prog.vertexShaderIndex ] );
|
||
}
|
||
|
||
if( prog.fragmentShaderIndex >= 0 )
|
||
{
|
||
commitarray( localVectors, shaders[ prog.fragmentShaderIndex ] );
|
||
}
|
||
|
||
#endif
|
||
|
||
renderProg_t& prog = renderProgs[ current ];
|
||
|
||
VkPipeline pipeline = prog.GetPipeline( stateBits, shaders[ prog.vertexShaderIndex ].module, shaders[ prog.fragmentShaderIndex ].module );
|
||
|
||
VkDescriptorSetAllocateInfo setAllocInfo = {};
|
||
setAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||
setAllocInfo.pNext = NULL;
|
||
setAllocInfo.descriptorPool = descriptorPools[ currentData ];
|
||
setAllocInfo.descriptorSetCount = 1;
|
||
setAllocInfo.pSetLayouts = &prog.descriptorSetLayout;
|
||
|
||
ID_VK_CHECK( vkAllocateDescriptorSets( vkcontext.device, &setAllocInfo, &descriptorSets[ currentData ][ currentDescSet ] ) );
|
||
|
||
VkDescriptorSet descSet = descriptorSets[ currentData ][ currentDescSet ];
|
||
currentDescSet++;
|
||
|
||
int writeIndex = 0;
|
||
int bufferIndex = 0;
|
||
int imageIndex = 0;
|
||
int bindingIndex = 0;
|
||
|
||
VkWriteDescriptorSet writes[ MAX_DESC_SET_WRITES ];
|
||
VkDescriptorBufferInfo bufferInfos[ MAX_DESC_SET_WRITES ];
|
||
VkDescriptorImageInfo imageInfos[ MAX_DESC_SET_WRITES ];
|
||
|
||
int uboIndex = 0;
|
||
idUniformBuffer* ubos[ 3 ] = { NULL, NULL, NULL };
|
||
|
||
idUniformBuffer vertParms;
|
||
if( prog.vertexShaderIndex > -1 && shaders[ prog.vertexShaderIndex ].parmIndices.Num() > 0 )
|
||
{
|
||
AllocParmBlockBuffer( shaders[ prog.vertexShaderIndex ].parmIndices, vertParms );
|
||
|
||
ubos[ uboIndex++ ] = &vertParms;
|
||
}
|
||
|
||
idUniformBuffer jointBuffer;
|
||
if( prog.usesJoints && vkcontext.jointCacheHandle > 0 )
|
||
{
|
||
if( !vertexCache.GetJointBuffer( vkcontext.jointCacheHandle, &jointBuffer ) )
|
||
{
|
||
idLib::Error( "idRenderProgManager::CommitCurrent: jointBuffer == NULL" );
|
||
return;
|
||
}
|
||
assert( ( jointBuffer.GetOffset() & ( vkcontext.gpu->props.limits.minUniformBufferOffsetAlignment - 1 ) ) == 0 );
|
||
|
||
ubos[ uboIndex++ ] = &jointBuffer;
|
||
}
|
||
else if( prog.optionalSkinning )
|
||
{
|
||
ubos[ uboIndex++ ] = &emptyUBO;
|
||
}
|
||
|
||
idUniformBuffer fragParms;
|
||
if( prog.fragmentShaderIndex > -1 && shaders[ prog.fragmentShaderIndex ].parmIndices.Num() > 0 )
|
||
{
|
||
AllocParmBlockBuffer( shaders[ prog.fragmentShaderIndex ].parmIndices, fragParms );
|
||
|
||
ubos[ uboIndex++ ] = &fragParms;
|
||
}
|
||
|
||
for( int i = 0; i < prog.bindings.Num(); ++i )
|
||
{
|
||
rpBinding_t binding = prog.bindings[ i ];
|
||
|
||
switch( binding )
|
||
{
|
||
case BINDING_TYPE_UNIFORM_BUFFER:
|
||
{
|
||
idUniformBuffer* ubo = ubos[ bufferIndex ];
|
||
|
||
VkDescriptorBufferInfo& bufferInfo = bufferInfos[ bufferIndex++ ];
|
||
memset( &bufferInfo, 0, sizeof( VkDescriptorBufferInfo ) );
|
||
bufferInfo.buffer = ubo->GetAPIObject();
|
||
bufferInfo.offset = ubo->GetOffset();
|
||
bufferInfo.range = ubo->GetSize();
|
||
|
||
VkWriteDescriptorSet& write = writes[ writeIndex++ ];
|
||
memset( &write, 0, sizeof( VkWriteDescriptorSet ) );
|
||
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||
write.dstSet = descSet;
|
||
write.dstBinding = bindingIndex++;
|
||
write.descriptorCount = 1;
|
||
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||
write.pBufferInfo = &bufferInfo;
|
||
|
||
break;
|
||
}
|
||
case BINDING_TYPE_SAMPLER:
|
||
{
|
||
idImage* image = vkcontext.imageParms[ imageIndex ];
|
||
|
||
VkDescriptorImageInfo& imageInfo = imageInfos[ imageIndex++ ];
|
||
memset( &imageInfo, 0, sizeof( VkDescriptorImageInfo ) );
|
||
imageInfo.imageLayout = image->GetLayout();
|
||
imageInfo.imageView = image->GetView();
|
||
imageInfo.sampler = image->GetSampler();
|
||
|
||
assert( image->GetView() != VK_NULL_HANDLE );
|
||
|
||
VkWriteDescriptorSet& write = writes[ writeIndex++ ];
|
||
memset( &write, 0, sizeof( VkWriteDescriptorSet ) );
|
||
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||
write.dstSet = descSet;
|
||
write.dstBinding = bindingIndex++;
|
||
write.descriptorCount = 1;
|
||
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||
write.pImageInfo = &imageInfo;
|
||
|
||
//imageIndex++;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
vkUpdateDescriptorSets( vkcontext.device, writeIndex, writes, 0, NULL );
|
||
|
||
vkCmdBindDescriptorSets(
|
||
vkcontext.commandBuffer[ vkcontext.frameParity ],
|
||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||
prog.pipelineLayout, 0, 1, &descSet,
|
||
0, NULL );
|
||
|
||
vkCmdBindPipeline(
|
||
vkcontext.commandBuffer[ vkcontext.frameParity ],
|
||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||
pipeline );
|
||
}
|
||
|
||
void idRenderProgManager::CachePipeline( uint64 stateBits )
|
||
{
|
||
renderProg_t& prog = renderProgs[ current ];
|
||
|
||
VkPipeline pipeline = prog.GetPipeline( stateBits, shaders[ prog.vertexShaderIndex ].module, shaders[ prog.fragmentShaderIndex ].module );
|
||
}
|
||
|
||
|
||
void idRenderProgManager::PrintPipelines()
|
||
{
|
||
for( int i = 0; i < renderProgManager.renderProgs.Num(); ++i )
|
||
{
|
||
renderProg_t& prog = renderProgManager.renderProgs[ i ];
|
||
for( int j = 0; j < prog.pipelines.Num(); ++j )
|
||
{
|
||
idLib::Printf( "%s: %llu\n", prog.name.c_str(), prog.pipelines[ j ].stateBits );
|
||
idLib::Printf( "------------------------------------------\n" );
|
||
RpPrintState( prog.pipelines[ j ].stateBits );
|
||
idLib::Printf( "\n" );
|
||
}
|
||
}
|
||
}
|
||
|
||
void idRenderProgManager::ClearPipelines()
|
||
{
|
||
for( int i = 0; i < renderProgManager.renderProgs.Num(); ++i )
|
||
{
|
||
renderProg_t& prog = renderProgManager.renderProgs[ i ];
|
||
for( int j = 0; j < prog.pipelines.Num(); ++j )
|
||
{
|
||
vkDestroyPipeline( vkcontext.device, prog.pipelines[ j ].pipeline, NULL );
|
||
}
|
||
prog.pipelines.Clear();
|
||
}
|
||
}
|
||
|
||
|
||
CONSOLE_COMMAND( Vulkan_PrintPipelineStates, "Print the GLState bits associated with each pipeline.", 0 )
|
||
{
|
||
renderProgManager.PrintPipelines();
|
||
}
|
||
|
||
CONSOLE_COMMAND( Vulkan_ClearPipelines, "Clear all existing pipelines, forcing them to be recreated.", 0 )
|
||
{
|
||
renderProgManager.ClearPipelines();
|
||
}
|
||
|