2015-10-10 16:41:19 +02:00
// Copyright (c) 2015- 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-12-25 18:18:19 +01:00
# include <cstdio>
2015-10-10 16:41:19 +02:00
# include <vector>
# include <string>
# include <map>
2020-10-04 10:10:55 +02:00
# include "Common/System/Display.h"
2020-10-04 00:25:21 +02:00
# include "Common/Math/lin/matrix4x4.h"
# include "Common/Data/Convert/SmallDataConvert.h"
2020-10-04 23:24:14 +02:00
# include "Common/GPU/thin3d.h"
# include "Common/GPU/Vulkan/VulkanRenderManager.h"
2016-03-17 11:56:43 +01:00
2020-08-15 16:13:24 +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"
# include "Common/GPU/Vulkan/VulkanImage.h"
# include "Common/GPU/Vulkan/VulkanMemory.h"
2022-09-06 13:30:18 +02:00
# include "Common/Thread/Promise.h"
2015-10-10 16:41:19 +02:00
2020-08-15 16:13:24 +02:00
# include "Core/Config.h"
2020-10-04 23:24:14 +02:00
# include "Common/GPU/Vulkan/VulkanLoader.h"
2015-10-10 16:41:19 +02:00
2022-10-28 09:23:44 +02:00
// We support a frame-global descriptor set, which can be optionally used by other code,
// but is not directly used by thin3d. It has to be defined here though, be in set 0
// and specified in every pipeline layout, otherwise it can't sit undisturbed when other
// descriptor sets are bound on top.
// For descriptor set 1, we use a simple descriptor set for all thin3d rendering: 1 UBO binding point, 3 combined texture/samples.
//
// binding 0 - uniform buffer
// binding 1 - texture/sampler
// binding 2 - texture/sampler
// binding 3 - texture/sampler
//
// Vertex data lives in a separate namespace (location = 0, 1, etc).
2021-08-21 12:39:15 +02:00
using namespace PPSSPP_VK ;
2021-08-20 11:22:57 +02:00
2016-12-25 18:18:19 +01:00
namespace Draw {
2015-10-10 16:41:19 +02:00
// This can actually be replaced with a cast as the values are in the right order.
static const VkCompareOp compToVK [ ] = {
VK_COMPARE_OP_NEVER ,
VK_COMPARE_OP_LESS ,
VK_COMPARE_OP_EQUAL ,
VK_COMPARE_OP_LESS_OR_EQUAL ,
VK_COMPARE_OP_GREATER ,
VK_COMPARE_OP_NOT_EQUAL ,
VK_COMPARE_OP_GREATER_OR_EQUAL ,
VK_COMPARE_OP_ALWAYS
} ;
// So can this.
2016-12-26 18:32:52 +01:00
static const VkBlendOp blendEqToVk [ ] = {
2015-10-10 16:41:19 +02:00
VK_BLEND_OP_ADD ,
VK_BLEND_OP_SUBTRACT ,
VK_BLEND_OP_REVERSE_SUBTRACT ,
2016-12-26 23:51:17 +01:00
VK_BLEND_OP_MIN ,
VK_BLEND_OP_MAX ,
2015-10-10 16:41:19 +02:00
} ;
static const VkBlendFactor blendFactorToVk [ ] = {
VK_BLEND_FACTOR_ZERO ,
VK_BLEND_FACTOR_ONE ,
VK_BLEND_FACTOR_SRC_COLOR ,
VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR ,
VK_BLEND_FACTOR_DST_COLOR ,
VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR ,
2016-12-26 23:51:17 +01:00
VK_BLEND_FACTOR_SRC_ALPHA ,
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA ,
VK_BLEND_FACTOR_DST_ALPHA ,
2015-10-10 16:41:19 +02:00
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA ,
VK_BLEND_FACTOR_CONSTANT_COLOR ,
2016-12-26 23:51:17 +01:00
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR ,
VK_BLEND_FACTOR_CONSTANT_ALPHA ,
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA ,
VK_BLEND_FACTOR_SRC1_COLOR ,
VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR ,
VK_BLEND_FACTOR_SRC1_ALPHA ,
VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA ,
2015-10-10 16:41:19 +02:00
} ;
static const VkLogicOp logicOpToVK [ ] = {
VK_LOGIC_OP_CLEAR ,
VK_LOGIC_OP_SET ,
VK_LOGIC_OP_COPY ,
VK_LOGIC_OP_COPY_INVERTED ,
VK_LOGIC_OP_NO_OP ,
VK_LOGIC_OP_INVERT ,
VK_LOGIC_OP_AND ,
VK_LOGIC_OP_NAND ,
VK_LOGIC_OP_OR ,
VK_LOGIC_OP_NOR ,
VK_LOGIC_OP_XOR ,
VK_LOGIC_OP_EQUIVALENT ,
VK_LOGIC_OP_AND_REVERSE ,
VK_LOGIC_OP_AND_INVERTED ,
VK_LOGIC_OP_OR_REVERSE ,
VK_LOGIC_OP_OR_INVERTED ,
} ;
static const VkPrimitiveTopology primToVK [ ] = {
VK_PRIMITIVE_TOPOLOGY_POINT_LIST ,
VK_PRIMITIVE_TOPOLOGY_LINE_LIST ,
2016-12-25 18:52:05 +01:00
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP ,
2015-10-10 16:41:19 +02:00
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ,
2016-12-25 18:52:05 +01:00
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP ,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN ,
2017-01-21 13:11:03 +01:00
// Tesselation shader primitive.
2016-12-25 18:52:05 +01:00
VK_PRIMITIVE_TOPOLOGY_PATCH_LIST ,
2017-01-21 13:11:03 +01:00
// The rest are for geometry shaders only.
2016-12-25 18:52:05 +01:00
VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY ,
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY ,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY ,
2015-10-10 16:41:19 +02:00
} ;
2016-12-26 23:11:31 +01:00
static const VkStencilOp stencilOpToVK [ 8 ] = {
VK_STENCIL_OP_KEEP ,
VK_STENCIL_OP_ZERO ,
VK_STENCIL_OP_REPLACE ,
VK_STENCIL_OP_INCREMENT_AND_CLAMP ,
VK_STENCIL_OP_DECREMENT_AND_CLAMP ,
VK_STENCIL_OP_INVERT ,
VK_STENCIL_OP_INCREMENT_AND_WRAP ,
VK_STENCIL_OP_DECREMENT_AND_WRAP ,
} ;
2016-12-25 21:21:56 +01:00
class VKBlendState : public BlendState {
2015-10-10 16:41:19 +02:00
public :
2016-12-26 23:11:31 +01:00
VkPipelineColorBlendStateCreateInfo info { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO } ;
2016-12-26 18:32:52 +01:00
std : : vector < VkPipelineColorBlendAttachmentState > attachments ;
2015-10-10 16:41:19 +02:00
} ;
2016-12-25 21:21:56 +01:00
class VKDepthStencilState : public DepthStencilState {
2015-10-10 16:41:19 +02:00
public :
2016-12-26 23:11:31 +01:00
VkPipelineDepthStencilStateCreateInfo info { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO } ;
2015-10-10 16:41:19 +02:00
} ;
2016-12-25 21:21:56 +01:00
class VKRasterState : public RasterState {
2016-12-23 23:46:11 +01:00
public :
2016-12-25 22:24:14 +01:00
VKRasterState ( VulkanContext * vulkan , const RasterStateDesc & desc ) {
2016-12-23 23:46:11 +01:00
cullFace = desc . cull ;
2016-12-27 15:52:03 +01:00
frontFace = desc . frontFace ;
2016-12-23 23:46:11 +01:00
}
2016-12-25 18:52:05 +01:00
Facing frontFace ;
CullMode cullFace ;
2016-12-23 23:46:11 +01:00
2016-12-26 17:03:01 +01:00
void ToVulkan ( VkPipelineRasterizationStateCreateInfo * info ) const {
2016-12-23 23:46:11 +01:00
memset ( info , 0 , sizeof ( * info ) ) ;
info - > sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO ;
2016-12-25 18:52:05 +01:00
info - > frontFace = frontFace = = Facing : : CCW ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE ;
2016-12-23 23:46:11 +01:00
switch ( cullFace ) {
2016-12-25 18:52:05 +01:00
case CullMode : : BACK : info - > cullMode = VK_CULL_MODE_BACK_BIT ; break ;
case CullMode : : FRONT : info - > cullMode = VK_CULL_MODE_FRONT_BIT ; break ;
case CullMode : : FRONT_AND_BACK : info - > cullMode = VK_CULL_MODE_FRONT_AND_BACK ; break ;
case CullMode : : NONE : info - > cullMode = VK_CULL_MODE_NONE ; break ;
2016-12-23 23:46:11 +01:00
}
info - > polygonMode = VK_POLYGON_MODE_FILL ;
info - > lineWidth = 1.0f ;
}
} ;
2016-12-25 22:24:14 +01:00
VkShaderStageFlagBits StageToVulkan ( ShaderStage stage ) {
switch ( stage ) {
2020-11-05 08:34:35 +01:00
case ShaderStage : : Vertex : return VK_SHADER_STAGE_VERTEX_BIT ;
case ShaderStage : : Geometry : return VK_SHADER_STAGE_GEOMETRY_BIT ;
case ShaderStage : : Compute : return VK_SHADER_STAGE_COMPUTE_BIT ;
case ShaderStage : : Fragment : return VK_SHADER_STAGE_FRAGMENT_BIT ;
2016-12-25 22:24:14 +01:00
}
2022-10-01 14:57:00 -07:00
return VK_SHADER_STAGE_FRAGMENT_BIT ;
2016-12-25 22:24:14 +01:00
}
2016-12-26 13:42:53 +01:00
// Not registering this as a resource holder, instead the pipeline is registered. It will
2015-10-10 16:41:19 +02:00
// invoke Compile again to recreate the shader then link them together.
2016-12-25 22:24:14 +01:00
class VKShaderModule : public ShaderModule {
2015-10-10 16:41:19 +02:00
public :
2020-05-10 15:06:17 -07:00
VKShaderModule ( ShaderStage stage , const std : : string & tag ) : stage_ ( stage ) , tag_ ( tag ) {
2016-12-25 22:24:14 +01:00
vkstage_ = StageToVulkan ( stage ) ;
2015-10-10 16:41:19 +02:00
}
2016-12-27 17:38:26 +01:00
bool Compile ( VulkanContext * vulkan , ShaderLanguage language , const uint8_t * data , size_t size ) ;
2015-10-10 16:41:19 +02:00
const std : : string & GetSource ( ) const { return source_ ; }
2016-12-25 22:24:14 +01:00
~ VKShaderModule ( ) {
2016-05-14 16:29:40 +02:00
if ( module_ ) {
2022-09-08 00:22:45 +02:00
DEBUG_LOG ( G3D , " Queueing %s (shmodule %p) for release " , tag_ . c_str ( ) , module_ ) ;
2022-09-23 13:31:32 +02:00
VkShaderModule shaderModule = module_ - > BlockUntilReady ( ) ;
vulkan_ - > Delete ( ) . QueueDeleteShaderModule ( shaderModule ) ;
2022-12-03 14:53:10 -08:00
vulkan_ - > Delete ( ) . QueueCallback ( [ ] ( void * m ) {
auto module = ( Promise < VkShaderModule > * ) m ;
delete module ;
} , module_ ) ;
2016-05-14 16:29:40 +02:00
}
2015-10-10 16:41:19 +02:00
}
2022-09-23 13:31:32 +02:00
Promise < VkShaderModule > * Get ( ) const { return module_ ; }
2016-12-25 22:24:14 +01:00
ShaderStage GetStage ( ) const override {
return stage_ ;
}
2015-10-10 16:41:19 +02:00
private :
2017-11-09 16:58:59 +01:00
VulkanContext * vulkan_ ;
2022-09-23 13:31:32 +02:00
Promise < VkShaderModule > * module_ = nullptr ;
2016-12-25 22:24:14 +01:00
VkShaderStageFlagBits vkstage_ ;
2020-05-10 15:06:17 -07:00
bool ok_ = false ;
2016-12-25 22:24:14 +01:00
ShaderStage stage_ ;
2015-10-10 16:41:19 +02:00
std : : string source_ ; // So we can recompile in case of context loss.
2020-05-10 15:06:17 -07:00
std : : string tag_ ;
2015-10-10 16:41:19 +02:00
} ;
2016-12-27 17:38:26 +01:00
bool VKShaderModule : : Compile ( VulkanContext * vulkan , ShaderLanguage language , const uint8_t * data , size_t size ) {
2016-03-21 00:03:34 -07:00
// We'll need this to free it later.
2022-10-01 11:37:10 -07:00
vulkan_ = vulkan ;
2017-11-09 16:58:59 +01:00
source_ = ( const char * ) data ;
2015-10-10 16:41:19 +02:00
std : : vector < uint32_t > spirv ;
2020-10-30 23:29:18 +01:00
std : : string errorMessage ;
if ( ! GLSLtoSPV ( vkstage_ , source_ . c_str ( ) , GLSLVariant : : VULKAN , spirv , & errorMessage ) ) {
2022-09-07 23:55:33 +02:00
WARN_LOG ( G3D , " Shader compile to module failed (%s): %s " , tag_ . c_str ( ) , errorMessage . c_str ( ) ) ;
2015-10-10 16:41:19 +02:00
return false ;
}
2016-01-06 12:52:08 +01:00
// Just for kicks, sanity check the SPIR-V. The disasm isn't perfect
// but gives you some idea of what's going on.
#if 0
std : : string disasm ;
if ( DisassembleSPIRV ( spirv , & disasm ) ) {
OutputDebugStringA ( disasm . c_str ( ) ) ;
}
# endif
2022-09-23 13:31:32 +02:00
VkShaderModule shaderModule = VK_NULL_HANDLE ;
2022-12-01 23:41:31 +01:00
if ( vulkan - > CreateShaderModule ( spirv , & shaderModule , tag_ . c_str ( ) ) ) {
2022-09-23 13:31:32 +02:00
module_ = Promise < VkShaderModule > : : AlreadyDone ( shaderModule ) ;
2015-10-10 16:41:19 +02:00
ok_ = true ;
} else {
2022-09-07 23:55:33 +02:00
WARN_LOG ( G3D , " vkCreateShaderModule failed (%s) " , tag_ . c_str ( ) ) ;
2015-10-10 16:41:19 +02:00
ok_ = false ;
}
return ok_ ;
}
2016-12-26 13:22:48 +01:00
class VKInputLayout : public InputLayout {
2015-10-10 16:41:19 +02:00
public :
2016-12-26 13:22:48 +01:00
std : : vector < VkVertexInputBindingDescription > bindings ;
std : : vector < VkVertexInputAttributeDescription > attributes ;
VkPipelineVertexInputStateCreateInfo visc ;
2015-10-10 16:41:19 +02:00
} ;
2016-12-26 11:06:17 +01:00
class VKPipeline : public Pipeline {
2015-10-10 16:41:19 +02:00
public :
2022-09-08 00:22:45 +02:00
VKPipeline ( VulkanContext * vulkan , size_t size , PipelineFlags _flags , const char * tag ) : vulkan_ ( vulkan ) , flags ( _flags ) , tag_ ( tag ) {
2017-02-08 12:55:58 +01:00
uboSize_ = ( int ) size ;
2015-10-10 16:41:19 +02:00
ubo_ = new uint8_t [ uboSize_ ] ;
2022-12-03 14:52:06 -08:00
vkrDesc = new VKRGraphicsPipelineDesc ( ) ;
2015-10-10 16:41:19 +02:00
}
2016-12-26 11:06:17 +01:00
~ VKPipeline ( ) {
2022-09-08 00:22:45 +02:00
DEBUG_LOG ( G3D , " Queueing %s (pipeline) for release " , tag_ . c_str ( ) ) ;
2022-09-07 16:11:15 +02:00
if ( pipeline ) {
pipeline - > QueueForDeletion ( vulkan_ ) ;
}
2022-09-08 00:22:45 +02:00
for ( auto dep : deps ) {
dep - > Release ( ) ;
}
2016-01-10 14:24:10 +01:00
delete [ ] ubo_ ;
2022-12-03 14:52:06 -08:00
vkrDesc - > Release ( ) ;
2015-10-10 16:41:19 +02:00
}
2017-02-08 12:26:48 +01:00
void SetDynamicUniformData ( const void * data , size_t size ) {
2022-10-22 17:34:23 +02:00
_dbg_assert_ ( size < = uboSize_ ) ;
2017-02-08 12:26:48 +01:00
memcpy ( ubo_ , data , size ) ;
}
2016-03-20 09:52:13 +01:00
// Returns the binding offset, and the VkBuffer to bind.
size_t PushUBO ( VulkanPushBuffer * buf , VulkanContext * vulkan , VkBuffer * vkbuf ) {
2019-02-05 10:05:22 +01:00
return buf - > PushAligned ( ubo_ , uboSize_ , vulkan - > GetPhysicalDeviceProperties ( ) . properties . limits . minUniformBufferOffsetAlignment , vkbuf ) ;
2015-10-10 16:41:19 +02:00
}
2016-01-02 02:08:05 +01:00
int GetUBOSize ( ) const {
return uboSize_ ;
}
2022-09-06 13:30:18 +02:00
VKRGraphicsPipeline * pipeline = nullptr ;
2022-12-03 14:52:06 -08:00
VKRGraphicsPipelineDesc * vkrDesc = nullptr ;
2020-10-11 11:47:24 +02:00
PipelineFlags flags ;
2022-09-06 13:30:18 +02:00
2022-09-08 00:22:45 +02:00
std : : vector < VKShaderModule * > deps ;
2017-02-08 12:26:48 +01:00
int stride [ 4 ] { } ;
int dynamicUniformSize = 0 ;
2015-10-10 16:41:19 +02:00
2018-12-18 09:35:53 +01:00
bool usesStencil = false ;
2015-10-10 16:41:19 +02:00
private :
2022-09-07 16:11:15 +02:00
VulkanContext * vulkan_ ;
2015-10-10 16:41:19 +02:00
uint8_t * ubo_ ;
int uboSize_ ;
2022-09-08 00:22:45 +02:00
std : : string tag_ ;
2015-10-10 16:41:19 +02:00
} ;
2016-12-25 21:21:56 +01:00
class VKTexture ;
2017-02-07 19:04:44 +01:00
class VKBuffer ;
2016-12-25 21:21:56 +01:00
class VKSamplerState ;
2015-10-10 16:41:19 +02:00
2020-05-17 10:50:11 -07:00
enum {
2021-06-12 10:10:42 -07:00
MAX_BOUND_TEXTURES = MAX_TEXTURE_SLOTS ,
2020-05-17 10:50:11 -07:00
} ;
2015-10-10 16:41:19 +02:00
struct DescriptorSetKey {
2020-05-17 10:50:11 -07:00
VkImageView imageViews_ [ MAX_BOUND_TEXTURES ] ;
VKSamplerState * samplers_ [ MAX_BOUND_TEXTURES ] ;
2016-03-20 09:52:13 +01:00
VkBuffer buffer_ ;
2015-10-10 16:41:19 +02:00
bool operator < ( const DescriptorSetKey & other ) const {
2020-05-17 10:50:11 -07:00
for ( int i = 0 ; i < MAX_BOUND_TEXTURES ; + + i ) {
if ( imageViews_ [ i ] < other . imageViews_ [ i ] ) return true ; else if ( imageViews_ [ i ] > other . imageViews_ [ i ] ) return false ;
if ( samplers_ [ i ] < other . samplers_ [ i ] ) return true ; else if ( samplers_ [ i ] > other . samplers_ [ i ] ) return false ;
}
2016-01-03 13:27:19 +01:00
if ( buffer_ < other . buffer_ ) return true ; else if ( buffer_ > other . buffer_ ) return false ;
2015-10-10 16:41:19 +02:00
return false ;
}
} ;
2017-05-19 17:21:08 +02:00
class VKTexture : public Texture {
public :
2018-11-21 17:33:30 +01:00
VKTexture ( VulkanContext * vulkan , VkCommandBuffer cmd , VulkanPushBuffer * pushBuffer , const TextureDesc & desc )
: vulkan_ ( vulkan ) , mipLevels_ ( desc . mipLevels ) , format_ ( desc . format ) { }
2021-11-21 23:38:14 +01:00
bool Create ( VkCommandBuffer cmd , VulkanPushBuffer * pushBuffer , const TextureDesc & desc ) ;
2017-05-19 17:21:08 +02:00
~ VKTexture ( ) {
Destroy ( ) ;
}
2018-04-06 21:32:33 -07:00
VkImageView GetImageView ( ) {
2018-05-27 21:54:07 +02:00
if ( vkTex_ ) {
return vkTex_ - > GetImageView ( ) ;
}
2022-10-25 23:32:28 +02:00
return VK_NULL_HANDLE ; // This would be bad.
}
VkImageView GetImageArrayView ( ) {
if ( vkTex_ ) {
return vkTex_ - > GetImageArrayView ( ) ;
}
return VK_NULL_HANDLE ; // This would be bad.
2018-04-06 21:32:33 -07:00
}
2017-05-19 17:21:08 +02:00
private :
void Destroy ( ) {
if ( vkTex_ ) {
vkTex_ - > Destroy ( ) ;
delete vkTex_ ;
2017-08-18 13:39:42 +02:00
vkTex_ = nullptr ;
2017-05-19 17:21:08 +02:00
}
}
VulkanContext * vulkan_ ;
2017-11-11 17:45:47 -08:00
VulkanTexture * vkTex_ = nullptr ;
2017-05-19 17:21:08 +02:00
2018-11-21 17:33:30 +01:00
int mipLevels_ = 0 ;
2017-05-19 17:21:08 +02:00
2018-11-21 17:33:30 +01:00
DataFormat format_ = DataFormat : : UNDEFINED ;
2017-05-19 17:21:08 +02:00
} ;
2017-10-31 10:54:01 +01:00
class VKFramebuffer ;
2016-12-25 21:21:56 +01:00
class VKContext : public DrawContext {
2015-10-10 16:41:19 +02:00
public :
2022-09-17 00:36:43 +02:00
VKContext ( VulkanContext * vulkan ) ;
2022-12-10 20:32:12 -08:00
~ VKContext ( ) ;
2015-10-10 16:41:19 +02:00
2022-10-13 22:34:21 +02:00
void DebugAnnotate ( const char * annotation ) override ;
2016-12-26 17:31:20 +01:00
const DeviceCaps & GetDeviceCaps ( ) const override {
return caps_ ;
}
2018-04-15 09:56:37 +02:00
std : : vector < std : : string > GetDeviceList ( ) const override {
std : : vector < std : : string > list ;
for ( int i = 0 ; i < vulkan_ - > GetNumPhysicalDevices ( ) ; i + + ) {
2019-02-05 10:05:22 +01:00
list . push_back ( vulkan_ - > GetPhysicalDeviceProperties ( i ) . properties . deviceName ) ;
2018-04-15 09:56:37 +02:00
}
return list ;
}
2016-12-27 16:33:54 +01:00
uint32_t GetSupportedShaderLanguages ( ) const override {
2018-12-16 20:18:40 +01:00
return ( uint32_t ) ShaderLanguage : : GLSL_VULKAN ;
2016-12-27 16:33:54 +01:00
}
2017-01-19 12:16:36 +07:00
uint32_t GetDataFormatSupport ( DataFormat fmt ) const override ;
2016-12-26 17:31:20 +01:00
2016-12-25 21:10:46 +01:00
DepthStencilState * CreateDepthStencilState ( const DepthStencilStateDesc & desc ) override ;
2016-12-25 18:52:05 +01:00
BlendState * CreateBlendState ( const BlendStateDesc & desc ) override ;
2016-12-26 13:22:48 +01:00
InputLayout * CreateInputLayout ( const InputLayoutDesc & desc ) override ;
2016-12-25 20:54:37 +01:00
SamplerState * CreateSamplerState ( const SamplerStateDesc & desc ) override ;
2016-12-25 22:24:14 +01:00
RasterState * CreateRasterState ( const RasterStateDesc & desc ) override ;
2022-09-07 23:55:33 +02:00
Pipeline * CreateGraphicsPipeline ( const PipelineDesc & desc , const char * tag ) override ;
ShaderModule * CreateShaderModule ( ShaderStage stage , ShaderLanguage language , const uint8_t * data , size_t dataSize , const char * tag ) override ;
2016-12-25 22:24:14 +01:00
2017-01-16 23:43:07 +07:00
Texture * CreateTexture ( const TextureDesc & desc ) override ;
2017-02-04 18:46:12 +01:00
Buffer * CreateBuffer ( size_t size , uint32_t usageFlags ) override ;
2017-02-06 11:26:24 +01:00
Framebuffer * CreateFramebuffer ( const FramebufferDesc & desc ) override ;
2017-02-04 18:46:12 +01:00
2017-02-07 19:41:58 +01:00
void UpdateBuffer ( Buffer * buffer , const uint8_t * data , size_t offset , size_t size , UpdateBufferFlags flags ) override ;
2017-02-07 18:16:52 +01:00
2020-05-21 11:24:05 +02:00
void CopyFramebufferImage ( Framebuffer * src , int level , int x , int y , int z , Framebuffer * dst , int dstLevel , int dstX , int dstY , int dstZ , int width , int height , int depth , int channelBits , const char * tag ) override ;
bool BlitFramebuffer ( Framebuffer * src , int srcX1 , int srcY1 , int srcX2 , int srcY2 , Framebuffer * dst , int dstX1 , int dstY1 , int dstX2 , int dstY2 , int channelBits , FBBlitFilter filter , const char * tag ) override ;
bool CopyFramebufferToMemorySync ( Framebuffer * src , int channelBits , int x , int y , int w , int h , Draw : : DataFormat format , void * pixels , int pixelStride , const char * tag ) override ;
2018-06-16 13:47:51 -07:00
DataFormat PreferredFramebufferReadbackFormat ( Framebuffer * src ) override ;
2017-02-04 18:46:12 +01:00
// These functions should be self explanatory.
2022-10-23 11:21:35 +02:00
void BindFramebufferAsRenderTarget ( Framebuffer * fbo , const RenderPassInfo & rp , const char * tag ) override ;
2022-10-18 00:26:10 +02:00
void BindFramebufferAsTexture ( Framebuffer * fbo , int binding , FBChannel channelBit , int layer ) override ;
2022-02-19 20:40:27 +01:00
void BindCurrentFramebufferForColorInput ( ) override ;
2017-02-04 18:46:12 +01:00
2017-02-06 11:26:24 +01:00
void GetFramebufferDimensions ( Framebuffer * fbo , int * w , int * h ) override ;
2015-10-10 16:41:19 +02:00
void SetScissorRect ( int left , int top , int width , int height ) override ;
2016-12-25 18:52:05 +01:00
void SetViewports ( int count , Viewport * viewports ) override ;
2016-12-27 15:52:03 +01:00
void SetBlendFactor ( float color [ 4 ] ) override ;
2022-07-24 16:31:02 +02:00
void SetStencilParams ( uint8_t refValue , uint8_t writeMask , uint8_t compareMask ) override ;
2015-10-10 16:41:19 +02:00
2016-12-26 11:16:59 +01:00
void BindSamplerStates ( int start , int count , SamplerState * * state ) override ;
2022-10-25 23:32:28 +02:00
void BindTextures ( int start , int count , Texture * * textures , TextureBindFlags flags ) override ;
2022-09-14 00:13:29 +02:00
void BindNativeTexture ( int sampler , void * nativeTexture ) override ;
2020-07-13 23:11:52 +02:00
2016-12-26 11:16:59 +01:00
void BindPipeline ( Pipeline * pipeline ) override {
curPipeline_ = ( VKPipeline * ) pipeline ;
}
2015-10-10 16:41:19 +02:00
2017-01-17 23:14:47 +07:00
// TODO: Make VKBuffers proper buffers, and do a proper binding model. This is just silly.
2021-08-07 22:22:11 -07:00
void BindVertexBuffers ( int start , int count , Buffer * * buffers , const int * offsets ) override {
2021-06-12 10:10:42 -07:00
_assert_ ( start + count < = ARRAY_SIZE ( curVBuffers_ ) ) ;
2017-01-17 23:14:47 +07:00
for ( int i = 0 ; i < count ; i + + ) {
curVBuffers_ [ i + start ] = ( VKBuffer * ) buffers [ i ] ;
curVBufferOffsets_ [ i + start ] = offsets ? offsets [ i ] : 0 ;
}
}
void BindIndexBuffer ( Buffer * indexBuffer , int offset ) override {
curIBuffer_ = ( VKBuffer * ) indexBuffer ;
curIBufferOffset_ = offset ;
}
2017-05-06 18:45:04 -07:00
void UpdateDynamicUniformBuffer ( const void * ub , size_t size ) override ;
2017-02-08 12:26:48 +01:00
2015-10-10 16:41:19 +02:00
// TODO: Add more sophisticated draws.
2017-01-17 23:14:47 +07:00
void Draw ( int vertexCount , int offset ) override ;
void DrawIndexed ( int vertexCount , int offset ) override ;
2016-12-26 17:03:01 +01:00
void DrawUP ( const void * vdata , int vertexCount ) override ;
2015-10-10 16:41:19 +02:00
2022-09-06 13:30:18 +02:00
void BindCurrentPipeline ( ) ;
2018-12-18 09:35:53 +01:00
void ApplyDynamicState ( ) ;
2015-10-10 16:41:19 +02:00
void Clear ( int mask , uint32_t colorval , float depthVal , int stencilVal ) override ;
2017-05-16 13:30:10 +02:00
void BeginFrame ( ) override ;
void EndFrame ( ) override ;
2017-11-01 21:42:19 +01:00
void WipeQueue ( ) override ;
2015-10-10 16:41:19 +02:00
2019-02-05 13:10:05 +01:00
void FlushState ( ) override { }
2017-05-21 23:13:53 +02:00
2022-10-10 10:53:27 +02:00
void ResetStats ( ) override {
renderManager_ . ResetStats ( ) ;
}
2016-12-25 18:52:05 +01:00
std : : string GetInfoString ( InfoField info ) const override {
2015-10-10 16:41:19 +02:00
// TODO: Make these actually query the right information
switch ( info ) {
2016-01-03 14:00:05 +01:00
case APINAME : return " Vulkan " ;
2019-02-05 10:05:22 +01:00
case VENDORSTRING : return vulkan_ - > GetPhysicalDeviceProperties ( ) . properties . deviceName ;
case VENDOR : return VulkanVendorString ( vulkan_ - > GetPhysicalDeviceProperties ( ) . properties . vendorID ) ;
case DRIVER : return FormatDriverVersion ( vulkan_ - > GetPhysicalDeviceProperties ( ) . properties ) ;
2015-10-10 16:41:19 +02:00
case SHADELANGVERSION : return " N/A " ; ;
2016-01-03 14:00:05 +01:00
case APIVERSION :
{
2019-02-05 10:05:22 +01:00
uint32_t ver = vulkan_ - > GetPhysicalDeviceProperties ( ) . properties . apiVersion ;
2016-01-03 14:00:05 +01:00
return StringFromFormat ( " %d.%d.%d " , ver > > 22 , ( ver > > 12 ) & 0x3ff , ver & 0xfff ) ;
}
2015-10-10 16:41:19 +02:00
default : return " ? " ;
}
}
2016-03-20 09:52:13 +01:00
VkDescriptorSet GetOrCreateDescriptorSet ( VkBuffer buffer ) ;
2015-10-10 16:41:19 +02:00
2016-12-26 17:31:20 +01:00
std : : vector < std : : string > GetFeatureList ( ) const override ;
2017-08-28 13:45:04 +02:00
std : : vector < std : : string > GetExtensionList ( ) const override ;
2016-01-03 14:00:05 +01:00
2022-02-19 20:40:27 +01:00
uint64_t GetNativeObject ( NativeObject obj , void * srcObject ) override ;
2017-02-05 20:05:03 +01:00
2017-03-05 20:30:39 +01:00
void HandleEvent ( Event ev , int width , int height , void * param1 , void * param2 ) override ;
2017-02-06 11:20:27 +01:00
2022-12-01 19:15:38 +01:00
void Invalidate ( InvalidationFlags flags ) override ;
2020-08-22 00:30:29 +02:00
2022-08-28 23:16:48 +02:00
void InvalidateFramebuffer ( FBInvalidationStage stage , uint32_t channels ) override ;
2022-11-24 12:14:52 +01:00
void SetInvalidationCallback ( InvalidationCallback callback ) override {
2022-11-24 10:38:49 +01:00
renderManager_ . SetInvalidationCallback ( callback ) ;
}
2015-10-10 16:41:19 +02:00
private :
2018-06-01 18:51:37 +02:00
VulkanTexture * GetNullTexture ( ) ;
2017-02-20 11:21:07 +01:00
VulkanContext * vulkan_ = nullptr ;
2015-10-10 16:41:19 +02:00
2017-08-16 23:03:30 +02:00
VulkanRenderManager renderManager_ ;
2018-06-01 18:51:37 +02:00
VulkanTexture * nullTexture_ = nullptr ;
2021-02-16 00:47:26 -08:00
AutoRef < VKPipeline > curPipeline_ ;
AutoRef < VKBuffer > curVBuffers_ [ 4 ] ;
2017-02-20 11:21:07 +01:00
int curVBufferOffsets_ [ 4 ] { } ;
2021-02-16 00:47:26 -08:00
AutoRef < VKBuffer > curIBuffer_ ;
2017-02-20 11:21:07 +01:00
int curIBufferOffset_ = 0 ;
2015-10-10 16:41:19 +02:00
2017-10-31 12:02:10 +01:00
VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE ;
2022-10-28 09:23:44 +02:00
VkDescriptorSetLayout frameDescSetLayout_ = VK_NULL_HANDLE ;
2017-10-31 12:02:10 +01:00
VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE ;
VkPipelineCache pipelineCache_ = VK_NULL_HANDLE ;
2022-02-19 20:40:27 +01:00
AutoRef < VKFramebuffer > curFramebuffer_ ;
2015-10-10 16:41:19 +02:00
VkDevice device_ ;
VkQueue queue_ ;
int queueFamilyIndex_ ;
2017-05-19 17:21:08 +02:00
enum {
2017-05-22 15:29:14 +02:00
MAX_FRAME_COMMAND_BUFFERS = 256 ,
2017-05-19 17:21:08 +02:00
} ;
2021-02-16 00:47:26 -08:00
AutoRef < VKTexture > boundTextures_ [ MAX_BOUND_TEXTURES ] ;
AutoRef < VKSamplerState > boundSamplers_ [ MAX_BOUND_TEXTURES ] ;
2017-10-31 12:02:10 +01:00
VkImageView boundImageView_ [ MAX_BOUND_TEXTURES ] { } ;
2022-10-25 23:59:42 +02:00
TextureBindFlags boundTextureFlags_ [ MAX_BOUND_TEXTURES ] ;
2015-10-10 16:41:19 +02:00
2016-01-03 12:37:05 +01:00
struct FrameData {
2021-12-09 19:03:17 -08:00
FrameData ( ) : descriptorPool ( " VKContext " , false ) {
descriptorPool . Setup ( [ this ] { descSets_ . clear ( ) ; } ) ;
}
VulkanPushBuffer * pushBuffer = nullptr ;
2016-01-03 13:27:19 +01:00
// Per-frame descriptor set cache. As it's per frame and reset every frame, we don't need to
// worry about invalidating descriptors pointing to deleted textures.
2017-05-19 17:21:08 +02:00
// However! ARM is not a fan of doing it this way.
2016-01-03 13:27:19 +01:00
std : : map < DescriptorSetKey , VkDescriptorSet > descSets_ ;
2021-12-09 19:03:17 -08:00
VulkanDescSetPool descriptorPool ;
2016-01-03 12:37:05 +01:00
} ;
2021-12-09 19:03:17 -08:00
FrameData frame_ [ VulkanContext : : MAX_INFLIGHT_FRAMES ] ;
2016-01-03 12:37:05 +01:00
2017-02-20 11:21:07 +01:00
VulkanPushBuffer * push_ = nullptr ;
2016-12-26 17:31:20 +01:00
2017-02-20 11:21:07 +01:00
DeviceCaps caps_ { } ;
2018-12-18 09:35:53 +01:00
uint8_t stencilRef_ = 0 ;
2022-07-24 16:31:02 +02:00
uint8_t stencilWriteMask_ = 0xFF ;
uint8_t stencilCompareMask_ = 0xFF ;
2015-10-10 16:41:19 +02:00
} ;
2017-01-21 13:11:03 +01:00
static int GetBpp ( VkFormat format ) {
2016-12-26 13:22:48 +01:00
switch ( format ) {
case VK_FORMAT_R8G8B8A8_UNORM :
2017-01-21 13:11:03 +01:00
case VK_FORMAT_B8G8R8A8_UNORM :
2016-12-26 13:22:48 +01:00
return 32 ;
2022-09-12 15:34:32 +02:00
case VK_FORMAT_R8_UNORM :
return 8 ;
case VK_FORMAT_R8G8_UNORM :
case VK_FORMAT_R16_UNORM :
return 16 ;
2016-12-26 13:22:48 +01:00
case VK_FORMAT_R4G4B4A4_UNORM_PACK16 :
2017-01-21 13:11:03 +01:00
case VK_FORMAT_B4G4R4A4_UNORM_PACK16 :
case VK_FORMAT_R5G5B5A1_UNORM_PACK16 :
case VK_FORMAT_R5G6B5_UNORM_PACK16 :
case VK_FORMAT_B5G5R5A1_UNORM_PACK16 :
case VK_FORMAT_B5G6R5_UNORM_PACK16 :
case VK_FORMAT_A1R5G5B5_UNORM_PACK16 :
2016-12-26 13:22:48 +01:00
return 16 ;
case VK_FORMAT_D24_UNORM_S8_UINT :
return 32 ;
case VK_FORMAT_D16_UNORM :
return 16 ;
default :
return 0 ;
}
}
2022-08-01 23:21:14 +02:00
static VkFormat DataFormatToVulkan ( DataFormat format ) {
2016-12-26 13:22:48 +01:00
switch ( format ) {
case DataFormat : : D16 : return VK_FORMAT_D16_UNORM ;
2022-11-24 19:09:42 -08:00
case DataFormat : : D16_S8 : return VK_FORMAT_D16_UNORM_S8_UINT ;
case DataFormat : : D24_S8 : return VK_FORMAT_D24_UNORM_S8_UINT ;
2016-12-26 13:22:48 +01:00
case DataFormat : : D32F : return VK_FORMAT_D32_SFLOAT ;
case DataFormat : : D32F_S8 : return VK_FORMAT_D32_SFLOAT_S8_UINT ;
case DataFormat : : S8 : return VK_FORMAT_S8_UINT ;
2022-09-12 15:34:32 +02:00
case DataFormat : : R16_UNORM : return VK_FORMAT_R16_UNORM ;
2016-12-26 13:22:48 +01:00
case DataFormat : : R16_FLOAT : return VK_FORMAT_R16_SFLOAT ;
case DataFormat : : R16G16_FLOAT : return VK_FORMAT_R16G16_SFLOAT ;
case DataFormat : : R16G16B16A16_FLOAT : return VK_FORMAT_R16G16B16A16_SFLOAT ;
case DataFormat : : R8_UNORM : return VK_FORMAT_R8_UNORM ;
case DataFormat : : R8G8_UNORM : return VK_FORMAT_R8G8_UNORM ;
case DataFormat : : R8G8B8_UNORM : return VK_FORMAT_R8G8B8_UNORM ;
case DataFormat : : R8G8B8A8_UNORM : return VK_FORMAT_R8G8B8A8_UNORM ;
2017-01-21 13:11:03 +01:00
case DataFormat : : R4G4_UNORM_PACK8 : return VK_FORMAT_R4G4_UNORM_PACK8 ;
2020-03-01 14:07:13 +01:00
// Note: A4R4G4B4_UNORM_PACK16 is not supported.
2017-01-21 13:11:03 +01:00
case DataFormat : : R4G4B4A4_UNORM_PACK16 : return VK_FORMAT_R4G4B4A4_UNORM_PACK16 ;
case DataFormat : : B4G4R4A4_UNORM_PACK16 : return VK_FORMAT_B4G4R4A4_UNORM_PACK16 ;
case DataFormat : : R5G5B5A1_UNORM_PACK16 : return VK_FORMAT_R5G5B5A1_UNORM_PACK16 ;
case DataFormat : : B5G5R5A1_UNORM_PACK16 : return VK_FORMAT_B5G5R5A1_UNORM_PACK16 ;
case DataFormat : : R5G6B5_UNORM_PACK16 : return VK_FORMAT_R5G6B5_UNORM_PACK16 ;
case DataFormat : : B5G6R5_UNORM_PACK16 : return VK_FORMAT_B5G6R5_UNORM_PACK16 ;
case DataFormat : : A1R5G5B5_UNORM_PACK16 : return VK_FORMAT_A1R5G5B5_UNORM_PACK16 ;
2020-03-01 14:07:13 +01:00
2016-12-26 13:22:48 +01:00
case DataFormat : : R32_FLOAT : return VK_FORMAT_R32_SFLOAT ;
case DataFormat : : R32G32_FLOAT : return VK_FORMAT_R32G32_SFLOAT ;
case DataFormat : : R32G32B32_FLOAT : return VK_FORMAT_R32G32B32_SFLOAT ;
case DataFormat : : R32G32B32A32_FLOAT : return VK_FORMAT_R32G32B32A32_SFLOAT ;
case DataFormat : : BC1_RGBA_UNORM_BLOCK : return VK_FORMAT_BC1_RGBA_UNORM_BLOCK ;
case DataFormat : : BC2_UNORM_BLOCK : return VK_FORMAT_BC2_UNORM_BLOCK ;
case DataFormat : : BC3_UNORM_BLOCK : return VK_FORMAT_BC3_UNORM_BLOCK ;
case DataFormat : : BC4_UNORM_BLOCK : return VK_FORMAT_BC4_UNORM_BLOCK ;
case DataFormat : : BC4_SNORM_BLOCK : return VK_FORMAT_BC4_SNORM_BLOCK ;
case DataFormat : : BC5_UNORM_BLOCK : return VK_FORMAT_BC5_UNORM_BLOCK ;
case DataFormat : : BC5_SNORM_BLOCK : return VK_FORMAT_BC5_SNORM_BLOCK ;
case DataFormat : : BC6H_SFLOAT_BLOCK : return VK_FORMAT_BC6H_SFLOAT_BLOCK ;
case DataFormat : : BC6H_UFLOAT_BLOCK : return VK_FORMAT_BC6H_UFLOAT_BLOCK ;
case DataFormat : : BC7_UNORM_BLOCK : return VK_FORMAT_BC7_UNORM_BLOCK ;
case DataFormat : : BC7_SRGB_BLOCK : return VK_FORMAT_BC7_SRGB_BLOCK ;
default :
return VK_FORMAT_UNDEFINED ;
2015-10-10 16:41:19 +02:00
}
}
2017-12-21 11:43:05 -08:00
static inline VkSamplerAddressMode AddressModeToVulkan ( Draw : : TextureAddressMode mode ) {
2016-12-25 21:21:56 +01:00
switch ( mode ) {
case TextureAddressMode : : CLAMP_TO_BORDER : return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ;
case TextureAddressMode : : CLAMP_TO_EDGE : return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ;
case TextureAddressMode : : REPEAT_MIRROR : return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT ;
default :
case TextureAddressMode : : REPEAT : return VK_SAMPLER_ADDRESS_MODE_REPEAT ;
}
}
2018-06-01 18:51:37 +02:00
VulkanTexture * VKContext : : GetNullTexture ( ) {
if ( ! nullTexture_ ) {
VkCommandBuffer cmdInit = renderManager_ . GetInitCmd ( ) ;
2022-12-01 11:58:16 +01:00
nullTexture_ = new VulkanTexture ( vulkan_ , " Null " ) ;
2018-06-01 18:51:37 +02:00
int w = 8 ;
int h = 8 ;
2022-07-25 18:51:08 +02:00
nullTexture_ - > CreateDirect ( cmdInit , w , h , 1 , 1 , VK_FORMAT_A8B8G8R8_UNORM_PACK32 , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
2018-06-01 18:51:37 +02:00
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT ) ;
uint32_t bindOffset ;
VkBuffer bindBuf ;
uint32_t * data = ( uint32_t * ) push_ - > Push ( w * h * 4 , & bindOffset , & bindBuf ) ;
for ( int y = 0 ; y < h ; y + + ) {
for ( int x = 0 ; x < w ; x + + ) {
// data[y*w + x] = ((x ^ y) & 1) ? 0xFF808080 : 0xFF000000; // gray/black checkerboard
data [ y * w + x ] = 0 ; // black
}
}
2022-07-25 18:51:08 +02:00
nullTexture_ - > UploadMip ( cmdInit , 0 , w , h , 0 , bindBuf , bindOffset , w ) ;
2021-10-08 21:58:03 +02:00
nullTexture_ - > EndCreate ( cmdInit , false , VK_PIPELINE_STAGE_TRANSFER_BIT ) ;
2018-06-01 18:51:37 +02:00
}
return nullTexture_ ;
}
2016-12-25 21:21:56 +01:00
class VKSamplerState : public SamplerState {
2015-10-10 16:41:19 +02:00
public :
2016-12-25 21:21:56 +01:00
VKSamplerState ( VulkanContext * vulkan , const SamplerStateDesc & desc ) : vulkan_ ( vulkan ) {
2015-10-10 16:41:19 +02:00
VkSamplerCreateInfo s = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO } ;
2016-12-25 21:21:56 +01:00
s . addressModeU = AddressModeToVulkan ( desc . wrapU ) ;
s . addressModeV = AddressModeToVulkan ( desc . wrapV ) ;
s . addressModeW = AddressModeToVulkan ( desc . wrapW ) ;
s . anisotropyEnable = desc . maxAniso > 1.0f ;
2022-11-27 19:17:01 -08:00
s . maxAnisotropy = desc . maxAniso ;
2016-12-25 21:21:56 +01:00
s . magFilter = desc . magFilter = = TextureFilter : : LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST ;
s . minFilter = desc . minFilter = = TextureFilter : : LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST ;
s . mipmapMode = desc . mipFilter = = TextureFilter : : LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST ;
2022-08-23 23:55:53 +02:00
s . maxLod = VK_LOD_CLAMP_NONE ;
2016-01-03 12:37:05 +01:00
VkResult res = vkCreateSampler ( vulkan_ - > GetDevice ( ) , & s , nullptr , & sampler_ ) ;
2018-06-24 07:35:19 -07:00
_assert_ ( VK_SUCCESS = = res ) ;
2015-10-10 16:41:19 +02:00
}
2016-12-25 21:21:56 +01:00
~ VKSamplerState ( ) {
2017-05-07 10:40:11 +02:00
vulkan_ - > Delete ( ) . QueueDeleteSampler ( sampler_ ) ;
2015-10-10 16:41:19 +02:00
}
VkSampler GetSampler ( ) { return sampler_ ; }
private :
VulkanContext * vulkan_ ;
VkSampler sampler_ ;
} ;
2016-12-25 21:21:56 +01:00
SamplerState * VKContext : : CreateSamplerState ( const SamplerStateDesc & desc ) {
return new VKSamplerState ( vulkan_ , desc ) ;
2015-10-10 16:41:19 +02:00
}
2016-12-25 22:24:14 +01:00
RasterState * VKContext : : CreateRasterState ( const RasterStateDesc & desc ) {
2016-12-25 21:21:56 +01:00
return new VKRasterState ( vulkan_ , desc ) ;
2016-12-23 23:46:11 +01:00
}
2016-12-26 11:16:59 +01:00
void VKContext : : BindSamplerStates ( int start , int count , SamplerState * * state ) {
2021-06-12 10:10:42 -07:00
_assert_ ( start + count < = MAX_BOUND_TEXTURES ) ;
2015-10-10 16:41:19 +02:00
for ( int i = start ; i < start + count ; i + + ) {
2020-05-17 10:44:21 -07:00
boundSamplers_ [ i ] = ( VKSamplerState * ) state [ i - start ] ;
2015-10-10 16:41:19 +02:00
}
}
enum class TextureState {
UNINITIALIZED ,
STAGED ,
INITIALIZED ,
PENDING_DESTRUCTION ,
} ;
2021-11-21 23:38:14 +01:00
bool VKTexture : : Create ( VkCommandBuffer cmd , VulkanPushBuffer * push , const TextureDesc & desc ) {
2017-06-05 13:22:01 +02:00
// Zero-sized textures not allowed.
2018-03-01 12:11:10 +01:00
_assert_ ( desc . width * desc . height * desc . depth > 0 ) ; // remember to set depth to 1!
2018-11-21 17:33:30 +01:00
if ( desc . width * desc . height * desc . depth < = 0 ) {
2020-08-15 16:13:24 +02:00
ERROR_LOG ( G3D , " Bad texture dimensions %dx%dx%d " , desc . width , desc . height , desc . depth ) ;
2018-11-21 17:33:30 +01:00
return false ;
}
2018-03-01 12:11:10 +01:00
_assert_ ( push ) ;
2017-05-19 17:21:08 +02:00
format_ = desc . format ;
mipLevels_ = desc . mipLevels ;
width_ = desc . width ;
height_ = desc . height ;
depth_ = desc . depth ;
2022-12-01 11:58:16 +01:00
vkTex_ = new VulkanTexture ( vulkan_ , desc . tag ) ;
2018-02-25 10:13:01 +01:00
VkFormat vulkanFormat = DataFormatToVulkan ( format_ ) ;
int bpp = GetBpp ( vulkanFormat ) ;
int bytesPerPixel = bpp / 8 ;
int usageBits = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT ;
if ( mipLevels_ > ( int ) desc . initData . size ( ) ) {
// Gonna have to generate some, which requires TRANSFER_SRC
usageBits | = VK_IMAGE_USAGE_TRANSFER_SRC_BIT ;
}
2019-10-22 23:14:27 +02:00
2022-07-25 18:51:08 +02:00
if ( ! vkTex_ - > CreateDirect ( cmd , width_ , height_ , 1 , mipLevels_ , vulkanFormat , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL , usageBits ) ) {
2020-08-15 16:13:24 +02:00
ERROR_LOG ( G3D , " Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels " , width_ , height_ , depth_ , ( int ) vulkanFormat , mipLevels_ ) ;
2018-03-01 12:11:10 +01:00
return false ;
}
2021-10-05 22:49:33 +02:00
VkImageLayout layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ;
2017-05-19 17:21:08 +02:00
if ( desc . initData . size ( ) ) {
2018-02-25 10:13:01 +01:00
int w = width_ ;
int h = height_ ;
2020-05-11 09:47:26 -07:00
int d = depth_ ;
2018-02-25 10:13:01 +01:00
int i ;
for ( i = 0 ; i < ( int ) desc . initData . size ( ) ; i + + ) {
uint32_t offset ;
VkBuffer buf ;
2020-05-11 09:47:26 -07:00
size_t size = w * h * d * bytesPerPixel ;
if ( desc . initDataCallback ) {
uint8_t * dest = ( uint8_t * ) push - > PushAligned ( size , & offset , & buf , 16 ) ;
2020-05-13 20:30:24 -07:00
if ( ! desc . initDataCallback ( dest , desc . initData [ i ] , w , h , d , w * bytesPerPixel , h * w * bytesPerPixel ) ) {
memcpy ( dest , desc . initData [ i ] , size ) ;
}
2020-05-11 09:47:26 -07:00
} else {
offset = push - > PushAligned ( ( const void * ) desc . initData [ i ] , size , 16 , & buf ) ;
}
2022-07-25 18:51:08 +02:00
vkTex_ - > UploadMip ( cmd , i , w , h , 0 , buf , offset , w ) ;
2018-02-25 10:13:01 +01:00
w = ( w + 1 ) / 2 ;
h = ( h + 1 ) / 2 ;
2020-05-11 09:47:26 -07:00
d = ( d + 1 ) / 2 ;
2018-02-25 10:13:01 +01:00
}
// Generate the rest of the mips automatically.
2021-10-05 22:49:33 +02:00
if ( i < mipLevels_ ) {
vkTex_ - > GenerateMips ( cmd , i , false ) ;
layout = VK_IMAGE_LAYOUT_GENERAL ;
2017-01-18 00:31:44 +07:00
}
2017-01-16 23:43:07 +07:00
}
2021-10-08 21:58:03 +02:00
vkTex_ - > EndCreate ( cmd , false , VK_PIPELINE_STAGE_TRANSFER_BIT , layout ) ;
2017-05-19 17:21:08 +02:00
return true ;
}
2015-10-10 16:41:19 +02:00
2022-11-24 19:09:42 -08:00
static DataFormat DataFormatFromVulkanDepth ( VkFormat fmt ) {
switch ( fmt ) {
case VK_FORMAT_D24_UNORM_S8_UINT :
return DataFormat : : D24_S8 ;
case VK_FORMAT_D16_UNORM :
return DataFormat : : D16 ;
case VK_FORMAT_D32_SFLOAT :
return DataFormat : : D32F ;
case VK_FORMAT_D32_SFLOAT_S8_UINT :
return DataFormat : : D32F_S8 ;
case VK_FORMAT_D16_UNORM_S8_UINT :
return DataFormat : : D16_S8 ;
default :
break ;
}
return DataFormat : : UNDEFINED ;
}
2022-09-17 00:36:43 +02:00
VKContext : : VKContext ( VulkanContext * vulkan )
2021-02-15 10:29:34 -08:00
: vulkan_ ( vulkan ) , renderManager_ ( vulkan ) {
2020-11-06 09:01:13 +01:00
shaderLanguageDesc_ . Init ( GLSL_VULKAN ) ;
2022-08-01 23:21:14 +02:00
VkFormat depthStencilFormat = vulkan - > GetDeviceInfo ( ) . preferredDepthStencilFormat ;
2022-10-23 22:05:33 +02:00
caps_ . anisoSupported = vulkan - > GetDeviceFeatures ( ) . enabled . standard . samplerAnisotropy ! = 0 ;
caps_ . geometryShaderSupported = vulkan - > GetDeviceFeatures ( ) . enabled . standard . geometryShader ! = 0 ;
caps_ . tesselationShaderSupported = vulkan - > GetDeviceFeatures ( ) . enabled . standard . tessellationShader ! = 0 ;
caps_ . dualSourceBlend = vulkan - > GetDeviceFeatures ( ) . enabled . standard . dualSrcBlend ! = 0 ;
caps_ . depthClampSupported = vulkan - > GetDeviceFeatures ( ) . enabled . standard . depthClamp ! = 0 ;
caps_ . clipDistanceSupported = vulkan - > GetDeviceFeatures ( ) . enabled . standard . shaderClipDistance ! = 0 ;
caps_ . cullDistanceSupported = vulkan - > GetDeviceFeatures ( ) . enabled . standard . shaderCullDistance ! = 0 ;
2017-02-12 18:29:58 +01:00
caps_ . framebufferBlitSupported = true ;
caps_ . framebufferCopySupported = true ;
2022-08-01 23:21:14 +02:00
caps_ . framebufferDepthBlitSupported = vulkan - > GetDeviceInfo ( ) . canBlitToPreferredDepthStencilFormat ;
2022-08-03 13:40:21 +02:00
caps_ . framebufferStencilBlitSupported = caps_ . framebufferDepthBlitSupported ;
2017-10-25 21:56:39 +02:00
caps_ . framebufferDepthCopySupported = true ; // Will pretty much always be the case.
2022-08-01 23:21:14 +02:00
caps_ . framebufferSeparateDepthCopySupported = true ; // Will pretty much always be the case.
2022-11-24 19:09:42 -08:00
// This doesn't affect what depth/stencil format is actually used, see VulkanQueueRunner.
caps_ . preferredDepthBufferFormat = DataFormatFromVulkanDepth ( vulkan - > GetDeviceInfo ( ) . preferredDepthStencilFormat ) ;
2022-07-31 00:18:28 +02:00
caps_ . texture3DSupported = true ;
2022-08-24 11:26:07 +02:00
caps_ . textureDepthSupported = true ;
2022-08-05 14:18:22 +02:00
caps_ . fragmentShaderInt32Supported = true ;
2022-08-07 11:48:59 +02:00
caps_ . textureNPOTFullySupported = true ;
2022-08-08 12:07:50 +02:00
caps_ . fragmentShaderDepthWriteSupported = true ;
2022-11-24 18:48:46 -08:00
caps_ . fragmentShaderStencilWriteSupported = vulkan - > Extensions ( ) . EXT_shader_stencil_export ;
2022-09-20 10:02:15 +02:00
caps_ . blendMinMaxSupported = true ;
2022-10-23 22:05:33 +02:00
caps_ . logicOpSupported = vulkan - > GetDeviceFeatures ( ) . enabled . standard . logicOp ! = 0 ;
2022-10-26 16:02:18 +02:00
caps_ . multiViewSupported = vulkan - > GetDeviceFeatures ( ) . enabled . multiview . multiview ! = 0 ;
2022-11-28 23:56:55 +01:00
caps_ . sampleRateShadingSupported = vulkan - > GetDeviceFeatures ( ) . enabled . standard . sampleRateShading ! = 0 ;
2022-11-28 11:50:28 +01:00
const auto & limits = vulkan - > GetPhysicalDeviceProperties ( ) . properties . limits ;
2017-10-25 21:56:39 +02:00
2020-03-01 14:07:13 +01:00
auto deviceProps = vulkan - > GetPhysicalDeviceProperties ( vulkan_ - > GetCurrentPhysicalDeviceIndex ( ) ) . properties ;
2022-09-20 10:02:15 +02:00
2018-12-23 12:19:34 -08:00
switch ( deviceProps . vendorID ) {
2017-11-22 11:01:42 +01:00
case VULKAN_VENDOR_AMD : caps_ . vendor = GPUVendor : : VENDOR_AMD ; break ;
case VULKAN_VENDOR_ARM : caps_ . vendor = GPUVendor : : VENDOR_ARM ; break ;
case VULKAN_VENDOR_IMGTEC : caps_ . vendor = GPUVendor : : VENDOR_IMGTEC ; break ;
case VULKAN_VENDOR_NVIDIA : caps_ . vendor = GPUVendor : : VENDOR_NVIDIA ; break ;
case VULKAN_VENDOR_QUALCOMM : caps_ . vendor = GPUVendor : : VENDOR_QUALCOMM ; break ;
case VULKAN_VENDOR_INTEL : caps_ . vendor = GPUVendor : : VENDOR_INTEL ; break ;
2022-12-01 18:15:13 +01:00
case VULKAN_VENDOR_APPLE : caps_ . vendor = GPUVendor : : VENDOR_APPLE ; break ;
default :
WARN_LOG ( G3D , " Unknown vendor ID %08x " , deviceProps . vendorID ) ;
caps_ . vendor = GPUVendor : : VENDOR_UNKNOWN ;
break ;
2017-11-21 15:42:01 +01:00
}
2022-11-27 10:13:05 +01:00
bool hasLazyMemory = false ;
for ( u32 i = 0 ; i < vulkan - > GetMemoryProperties ( ) . memoryTypeCount ; i + + ) {
if ( vulkan - > GetMemoryProperties ( ) . memoryTypes [ i ] . propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT ) {
hasLazyMemory = true ;
}
}
2022-12-01 18:15:13 +01:00
caps_ . isTilingGPU = hasLazyMemory & & caps_ . vendor ! = GPUVendor : : VENDOR_APPLE ;
2022-11-27 10:13:05 +01:00
2022-11-28 11:50:28 +01:00
// VkSampleCountFlagBits is arranged correctly for our purposes.
// Only support MSAA levels that have support for all three of color, depth, stencil.
if ( ! caps_ . isTilingGPU ) {
2022-11-28 20:34:51 +01:00
// Check for depth stencil resolve. Without it, depth textures won't work, and we don't want that mess
2022-12-02 14:35:43 +01:00
// of compatibility reports, so we'll just disable multisampling in this case for now.
2022-11-28 20:34:51 +01:00
// There are potential workarounds for devices that don't support it, but those are nearly non-existent now.
const auto & resolveProperties = vulkan - > GetPhysicalDeviceProperties ( ) . depthStencilResolve ;
2022-12-02 15:19:06 +01:00
if ( vulkan - > Extensions ( ) . KHR_depth_stencil_resolve & &
( ( resolveProperties . supportedDepthResolveModes & resolveProperties . supportedStencilResolveModes ) & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT ) ! = 0 ) {
2022-11-28 20:34:51 +01:00
caps_ . multiSampleLevelsMask = ( limits . framebufferColorSampleCounts & limits . framebufferDepthSampleCounts & limits . framebufferStencilSampleCounts ) ;
} else {
caps_ . multiSampleLevelsMask = 1 ;
}
2022-11-28 11:50:28 +01:00
} else {
caps_ . multiSampleLevelsMask = 1 ;
}
2018-12-23 12:19:34 -08:00
if ( caps_ . vendor = = GPUVendor : : VENDOR_QUALCOMM ) {
// Adreno 5xx devices, all known driver versions, fail to discard stencil when depth write is off.
// See: https://github.com/hrydgard/ppsspp/pull/11684
if ( deviceProps . deviceID > = 0x05000000 & & deviceProps . deviceID < 0x06000000 ) {
2020-05-19 22:13:15 -07:00
if ( deviceProps . driverVersion < 0x80180000 ) {
bugs_ . Infest ( Bugs : : NO_DEPTH_CANNOT_DISCARD_STENCIL ) ;
}
2018-12-23 12:19:34 -08:00
}
2020-05-19 22:12:30 -07:00
// Color write mask not masking write in certain scenarios with a depth test, see #10421.
// Known still present on driver 0x80180000 and Adreno 5xx (possibly more.)
2022-11-12 17:36:37 -08:00
// Known working on driver 0x801EA000 and Adreno 620.
if ( deviceProps . driverVersion < 0x801EA000 | | deviceProps . deviceID < 0x06000000 )
bugs_ . Infest ( Bugs : : COLORWRITEMASK_BROKEN_WITH_DEPTHTEST ) ;
2022-09-16 19:18:38 +02:00
// Trying to follow all the rules in https://registry.khronos.org/vulkan/specs/1.3/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies
// and https://registry.khronos.org/vulkan/specs/1.3/html/vkspec.html#renderpass-feedbackloop, but still it doesn't
// quite work - artifacts on triangle boundaries on Adreno.
bugs_ . Infest ( Bugs : : SUBPASS_FEEDBACK_BROKEN ) ;
2018-12-23 12:31:19 -08:00
} else if ( caps_ . vendor = = GPUVendor : : VENDOR_AMD ) {
// See issue #10074, and also #10065 (AMD) and #10109 for the choice of the driver version to check for.
if ( deviceProps . driverVersion < 0x00407000 ) {
bugs_ . Infest ( Bugs : : DUAL_SOURCE_BLENDING_BROKEN ) ;
}
} else if ( caps_ . vendor = = GPUVendor : : VENDOR_INTEL ) {
// Workaround for Intel driver bug. TODO: Re-enable after some driver version
bugs_ . Infest ( Bugs : : DUAL_SOURCE_BLENDING_BROKEN ) ;
2021-09-19 23:16:21 -07:00
} else if ( caps_ . vendor = = GPUVendor : : VENDOR_ARM ) {
2022-09-16 13:14:44 +02:00
int majorVersion = VK_API_VERSION_MAJOR ( deviceProps . driverVersion ) ;
2021-09-19 23:16:21 -07:00
// These GPUs (up to some certain hardware version?) have a bug where draws where gl_Position.w == .z
// corrupt the depth buffer. This is easily worked around by simply scaling Z down a tiny bit when this case
// is detected. See: https://github.com/hrydgard/ppsspp/issues/11937
bugs_ . Infest ( Bugs : : EQUAL_WZ_CORRUPTS_DEPTH ) ;
2022-09-16 13:14:44 +02:00
2022-09-18 10:34:43 +02:00
// Nearly identical to the the Adreno bug, see #13833 (Midnight Club map broken) and other issues.
2022-09-16 13:14:44 +02:00
// Reported fixed in major version 40 - let's add a check once confirmed.
2022-09-18 10:34:43 +02:00
bugs_ . Infest ( Bugs : : NO_DEPTH_CANNOT_DISCARD_STENCIL ) ;
2022-07-17 22:50:37 +02:00
2022-09-16 13:14:44 +02:00
// This started in driver 31 or 32, fixed in 40 - let's add a check once confirmed.
if ( majorVersion > = 32 ) {
2022-07-17 22:50:37 +02:00
bugs_ . Infest ( Bugs : : MALI_CONSTANT_LOAD_BUG ) ; // See issue #15661
}
2022-10-02 07:32:31 -07:00
// Older ARM devices have very slow geometry shaders, not worth using. At least before 15.
2022-10-09 00:57:10 -07:00
// Also seen to cause weird issues on 18, so let's lump it in.
if ( majorVersion < = 18 ) {
bugs_ . Infest ( Bugs : : GEOMETRY_SHADERS_SLOW_OR_BROKEN ) ;
2022-10-02 07:32:31 -07:00
}
2018-12-23 12:19:34 -08:00
}
2022-09-16 19:18:38 +02:00
// Limited, through input attachments and self-dependencies.
// We turn it off here already if buggy.
caps_ . framebufferFetchSupported = ! bugs_ . Has ( Bugs : : SUBPASS_FEEDBACK_BROKEN ) ;
2019-02-06 22:43:31 +01:00
caps_ . deviceID = deviceProps . deviceID ;
2015-12-31 01:07:06 +01:00
device_ = vulkan - > GetDevice ( ) ;
2015-10-10 16:41:19 +02:00
2016-01-02 02:08:05 +01:00
queue_ = vulkan - > GetGraphicsQueue ( ) ;
queueFamilyIndex_ = vulkan - > GetGraphicsQueueFamilyIndex ( ) ;
2015-10-10 16:41:19 +02:00
2018-02-25 10:13:01 +01:00
VkCommandPoolCreateInfo p { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO } ;
2017-05-17 02:21:03 +02:00
p . flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT ;
p . queueFamilyIndex = vulkan - > GetGraphicsQueueFamilyIndex ( ) ;
2021-12-09 19:03:17 -08:00
std : : vector < VkDescriptorPoolSize > dpTypes ;
dpTypes . resize ( 2 ) ;
dpTypes [ 0 ] . descriptorCount = 200 ;
dpTypes [ 0 ] . type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ;
dpTypes [ 1 ] . descriptorCount = 200 * MAX_BOUND_TEXTURES ;
dpTypes [ 1 ] . type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
VkDescriptorPoolCreateInfo dp { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO } ;
// Don't want to mess around with individually freeing these, let's go dynamic each frame.
dp . flags = 0 ;
// 200 textures per frame was not enough for the UI.
dp . maxSets = 4096 ;
2017-08-17 17:55:21 +02:00
for ( int i = 0 ; i < VulkanContext : : MAX_INFLIGHT_FRAMES ; i + + ) {
2019-03-13 23:31:54 +01:00
VkBufferUsageFlags usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT ;
2021-12-10 21:01:01 +01:00
frame_ [ i ] . pushBuffer = new VulkanPushBuffer ( vulkan_ , " pushBuffer " , 1024 * 1024 , usage , PushBufferType : : CPU_TO_GPU ) ;
2021-12-09 19:03:17 -08:00
frame_ [ i ] . descriptorPool . Create ( vulkan_ , dp , dpTypes ) ;
2017-05-17 02:21:03 +02:00
}
2015-10-10 16:41:19 +02:00
2016-01-02 02:08:05 +01:00
// binding 0 - uniform data
2020-05-17 10:50:11 -07:00
// binding 1 - combined sampler/image 0
// binding 2 - combined sampler/image 1
VkDescriptorSetLayoutBinding bindings [ MAX_BOUND_TEXTURES + 1 ] ;
2015-10-10 16:41:19 +02:00
bindings [ 0 ] . descriptorCount = 1 ;
bindings [ 0 ] . pImmutableSamplers = nullptr ;
2016-01-02 02:08:05 +01:00
bindings [ 0 ] . descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ;
2020-05-10 21:17:33 -07:00
bindings [ 0 ] . stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT ;
2015-12-31 01:33:23 +01:00
bindings [ 0 ] . binding = 0 ;
2020-05-17 10:50:11 -07:00
for ( int i = 0 ; i < MAX_BOUND_TEXTURES ; + + i ) {
bindings [ i + 1 ] . descriptorCount = 1 ;
bindings [ i + 1 ] . pImmutableSamplers = nullptr ;
bindings [ i + 1 ] . descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
bindings [ i + 1 ] . stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT ;
bindings [ i + 1 ] . binding = i + 1 ;
}
2015-10-10 16:41:19 +02:00
2016-04-02 23:57:23 +02:00
VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO } ;
2020-05-17 10:50:11 -07:00
dsl . bindingCount = ARRAY_SIZE ( bindings ) ;
2015-10-10 16:41:19 +02:00
dsl . pBindings = bindings ;
2017-05-17 02:21:03 +02:00
VkResult res = vkCreateDescriptorSetLayout ( device_ , & dsl , nullptr , & descriptorSetLayout_ ) ;
2020-08-16 00:38:55 +02:00
_assert_ ( VK_SUCCESS = = res ) ;
2015-10-10 16:41:19 +02:00
2022-10-28 09:23:44 +02:00
VkDescriptorSetLayoutBinding frameBindings [ 1 ] { } ;
frameBindings [ 0 ] . descriptorCount = 1 ;
frameBindings [ 0 ] . descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ;
frameBindings [ 0 ] . stageFlags = VK_SHADER_STAGE_VERTEX_BIT ;
frameBindings [ 0 ] . binding = 0 ;
dsl . bindingCount = ARRAY_SIZE ( frameBindings ) ;
dsl . pBindings = frameBindings ;
res = vkCreateDescriptorSetLayout ( device_ , & dsl , nullptr , & frameDescSetLayout_ ) ;
_dbg_assert_ ( VK_SUCCESS = = res ) ;
2022-09-08 09:15:06 +02:00
vulkan_ - > SetDebugName ( descriptorSetLayout_ , VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT , " thin3d_d_layout " ) ;
2016-04-02 23:57:23 +02:00
VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO } ;
2015-10-10 16:41:19 +02:00
pl . pPushConstantRanges = nullptr ;
pl . pushConstantRangeCount = 0 ;
2022-10-28 09:23:44 +02:00
VkDescriptorSetLayout setLayouts [ 2 ] = { frameDescSetLayout_ , descriptorSetLayout_ } ;
pl . setLayoutCount = ARRAY_SIZE ( setLayouts ) ;
pl . pSetLayouts = setLayouts ;
2015-10-10 16:41:19 +02:00
res = vkCreatePipelineLayout ( device_ , & pl , nullptr , & pipelineLayout_ ) ;
2020-08-16 00:38:55 +02:00
_assert_ ( VK_SUCCESS = = res ) ;
2015-10-10 16:41:19 +02:00
2022-09-08 09:15:06 +02:00
vulkan_ - > SetDebugName ( pipelineLayout_ , VK_OBJECT_TYPE_PIPELINE_LAYOUT , " thin3d_p_layout " ) ;
2018-03-13 23:22:21 +01:00
VkPipelineCacheCreateInfo pc { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO } ;
res = vkCreatePipelineCache ( vulkan_ - > GetDevice ( ) , & pc , nullptr , & pipelineCache_ ) ;
2020-08-16 00:38:55 +02:00
_assert_ ( VK_SUCCESS = = res ) ;
2015-10-10 16:41:19 +02:00
}
2016-12-25 21:21:56 +01:00
VKContext : : ~ VKContext ( ) {
2018-06-01 18:51:37 +02:00
delete nullTexture_ ;
2015-10-10 16:41:19 +02:00
// This also destroys all descriptor sets.
2017-08-17 17:55:21 +02:00
for ( int i = 0 ; i < VulkanContext : : MAX_INFLIGHT_FRAMES ; i + + ) {
2021-12-09 19:03:17 -08:00
frame_ [ i ] . descriptorPool . Destroy ( ) ;
2016-03-20 09:52:13 +01:00
frame_ [ i ] . pushBuffer - > Destroy ( vulkan_ ) ;
2016-01-10 14:24:10 +01:00
delete frame_ [ i ] . pushBuffer ;
2016-01-03 13:27:19 +01:00
}
2017-05-07 10:40:11 +02:00
vulkan_ - > Delete ( ) . QueueDeleteDescriptorSetLayout ( descriptorSetLayout_ ) ;
2022-10-28 09:23:44 +02:00
vulkan_ - > Delete ( ) . QueueDeleteDescriptorSetLayout ( frameDescSetLayout_ ) ;
2017-05-07 10:40:11 +02:00
vulkan_ - > Delete ( ) . QueueDeletePipelineLayout ( pipelineLayout_ ) ;
vulkan_ - > Delete ( ) . QueueDeletePipelineCache ( pipelineCache_ ) ;
2015-10-10 16:41:19 +02:00
}
2017-05-16 13:30:10 +02:00
void VKContext : : BeginFrame ( ) {
2021-12-19 22:49:42 +01:00
// TODO: Bad dependency on g_Config here!
renderManager_ . BeginFrame ( g_Config . bShowGpuProfile , g_Config . bGpuLogProfiler ) ;
2017-05-07 11:28:57 +02:00
2017-10-31 23:49:47 +01:00
FrameData & frame = frame_ [ vulkan_ - > GetCurFrame ( ) ] ;
2017-05-21 23:13:53 +02:00
push_ = frame . pushBuffer ;
2016-01-02 02:08:05 +01:00
// OK, we now know that nothing is reading from this frame's data pushbuffer,
2016-03-20 09:52:13 +01:00
push_ - > Reset ( ) ;
2016-03-20 15:36:22 -07:00
push_ - > Begin ( vulkan_ ) ;
2016-01-03 13:27:19 +01:00
2021-12-09 19:03:17 -08:00
frame . descriptorPool . Reset ( ) ;
2015-10-10 16:41:19 +02:00
}
2017-05-16 13:30:10 +02:00
void VKContext : : EndFrame ( ) {
2016-01-03 12:37:05 +01:00
// Stop collecting data in the frame's data pushbuffer.
2016-03-20 15:36:22 -07:00
push_ - > End ( ) ;
2017-08-18 15:08:40 +02:00
2017-10-28 16:47:08 +02:00
renderManager_ . Finish ( ) ;
2015-10-10 16:41:19 +02:00
2016-01-02 02:08:05 +01:00
push_ = nullptr ;
2020-07-13 23:11:52 +02:00
// Unbind stuff, to avoid accidentally relying on it across frames (and provide some protection against forgotten unbinds of deleted things).
2022-12-01 19:15:38 +01:00
Invalidate ( InvalidationFlags : : CACHED_RENDER_STATE ) ;
2020-07-13 23:11:52 +02:00
}
2022-12-01 19:15:38 +01:00
void VKContext : : Invalidate ( InvalidationFlags flags ) {
if ( flags & InvalidationFlags : : CACHED_RENDER_STATE ) {
curPipeline_ = nullptr ;
2020-07-13 23:11:52 +02:00
2022-12-01 19:15:38 +01:00
for ( auto & view : boundImageView_ ) {
view = VK_NULL_HANDLE ;
}
for ( auto & sampler : boundSamplers_ ) {
sampler = nullptr ;
}
for ( auto & texture : boundTextures_ ) {
texture = nullptr ;
}
2020-07-13 23:11:52 +02:00
}
2015-10-10 16:41:19 +02:00
}
2017-11-01 21:42:19 +01:00
void VKContext : : WipeQueue ( ) {
renderManager_ . Wipe ( ) ;
}
2016-12-25 21:21:56 +01:00
VkDescriptorSet VKContext : : GetOrCreateDescriptorSet ( VkBuffer buf ) {
2022-09-23 12:24:43 +02:00
DescriptorSetKey key { } ;
2016-01-03 13:27:19 +01:00
2017-10-31 23:49:47 +01:00
FrameData * frame = & frame_ [ vulkan_ - > GetCurFrame ( ) ] ;
2016-01-03 13:27:19 +01:00
2020-05-17 10:50:11 -07:00
for ( int i = 0 ; i < MAX_BOUND_TEXTURES ; + + i ) {
2022-10-25 23:32:28 +02:00
if ( boundTextures_ [ i ] ) {
key . imageViews_ [ i ] = ( boundTextureFlags_ [ i ] & TextureBindFlags : : VULKAN_BIND_ARRAY ) ? boundTextures_ [ i ] - > GetImageArrayView ( ) : boundTextures_ [ i ] - > GetImageView ( ) ;
} else {
key . imageViews_ [ i ] = boundImageView_ [ i ] ;
}
2020-05-17 10:50:11 -07:00
key . samplers_ [ i ] = boundSamplers_ [ i ] ;
}
2016-03-20 09:52:13 +01:00
key . buffer_ = buf ;
2015-10-10 16:41:19 +02:00
2016-01-03 13:27:19 +01:00
auto iter = frame - > descSets_ . find ( key ) ;
if ( iter ! = frame - > descSets_ . end ( ) ) {
2015-10-10 16:41:19 +02:00
return iter - > second ;
}
2022-10-26 13:29:56 +02:00
VkDescriptorSet descSet = frame - > descriptorPool . Allocate ( 1 , & descriptorSetLayout_ , " thin3d_descset " ) ;
2021-12-09 19:03:17 -08:00
if ( descSet = = VK_NULL_HANDLE ) {
ERROR_LOG ( G3D , " GetOrCreateDescriptorSet failed " ) ;
return VK_NULL_HANDLE ;
2021-10-06 23:20:13 -07:00
}
2015-12-20 23:39:03 +01:00
2022-10-13 22:34:21 +02:00
vulkan_ - > SetDebugName ( descSet , VK_OBJECT_TYPE_DESCRIPTOR_SET , " (thin3d desc set) " ) ;
2015-10-10 16:41:19 +02:00
VkDescriptorBufferInfo bufferDesc ;
2016-03-20 09:52:13 +01:00
bufferDesc . buffer = buf ;
2015-10-10 16:41:19 +02:00
bufferDesc . offset = 0 ;
2016-12-26 11:06:17 +01:00
bufferDesc . range = curPipeline_ - > GetUBOSize ( ) ;
2015-10-10 16:41:19 +02:00
2020-06-12 12:40:53 -07:00
VkDescriptorImageInfo imageDesc [ MAX_BOUND_TEXTURES ] { } ;
VkWriteDescriptorSet writes [ 1 + MAX_BOUND_TEXTURES ] { } ;
2019-10-20 17:04:27 +02:00
// If handles are NULL for whatever buggy reason, it's best to leave the descriptors
// unwritten instead of trying to write a zero, which is not legal.
int numWrites = 0 ;
if ( buf ) {
writes [ numWrites ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writes [ numWrites ] . dstSet = descSet ;
writes [ numWrites ] . dstArrayElement = 0 ;
writes [ numWrites ] . dstBinding = 0 ;
writes [ numWrites ] . pBufferInfo = & bufferDesc ;
writes [ numWrites ] . pImageInfo = nullptr ;
writes [ numWrites ] . pTexelBufferView = nullptr ;
writes [ numWrites ] . descriptorCount = 1 ;
writes [ numWrites ] . descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ;
numWrites + + ;
}
2020-05-17 10:50:11 -07:00
for ( int i = 0 ; i < MAX_BOUND_TEXTURES ; + + i ) {
if ( key . imageViews_ [ i ] & & key . samplers_ [ i ] & & key . samplers_ [ i ] - > GetSampler ( ) ) {
2020-06-12 12:40:53 -07:00
imageDesc [ i ] . imageView = key . imageViews_ [ i ] ;
imageDesc [ i ] . sampler = key . samplers_ [ i ] - > GetSampler ( ) ;
imageDesc [ i ] . imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
2020-05-17 10:50:11 -07:00
writes [ numWrites ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writes [ numWrites ] . dstSet = descSet ;
writes [ numWrites ] . dstArrayElement = 0 ;
writes [ numWrites ] . dstBinding = i + 1 ;
writes [ numWrites ] . pBufferInfo = nullptr ;
2020-06-12 12:40:53 -07:00
writes [ numWrites ] . pImageInfo = & imageDesc [ i ] ;
2020-05-17 10:50:11 -07:00
writes [ numWrites ] . pTexelBufferView = nullptr ;
writes [ numWrites ] . descriptorCount = 1 ;
writes [ numWrites ] . descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
numWrites + + ;
}
2019-10-20 17:04:27 +02:00
}
vkUpdateDescriptorSets ( device_ , numWrites , writes , 0 , nullptr ) ;
2015-10-10 16:41:19 +02:00
2016-01-03 13:27:19 +01:00
frame - > descSets_ [ key ] = descSet ;
2015-10-10 16:41:19 +02:00
return descSet ;
}
2022-09-07 23:55:33 +02:00
Pipeline * VKContext : : CreateGraphicsPipeline ( const PipelineDesc & desc , const char * tag ) {
2016-12-26 17:03:01 +01:00
VKInputLayout * input = ( VKInputLayout * ) desc . inputLayout ;
VKBlendState * blend = ( VKBlendState * ) desc . blend ;
VKDepthStencilState * depth = ( VKDepthStencilState * ) desc . depthStencil ;
VKRasterState * raster = ( VKRasterState * ) desc . raster ;
2020-10-11 11:47:24 +02:00
2022-02-19 20:40:27 +01:00
PipelineFlags pipelineFlags = ( PipelineFlags ) 0 ;
2020-10-11 11:47:24 +02:00
if ( depth - > info . depthTestEnable | | depth - > info . stencilTestEnable ) {
2022-02-19 20:40:27 +01:00
pipelineFlags | = PipelineFlags : : USES_DEPTH_STENCIL ;
2020-10-11 11:47:24 +02:00
}
2022-09-22 19:37:46 +02:00
// TODO: We need code to set USES_BLEND_CONSTANT here too, if we're ever gonna use those in thin3d code.
2020-10-11 11:47:24 +02:00
2022-02-19 20:40:27 +01:00
VKPipeline * pipeline = new VKPipeline ( vulkan_ , desc . uniformDesc ? desc . uniformDesc - > uniformBufferSize : 16 * sizeof ( float ) , pipelineFlags , tag ) ;
2022-09-06 13:30:18 +02:00
2022-12-03 14:52:06 -08:00
VKRGraphicsPipelineDesc & gDesc = * pipeline - > vkrDesc ;
2022-09-06 13:30:18 +02:00
std : : vector < VkPipelineShaderStageCreateInfo > stages ;
stages . resize ( desc . shaders . size ( ) ) ;
for ( auto & iter : desc . shaders ) {
VKShaderModule * vkshader = ( VKShaderModule * ) iter ;
2022-09-08 00:22:45 +02:00
vkshader - > AddRef ( ) ;
pipeline - > deps . push_back ( vkshader ) ;
2022-09-06 13:30:18 +02:00
if ( vkshader - > GetStage ( ) = = ShaderStage : : Vertex ) {
2022-09-23 13:31:32 +02:00
gDesc . vertexShader = vkshader - > Get ( ) ;
2022-09-06 13:30:18 +02:00
} else if ( vkshader - > GetStage ( ) = = ShaderStage : : Fragment ) {
2022-09-23 13:31:32 +02:00
gDesc . fragmentShader = vkshader - > Get ( ) ;
2022-09-06 13:30:18 +02:00
} else {
ERROR_LOG ( G3D , " Bad stage " ) ;
2022-09-30 12:32:49 +03:00
delete pipeline ;
2022-09-06 13:30:18 +02:00
return nullptr ;
}
}
2020-10-11 11:47:24 +02:00
2020-11-06 20:08:57 +01:00
if ( input ) {
for ( int i = 0 ; i < ( int ) input - > bindings . size ( ) ; i + + ) {
pipeline - > stride [ i ] = input - > bindings [ i ] . stride ;
}
} else {
pipeline - > stride [ 0 ] = 0 ;
2015-10-10 16:41:19 +02:00
}
2022-09-06 13:30:18 +02:00
_dbg_assert_ ( input - > bindings . size ( ) = = 1 ) ;
_dbg_assert_ ( ( int ) input - > attributes . size ( ) = = ( int ) input - > visc . vertexAttributeDescriptionCount ) ;
2015-10-10 16:41:19 +02:00
2022-09-06 13:30:18 +02:00
gDesc . ibd = input - > bindings [ 0 ] ;
2022-09-12 22:14:48 -07:00
for ( size_t i = 0 ; i < input - > attributes . size ( ) ; i + + ) {
2022-09-06 13:30:18 +02:00
gDesc . attrs [ i ] = input - > attributes [ i ] ;
2016-12-25 23:03:20 +01:00
}
2022-09-06 13:30:18 +02:00
gDesc . vis . vertexAttributeDescriptionCount = input - > visc . vertexAttributeDescriptionCount ;
gDesc . vis . vertexBindingDescriptionCount = input - > visc . vertexBindingDescriptionCount ;
gDesc . vis . pVertexBindingDescriptions = & gDesc . ibd ;
gDesc . vis . pVertexAttributeDescriptions = gDesc . attrs ;
gDesc . blend0 = blend - > attachments [ 0 ] ;
gDesc . cbs = blend - > info ;
2022-09-07 12:37:45 +02:00
gDesc . cbs . pAttachments = & gDesc . blend0 ;
2022-09-06 13:30:18 +02:00
gDesc . dss = depth - > info ;
2015-10-10 16:41:19 +02:00
2022-09-06 13:30:18 +02:00
raster - > ToVulkan ( & gDesc . rs ) ;
// Copy bindings from input layout.
gDesc . inputAssembly . topology = primToVK [ ( int ) desc . prim ] ;
2015-10-10 16:41:19 +02:00
2018-12-18 09:35:53 +01:00
// We treat the three stencil states as a unit in other places, so let's do that here too.
2022-09-06 13:30:18 +02:00
const VkDynamicState dynamics [ ] = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR , VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK , VK_DYNAMIC_STATE_STENCIL_REFERENCE , VK_DYNAMIC_STATE_STENCIL_WRITE_MASK } ;
gDesc . ds . dynamicStateCount = depth - > info . stencilTestEnable ? ARRAY_SIZE ( dynamics ) : 2 ;
2022-09-07 12:37:45 +02:00
for ( size_t i = 0 ; i < gDesc . ds . dynamicStateCount ; i + + ) {
2022-09-06 13:30:18 +02:00
gDesc . dynamicStates [ i ] = dynamics [ i ] ;
}
gDesc . ds . pDynamicStates = gDesc . dynamicStates ;
2015-10-10 16:41:19 +02:00
2022-09-06 13:30:18 +02:00
gDesc . views . viewportCount = 1 ;
gDesc . views . scissorCount = 1 ;
gDesc . views . pViewports = nullptr ; // dynamic
gDesc . views . pScissors = nullptr ; // dynamic
gDesc . pipelineLayout = pipelineLayout_ ;
2015-10-10 16:41:19 +02:00
2016-12-26 17:03:01 +01:00
VkPipelineRasterizationStateCreateInfo rs { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO } ;
2022-09-06 13:30:18 +02:00
raster - > ToVulkan ( & gDesc . rs ) ;
2020-05-18 22:45:20 -07:00
2022-11-27 11:39:44 +01:00
pipeline - > pipeline = renderManager_ . CreateGraphicsPipeline ( & gDesc , pipelineFlags , 1 < < ( size_t ) RenderPassType : : BACKBUFFER , VK_SAMPLE_COUNT_1_BIT , tag ? tag : " thin3d " ) ;
2020-05-18 22:45:20 -07:00
2017-02-08 12:26:48 +01:00
if ( desc . uniformDesc ) {
2017-02-09 13:27:45 +01:00
pipeline - > dynamicUniformSize = ( int ) desc . uniformDesc - > uniformBufferSize ;
2017-02-08 12:26:48 +01:00
}
2018-12-18 09:35:53 +01:00
if ( depth - > info . stencilTestEnable ) {
pipeline - > usesStencil = true ;
}
2015-10-10 16:41:19 +02:00
return pipeline ;
}
2016-12-25 21:21:56 +01:00
void VKContext : : SetScissorRect ( int left , int top , int width , int height ) {
2021-12-08 22:34:47 +01:00
renderManager_ . SetScissor ( left , top , width , height ) ;
2015-10-10 16:41:19 +02:00
}
2016-12-25 21:21:56 +01:00
void VKContext : : SetViewports ( int count , Viewport * viewports ) {
2017-05-21 17:24:40 +02:00
if ( count > 0 ) {
2019-06-21 00:53:51 +02:00
// Ignore viewports more than the first.
2017-08-19 17:32:10 +02:00
VkViewport viewport ;
2019-10-13 19:56:25 +02:00
viewport . x = viewports [ 0 ] . TopLeftX ;
viewport . y = viewports [ 0 ] . TopLeftY ;
viewport . width = viewports [ 0 ] . Width ;
viewport . height = viewports [ 0 ] . Height ;
2017-08-19 17:32:10 +02:00
viewport . minDepth = viewports [ 0 ] . MinDepth ;
viewport . maxDepth = viewports [ 0 ] . MaxDepth ;
renderManager_ . SetViewport ( viewport ) ;
2017-05-21 17:24:40 +02:00
}
2015-10-10 16:41:19 +02:00
}
2016-12-27 15:52:03 +01:00
void VKContext : : SetBlendFactor ( float color [ 4 ] ) {
2019-10-13 21:15:01 +02:00
uint32_t col = Float4ToUint8x4 ( color ) ;
renderManager_ . SetBlendFactor ( col ) ;
2016-12-27 15:52:03 +01:00
}
2022-07-24 16:31:02 +02:00
void VKContext : : SetStencilParams ( uint8_t refValue , uint8_t writeMask , uint8_t compareMask ) {
2018-12-18 09:35:53 +01:00
if ( curPipeline_ - > usesStencil )
2022-07-24 16:31:02 +02:00
renderManager_ . SetStencilParams ( writeMask , compareMask , refValue ) ;
stencilRef_ = refValue ;
2022-07-24 18:56:02 +02:00
stencilWriteMask_ = writeMask ;
stencilCompareMask_ = compareMask ;
2018-12-18 09:35:53 +01:00
}
2016-12-26 13:22:48 +01:00
InputLayout * VKContext : : CreateInputLayout ( const InputLayoutDesc & desc ) {
VKInputLayout * vl = new VKInputLayout ( ) ;
vl - > visc = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO } ;
vl - > visc . flags = 0 ;
vl - > visc . vertexAttributeDescriptionCount = ( uint32_t ) desc . attributes . size ( ) ;
vl - > visc . vertexBindingDescriptionCount = ( uint32_t ) desc . bindings . size ( ) ;
vl - > bindings . resize ( vl - > visc . vertexBindingDescriptionCount ) ;
vl - > attributes . resize ( vl - > visc . vertexAttributeDescriptionCount ) ;
vl - > visc . pVertexBindingDescriptions = vl - > bindings . data ( ) ;
vl - > visc . pVertexAttributeDescriptions = vl - > attributes . data ( ) ;
for ( size_t i = 0 ; i < desc . attributes . size ( ) ; i + + ) {
vl - > attributes [ i ] . binding = ( uint32_t ) desc . attributes [ i ] . binding ;
vl - > attributes [ i ] . format = DataFormatToVulkan ( desc . attributes [ i ] . format ) ;
vl - > attributes [ i ] . location = desc . attributes [ i ] . location ;
vl - > attributes [ i ] . offset = desc . attributes [ i ] . offset ;
}
for ( size_t i = 0 ; i < desc . bindings . size ( ) ; i + + ) {
vl - > bindings [ i ] . inputRate = desc . bindings [ i ] . instanceRate ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX ;
vl - > bindings [ i ] . binding = ( uint32_t ) i ;
vl - > bindings [ i ] . stride = desc . bindings [ i ] . stride ;
}
return vl ;
2015-10-10 16:41:19 +02:00
}
2017-01-16 23:43:07 +07:00
Texture * VKContext : : CreateTexture ( const TextureDesc & desc ) {
2018-11-21 17:33:30 +01:00
VkCommandBuffer initCmd = renderManager_ . GetInitCmd ( ) ;
if ( ! push_ | | ! initCmd ) {
2018-03-01 12:11:10 +01:00
// Too early! Fail.
2020-08-15 16:13:24 +02:00
ERROR_LOG ( G3D , " Can't create textures before the first frame has started. " ) ;
2018-03-01 12:11:10 +01:00
return nullptr ;
}
2018-11-21 17:33:30 +01:00
VKTexture * tex = new VKTexture ( vulkan_ , initCmd , push_ , desc ) ;
2021-11-21 23:38:14 +01:00
if ( tex - > Create ( initCmd , push_ , desc ) ) {
2018-11-21 17:33:30 +01:00
return tex ;
} else {
2020-08-15 16:13:24 +02:00
ERROR_LOG ( G3D , " Failed to create texture " ) ;
2018-11-21 17:33:30 +01:00
delete tex ;
return nullptr ;
}
2015-10-10 16:41:19 +02:00
}
2022-07-24 15:56:06 +02:00
static inline void CopySide ( VkStencilOpState & dest , const StencilSetup & src ) {
2016-12-26 23:11:31 +01:00
dest . compareOp = compToVK [ ( int ) src . compareOp ] ;
dest . failOp = stencilOpToVK [ ( int ) src . failOp ] ;
dest . passOp = stencilOpToVK [ ( int ) src . passOp ] ;
dest . depthFailOp = stencilOpToVK [ ( int ) src . depthFailOp ] ;
}
2016-12-25 21:21:56 +01:00
DepthStencilState * VKContext : : CreateDepthStencilState ( const DepthStencilStateDesc & desc ) {
VKDepthStencilState * ds = new VKDepthStencilState ( ) ;
2016-12-26 23:11:31 +01:00
ds - > info . depthCompareOp = compToVK [ ( int ) desc . depthCompare ] ;
ds - > info . depthTestEnable = desc . depthTestEnabled ;
ds - > info . depthWriteEnable = desc . depthWriteEnabled ;
2018-12-18 09:35:53 +01:00
ds - > info . stencilTestEnable = desc . stencilEnabled ;
2016-12-26 23:11:31 +01:00
ds - > info . depthBoundsTestEnable = false ;
if ( ds - > info . stencilTestEnable ) {
2022-07-24 15:56:06 +02:00
CopySide ( ds - > info . front , desc . stencil ) ;
CopySide ( ds - > info . back , desc . stencil ) ;
2016-12-26 23:11:31 +01:00
}
2015-10-10 16:41:19 +02:00
return ds ;
}
2016-12-25 21:21:56 +01:00
BlendState * VKContext : : CreateBlendState ( const BlendStateDesc & desc ) {
VKBlendState * bs = new VKBlendState ( ) ;
2016-12-26 18:32:52 +01:00
bs - > info . sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO ;
bs - > info . attachmentCount = 1 ;
bs - > info . logicOp = logicOpToVK [ ( int ) desc . logicOp ] ;
bs - > info . logicOpEnable = desc . logicEnabled ;
bs - > attachments . resize ( 1 ) ;
bs - > attachments [ 0 ] . blendEnable = desc . enabled ;
bs - > attachments [ 0 ] . colorBlendOp = blendEqToVk [ ( int ) desc . eqCol ] ;
bs - > attachments [ 0 ] . alphaBlendOp = blendEqToVk [ ( int ) desc . eqAlpha ] ;
bs - > attachments [ 0 ] . colorWriteMask = desc . colorMask ;
bs - > attachments [ 0 ] . dstAlphaBlendFactor = blendFactorToVk [ ( int ) desc . dstAlpha ] ;
bs - > attachments [ 0 ] . dstColorBlendFactor = blendFactorToVk [ ( int ) desc . dstCol ] ;
bs - > attachments [ 0 ] . srcAlphaBlendFactor = blendFactorToVk [ ( int ) desc . srcAlpha ] ;
bs - > attachments [ 0 ] . srcColorBlendFactor = blendFactorToVk [ ( int ) desc . srcCol ] ;
bs - > info . pAttachments = bs - > attachments . data ( ) ;
2015-10-10 16:41:19 +02:00
return bs ;
}
2017-02-07 19:04:44 +01:00
// Very simplistic buffer that will simply copy its contents into our "pushbuffer" when it's time to draw,
// to avoid synchronization issues.
class VKBuffer : public Buffer {
public :
VKBuffer ( size_t size , uint32_t flags ) : dataSize_ ( size ) {
data_ = new uint8_t [ size ] ;
}
2022-12-10 20:32:12 -08:00
~ VKBuffer ( ) {
2017-02-07 19:04:44 +01:00
delete [ ] data_ ;
}
size_t GetSize ( ) const { return dataSize_ ; }
const uint8_t * GetData ( ) const { return data_ ; }
uint8_t * data_ ;
size_t dataSize_ ;
} ;
2016-12-25 21:21:56 +01:00
Buffer * VKContext : : CreateBuffer ( size_t size , uint32_t usageFlags ) {
2017-01-17 23:14:47 +07:00
return new VKBuffer ( size , usageFlags ) ;
2015-10-10 16:41:19 +02:00
}
2017-02-07 19:41:58 +01:00
void VKContext : : UpdateBuffer ( Buffer * buffer , const uint8_t * data , size_t offset , size_t size , UpdateBufferFlags flags ) {
2017-02-07 19:04:44 +01:00
VKBuffer * buf = ( VKBuffer * ) buffer ;
memcpy ( buf - > data_ + offset , data , size ) ;
2017-02-07 18:16:52 +01:00
}
2022-10-25 23:32:28 +02:00
void VKContext : : BindTextures ( int start , int count , Texture * * textures , TextureBindFlags flags ) {
2021-06-12 10:10:42 -07:00
_assert_ ( start + count < = MAX_BOUND_TEXTURES ) ;
2015-10-10 16:41:19 +02:00
for ( int i = start ; i < start + count ; i + + ) {
2022-10-25 23:59:42 +02:00
_dbg_assert_ ( i > = 0 & & i < MAX_BOUND_TEXTURES ) ;
2020-05-17 10:44:21 -07:00
boundTextures_ [ i ] = static_cast < VKTexture * > ( textures [ i - start ] ) ;
2022-10-25 23:32:28 +02:00
boundTextureFlags_ [ i ] = flags ;
if ( boundTextures_ [ i ] ) {
2022-10-26 10:45:58 +02:00
// If a texture is bound, we set these up in GetOrCreateDescriptorSet too.
// But we might need to set the view here anyway so it can be queried using GetNativeObject.
2022-10-25 23:32:28 +02:00
if ( flags & TextureBindFlags : : VULKAN_BIND_ARRAY ) {
boundImageView_ [ i ] = boundTextures_ [ i ] - > GetImageArrayView ( ) ;
} else {
boundImageView_ [ i ] = boundTextures_ [ i ] - > GetImageView ( ) ;
}
} else {
2022-10-28 18:40:55 +02:00
if ( flags & TextureBindFlags : : VULKAN_BIND_ARRAY ) {
boundImageView_ [ i ] = GetNullTexture ( ) - > GetImageArrayView ( ) ;
} else {
boundImageView_ [ i ] = GetNullTexture ( ) - > GetImageView ( ) ;
}
2022-10-25 23:32:28 +02:00
}
2015-10-10 16:41:19 +02:00
}
}
2022-09-14 00:13:29 +02:00
void VKContext : : BindNativeTexture ( int sampler , void * nativeTexture ) {
2022-10-25 23:59:42 +02:00
_dbg_assert_ ( sampler > = 0 & & sampler < MAX_BOUND_TEXTURES ) ;
2022-09-14 00:13:29 +02:00
boundTextures_ [ sampler ] = nullptr ;
boundImageView_ [ sampler ] = ( VkImageView ) nativeTexture ;
}
2022-09-07 23:55:33 +02:00
ShaderModule * VKContext : : CreateShaderModule ( ShaderStage stage , ShaderLanguage language , const uint8_t * data , size_t size , const char * tag ) {
2020-05-10 15:06:17 -07:00
VKShaderModule * shader = new VKShaderModule ( stage , tag ) ;
2016-12-27 17:38:26 +01:00
if ( shader - > Compile ( vulkan_ , language , data , size ) ) {
2015-10-10 16:41:19 +02:00
return shader ;
} else {
2022-09-07 23:55:33 +02:00
ERROR_LOG ( G3D , " Failed to compile shader %s: \n %s " , tag , ( const char * ) LineNumberString ( ( const char * ) data ) . c_str ( ) ) ;
2015-10-10 16:41:19 +02:00
shader - > Release ( ) ;
return nullptr ;
}
}
2017-02-08 12:26:48 +01:00
void VKContext : : UpdateDynamicUniformBuffer ( const void * ub , size_t size ) {
curPipeline_ - > SetDynamicUniformData ( ub , size ) ;
}
2018-12-18 09:35:53 +01:00
void VKContext : : ApplyDynamicState ( ) {
// TODO: blend constants, stencil, viewports should be here, after bindpipeline..
if ( curPipeline_ - > usesStencil ) {
2022-07-24 18:56:02 +02:00
renderManager_ . SetStencilParams ( stencilWriteMask_ , stencilCompareMask_ , stencilRef_ ) ;
2018-12-18 09:35:53 +01:00
}
}
2017-01-17 23:14:47 +07:00
void VKContext : : Draw ( int vertexCount , int offset ) {
VKBuffer * vbuf = curVBuffers_ [ 0 ] ;
2015-10-10 16:41:19 +02:00
2016-03-20 09:52:13 +01:00
VkBuffer vulkanVbuf ;
VkBuffer vulkanUBObuf ;
2016-12-26 11:06:17 +01:00
uint32_t ubo_offset = ( uint32_t ) curPipeline_ - > PushUBO ( push_ , vulkan_ , & vulkanUBObuf ) ;
2016-03-21 00:35:27 -07:00
size_t vbBindOffset = push_ - > Push ( vbuf - > GetData ( ) , vbuf - > GetSize ( ) , & vulkanVbuf ) ;
2015-10-10 16:41:19 +02:00
2016-03-20 09:52:13 +01:00
VkDescriptorSet descSet = GetOrCreateDescriptorSet ( vulkanUBObuf ) ;
2021-10-06 23:20:13 -07:00
if ( descSet = = VK_NULL_HANDLE ) {
ERROR_LOG ( G3D , " GetOrCreateDescriptorSet failed, skipping %s " , __FUNCTION__ ) ;
return ;
}
2017-08-18 15:08:40 +02:00
2022-09-06 13:30:18 +02:00
BindCurrentPipeline ( ) ;
2018-12-18 09:35:53 +01:00
ApplyDynamicState ( ) ;
2022-09-01 14:21:34 +02:00
renderManager_ . Draw ( descSet , 1 , & ubo_offset , vulkanVbuf , ( int ) vbBindOffset + curVBufferOffsets_ [ 0 ] , vertexCount , offset ) ;
2015-10-10 16:41:19 +02:00
}
2017-01-17 23:14:47 +07:00
void VKContext : : DrawIndexed ( int vertexCount , int offset ) {
2017-11-05 22:15:27 -08:00
VKBuffer * ibuf = curIBuffer_ ;
VKBuffer * vbuf = curVBuffers_ [ 0 ] ;
2015-10-10 16:41:19 +02:00
2016-03-20 09:52:13 +01:00
VkBuffer vulkanVbuf , vulkanIbuf , vulkanUBObuf ;
2016-12-26 11:06:17 +01:00
uint32_t ubo_offset = ( uint32_t ) curPipeline_ - > PushUBO ( push_ , vulkan_ , & vulkanUBObuf ) ;
2016-03-20 09:52:13 +01:00
size_t vbBindOffset = push_ - > Push ( vbuf - > GetData ( ) , vbuf - > GetSize ( ) , & vulkanVbuf ) ;
size_t ibBindOffset = push_ - > Push ( ibuf - > GetData ( ) , ibuf - > GetSize ( ) , & vulkanIbuf ) ;
2015-10-10 16:41:19 +02:00
2016-03-20 09:52:13 +01:00
VkDescriptorSet descSet = GetOrCreateDescriptorSet ( vulkanUBObuf ) ;
2021-10-06 23:20:13 -07:00
if ( descSet = = VK_NULL_HANDLE ) {
ERROR_LOG ( G3D , " GetOrCreateDescriptorSet failed, skipping %s " , __FUNCTION__ ) ;
return ;
}
2015-10-10 16:41:19 +02:00
2022-09-06 13:30:18 +02:00
BindCurrentPipeline ( ) ;
2018-12-18 09:35:53 +01:00
ApplyDynamicState ( ) ;
2022-09-01 14:21:34 +02:00
renderManager_ . DrawIndexed ( descSet , 1 , & ubo_offset , vulkanVbuf , ( int ) vbBindOffset + curVBufferOffsets_ [ 0 ] , vulkanIbuf , ( int ) ibBindOffset + offset * sizeof ( uint32_t ) , vertexCount , 1 , VK_INDEX_TYPE_UINT16 ) ;
2015-10-10 16:41:19 +02:00
}
2016-12-26 17:03:01 +01:00
void VKContext : : DrawUP ( const void * vdata , int vertexCount ) {
2016-03-20 09:52:13 +01:00
VkBuffer vulkanVbuf , vulkanUBObuf ;
2016-12-26 17:03:01 +01:00
size_t vbBindOffset = push_ - > Push ( vdata , vertexCount * curPipeline_ - > stride [ 0 ] , & vulkanVbuf ) ;
2016-12-26 11:06:17 +01:00
uint32_t ubo_offset = ( uint32_t ) curPipeline_ - > PushUBO ( push_ , vulkan_ , & vulkanUBObuf ) ;
2015-10-10 16:41:19 +02:00
2016-03-20 09:52:13 +01:00
VkDescriptorSet descSet = GetOrCreateDescriptorSet ( vulkanUBObuf ) ;
2021-10-06 23:20:13 -07:00
if ( descSet = = VK_NULL_HANDLE ) {
ERROR_LOG ( G3D , " GetOrCreateDescriptorSet failed, skipping %s " , __FUNCTION__ ) ;
return ;
}
2017-08-18 15:08:40 +02:00
2022-09-06 13:30:18 +02:00
BindCurrentPipeline ( ) ;
2018-12-18 09:35:53 +01:00
ApplyDynamicState ( ) ;
2022-09-01 14:21:34 +02:00
renderManager_ . Draw ( descSet , 1 , & ubo_offset , vulkanVbuf , ( int ) vbBindOffset + curVBufferOffsets_ [ 0 ] , vertexCount ) ;
2015-10-10 16:41:19 +02:00
}
2022-09-06 13:30:18 +02:00
void VKContext : : BindCurrentPipeline ( ) {
renderManager_ . BindPipeline ( curPipeline_ - > pipeline , curPipeline_ - > flags , pipelineLayout_ ) ;
2020-05-18 22:45:20 -07:00
}
2017-08-18 15:08:40 +02:00
void VKContext : : Clear ( int clearMask , uint32_t colorval , float depthVal , int stencilVal ) {
int mask = 0 ;
if ( clearMask & FBChannel : : FB_COLOR_BIT )
mask | = VK_IMAGE_ASPECT_COLOR_BIT ;
if ( clearMask & FBChannel : : FB_DEPTH_BIT )
mask | = VK_IMAGE_ASPECT_DEPTH_BIT ;
if ( clearMask & FBChannel : : FB_STENCIL_BIT )
mask | = VK_IMAGE_ASPECT_STENCIL_BIT ;
renderManager_ . Clear ( colorval , depthVal , stencilVal , mask ) ;
2015-10-10 16:41:19 +02:00
}
2022-09-17 00:36:43 +02:00
DrawContext * T3DCreateVulkanContext ( VulkanContext * vulkan ) {
return new VKContext ( vulkan ) ;
2016-01-06 12:52:08 +01:00
}
2016-01-03 14:00:05 +01:00
void AddFeature ( std : : vector < std : : string > & features , const char * name , VkBool32 available , VkBool32 enabled ) {
char buf [ 512 ] ;
snprintf ( buf , sizeof ( buf ) , " %s: Available: %d Enabled: %d " , name , ( int ) available , ( int ) enabled ) ;
features . push_back ( buf ) ;
}
2016-12-26 17:31:20 +01:00
std : : vector < std : : string > VKContext : : GetFeatureList ( ) const {
2022-10-23 22:05:33 +02:00
const VkPhysicalDeviceFeatures & available = vulkan_ - > GetDeviceFeatures ( ) . available . standard ;
const VkPhysicalDeviceFeatures & enabled = vulkan_ - > GetDeviceFeatures ( ) . enabled . standard ;
2016-12-26 17:31:20 +01:00
2016-01-03 14:00:05 +01:00
std : : vector < std : : string > features ;
AddFeature ( features , " dualSrcBlend " , available . dualSrcBlend , enabled . dualSrcBlend ) ;
AddFeature ( features , " logicOp " , available . logicOp , enabled . logicOp ) ;
AddFeature ( features , " geometryShader " , available . geometryShader , enabled . geometryShader ) ;
AddFeature ( features , " depthBounds " , available . depthBounds , enabled . depthBounds ) ;
AddFeature ( features , " depthClamp " , available . depthClamp , enabled . depthClamp ) ;
AddFeature ( features , " fillModeNonSolid " , available . fillModeNonSolid , enabled . fillModeNonSolid ) ;
AddFeature ( features , " pipelineStatisticsQuery " , available . pipelineStatisticsQuery , enabled . pipelineStatisticsQuery ) ;
AddFeature ( features , " samplerAnisotropy " , available . samplerAnisotropy , enabled . samplerAnisotropy ) ;
AddFeature ( features , " textureCompressionBC " , available . textureCompressionBC , enabled . textureCompressionBC ) ;
AddFeature ( features , " textureCompressionETC2 " , available . textureCompressionETC2 , enabled . textureCompressionETC2 ) ;
AddFeature ( features , " textureCompressionASTC_LDR " , available . textureCompressionASTC_LDR , enabled . textureCompressionASTC_LDR ) ;
AddFeature ( features , " shaderClipDistance " , available . shaderClipDistance , enabled . shaderClipDistance ) ;
AddFeature ( features , " shaderCullDistance " , available . shaderCullDistance , enabled . shaderCullDistance ) ;
2016-01-19 18:41:45 +01:00
AddFeature ( features , " occlusionQueryPrecise " , available . occlusionQueryPrecise , enabled . occlusionQueryPrecise ) ;
AddFeature ( features , " multiDrawIndirect " , available . multiDrawIndirect , enabled . multiDrawIndirect ) ;
2016-01-10 12:27:45 +01:00
2022-10-23 22:05:33 +02:00
AddFeature ( features , " multiview " , vulkan_ - > GetDeviceFeatures ( ) . available . multiview . multiview , vulkan_ - > GetDeviceFeatures ( ) . enabled . multiview . multiview ) ;
AddFeature ( features , " multiviewGeometryShader " , vulkan_ - > GetDeviceFeatures ( ) . available . multiview . multiviewGeometryShader , vulkan_ - > GetDeviceFeatures ( ) . enabled . multiview . multiviewGeometryShader ) ;
2022-09-30 12:35:28 +03:00
features . emplace_back ( std : : string ( " Preferred depth buffer format: " ) + VulkanFormatToString ( vulkan_ - > GetDeviceInfo ( ) . preferredDepthStencilFormat ) ) ;
2017-11-15 09:07:51 +01:00
2016-01-03 14:00:05 +01:00
return features ;
}
2016-12-25 18:18:19 +01:00
2017-08-28 13:45:04 +02:00
std : : vector < std : : string > VKContext : : GetExtensionList ( ) const {
std : : vector < std : : string > extensions ;
for ( auto & iter : vulkan_ - > GetDeviceExtensionsAvailable ( ) ) {
extensions . push_back ( iter . extensionName ) ;
}
return extensions ;
}
2017-01-19 12:16:36 +07:00
uint32_t VKContext : : GetDataFormatSupport ( DataFormat fmt ) const {
2020-03-01 14:07:13 +01:00
VkFormat vulkan_format = DataFormatToVulkan ( fmt ) ;
VkFormatProperties properties ;
vkGetPhysicalDeviceFormatProperties ( vulkan_ - > GetCurrentPhysicalDevice ( ) , vulkan_format , & properties ) ;
uint32_t flags = 0 ;
2022-08-01 23:21:14 +02:00
if ( properties . optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT ) {
2020-03-01 14:07:13 +01:00
flags | = FMT_RENDERTARGET ;
}
2022-08-01 23:21:14 +02:00
if ( properties . optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT ) {
2020-03-01 14:07:13 +01:00
flags | = FMT_DEPTHSTENCIL ;
}
2022-08-01 23:21:14 +02:00
if ( properties . optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT ) {
2020-03-01 14:07:13 +01:00
flags | = FMT_TEXTURE ;
}
2022-08-01 23:21:14 +02:00
if ( properties . bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT ) {
2020-03-01 14:07:13 +01:00
flags | = FMT_INPUTLAYOUT ;
2017-01-19 12:16:36 +07:00
}
2022-08-01 23:21:14 +02:00
if ( ( properties . optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT ) & & ( properties . optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT ) ) {
flags | = FMT_BLIT ;
}
if ( properties . optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT ) {
flags | = FMT_STORAGE_IMAGE ;
}
2020-03-01 14:07:13 +01:00
return flags ;
2017-01-19 12:16:36 +07:00
}
2017-05-23 21:56:48 +02:00
// A VKFramebuffer is a VkFramebuffer (note caps difference) plus all the textures it owns.
2017-05-19 17:21:08 +02:00
// It also has a reference to the command buffer that it was last rendered to with.
// If it needs to be transitioned, and the frame number matches, use it, otherwise
// use this frame's init command buffer.
2017-02-06 01:38:50 +01:00
class VKFramebuffer : public Framebuffer {
public :
2022-11-28 23:56:55 +01:00
VKFramebuffer ( VKRFramebuffer * fb , int multiSampleLevel ) : buf_ ( fb ) {
2020-11-06 09:01:13 +01:00
_assert_msg_ ( fb , " Null fb in VKFramebuffer constructor " ) ;
width_ = fb - > width ;
height_ = fb - > height ;
2022-10-21 12:35:49 +02:00
layers_ = fb - > numLayers ;
2022-11-28 23:56:55 +01:00
multiSampleLevel_ = multiSampleLevel ;
2020-11-06 09:01:13 +01:00
}
2017-05-16 17:20:22 +02:00
~ VKFramebuffer ( ) {
2020-07-19 17:47:02 +02:00
_assert_msg_ ( buf_ , " Null buf_ in VKFramebuffer - double delete? " ) ;
2022-11-27 11:39:44 +01:00
buf_ - > Vulkan ( ) - > Delete ( ) . QueueCallback ( [ ] ( void * fb ) {
2017-11-11 19:41:43 +01:00
VKRFramebuffer * vfb = static_cast < VKRFramebuffer * > ( fb ) ;
delete vfb ;
} , buf_ ) ;
2017-12-01 12:03:02 +01:00
buf_ = nullptr ;
2017-05-16 17:20:22 +02:00
}
2017-08-19 17:32:10 +02:00
VKRFramebuffer * GetFB ( ) const { return buf_ ; }
2022-09-28 14:09:40 +02:00
void UpdateTag ( const char * newTag ) override {
buf_ - > UpdateTag ( newTag ) ;
}
2017-05-16 17:20:22 +02:00
private :
2017-08-19 17:32:10 +02:00
VKRFramebuffer * buf_ ;
2017-02-06 01:38:50 +01:00
} ;
2017-02-06 11:26:24 +01:00
Framebuffer * VKContext : : CreateFramebuffer ( const FramebufferDesc & desc ) {
2022-11-28 18:20:30 +01:00
_assert_ ( desc . multiSampleLevel > = 0 ) ;
2022-11-27 11:39:44 +01:00
_assert_ ( desc . numLayers > 0 ) ;
_assert_ ( desc . width > 0 ) ;
_assert_ ( desc . height > 0 ) ;
2017-08-19 17:32:10 +02:00
VkCommandBuffer cmd = renderManager_ . GetInitCmd ( ) ;
2022-11-28 18:20:30 +01:00
VKRFramebuffer * vkrfb = new VKRFramebuffer ( vulkan_ , cmd , renderManager_ . GetQueueRunner ( ) - > GetCompatibleRenderPass ( ) , desc . width , desc . height , desc . numLayers , desc . multiSampleLevel , desc . z_stencil , desc . tag ) ;
2022-11-28 23:56:55 +01:00
return new VKFramebuffer ( vkrfb , desc . multiSampleLevel ) ;
2017-02-06 01:38:50 +01:00
}
2020-05-21 11:24:05 +02:00
void VKContext : : CopyFramebufferImage ( Framebuffer * srcfb , int level , int x , int y , int z , Framebuffer * dstfb , int dstLevel , int dstX , int dstY , int dstZ , int width , int height , int depth , int channelBits , const char * tag ) {
2017-02-12 11:20:55 +01:00
VKFramebuffer * src = ( VKFramebuffer * ) srcfb ;
VKFramebuffer * dst = ( VKFramebuffer * ) dstfb ;
2017-05-23 23:10:35 +02:00
2017-08-22 12:55:30 +02:00
int aspectMask = 0 ;
if ( channelBits & FBChannel : : FB_COLOR_BIT ) aspectMask | = VK_IMAGE_ASPECT_COLOR_BIT ;
if ( channelBits & FBChannel : : FB_DEPTH_BIT ) aspectMask | = VK_IMAGE_ASPECT_DEPTH_BIT ;
if ( channelBits & FBChannel : : FB_STENCIL_BIT ) aspectMask | = VK_IMAGE_ASPECT_STENCIL_BIT ;
2020-05-21 11:24:05 +02:00
renderManager_ . CopyFramebuffer ( src - > GetFB ( ) , VkRect2D { { x , y } , { ( uint32_t ) width , ( uint32_t ) height } } , dst - > GetFB ( ) , VkOffset2D { dstX , dstY } , aspectMask , tag ) ;
2017-05-23 23:10:35 +02:00
}
2020-05-21 11:24:05 +02:00
bool VKContext : : BlitFramebuffer ( Framebuffer * srcfb , int srcX1 , int srcY1 , int srcX2 , int srcY2 , Framebuffer * dstfb , int dstX1 , int dstY1 , int dstX2 , int dstY2 , int channelBits , FBBlitFilter filter , const char * tag ) {
2017-05-24 00:45:15 +02:00
VKFramebuffer * src = ( VKFramebuffer * ) srcfb ;
VKFramebuffer * dst = ( VKFramebuffer * ) dstfb ;
2017-08-22 12:55:30 +02:00
int aspectMask = 0 ;
if ( channelBits & FBChannel : : FB_COLOR_BIT ) aspectMask | = VK_IMAGE_ASPECT_COLOR_BIT ;
if ( channelBits & FBChannel : : FB_DEPTH_BIT ) aspectMask | = VK_IMAGE_ASPECT_DEPTH_BIT ;
if ( channelBits & FBChannel : : FB_STENCIL_BIT ) aspectMask | = VK_IMAGE_ASPECT_STENCIL_BIT ;
2020-05-21 11:24:05 +02:00
renderManager_ . BlitFramebuffer ( src - > GetFB ( ) , VkRect2D { { srcX1 , srcY1 } , { ( uint32_t ) ( srcX2 - srcX1 ) , ( uint32_t ) ( srcY2 - srcY1 ) } } , dst - > GetFB ( ) , VkRect2D { { dstX1 , dstY1 } , { ( uint32_t ) ( dstX2 - dstX1 ) , ( uint32_t ) ( dstY2 - dstY1 ) } } , aspectMask , filter = = FB_BLIT_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST , tag ) ;
2017-05-24 00:45:15 +02:00
return true ;
}
2020-05-21 11:24:05 +02:00
bool VKContext : : CopyFramebufferToMemorySync ( Framebuffer * srcfb , int channelBits , int x , int y , int w , int h , Draw : : DataFormat format , void * pixels , int pixelStride , const char * tag ) {
2017-10-28 18:03:27 +02:00
VKFramebuffer * src = ( VKFramebuffer * ) srcfb ;
int aspectMask = 0 ;
2017-10-31 12:02:10 +01:00
if ( channelBits & FBChannel : : FB_COLOR_BIT ) aspectMask | = VK_IMAGE_ASPECT_COLOR_BIT ;
2017-10-28 18:03:27 +02:00
if ( channelBits & FBChannel : : FB_DEPTH_BIT ) aspectMask | = VK_IMAGE_ASPECT_DEPTH_BIT ;
if ( channelBits & FBChannel : : FB_STENCIL_BIT ) aspectMask | = VK_IMAGE_ASPECT_STENCIL_BIT ;
2020-05-21 11:24:05 +02:00
return renderManager_ . CopyFramebufferToMemorySync ( src ? src - > GetFB ( ) : nullptr , aspectMask , x , y , w , h , format , ( uint8_t * ) pixels , pixelStride , tag ) ;
2017-10-28 18:03:27 +02:00
}
2018-06-16 13:47:51 -07:00
DataFormat VKContext : : PreferredFramebufferReadbackFormat ( Framebuffer * src ) {
if ( src ) {
return DrawContext : : PreferredFramebufferReadbackFormat ( src ) ;
}
if ( vulkan_ - > GetSwapchainFormat ( ) = = VK_FORMAT_B8G8R8A8_UNORM ) {
return Draw : : DataFormat : : B8G8R8A8_UNORM ;
}
return DrawContext : : PreferredFramebufferReadbackFormat ( src ) ;
}
2022-10-23 11:21:35 +02:00
void VKContext : : BindFramebufferAsRenderTarget ( Framebuffer * fbo , const RenderPassInfo & rp , const char * tag ) {
2017-08-19 17:32:10 +02:00
VKFramebuffer * fb = ( VKFramebuffer * ) fbo ;
2022-06-11 13:22:40 +02:00
VKRRenderPassLoadAction color = ( VKRRenderPassLoadAction ) rp . color ;
VKRRenderPassLoadAction depth = ( VKRRenderPassLoadAction ) rp . depth ;
VKRRenderPassLoadAction stencil = ( VKRRenderPassLoadAction ) rp . stencil ;
2017-10-31 10:54:01 +01:00
2022-10-23 11:21:35 +02:00
renderManager_ . BindFramebufferAsRenderTarget ( fb ? fb - > GetFB ( ) : nullptr , color , depth , stencil , rp . clearColor , rp . clearDepth , rp . clearStencil , tag ) ;
2017-10-31 10:54:01 +01:00
curFramebuffer_ = fb ;
2017-02-12 11:20:55 +01:00
}
2017-05-16 13:53:57 +02:00
2022-10-18 00:26:10 +02:00
void VKContext : : BindFramebufferAsTexture ( Framebuffer * fbo , int binding , FBChannel channelBit , int layer ) {
2017-05-17 02:21:03 +02:00
VKFramebuffer * fb = ( VKFramebuffer * ) fbo ;
2022-10-25 23:59:42 +02:00
_assert_ ( binding > = 0 & & binding < MAX_BOUND_TEXTURES ) ;
2017-05-17 02:21:03 +02:00
2020-11-08 23:17:06 +01:00
// TODO: There are cases where this is okay, actually. But requires layout transitions and stuff -
// we're not ready for this.
2020-08-27 21:23:41 +02:00
_assert_ ( fb ! = curFramebuffer_ ) ;
2017-10-31 10:54:01 +01:00
2017-08-19 17:32:10 +02:00
int aspect = 0 ;
2020-08-27 21:23:41 +02:00
switch ( channelBit ) {
case FBChannel : : FB_COLOR_BIT :
aspect = VK_IMAGE_ASPECT_COLOR_BIT ;
break ;
case FBChannel : : FB_DEPTH_BIT :
aspect = VK_IMAGE_ASPECT_DEPTH_BIT ;
break ;
default :
_assert_ ( false ) ;
break ;
}
2022-10-20 10:15:19 +02:00
2022-10-25 23:59:42 +02:00
boundTextures_ [ binding ] . clear ( ) ;
2022-10-18 00:26:10 +02:00
boundImageView_ [ binding ] = renderManager_ . BindFramebufferAsTexture ( fb - > GetFB ( ) , binding , aspect , layer ) ;
2017-02-12 11:20:55 +01:00
}
2017-05-16 17:20:22 +02:00
2022-02-19 20:40:27 +01:00
void VKContext : : BindCurrentFramebufferForColorInput ( ) {
renderManager_ . BindCurrentFramebufferAsInputAttachment0 ( VK_IMAGE_ASPECT_COLOR_BIT ) ;
}
2017-02-06 11:26:24 +01:00
void VKContext : : GetFramebufferDimensions ( Framebuffer * fbo , int * w , int * h ) {
2017-02-06 01:38:50 +01:00
VKFramebuffer * fb = ( VKFramebuffer * ) fbo ;
2017-10-20 11:11:04 +02:00
if ( fb ) {
2017-08-19 17:32:10 +02:00
* w = fb - > GetFB ( ) - > width ;
* h = fb - > GetFB ( ) - > height ;
2017-10-20 11:11:04 +02:00
} else {
2017-08-19 17:32:10 +02:00
* w = vulkan_ - > GetBackbufferWidth ( ) ;
* h = vulkan_ - > GetBackbufferHeight ( ) ;
2017-10-20 11:11:04 +02:00
}
2017-02-06 01:38:50 +01:00
}
2017-03-05 20:30:39 +01:00
void VKContext : : HandleEvent ( Event ev , int width , int height , void * param1 , void * param2 ) {
2017-08-19 17:32:10 +02:00
switch ( ev ) {
case Event : : LOST_BACKBUFFER :
2017-08-22 12:55:30 +02:00
renderManager_ . DestroyBackbuffers ( ) ;
2017-08-19 17:32:10 +02:00
break ;
case Event : : GOT_BACKBUFFER :
2017-08-22 12:55:30 +02:00
renderManager_ . CreateBackbuffers ( ) ;
2017-08-19 17:32:10 +02:00
break ;
2017-10-25 19:05:09 +02:00
default :
2020-08-16 00:38:55 +02:00
_assert_ ( false ) ;
2017-10-25 19:05:09 +02:00
break ;
2017-08-19 17:32:10 +02:00
}
2017-02-27 10:09:21 +01:00
}
2022-08-28 23:16:48 +02:00
void VKContext : : InvalidateFramebuffer ( FBInvalidationStage stage , uint32_t channels ) {
VkImageAspectFlags flags = 0 ;
if ( channels & FBChannel : : FB_COLOR_BIT )
flags | = VK_IMAGE_ASPECT_COLOR_BIT ;
if ( channels & FBChannel : : FB_DEPTH_BIT )
flags | = VK_IMAGE_ASPECT_DEPTH_BIT ;
if ( channels & FBChannel : : FB_STENCIL_BIT )
flags | = VK_IMAGE_ASPECT_STENCIL_BIT ;
if ( stage = = FB_INVALIDATION_LOAD ) {
renderManager_ . SetLoadDontCare ( flags ) ;
} else if ( stage = = FB_INVALIDATION_STORE ) {
renderManager_ . SetStoreDontCare ( flags ) ;
}
}
2022-02-19 20:40:27 +01:00
uint64_t VKContext : : GetNativeObject ( NativeObject obj , void * srcObject ) {
switch ( obj ) {
case NativeObject : : CONTEXT :
return ( uint64_t ) vulkan_ ;
case NativeObject : : INIT_COMMANDBUFFER :
return ( uint64_t ) renderManager_ . GetInitCmd ( ) ;
case NativeObject : : BOUND_TEXTURE0_IMAGEVIEW :
return ( uint64_t ) boundImageView_ [ 0 ] ;
case NativeObject : : BOUND_TEXTURE1_IMAGEVIEW :
return ( uint64_t ) boundImageView_ [ 1 ] ;
case NativeObject : : RENDER_MANAGER :
return ( uint64_t ) ( uintptr_t ) & renderManager_ ;
case NativeObject : : NULL_IMAGEVIEW :
return ( uint64_t ) GetNullTexture ( ) - > GetImageView ( ) ;
2022-10-28 18:40:55 +02:00
case NativeObject : : NULL_IMAGEVIEW_ARRAY :
return ( uint64_t ) GetNullTexture ( ) - > GetImageArrayView ( ) ;
2022-02-19 20:40:27 +01:00
case NativeObject : : TEXTURE_VIEW :
return ( uint64_t ) ( ( ( VKTexture * ) srcObject ) - > GetImageView ( ) ) ;
2022-10-23 11:21:35 +02:00
case NativeObject : : BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_ALL_LAYERS :
return ( uint64_t ) curFramebuffer_ - > GetFB ( ) - > color . texAllLayersView ;
2022-11-07 09:14:55 +01:00
case NativeObject : : BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_RT :
2022-11-28 11:50:28 +01:00
return ( uint64_t ) curFramebuffer_ - > GetFB ( ) - > GetRTView ( ) ;
2022-10-28 09:23:44 +02:00
case NativeObject : : FRAME_DATA_DESC_SET_LAYOUT :
return ( uint64_t ) frameDescSetLayout_ ;
case NativeObject : : THIN3D_PIPELINE_LAYOUT :
return ( uint64_t ) pipelineLayout_ ;
2022-02-19 20:40:27 +01:00
default :
Crash ( ) ;
return 0 ;
}
}
2022-10-13 22:34:21 +02:00
void VKContext : : DebugAnnotate ( const char * annotation ) {
renderManager_ . DebugAnnotate ( annotation ) ;
}
2017-05-06 18:45:04 -07:00
} // namespace Draw