2016-03-17 11:56:43 +01:00
// Copyright (c) 2016- PPSSPP Project.
// This program 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, version 2.0 or later versions.
// This program 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2016-03-28 22:14:04 +02:00
# include "Common/Log.h"
2020-09-29 12:19:22 +02:00
# include "Common/StringUtils.h"
2020-10-04 23:24:14 +02:00
# include "Common/GPU/Vulkan/VulkanContext.h"
2016-03-17 11:56:43 +01:00
# include "GPU/Vulkan/VulkanUtil.h"
2021-08-21 12:39:15 +02:00
using namespace PPSSPP_VK ;
2021-08-20 11:22:57 +02:00
2021-07-11 11:26:25 +02:00
const VkComponentMapping VULKAN_4444_SWIZZLE = { VK_COMPONENT_SWIZZLE_A , VK_COMPONENT_SWIZZLE_R , VK_COMPONENT_SWIZZLE_G , VK_COMPONENT_SWIZZLE_B } ;
const VkComponentMapping VULKAN_1555_SWIZZLE = { VK_COMPONENT_SWIZZLE_B , VK_COMPONENT_SWIZZLE_G , VK_COMPONENT_SWIZZLE_R , VK_COMPONENT_SWIZZLE_A } ;
const VkComponentMapping VULKAN_565_SWIZZLE = { VK_COMPONENT_SWIZZLE_IDENTITY , VK_COMPONENT_SWIZZLE_IDENTITY , VK_COMPONENT_SWIZZLE_IDENTITY , VK_COMPONENT_SWIZZLE_IDENTITY } ;
const VkComponentMapping VULKAN_8888_SWIZZLE = { VK_COMPONENT_SWIZZLE_IDENTITY , VK_COMPONENT_SWIZZLE_IDENTITY , VK_COMPONENT_SWIZZLE_IDENTITY , VK_COMPONENT_SWIZZLE_IDENTITY } ;
2016-03-28 22:14:04 +02:00
VkShaderModule CompileShaderModule ( VulkanContext * vulkan , VkShaderStageFlagBits stage , const char * code , std : : string * error ) {
std : : vector < uint32_t > spirv ;
2020-10-30 23:29:18 +01:00
bool success = GLSLtoSPV ( stage , code , GLSLVariant : : VULKAN , spirv , error ) ;
2016-03-28 22:14:04 +02:00
if ( ! error - > empty ( ) ) {
if ( success ) {
ERROR_LOG ( G3D , " Warnings in shader compilation! " ) ;
} else {
ERROR_LOG ( G3D , " Error in shader compilation! " ) ;
}
ERROR_LOG ( G3D , " Messages: %s " , error - > c_str ( ) ) ;
2017-12-11 12:22:24 +01:00
ERROR_LOG ( G3D , " Shader source: \n %s " , LineNumberString ( code ) . c_str ( ) ) ;
2016-03-28 22:14:04 +02:00
OutputDebugStringUTF8 ( " Messages: \n " ) ;
OutputDebugStringUTF8 ( error - > c_str ( ) ) ;
2021-11-07 15:47:05 +01:00
OutputDebugStringUTF8 ( LineNumberString ( code ) . c_str ( ) ) ;
2016-03-28 22:14:04 +02:00
return VK_NULL_HANDLE ;
} else {
VkShaderModule module ;
2022-09-07 19:29:54 +02:00
if ( vulkan - > CreateShaderModule ( spirv , & module , stage = = VK_SHADER_STAGE_VERTEX_BIT ? " system_vs " : " system_fs " ) ) {
2016-03-28 22:14:04 +02:00
return module ;
} else {
return VK_NULL_HANDLE ;
}
}
2016-10-09 10:38:25 -07:00
}
2017-12-11 11:26:05 +01:00
2017-12-11 13:23:06 +01:00
VulkanComputeShaderManager : : VulkanComputeShaderManager ( VulkanContext * vulkan ) : vulkan_ ( vulkan ) , pipelines_ ( 8 ) {
2017-12-11 11:26:05 +01:00
}
2017-12-11 13:23:06 +01:00
VulkanComputeShaderManager : : ~ VulkanComputeShaderManager ( ) { }
2017-12-11 11:26:05 +01:00
2017-12-11 13:23:06 +01:00
void VulkanComputeShaderManager : : InitDeviceObjects ( ) {
2017-12-11 12:22:24 +01:00
VkPipelineCacheCreateInfo pc { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO } ;
VkResult res = vkCreatePipelineCache ( vulkan_ - > GetDevice ( ) , & pc , nullptr , & pipelineCache_ ) ;
2020-08-16 00:38:55 +02:00
_assert_ ( VK_SUCCESS = = res ) ;
2017-12-11 11:26:05 +01:00
2017-12-11 13:23:06 +01:00
VkDescriptorSetLayoutBinding bindings [ 3 ] = { } ;
2017-12-11 11:26:05 +01:00
bindings [ 0 ] . descriptorCount = 1 ;
2017-12-11 13:23:06 +01:00
bindings [ 0 ] . descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ;
2017-12-11 11:26:05 +01:00
bindings [ 0 ] . stageFlags = VK_SHADER_STAGE_COMPUTE_BIT ;
bindings [ 0 ] . binding = 0 ;
bindings [ 1 ] . descriptorCount = 1 ;
2017-12-11 13:23:06 +01:00
bindings [ 1 ] . descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ;
2017-12-11 11:26:05 +01:00
bindings [ 1 ] . stageFlags = VK_SHADER_STAGE_COMPUTE_BIT ;
bindings [ 1 ] . binding = 1 ;
2017-12-11 13:23:06 +01:00
bindings [ 2 ] . descriptorCount = 1 ;
bindings [ 2 ] . descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ;
bindings [ 2 ] . stageFlags = VK_SHADER_STAGE_COMPUTE_BIT ;
bindings [ 2 ] . binding = 2 ;
2017-12-11 11:26:05 +01:00
VkDevice device = vulkan_ - > GetDevice ( ) ;
VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO } ;
2017-12-11 13:23:06 +01:00
dsl . bindingCount = ARRAY_SIZE ( bindings ) ;
2017-12-11 11:26:05 +01:00
dsl . pBindings = bindings ;
2017-12-11 12:22:24 +01:00
res = vkCreateDescriptorSetLayout ( device , & dsl , nullptr , & descriptorSetLayout_ ) ;
2020-08-16 00:38:55 +02:00
_assert_ ( VK_SUCCESS = = res ) ;
2017-12-11 11:26:05 +01:00
2021-12-09 19:03:17 -08:00
std : : vector < VkDescriptorPoolSize > dpTypes ;
dpTypes . resize ( 2 ) ;
2017-12-11 20:23:10 +01:00
dpTypes [ 0 ] . descriptorCount = 8192 ;
2017-12-11 11:26:05 +01:00
dpTypes [ 0 ] . type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ;
2017-12-11 20:23:10 +01:00
dpTypes [ 1 ] . descriptorCount = 4096 ;
2017-12-11 11:26:05 +01:00
dpTypes [ 1 ] . type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ;
VkDescriptorPoolCreateInfo dp = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO } ;
dp . flags = 0 ; // Don't want to mess around with individually freeing these, let's go fixed each frame and zap the whole array. Might try the dynamic approach later.
2017-12-11 20:23:10 +01:00
dp . maxSets = 4096 ; // GTA can end up creating more than 1000 textures in the first frame!
2021-12-09 19:03:17 -08:00
2017-12-11 11:26:05 +01:00
for ( int i = 0 ; i < ARRAY_SIZE ( frameData_ ) ; i + + ) {
2021-12-09 19:03:17 -08:00
frameData_ [ i ] . descPool . Create ( vulkan_ , dp , dpTypes ) ;
2017-12-11 11:26:05 +01:00
}
VkPushConstantRange push = { } ;
push . offset = 0 ;
2017-12-11 12:22:24 +01:00
push . size = 16 ;
2017-12-11 11:26:05 +01:00
push . stageFlags = VK_SHADER_STAGE_COMPUTE_BIT ;
VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO } ;
pl . pPushConstantRanges = & push ;
pl . pushConstantRangeCount = 1 ;
pl . setLayoutCount = 1 ;
pl . pSetLayouts = & descriptorSetLayout_ ;
pl . flags = 0 ;
res = vkCreatePipelineLayout ( device , & pl , nullptr , & pipelineLayout_ ) ;
2020-08-16 00:38:55 +02:00
_assert_ ( VK_SUCCESS = = res ) ;
2017-12-11 11:26:05 +01:00
}
2017-12-11 13:23:06 +01:00
void VulkanComputeShaderManager : : DestroyDeviceObjects ( ) {
2017-12-11 11:26:05 +01:00
for ( int i = 0 ; i < ARRAY_SIZE ( frameData_ ) ; i + + ) {
2021-12-09 19:03:17 -08:00
frameData_ [ i ] . descPool . Destroy ( ) ;
2017-12-11 11:26:05 +01:00
}
if ( descriptorSetLayout_ ) {
vulkan_ - > Delete ( ) . QueueDeleteDescriptorSetLayout ( descriptorSetLayout_ ) ;
}
pipelines_ . Iterate ( [ & ] ( const PipelineKey & key , VkPipeline pipeline ) {
vulkan_ - > Delete ( ) . QueueDeletePipeline ( pipeline ) ;
} ) ;
pipelines_ . Clear ( ) ;
if ( pipelineLayout_ ) {
vulkan_ - > Delete ( ) . QueueDeletePipelineLayout ( pipelineLayout_ ) ;
}
if ( pipelineCache_ ! = VK_NULL_HANDLE ) {
vulkan_ - > Delete ( ) . QueueDeletePipelineCache ( pipelineCache_ ) ;
}
}
2017-12-11 13:23:06 +01:00
VkDescriptorSet VulkanComputeShaderManager : : GetDescriptorSet ( VkImageView image , VkBuffer buffer , VkDeviceSize offset , VkDeviceSize range , VkBuffer buffer2 , VkDeviceSize offset2 , VkDeviceSize range2 ) {
2017-12-11 11:26:05 +01:00
int curFrame = vulkan_ - > GetCurFrame ( ) ;
2017-12-11 20:23:10 +01:00
FrameData & frameData = frameData_ [ curFrame ] ;
2022-10-26 13:29:56 +02:00
VkDescriptorSet desc = frameData . descPool . Allocate ( 1 , & descriptorSetLayout_ , " compute_descset " ) ;
2021-12-09 19:03:17 -08:00
_assert_ ( desc ! = VK_NULL_HANDLE ) ;
2017-12-11 11:26:05 +01:00
VkWriteDescriptorSet writes [ 2 ] { } ;
int n = 0 ;
VkDescriptorImageInfo imageInfo = { } ;
2017-12-11 13:23:06 +01:00
VkDescriptorBufferInfo bufferInfo [ 2 ] = { } ;
if ( image ) {
imageInfo . imageLayout = VK_IMAGE_LAYOUT_GENERAL ;
imageInfo . imageView = image ;
imageInfo . sampler = VK_NULL_HANDLE ;
writes [ n ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writes [ n ] . dstBinding = 0 ;
writes [ n ] . pImageInfo = & imageInfo ;
writes [ n ] . descriptorCount = 1 ;
writes [ n ] . descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ;
writes [ n ] . dstSet = desc ;
n + + ;
}
bufferInfo [ 0 ] . buffer = buffer ;
bufferInfo [ 0 ] . offset = offset ;
bufferInfo [ 0 ] . range = range ;
2017-12-11 11:26:05 +01:00
writes [ n ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writes [ n ] . dstBinding = 1 ;
2017-12-11 13:23:06 +01:00
writes [ n ] . pBufferInfo = & bufferInfo [ 0 ] ;
2017-12-11 11:26:05 +01:00
writes [ n ] . descriptorCount = 1 ;
2017-12-11 13:23:06 +01:00
writes [ n ] . descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ;
2017-12-11 11:26:05 +01:00
writes [ n ] . dstSet = desc ;
n + + ;
2017-12-11 13:23:06 +01:00
if ( buffer2 ) {
bufferInfo [ 1 ] . buffer = buffer2 ;
bufferInfo [ 1 ] . offset = offset2 ;
bufferInfo [ 1 ] . range = range2 ;
writes [ n ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writes [ n ] . dstBinding = 2 ;
writes [ n ] . pBufferInfo = & bufferInfo [ 1 ] ;
writes [ n ] . descriptorCount = 1 ;
writes [ n ] . descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ;
writes [ n ] . dstSet = desc ;
n + + ;
}
2017-12-11 11:26:05 +01:00
vkUpdateDescriptorSets ( vulkan_ - > GetDevice ( ) , n , writes , 0 , nullptr ) ;
return desc ;
}
2017-12-11 13:23:06 +01:00
VkPipeline VulkanComputeShaderManager : : GetPipeline ( VkShaderModule cs ) {
2017-12-11 11:26:05 +01:00
PipelineKey key { cs } ;
VkPipeline pipeline = pipelines_ . Get ( key ) ;
if ( pipeline )
return pipeline ;
VkComputePipelineCreateInfo pci { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO } ;
pci . stage . sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO ;
pci . stage . module = cs ;
pci . stage . pName = " main " ;
2017-12-11 12:22:24 +01:00
pci . stage . stage = VK_SHADER_STAGE_COMPUTE_BIT ;
2017-12-11 11:26:05 +01:00
pci . layout = pipelineLayout_ ;
pci . flags = 0 ;
2020-09-15 23:09:58 +02:00
VkResult res = vkCreateComputePipelines ( vulkan_ - > GetDevice ( ) , pipelineCache_ , 1 , & pci , nullptr , & pipeline ) ;
_assert_ ( res = = VK_SUCCESS ) ;
2017-12-11 11:26:05 +01:00
pipelines_ . Insert ( key , pipeline ) ;
return pipeline ;
2017-12-11 12:22:24 +01:00
}
2017-12-11 13:23:06 +01:00
void VulkanComputeShaderManager : : BeginFrame ( ) {
2017-12-11 12:22:24 +01:00
int curFrame = vulkan_ - > GetCurFrame ( ) ;
FrameData & frame = frameData_ [ curFrame ] ;
2021-12-09 19:03:17 -08:00
frame . descPool . Reset ( ) ;
2017-12-11 12:22:24 +01:00
}
2017-12-11 13:23:06 +01:00
void VulkanComputeShaderManager : : EndFrame ( ) {
2017-12-11 12:22:24 +01:00
}