2016-02-21 18:50:49 +03:00
# include "stdafx.h"
# include "Emu/Memory/Memory.h"
# include "Emu/System.h"
# include "VKGSRender.h"
# include "../rsx_methods.h"
# include "../Common/BufferUtils.h"
namespace vk
{
bool requires_component_expansion ( rsx : : vertex_base_type type , u32 size )
{
if ( size = = 3 )
{
switch ( type )
{
case rsx : : vertex_base_type : : f :
return true ;
}
}
return false ;
}
u32 get_suitable_vk_size ( rsx : : vertex_base_type type , u32 size )
{
if ( size = = 3 )
{
switch ( type )
{
case rsx : : vertex_base_type : : f :
return 16 ;
}
}
return rsx : : get_vertex_type_size_on_host ( type , size ) ;
}
VkFormat get_suitable_vk_format ( rsx : : vertex_base_type type , u8 size )
{
/**
* Set up buffer fetches to only work on 4 - component access . This is hardware dependant so we use 4 - component access to avoid branching based on IHV implementation
* AMD GCN 1.0 for example does not support RGB32 formats for texel buffers
*/
2016-10-18 10:57:28 +03:00
const VkFormat vec1_types [ ] = { VK_FORMAT_R16_SNORM , VK_FORMAT_R32_SFLOAT , VK_FORMAT_R16_SFLOAT , VK_FORMAT_R8_UNORM , VK_FORMAT_R16_SINT , VK_FORMAT_R16G16B16A16_SNORM , VK_FORMAT_R8_UINT } ;
const VkFormat vec2_types [ ] = { VK_FORMAT_R16G16_SNORM , VK_FORMAT_R32G32_SFLOAT , VK_FORMAT_R16G16_SFLOAT , VK_FORMAT_R8G8_UNORM , VK_FORMAT_R16G16_SINT , VK_FORMAT_R16G16B16A16_SNORM , VK_FORMAT_R8G8_UINT } ;
const VkFormat vec3_types [ ] = { VK_FORMAT_R16G16B16A16_SNORM , VK_FORMAT_R32G32B32A32_SFLOAT , VK_FORMAT_R16G16B16A16_SFLOAT , VK_FORMAT_R8G8B8A8_UNORM , VK_FORMAT_R16G16B16A16_SINT , VK_FORMAT_R16G16B16A16_SNORM , VK_FORMAT_R8G8B8A8_UINT } ; //VEC3 COMPONENTS NOT SUPPORTED!
const VkFormat vec4_types [ ] = { VK_FORMAT_R16G16B16A16_SNORM , VK_FORMAT_R32G32B32A32_SFLOAT , VK_FORMAT_R16G16B16A16_SFLOAT , VK_FORMAT_R8G8B8A8_UNORM , VK_FORMAT_R16G16B16A16_SINT , VK_FORMAT_R16G16B16A16_SNORM , VK_FORMAT_R8G8B8A8_UINT } ;
2016-02-21 18:50:49 +03:00
const VkFormat * vec_selectors [ ] = { 0 , vec1_types , vec2_types , vec3_types , vec4_types } ;
if ( type > rsx : : vertex_base_type : : ub256 )
2016-08-08 19:01:06 +03:00
fmt : : throw_exception ( " VKGS error: unknown vertex base type 0x%x " HERE , ( u32 ) type ) ;
2016-02-21 18:50:49 +03:00
return vec_selectors [ size ] [ ( int ) type ] ;
}
VkPrimitiveTopology get_appropriate_topology ( rsx : : primitive_type & mode , bool & requires_modification )
{
requires_modification = false ;
switch ( mode )
{
case rsx : : primitive_type : : lines :
return VK_PRIMITIVE_TOPOLOGY_LINE_LIST ;
case rsx : : primitive_type : : line_loop :
requires_modification = true ;
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP ;
case rsx : : primitive_type : : line_strip :
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP ;
case rsx : : primitive_type : : points :
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST ;
case rsx : : primitive_type : : triangles :
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ;
case rsx : : primitive_type : : triangle_strip :
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP ;
case rsx : : primitive_type : : triangle_fan :
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN ;
case rsx : : primitive_type : : quads :
case rsx : : primitive_type : : quad_strip :
case rsx : : primitive_type : : polygon :
requires_modification = true ;
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ;
default :
2016-08-08 19:01:06 +03:00
fmt : : throw_exception ( " Unsupported primitive topology 0x%x " , ( u8 ) mode ) ;
2016-02-21 18:50:49 +03:00
}
}
2016-09-29 10:16:00 +03:00
bool is_primitive_native ( rsx : : primitive_type & mode )
{
bool result ;
get_appropriate_topology ( mode , result ) ;
return ! result ;
}
2016-02-21 18:50:49 +03:00
template < typename T , u32 padding >
void copy_inlined_data_to_buffer ( void * src_data , void * dst_data , u32 vertex_count , rsx : : vertex_base_type type , u8 src_channels , u8 dst_channels , u16 element_size , u16 stride )
{
u8 * src = static_cast < u8 * > ( src_data ) ;
u8 * dst = static_cast < u8 * > ( dst_data ) ;
for ( u32 i = 0 ; i < vertex_count ; + + i )
{
T * src_ptr = reinterpret_cast < T * > ( src ) ;
T * dst_ptr = reinterpret_cast < T * > ( dst ) ;
switch ( type )
{
case rsx : : vertex_base_type : : ub :
{
if ( src_channels = = 4 )
{
dst [ 0 ] = src [ 3 ] ;
dst [ 1 ] = src [ 2 ] ;
dst [ 2 ] = src [ 1 ] ;
dst [ 3 ] = src [ 0 ] ;
break ;
}
}
default :
{
for ( u8 ch = 0 ; ch < dst_channels ; + + ch )
{
if ( ch < src_channels )
{
* dst_ptr = * src_ptr ;
src_ptr + + ;
}
else
* dst_ptr = ( T ) ( padding ) ;
dst_ptr + + ;
}
}
}
src + = stride ;
dst + = element_size ;
}
}
void prepare_buffer_for_writing ( void * data , rsx : : vertex_base_type type , u8 vertex_size , u32 vertex_count )
{
switch ( type )
{
2016-07-02 17:27:53 +03:00
case rsx : : vertex_base_type : : f :
{
if ( vertex_size = = 3 )
{
float * dst = reinterpret_cast < float * > ( data ) ;
for ( u32 i = 0 , idx = 3 ; i < vertex_count ; + + i , idx + = 4 )
dst [ idx ] = 1.f ;
}
break ;
}
2016-02-21 18:50:49 +03:00
case rsx : : vertex_base_type : : sf :
{
if ( vertex_size = = 3 )
{
/**
* Pad the 4 th component for half - float arrays to 1 , since texelfetch does not mask components
*/
u16 * dst = reinterpret_cast < u16 * > ( data ) ;
for ( u32 i = 0 , idx = 3 ; i < vertex_count ; + + i , idx + = 4 )
dst [ idx ] = 0x3c00 ;
}
break ;
}
}
}
2016-07-02 17:27:53 +03:00
/**
* Template : Expand any N - compoent vector to a larger X - component vector and pad unused slots with 1
*/
template < typename T , u8 src_components , u8 dst_components , u32 padding >
void expand_array_components ( const T * src_data , void * dst_ptr , u32 vertex_count )
{
T * src = const_cast < T * > ( src_data ) ;
T * dst = static_cast < T * > ( dst_ptr ) ;
for ( u32 index = 0 ; index < vertex_count ; + + index )
{
for ( u8 channel = 0 ; channel < dst_components ; channel + + )
{
if ( channel < src_components )
{
* dst = * src ;
dst + + ;
src + + ;
}
else
{
* dst = ( T ) ( padding ) ;
dst + + ;
}
}
}
}
2016-07-31 23:01:31 +02:00
VkIndexType get_index_type ( rsx : : index_array_type type )
2016-07-02 17:27:53 +03:00
{
switch ( type )
{
2016-07-31 23:01:31 +02:00
case rsx : : index_array_type : : u32 :
return VK_INDEX_TYPE_UINT32 ;
case rsx : : index_array_type : : u16 :
return VK_INDEX_TYPE_UINT16 ;
2016-07-02 17:27:53 +03:00
}
2016-07-31 23:01:31 +02:00
throw ;
2016-07-02 17:27:53 +03:00
}
2016-03-16 00:34:36 +01:00
}
2016-08-04 23:21:45 +02:00
namespace
2016-02-21 18:50:49 +03:00
{
2016-08-04 23:21:45 +02:00
static constexpr std : : array < const char * , 16 > s_reg_table =
2016-02-21 18:50:49 +03:00
{
" in_pos_buffer " , " in_weight_buffer " , " in_normal_buffer " ,
" in_diff_color_buffer " , " in_spec_color_buffer " ,
" in_fog_buffer " ,
" in_point_size_buffer " , " in_7_buffer " ,
" in_tc0_buffer " , " in_tc1_buffer " , " in_tc2_buffer " , " in_tc3_buffer " ,
" in_tc4_buffer " , " in_tc5_buffer " , " in_tc6_buffer " , " in_tc7_buffer "
} ;
2016-08-04 23:21:45 +02:00
2016-08-28 17:00:02 +02:00
/**
* Creates and fills an index buffer emulating unsupported primitive type .
* Returns index_count and ( offset_in_index_buffer , index_type )
*/
std : : tuple < u32 , std : : tuple < VkDeviceSize , VkIndexType > > generate_emulating_index_buffer (
const rsx : : draw_clause & clause , u32 vertex_count ,
vk : : vk_data_heap & m_index_buffer_ring_info )
2016-02-21 18:50:49 +03:00
{
2016-08-28 17:00:02 +02:00
u32 index_count = get_index_count ( clause . primitive , vertex_count ) ;
u32 upload_size = index_count * sizeof ( u16 ) ;
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
VkDeviceSize offset_in_index_buffer = m_index_buffer_ring_info . alloc < 256 > ( upload_size ) ;
void * buf = m_index_buffer_ring_info . map ( offset_in_index_buffer , upload_size ) ;
2016-08-24 03:50:07 +03:00
2016-08-28 17:00:02 +02:00
write_index_array_for_non_indexed_non_native_primitive_to_buffer (
2017-06-27 00:34:22 +03:00
reinterpret_cast < char * > ( buf ) , clause . primitive , vertex_count ) ;
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
m_index_buffer_ring_info . unmap ( ) ;
return std : : make_tuple (
index_count , std : : make_tuple ( offset_in_index_buffer , VK_INDEX_TYPE_UINT16 ) ) ;
2016-08-04 23:21:45 +02:00
}
2016-02-21 18:50:49 +03:00
2016-08-21 19:17:09 +02:00
struct vertex_buffer_visitor
2016-08-04 23:21:45 +02:00
{
2016-08-28 17:00:02 +02:00
vertex_buffer_visitor ( u32 vtx_cnt , VkDevice dev , vk : : vk_data_heap & heap ,
vk : : glsl : : program * prog , VkDescriptorSet desc_set ,
2017-07-22 16:45:15 +03:00
std : : vector < std : : unique_ptr < vk : : buffer_view > > & buffer_view_to_clean ,
2017-07-26 19:32:13 +03:00
vk : : vertex_cache * vertex_cache )
2016-08-28 17:00:02 +02:00
: vertex_count ( vtx_cnt ) , m_attrib_ring_info ( heap ) , device ( dev ) , m_program ( prog ) ,
2017-07-22 16:45:15 +03:00
descriptor_sets ( desc_set ) , m_buffer_view_to_clean ( buffer_view_to_clean ) ,
2017-07-24 20:49:51 +03:00
vertex_cache ( vertex_cache )
2016-08-04 23:21:45 +02:00
{
}
2016-08-21 19:17:09 +02:00
void operator ( ) ( const rsx : : vertex_array_buffer & vertex_array )
2016-02-21 18:50:49 +03:00
{
2017-07-22 01:54:28 +03:00
if ( ! m_program - > has_uniform ( s_reg_table [ vertex_array . index ] ) )
return ;
2016-08-04 23:21:45 +02:00
// Fill vertex_array
2017-05-17 14:37:36 +03:00
u32 element_size = rsx : : get_vertex_type_size_on_host ( vertex_array . type , vertex_array . attribute_size ) ;
2016-08-21 19:17:09 +02:00
u32 real_element_size = vk : : get_suitable_vk_size ( vertex_array . type , vertex_array . attribute_size ) ;
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
u32 upload_size = real_element_size * vertex_count ;
2016-02-21 18:50:49 +03:00
2016-08-04 23:21:45 +02:00
VkDeviceSize offset_in_attrib_buffer = m_attrib_ring_info . alloc < 256 > ( upload_size ) ;
void * dst = m_attrib_ring_info . map ( offset_in_attrib_buffer , upload_size ) ;
2017-03-29 12:29:11 +03:00
2016-08-04 23:21:45 +02:00
gsl : : span < gsl : : byte > dest_span ( static_cast < gsl : : byte * > ( dst ) , upload_size ) ;
2016-08-21 19:17:09 +02:00
write_vertex_array_data_to_buffer ( dest_span , vertex_array . data , vertex_count , vertex_array . type , vertex_array . attribute_size , vertex_array . stride , real_element_size ) ;
2016-02-21 18:50:49 +03:00
2017-03-29 12:29:11 +03:00
//Padding the vertex buffer should be done after the writes have been done
//write_vertex_data function may 'dirty' unused sections of the buffer as optimization
vk : : prepare_buffer_for_writing ( dst , vertex_array . type , vertex_array . attribute_size , vertex_count ) ;
2016-08-04 23:21:45 +02:00
m_attrib_ring_info . unmap ( ) ;
2016-08-21 19:17:09 +02:00
const VkFormat format = vk : : get_suitable_vk_format ( vertex_array . type , vertex_array . attribute_size ) ;
2016-02-21 18:50:49 +03:00
2017-07-22 16:45:15 +03:00
const uintptr_t local_addr = ( uintptr_t ) vertex_array . data . data ( ) ;
vertex_cache - > store_range ( local_addr , format , upload_size , ( u32 ) offset_in_attrib_buffer ) ;
2016-08-21 19:17:09 +02:00
m_buffer_view_to_clean . push_back ( std : : make_unique < vk : : buffer_view > ( device , m_attrib_ring_info . heap - > value , format , offset_in_attrib_buffer , upload_size ) ) ;
m_program - > bind_uniform ( m_buffer_view_to_clean . back ( ) - > value , s_reg_table [ vertex_array . index ] , descriptor_sets ) ;
2016-08-04 23:21:45 +02:00
}
2016-02-21 18:50:49 +03:00
2016-08-21 19:17:09 +02:00
void operator ( ) ( const rsx : : vertex_array_register & vertex_register )
{
2017-07-22 01:54:28 +03:00
if ( ! m_program - > has_uniform ( s_reg_table [ vertex_register . index ] ) )
return ;
2017-05-17 14:37:36 +03:00
size_t data_size = rsx : : get_vertex_type_size_on_host ( vertex_register . type , vertex_register . attribute_size ) ;
const VkFormat format = vk : : get_suitable_vk_format ( vertex_register . type , vertex_register . attribute_size ) ;
2016-08-04 23:21:45 +02:00
2017-06-18 17:53:02 +03:00
size_t offset_in_attrib_buffer = 0 ;
2016-08-04 23:21:45 +02:00
2017-05-17 14:37:36 +03:00
if ( vk : : requires_component_expansion ( vertex_register . type , vertex_register . attribute_size ) )
{
const u32 num_stored_verts = static_cast < u32 > (
data_size / ( sizeof ( float ) * vertex_register . attribute_size ) ) ;
const u32 real_element_size = vk : : get_suitable_vk_size ( vertex_register . type , vertex_register . attribute_size ) ;
2016-08-04 23:21:45 +02:00
2017-05-17 14:37:36 +03:00
data_size = real_element_size * num_stored_verts ;
offset_in_attrib_buffer = m_attrib_ring_info . alloc < 256 > ( data_size ) ;
void * dst = m_attrib_ring_info . map ( offset_in_attrib_buffer , data_size ) ;
2016-08-04 23:21:45 +02:00
2017-05-17 14:37:36 +03:00
vk : : expand_array_components < float , 3 , 4 , 1 > ( reinterpret_cast < const float * > ( vertex_register . data . data ( ) ) , dst , num_stored_verts ) ;
m_attrib_ring_info . unmap ( ) ;
2016-08-04 23:21:45 +02:00
}
2017-05-17 14:37:36 +03:00
else
{
offset_in_attrib_buffer = m_attrib_ring_info . alloc < 256 > ( data_size ) ;
void * dst = m_attrib_ring_info . map ( offset_in_attrib_buffer , data_size ) ;
memcpy ( dst , vertex_register . data . data ( ) , data_size ) ;
m_attrib_ring_info . unmap ( ) ;
2016-02-21 18:50:49 +03:00
}
2017-05-17 14:37:36 +03:00
m_buffer_view_to_clean . push_back ( std : : make_unique < vk : : buffer_view > ( device , m_attrib_ring_info . heap - > value , format , offset_in_attrib_buffer , data_size ) ) ;
m_program - > bind_uniform ( m_buffer_view_to_clean . back ( ) - > value , s_reg_table [ vertex_register . index ] , descriptor_sets ) ;
2016-08-04 23:21:45 +02:00
}
2016-02-21 18:50:49 +03:00
2016-08-21 19:17:09 +02:00
void operator ( ) ( const rsx : : empty_vertex_array & vbo )
{
2017-07-22 01:54:28 +03:00
if ( ! m_program - > has_uniform ( s_reg_table [ vbo . index ] ) )
return ;
m_buffer_view_to_clean . push_back ( std : : make_unique < vk : : buffer_view > ( device , m_attrib_ring_info . heap - > value , VK_FORMAT_R8G8B8A8_UNORM , 0 , 0 ) ) ;
2016-08-21 19:17:09 +02:00
m_program - > bind_uniform ( m_buffer_view_to_clean . back ( ) - > value , s_reg_table [ vbo . index ] , descriptor_sets ) ;
2016-02-21 18:50:49 +03:00
}
2016-08-21 19:17:09 +02:00
protected :
VkDevice device ;
u32 vertex_count ;
vk : : vk_data_heap & m_attrib_ring_info ;
vk : : glsl : : program * m_program ;
VkDescriptorSet descriptor_sets ;
std : : vector < std : : unique_ptr < vk : : buffer_view > > & m_buffer_view_to_clean ;
2017-07-26 19:32:13 +03:00
vk : : vertex_cache * vertex_cache ;
2016-08-21 19:17:09 +02:00
} ;
2016-08-28 17:00:02 +02:00
using attribute_storage = std : : vector < std : : variant < rsx : : vertex_array_buffer ,
rsx : : vertex_array_register , rsx : : empty_vertex_array > > ;
2016-08-04 23:21:45 +02:00
2016-08-28 17:00:02 +02:00
struct draw_command_visitor
2016-08-04 23:21:45 +02:00
{
2016-08-28 17:00:02 +02:00
using result_type = std : : tuple < VkPrimitiveTopology , u32 ,
std : : optional < std : : tuple < VkDeviceSize , VkIndexType > > > ;
draw_command_visitor ( VkDevice device , vk : : vk_data_heap & index_buffer_ring_info ,
vk : : vk_data_heap & attrib_ring_info , vk : : glsl : : program * program ,
VkDescriptorSet descriptor_sets ,
std : : vector < std : : unique_ptr < vk : : buffer_view > > & buffer_view_to_clean ,
std : : function < attribute_storage (
const rsx : : rsx_state & , const std : : vector < std : : pair < u32 , u32 > > & ) >
2017-06-25 23:14:56 +03:00
get_vertex_buffers_f ,
VKGSRender * thread )
2016-08-28 17:00:02 +02:00
: m_device ( device ) , m_index_buffer_ring_info ( index_buffer_ring_info ) ,
m_attrib_ring_info ( attrib_ring_info ) , m_program ( program ) ,
m_descriptor_sets ( descriptor_sets ) , m_buffer_view_to_clean ( buffer_view_to_clean ) ,
2017-06-25 23:14:56 +03:00
get_vertex_buffers ( get_vertex_buffers_f ) ,
rsxthr ( thread )
2016-08-28 17:00:02 +02:00
{
}
2016-08-04 23:21:45 +02:00
2016-08-28 17:00:02 +02:00
result_type operator ( ) ( const rsx : : draw_array_command & command )
{
bool primitives_emulated = false ;
VkPrimitiveTopology prims = vk : : get_appropriate_topology (
rsx : : method_registers . current_draw_clause . primitive , primitives_emulated ) ;
u32 index_count = 0 ;
std : : optional < std : : tuple < VkDeviceSize , VkIndexType > > index_info ;
u32 min_index =
rsx : : method_registers . current_draw_clause . first_count_commands . front ( ) . first ;
u32 max_index =
2017-03-26 01:24:19 +03:00
rsx : : method_registers . current_draw_clause . get_elements_count ( ) + min_index - 1 ;
2016-08-28 17:00:02 +02:00
if ( primitives_emulated ) {
std : : tie ( index_count , index_info ) =
generate_emulating_index_buffer ( rsx : : method_registers . current_draw_clause ,
max_index - min_index + 1 , m_index_buffer_ring_info ) ;
}
else
{
index_count = rsx : : method_registers . current_draw_clause . get_elements_count ( ) ;
}
2016-08-04 23:21:45 +02:00
2016-08-28 17:00:02 +02:00
upload_vertex_buffers ( min_index , max_index ) ;
return std : : make_tuple ( prims , index_count , index_info ) ;
}
2016-08-04 23:21:45 +02:00
2016-08-28 17:00:02 +02:00
result_type operator ( ) ( const rsx : : draw_indexed_array_command & command )
2016-02-21 18:50:49 +03:00
{
2016-08-28 17:00:02 +02:00
bool primitives_emulated = false ;
VkPrimitiveTopology prims = vk : : get_appropriate_topology (
rsx : : method_registers . current_draw_clause . primitive , primitives_emulated ) ;
2017-03-28 13:41:45 +03:00
rsx : : index_array_type index_type = rsx : : method_registers . current_draw_clause . is_immediate_draw ?
rsx : : index_array_type : : u32 :
rsx : : method_registers . index_type ( ) ;
2016-08-28 17:00:02 +02:00
u32 type_size = gsl : : narrow < u32 > ( get_index_type_size ( index_type ) ) ;
2016-09-29 10:16:00 +03:00
u32 index_count = rsx : : method_registers . current_draw_clause . get_elements_count ( ) ;
if ( primitives_emulated )
index_count = get_index_count ( rsx : : method_registers . current_draw_clause . primitive , index_count ) ;
2016-08-28 17:00:02 +02:00
u32 upload_size = index_count * type_size ;
VkDeviceSize offset_in_index_buffer = m_index_buffer_ring_info . alloc < 256 > ( upload_size ) ;
void * buf = m_index_buffer_ring_info . map ( offset_in_index_buffer , upload_size ) ;
/**
* Upload index ( and expands it if primitive type is not natively supported ) .
*/
u32 min_index , max_index ;
std : : tie ( min_index , max_index ) = write_index_array_data_to_buffer (
gsl : : span < gsl : : byte > ( static_cast < gsl : : byte * > ( buf ) , index_count * type_size ) ,
command . raw_index_buffer , index_type ,
rsx : : method_registers . current_draw_clause . primitive ,
rsx : : method_registers . restart_index_enabled ( ) ,
rsx : : method_registers . restart_index ( ) , command . ranges_to_fetch_in_index_buffer ,
2016-09-29 10:16:00 +03:00
[ ] ( auto prim ) { return ! vk : : is_primitive_native ( prim ) ; } ) ;
2016-08-28 17:00:02 +02:00
m_index_buffer_ring_info . unmap ( ) ;
std : : optional < std : : tuple < VkDeviceSize , VkIndexType > > index_info =
std : : make_tuple ( offset_in_index_buffer , vk : : get_index_type ( index_type ) ) ;
upload_vertex_buffers ( 0 , max_index ) ;
return std : : make_tuple ( prims , index_count , index_info ) ;
2016-08-04 23:21:45 +02:00
}
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
result_type operator ( ) ( const rsx : : draw_inlined_array & command )
{
bool primitives_emulated = false ;
VkPrimitiveTopology prims = vk : : get_appropriate_topology (
rsx : : method_registers . current_draw_clause . primitive , primitives_emulated ) ;
u32 index_count = upload_inlined_array ( ) ;
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
if ( ! primitives_emulated ) {
return std : : make_tuple ( prims , index_count , std : : nullopt ) ;
}
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
std : : optional < std : : tuple < VkDeviceSize , VkIndexType > > index_info ;
std : : tie ( index_count , index_info ) = generate_emulating_index_buffer (
rsx : : method_registers . current_draw_clause , index_count , m_index_buffer_ring_info ) ;
return std : : make_tuple ( prims , index_count , index_info ) ;
}
2016-07-02 17:27:53 +03:00
2016-08-28 17:00:02 +02:00
private :
vk : : vk_data_heap & m_index_buffer_ring_info ;
VkDevice m_device ;
vk : : vk_data_heap & m_attrib_ring_info ;
vk : : glsl : : program * m_program ;
VkDescriptorSet m_descriptor_sets ;
std : : vector < std : : unique_ptr < vk : : buffer_view > > & m_buffer_view_to_clean ;
std : : function < attribute_storage (
const rsx : : rsx_state & , const std : : vector < std : : pair < u32 , u32 > > & ) >
get_vertex_buffers ;
2017-06-25 23:14:56 +03:00
VKGSRender * rsxthr ;
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
void upload_vertex_buffers ( u32 min_index , u32 vertex_max_index )
2016-08-04 23:21:45 +02:00
{
2017-06-25 23:14:56 +03:00
const u32 vertex_count = vertex_max_index - min_index + 1 ;
vertex_buffer_visitor visitor ( vertex_count , m_device ,
2017-07-24 20:49:51 +03:00
m_attrib_ring_info , m_program , m_descriptor_sets , m_buffer_view_to_clean , rsxthr - > m_vertex_cache . get ( ) ) ;
2017-06-25 23:14:56 +03:00
2016-08-28 17:00:02 +02:00
const auto & vertex_buffers = get_vertex_buffers (
rsx : : method_registers , { { min_index , vertex_max_index - min_index + 1 } } ) ;
2017-06-25 23:14:56 +03:00
//1. Check if we can get all these allocations at once
std : : vector < size_t > memory_allocations ( 16 ) ;
std : : vector < u32 > allocated_sizes ( 16 ) ;
std : : vector < int > upload_jobs ( 16 ) ;
memory_allocations . resize ( 0 ) ;
allocated_sizes . resize ( 0 ) ;
upload_jobs . resize ( 0 ) ;
for ( int i = 0 ; i < vertex_buffers . size ( ) ; + + i )
{
const auto & vbo = vertex_buffers [ i ] ;
2017-07-22 01:54:28 +03:00
bool can_multithread = false ;
2017-06-25 23:14:56 +03:00
2017-07-22 16:45:15 +03:00
if ( vbo . which ( ) = = 0 )
2017-06-25 23:14:56 +03:00
{
//vertex array buffer. We can thread this thing heavily
const auto & v = vbo . get < rsx : : vertex_array_buffer > ( ) ;
2017-07-22 16:45:15 +03:00
const u32 element_size = rsx : : get_vertex_type_size_on_host ( v . type , v . attribute_size ) ;
const u32 real_element_size = vk : : get_suitable_vk_size ( v . type , v . attribute_size ) ;
const u32 upload_size = real_element_size * vertex_count ;
const VkFormat format = vk : : get_suitable_vk_format ( v . type , v . attribute_size ) ;
const uintptr_t local_addr = ( uintptr_t ) v . data . data ( ) ;
2017-07-24 20:49:51 +03:00
const auto cached = rsxthr - > m_vertex_cache - > find_vertex_range ( local_addr , format , upload_size ) ;
2017-07-22 16:45:15 +03:00
if ( cached )
{
m_buffer_view_to_clean . push_back ( std : : make_unique < vk : : buffer_view > ( m_device , m_attrib_ring_info . heap - > value , format , cached - > offset_in_heap , upload_size ) ) ;
m_program - > bind_uniform ( m_buffer_view_to_clean . back ( ) - > value , s_reg_table [ v . index ] , m_descriptor_sets ) ;
continue ;
}
2017-06-25 23:14:56 +03:00
2017-07-22 16:45:15 +03:00
if ( v . attribute_size > 1 & & vertex_count > = ( u32 ) g_cfg . video . mt_vertex_upload_threshold & & rsxthr - > vertex_upload_task_ready ( ) )
2017-07-22 01:54:28 +03:00
{
can_multithread = true ;
size_t offset = m_attrib_ring_info . alloc < 256 > ( upload_size ) ;
2017-06-25 23:14:56 +03:00
2017-07-22 01:54:28 +03:00
memory_allocations . push_back ( offset ) ;
allocated_sizes . push_back ( upload_size ) ;
upload_jobs . push_back ( i ) ;
2017-06-25 23:14:56 +03:00
2017-07-22 16:45:15 +03:00
const uintptr_t local_addr = ( uintptr_t ) v . data . data ( ) ;
2017-07-24 20:49:51 +03:00
rsxthr - > m_vertex_cache - > store_range ( local_addr , format , upload_size , ( u32 ) offset ) ;
2017-06-25 23:14:56 +03:00
2017-07-22 01:54:28 +03:00
m_buffer_view_to_clean . push_back ( std : : make_unique < vk : : buffer_view > ( m_device , m_attrib_ring_info . heap - > value , format , offset , upload_size ) ) ;
m_program - > bind_uniform ( m_buffer_view_to_clean . back ( ) - > value , s_reg_table [ v . index ] , m_descriptor_sets ) ;
}
2017-06-25 23:14:56 +03:00
}
2017-07-22 01:54:28 +03:00
if ( ! can_multithread )
2017-06-25 23:14:56 +03:00
std : : apply_visitor ( visitor , vbo ) ;
}
if ( memory_allocations . size ( ) > 0 )
{
if ( memory_allocations . size ( ) > 1 )
{
//2 sets in case the blocks dont fit
u8 available_jobs [ 2 ] = { } ;
u32 allocated_block [ 2 ] = { } ;
size_t last_offset = memory_allocations [ 0 ] ;
u8 current_index = 0 ;
for ( int n = 0 ; n < memory_allocations . size ( ) ; + + n )
{
if ( memory_allocations [ n ] < last_offset )
{
//queue went around
current_index = 1 ;
}
available_jobs [ current_index ] + + ;
allocated_block [ current_index ] + = allocated_sizes [ n ] ;
}
int n = 0 ;
for ( int task = 0 ; task < 2 ; + + task )
{
if ( available_jobs [ task ] )
{
if ( m_attrib_ring_info . mapped )
{
rsxthr - > wait_for_vertex_upload_task ( ) ;
m_attrib_ring_info . unmap ( ) ;
}
size_t space_remaining = allocated_block [ task ] ;
size_t offset_base = memory_allocations [ n ] ;
gsl : : byte * dst = ( gsl : : byte * ) m_attrib_ring_info . map ( memory_allocations [ n ] , space_remaining ) ;
while ( true )
{
if ( space_remaining = = 0 )
break ;
const auto & vertex_array = vertex_buffers [ upload_jobs [ n ] ] . get < rsx : : vertex_array_buffer > ( ) ;
const u32 real_element_size = vk : : get_suitable_vk_size ( vertex_array . type , vertex_array . attribute_size ) ;
gsl : : span < gsl : : byte > dest_span ( dst + ( memory_allocations [ n ] - offset_base ) , allocated_sizes [ n ] ) ;
2017-07-18 22:34:06 +03:00
rsxthr - > post_vertex_stream_to_upload ( vertex_array . data , dest_span , vertex_array . type , vertex_array . attribute_size , vertex_array . stride , real_element_size , vertex_count , vk : : prepare_buffer_for_writing ) ;
2017-06-25 23:14:56 +03:00
space_remaining - = allocated_sizes [ n ] ;
n + + ;
}
2017-07-18 22:34:06 +03:00
rsxthr - > start_vertex_upload_task ( ) ;
2017-06-25 23:14:56 +03:00
}
}
}
else
{
const size_t offset_in_attrib_buffer = memory_allocations [ 0 ] ;
const u32 upload_size = allocated_sizes [ 0 ] ;
const auto & vertex_array = vertex_buffers [ upload_jobs [ 0 ] ] . get < rsx : : vertex_array_buffer > ( ) ;
const u32 real_element_size = vk : : get_suitable_vk_size ( vertex_array . type , vertex_array . attribute_size ) ;
void * dst = m_attrib_ring_info . map ( offset_in_attrib_buffer , upload_size ) ;
gsl : : span < gsl : : byte > dest_span ( static_cast < gsl : : byte * > ( dst ) , upload_size ) ;
write_vertex_array_data_to_buffer ( dest_span , vertex_array . data , vertex_count , vertex_array . type , vertex_array . attribute_size , vertex_array . stride , real_element_size ) ;
vk : : prepare_buffer_for_writing ( dst , vertex_array . type , vertex_array . attribute_size , vertex_count ) ;
m_attrib_ring_info . unmap ( ) ;
}
}
2016-08-04 23:21:45 +02:00
}
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
u32 upload_inlined_array ( )
{
u32 stride = 0 ;
u32 offsets [ rsx : : limits : : vertex_count ] = { 0 } ;
2016-08-24 03:50:07 +03:00
2016-08-28 17:00:02 +02:00
for ( u32 i = 0 ; i < rsx : : limits : : vertex_count ; + + i ) {
const auto & info = rsx : : method_registers . vertex_arrays_info [ i ] ;
if ( ! info . size ( ) ) continue ;
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
offsets [ i ] = stride ;
stride + = rsx : : get_vertex_type_size_on_host ( info . type ( ) , info . size ( ) ) ;
}
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
u32 vertex_draw_count =
( u32 ) ( rsx : : method_registers . current_draw_clause . inline_vertex_array . size ( ) *
sizeof ( u32 ) ) /
stride ;
2016-02-21 18:50:49 +03:00
2017-07-22 01:54:28 +03:00
for ( int index = 0 ; index < rsx : : limits : : vertex_count ; + + index )
{
2016-08-28 17:00:02 +02:00
auto & vertex_info = rsx : : method_registers . vertex_arrays_info [ index ] ;
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
if ( ! m_program - > has_uniform ( s_reg_table [ index ] ) ) continue ;
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
if ( ! vertex_info . size ( ) ) // disabled
{
2017-07-22 01:54:28 +03:00
m_buffer_view_to_clean . push_back ( std : : make_unique < vk : : buffer_view > ( m_device , m_attrib_ring_info . heap - > value , VK_FORMAT_R8G8B8A8_UNORM , 0 , 0 ) ) ;
m_program - > bind_uniform ( m_buffer_view_to_clean . back ( ) - > value , s_reg_table [ index ] , m_descriptor_sets ) ;
2016-08-28 17:00:02 +02:00
continue ;
}
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
const u32 element_size =
vk : : get_suitable_vk_size ( vertex_info . type ( ) , vertex_info . size ( ) ) ;
const u32 data_size = element_size * vertex_draw_count ;
const VkFormat format =
vk : : get_suitable_vk_format ( vertex_info . type ( ) , vertex_info . size ( ) ) ;
2016-02-21 18:50:49 +03:00
2017-06-18 17:53:02 +03:00
size_t offset_in_attrib_buffer = m_attrib_ring_info . alloc < 256 > ( data_size ) ;
2016-08-28 17:00:02 +02:00
u8 * src = reinterpret_cast < u8 * > (
rsx : : method_registers . current_draw_clause . inline_vertex_array . data ( ) ) ;
u8 * dst =
static_cast < u8 * > ( m_attrib_ring_info . map ( offset_in_attrib_buffer , data_size ) ) ;
src + = offsets [ index ] ;
u8 opt_size = vertex_info . size ( ) ;
if ( vertex_info . size ( ) = = 3 ) opt_size = 4 ;
// TODO: properly handle cmp type
if ( vertex_info . type ( ) = = rsx : : vertex_base_type : : cmp )
2017-07-22 01:54:28 +03:00
LOG_ERROR ( RSX , " Compressed vertex attributes not supported for inlined arrays yet " ) ;
2016-08-28 17:00:02 +02:00
switch ( vertex_info . type ( ) )
{
case rsx : : vertex_base_type : : f :
vk : : copy_inlined_data_to_buffer < float , 1 > ( src , dst , vertex_draw_count ,
vertex_info . type ( ) , vertex_info . size ( ) , opt_size , element_size , stride ) ;
break ;
case rsx : : vertex_base_type : : sf :
vk : : copy_inlined_data_to_buffer < u16 , 0x3c00 > ( src , dst , vertex_draw_count ,
vertex_info . type ( ) , vertex_info . size ( ) , opt_size , element_size , stride ) ;
break ;
case rsx : : vertex_base_type : : s1 :
case rsx : : vertex_base_type : : ub :
case rsx : : vertex_base_type : : ub256 :
vk : : copy_inlined_data_to_buffer < u8 , 1 > ( src , dst , vertex_draw_count ,
vertex_info . type ( ) , vertex_info . size ( ) , opt_size , element_size , stride ) ;
break ;
case rsx : : vertex_base_type : : s32k :
case rsx : : vertex_base_type : : cmp :
vk : : copy_inlined_data_to_buffer < u16 , 1 > ( src , dst , vertex_draw_count ,
vertex_info . type ( ) , vertex_info . size ( ) , opt_size , element_size , stride ) ;
break ;
default : fmt : : throw_exception ( " Unknown base type %d " HERE , ( u32 ) vertex_info . type ( ) ) ;
}
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
m_attrib_ring_info . unmap ( ) ;
m_buffer_view_to_clean . push_back ( std : : make_unique < vk : : buffer_view > ( m_device ,
m_attrib_ring_info . heap - > value , format , offset_in_attrib_buffer , data_size ) ) ;
m_program - > bind_uniform (
m_buffer_view_to_clean . back ( ) - > value , s_reg_table [ index ] , m_descriptor_sets ) ;
}
2016-07-02 17:27:53 +03:00
2016-08-28 17:00:02 +02:00
return vertex_draw_count ;
}
} ;
}
2016-02-21 18:50:49 +03:00
2016-08-28 17:00:02 +02:00
std : : tuple < VkPrimitiveTopology , u32 , std : : optional < std : : tuple < VkDeviceSize , VkIndexType > > >
VKGSRender : : upload_vertex_data ( )
{
draw_command_visitor visitor ( * m_device , m_index_buffer_ring_info , m_attrib_ring_info , m_program ,
descriptor_sets , m_buffer_view_to_clean ,
2017-07-22 01:54:28 +03:00
[ this ] ( const auto & state , const auto & range ) { return this - > get_vertex_buffers ( state , range , m_program - > get_vertex_input_attributes_mask ( ) ) ; } , this ) ;
2016-08-28 17:00:02 +02:00
return std : : apply_visitor ( visitor , get_draw_command ( rsx : : method_registers ) ) ;
2016-02-02 00:50:02 +03:00
}