2018-09-19 00:21:57 +02:00
# pragma once
2016-02-15 10:50:14 +01:00
# include "stdafx.h"
# include <exception>
# include <string>
# include <functional>
# include <vector>
# include <memory>
2017-02-28 09:13:50 +01:00
# include <thread>
# include <condition_variable>
2017-03-29 21:27:29 +02:00
# include <chrono>
2016-02-15 10:50:14 +01:00
2017-07-27 15:29:08 +02:00
# include "Utilities/mutex.h"
2017-06-22 20:25:58 +02:00
# include "Emu/System.h"
2016-09-18 07:19:26 +02:00
# include "GLRenderTargets.h"
2017-11-30 19:50:19 +01:00
# include "GLOverlays.h"
2016-02-15 10:50:14 +01:00
# include "../Common/TextureUtils.h"
2017-09-08 16:52:13 +02:00
# include "../Common/texture_cache.h"
2017-03-29 21:27:29 +02:00
# include "../../Memory/vm.h"
2017-04-23 11:32:37 +02:00
# include "../rsx_utils.h"
2017-02-16 19:29:56 +01:00
class GLGSRender ;
2016-02-15 10:50:14 +01:00
2017-02-13 15:22:25 +01:00
namespace gl
{
2017-09-28 20:32:00 +02:00
class blitter ;
2017-09-08 16:52:13 +02:00
extern GLenum get_sized_internal_format ( u32 ) ;
2018-04-07 17:16:52 +02:00
extern void copy_typeless ( texture * , const texture * ) ;
2017-09-28 20:32:00 +02:00
extern blitter * g_hw_blitter ;
2018-10-28 14:59:39 +01:00
class cached_texture_section ;
class texture_cache ;
struct texture_cache_traits
2017-02-13 15:22:25 +01:00
{
2018-12-29 14:28:12 +01:00
using commandbuffer_type = gl : : command_context ;
2018-10-28 14:59:39 +01:00
using section_storage_type = gl : : cached_texture_section ;
using texture_cache_type = gl : : texture_cache ;
using texture_cache_base_type = rsx : : texture_cache < texture_cache_type , texture_cache_traits > ;
using image_resource_type = gl : : texture * ;
using image_view_type = gl : : texture_view * ;
using image_storage_type = gl : : texture ;
using texture_format = gl : : texture : : format ;
} ;
class cached_texture_section : public rsx : : cached_texture_section < gl : : cached_texture_section , gl : : texture_cache_traits >
{
using baseclass = rsx : : cached_texture_section < gl : : cached_texture_section , gl : : texture_cache_traits > ;
friend baseclass ;
2018-09-22 02:14:26 +02:00
2017-09-08 16:52:13 +02:00
fence m_fence ;
2018-02-10 09:52:44 +01:00
u32 pbo_id = 0 ;
2017-09-08 16:52:13 +02:00
u32 pbo_size = 0 ;
2017-02-13 15:22:25 +01:00
2018-07-17 18:42:51 +02:00
gl : : viewable_image * vram_texture = nullptr ;
2018-04-07 12:19:49 +02:00
2018-07-17 18:42:51 +02:00
std : : unique_ptr < gl : : viewable_image > managed_texture ;
2018-04-07 12:19:49 +02:00
std : : unique_ptr < gl : : texture > scaled_texture ;
2017-02-16 19:29:56 +01:00
2017-09-08 16:52:13 +02:00
texture : : format format = texture : : format : : rgba ;
texture : : type type = texture : : type : : ubyte ;
2017-11-29 15:05:36 +01:00
rsx : : surface_antialiasing aa_mode = rsx : : surface_antialiasing : : center_1_sample ;
2017-02-13 15:22:25 +01:00
2017-09-08 16:52:13 +02:00
u8 get_pixel_size ( texture : : format fmt_ , texture : : type type_ )
{
u8 size = 1 ;
switch ( type_ )
{
case texture : : type : : ubyte :
case texture : : type : : sbyte :
break ;
case texture : : type : : ushort :
case texture : : type : : sshort :
case texture : : type : : f16 :
size = 2 ;
break ;
case texture : : type : : ushort_5_6_5 :
case texture : : type : : ushort_5_6_5_rev :
case texture : : type : : ushort_4_4_4_4 :
case texture : : type : : ushort_4_4_4_4_rev :
case texture : : type : : ushort_5_5_5_1 :
case texture : : type : : ushort_1_5_5_5_rev :
return 2 ;
case texture : : type : : uint_8_8_8_8 :
case texture : : type : : uint_8_8_8_8_rev :
case texture : : type : : uint_10_10_10_2 :
case texture : : type : : uint_2_10_10_10_rev :
case texture : : type : : uint_24_8 :
return 4 ;
case texture : : type : : f32 :
case texture : : type : : sint :
case texture : : type : : uint :
size = 4 ;
break ;
2017-11-02 07:29:17 +01:00
default :
LOG_ERROR ( RSX , " Unsupported texture type " ) ;
2017-09-08 16:52:13 +02:00
}
switch ( fmt_ )
{
case texture : : format : : r :
break ;
case texture : : format : : rg :
size * = 2 ;
break ;
case texture : : format : : rgb :
case texture : : format : : bgr :
size * = 3 ;
break ;
case texture : : format : : rgba :
case texture : : format : : bgra :
size * = 4 ;
break ;
//Depth formats..
case texture : : format : : depth :
size = 2 ;
break ;
case texture : : format : : depth_stencil :
size = 4 ;
break ;
default :
LOG_ERROR ( RSX , " Unsupported rtt format %d " , ( GLenum ) fmt_ ) ;
size = 4 ;
}
return size ;
}
2017-02-13 15:22:25 +01:00
2017-09-08 16:52:13 +02:00
void init_buffer ( )
{
2018-02-03 09:37:42 +01:00
const f32 resolution_scale = ( context = = rsx : : texture_upload_context : : framebuffer_storage ? rsx : : get_resolution_scale ( ) : 1.f ) ;
2018-09-22 02:14:26 +02:00
const u32 real_buffer_size = ( resolution_scale < = 1.f ) ? get_section_size ( ) : ( u32 ) ( resolution_scale * resolution_scale * get_section_size ( ) ) ;
2018-02-03 09:37:42 +01:00
const u32 buffer_size = align ( real_buffer_size , 4096 ) ;
2017-09-08 16:52:13 +02:00
if ( pbo_id )
{
2018-02-03 09:37:42 +01:00
if ( pbo_size > = buffer_size )
return ;
2017-09-08 16:52:13 +02:00
glDeleteBuffers ( 1 , & pbo_id ) ;
pbo_id = 0 ;
pbo_size = 0 ;
2016-02-15 10:50:14 +01:00
}
2017-09-08 16:52:13 +02:00
glGenBuffers ( 1 , & pbo_id ) ;
2017-02-27 20:39:22 +01:00
2017-09-08 16:52:13 +02:00
glBindBuffer ( GL_PIXEL_PACK_BUFFER , pbo_id ) ;
glBufferStorage ( GL_PIXEL_PACK_BUFFER , buffer_size , nullptr , GL_MAP_READ_BIT ) ;
2018-04-23 15:13:00 +02:00
glBindBuffer ( GL_PIXEL_PACK_BUFFER , GL_NONE ) ;
2017-02-27 20:39:22 +01:00
2017-09-08 16:52:13 +02:00
pbo_size = buffer_size ;
}
2017-02-27 20:39:22 +01:00
2017-09-08 16:52:13 +02:00
public :
2018-09-22 02:14:26 +02:00
using baseclass : : cached_texture_section ;
2018-02-10 09:52:44 +01:00
2018-07-17 18:42:51 +02:00
void create ( u16 w , u16 h , u16 depth , u16 mipmaps , gl : : texture * image , u32 rsx_pitch , bool read_only ,
2017-09-08 16:52:13 +02:00
gl : : texture : : format gl_format , gl : : texture : : type gl_type , bool swap_bytes )
{
2018-10-19 00:22:00 +02:00
auto new_texture = static_cast < gl : : viewable_image * > ( image ) ;
ASSERT ( ! exists ( ) | | ! is_managed ( ) | | vram_texture = = new_texture ) ;
vram_texture = new_texture ;
2018-07-17 18:42:51 +02:00
2017-11-29 15:05:36 +01:00
if ( read_only )
{
2018-07-17 18:42:51 +02:00
managed_texture . reset ( vram_texture ) ;
2017-11-29 15:05:36 +01:00
aa_mode = rsx : : surface_antialiasing : : center_1_sample ;
}
else
{
if ( pbo_id = = 0 )
init_buffer ( ) ;
2018-06-03 13:52:21 +02:00
aa_mode = static_cast < gl : : render_target * > ( image ) - > read_aa_mode ;
2018-10-19 00:22:00 +02:00
ASSERT ( managed_texture . get ( ) = = nullptr ) ;
2017-11-29 15:05:36 +01:00
}
2017-03-29 21:27:29 +02:00
2017-09-08 16:52:13 +02:00
flushed = false ;
2018-02-10 17:21:16 +01:00
synchronized = false ;
2018-06-23 16:50:34 +02:00
sync_timestamp = 0ull ;
2017-03-29 21:27:29 +02:00
2018-12-18 18:04:03 +01:00
verify ( HERE ) , rsx_pitch ;
2018-09-10 12:22:24 +02:00
2018-12-18 18:04:03 +01:00
this - > rsx_pitch = rsx_pitch ;
2017-09-18 19:22:34 +02:00
this - > width = w ;
this - > height = h ;
2018-06-21 17:28:53 +02:00
this - > real_pitch = 0 ;
2017-09-22 15:12:10 +02:00
this - > depth = depth ;
this - > mipmaps = mipmaps ;
2017-03-29 21:27:29 +02:00
2017-09-08 16:52:13 +02:00
set_format ( gl_format , gl_type , swap_bytes ) ;
2018-09-22 02:14:26 +02:00
// Notify baseclass
baseclass : : on_section_resources_created ( ) ;
2017-09-08 16:52:13 +02:00
}
2017-03-29 21:27:29 +02:00
2018-12-18 18:04:03 +01:00
void create_read_only ( gl : : viewable_image * image , u32 width , u32 height , u32 depth , u32 mipmaps , u16 pitch )
2017-09-08 16:52:13 +02:00
{
2018-10-19 00:22:00 +02:00
ASSERT ( ! exists ( ) | | ! is_managed ( ) | | vram_texture = = image ) ;
2018-12-18 18:04:03 +01:00
verify ( HERE ) , pitch ;
2017-09-08 16:52:13 +02:00
//Only to be used for ro memory, we dont care about most members, just dimensions and the vram texture handle
2017-09-18 19:22:34 +02:00
this - > width = width ;
this - > height = height ;
2017-09-22 15:12:10 +02:00
this - > depth = depth ;
this - > mipmaps = mipmaps ;
2018-04-07 12:19:49 +02:00
managed_texture . reset ( image ) ;
vram_texture = image ;
2017-03-29 21:27:29 +02:00
2018-12-18 18:04:03 +01:00
rsx_pitch = pitch ;
2017-09-08 16:52:13 +02:00
real_pitch = 0 ;
2018-09-22 02:14:26 +02:00
// Notify baseclass
baseclass : : on_section_resources_created ( ) ;
2017-09-08 16:52:13 +02:00
}
2017-03-29 21:27:29 +02:00
2018-02-03 09:37:42 +01:00
void make_flushable ( )
{
//verify(HERE), pbo_id == 0;
init_buffer ( ) ;
}
2017-10-12 14:48:31 +02:00
void set_dimensions ( u32 width , u32 height , u32 /*depth*/ , u32 pitch )
2017-09-08 16:52:13 +02:00
{
2017-09-18 19:22:34 +02:00
this - > width = width ;
this - > height = height ;
rsx_pitch = pitch ;
2017-09-08 16:52:13 +02:00
}
2017-09-04 12:05:02 +02:00
2017-12-18 10:02:19 +01:00
void set_format ( texture : : format gl_format , texture : : type gl_type , bool swap_bytes )
2017-09-08 16:52:13 +02:00
{
format = gl_format ;
type = gl_type ;
pack_unpack_swap_bytes = swap_bytes ;
2017-11-30 19:50:19 +01:00
if ( format = = gl : : texture : : format : : rgba )
{
switch ( type )
{
case gl : : texture : : type : : f16 :
gcm_format = CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT ;
break ;
case gl : : texture : : type : : f32 :
gcm_format = CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT ;
break ;
}
}
2017-09-08 16:52:13 +02:00
}
2018-12-29 14:28:12 +01:00
void copy_texture ( gl : : command_context & cmd , bool manage_lifetime )
2017-09-08 16:52:13 +02:00
{
2018-10-19 00:22:00 +02:00
ASSERT ( exists ( ) ) ;
2018-10-28 14:59:39 +01:00
if ( ! manage_lifetime )
{
baseclass : : on_speculative_flush ( ) ;
}
2018-02-03 09:37:42 +01:00
if ( ! pbo_id )
{
init_buffer ( ) ;
}
2018-04-23 15:13:00 +02:00
gl : : texture * target_texture = vram_texture ;
2018-02-03 09:37:42 +01:00
if ( ( rsx : : get_resolution_scale_percent ( ) ! = 100 & & context = = rsx : : texture_upload_context : : framebuffer_storage ) | |
2018-06-21 17:28:53 +02:00
( vram_texture - > pitch ( ) ! = rsx_pitch ) )
2017-09-28 20:32:00 +02:00
{
2017-11-29 15:05:36 +01:00
u32 real_width = width ;
u32 real_height = height ;
switch ( aa_mode )
{
case rsx : : surface_antialiasing : : center_1_sample :
break ;
case rsx : : surface_antialiasing : : diagonal_centered_2_samples :
real_width * = 2 ;
break ;
default :
real_width * = 2 ;
real_height * = 2 ;
break ;
}
2017-09-28 20:32:00 +02:00
areai src_area = { 0 , 0 , 0 , 0 } ;
2017-10-02 15:53:27 +02:00
const areai dst_area = { 0 , 0 , ( s32 ) real_width , ( s32 ) real_height } ;
2017-09-28 20:32:00 +02:00
2018-04-07 12:19:49 +02:00
auto ifmt = vram_texture - > get_internal_format ( ) ;
src_area . x2 = vram_texture - > width ( ) ;
src_area . y2 = vram_texture - > height ( ) ;
2017-09-28 20:32:00 +02:00
2017-10-02 15:53:27 +02:00
if ( src_area . x2 ! = dst_area . x2 | | src_area . y2 ! = dst_area . y2 )
{
2018-04-07 12:19:49 +02:00
if ( scaled_texture )
2017-10-02 15:53:27 +02:00
{
2018-04-07 12:19:49 +02:00
auto sfmt = scaled_texture - > get_internal_format ( ) ;
if ( scaled_texture - > width ( ) ! = real_width | |
scaled_texture - > height ( ) ! = real_height | |
sfmt ! = ifmt )
2017-10-02 15:53:27 +02:00
{
2018-04-07 12:19:49 +02:00
//Discard current scaled texture
scaled_texture . reset ( ) ;
2017-10-02 15:53:27 +02:00
}
}
2018-04-07 12:19:49 +02:00
if ( ! scaled_texture )
2017-10-02 15:53:27 +02:00
{
2018-04-07 12:19:49 +02:00
scaled_texture = std : : make_unique < gl : : texture > ( GL_TEXTURE_2D , real_width , real_height , 1 , 1 , ( GLenum ) ifmt ) ;
2017-10-02 15:53:27 +02:00
}
2018-07-26 20:10:25 +02:00
const bool is_depth = is_depth_texture ( ) ;
const bool linear_interp = is_depth ? false : true ;
2018-12-29 14:28:12 +01:00
g_hw_blitter - > scale_image ( cmd , vram_texture , scaled_texture . get ( ) , src_area , dst_area , linear_interp , is_depth , { } ) ;
2018-04-23 15:13:00 +02:00
target_texture = scaled_texture . get ( ) ;
2017-10-02 15:53:27 +02:00
}
2017-09-28 20:32:00 +02:00
}
2017-10-03 13:38:00 +02:00
glGetError ( ) ;
2018-04-23 15:13:00 +02:00
glBindBuffer ( GL_PIXEL_PACK_BUFFER , pbo_id ) ;
2017-10-03 13:38:00 +02:00
2018-04-23 15:13:00 +02:00
pixel_pack_settings pack_settings ;
2018-04-29 08:41:51 +02:00
pack_settings . alignment ( 1 ) ;
2018-04-24 20:04:38 +02:00
2018-04-29 08:41:51 +02:00
//NOTE: AMD proprietary driver bug - disable swap bytes
2018-04-24 20:04:38 +02:00
if ( ! : : gl : : get_driver_caps ( ) . vendor_AMD )
pack_settings . swap_bytes ( pack_unpack_swap_bytes ) ;
2018-04-23 15:13:00 +02:00
target_texture - > copy_to ( nullptr , format , type , pack_settings ) ;
2018-06-21 17:28:53 +02:00
real_pitch = target_texture - > pitch ( ) ;
2017-04-04 18:14:36 +02:00
2018-04-23 15:13:00 +02:00
if ( auto error = glGetError ( ) )
2017-10-03 13:38:00 +02:00
{
2018-04-23 15:13:00 +02:00
if ( error = = GL_OUT_OF_MEMORY & & : : gl : : get_driver_caps ( ) . vendor_AMD )
2017-10-03 13:38:00 +02:00
{
2018-04-23 15:13:00 +02:00
//AMD driver bug
//Pixel transfer fails with GL_OUT_OF_MEMORY. Usually happens with float textures
//Failed operations also leak a large amount of memory
LOG_ERROR ( RSX , " Memory transfer failure (AMD bug). Format=0x%x, Type=0x%x " , ( u32 ) format , ( u32 ) type ) ;
2017-10-03 13:38:00 +02:00
}
2018-04-23 15:13:00 +02:00
else
2017-10-03 13:38:00 +02:00
{
2018-04-23 15:13:00 +02:00
LOG_ERROR ( RSX , " Memory transfer failed with error 0x%x. Format=0x%x, Type=0x%x " , error , ( u32 ) format , ( u32 ) type ) ;
2017-10-03 13:38:00 +02:00
}
}
2018-04-23 15:13:00 +02:00
glBindBuffer ( GL_PIXEL_PACK_BUFFER , GL_NONE ) ;
2017-02-13 15:22:25 +01:00
2017-09-08 16:52:13 +02:00
m_fence . reset ( ) ;
2018-02-10 17:21:16 +01:00
synchronized = true ;
2018-06-23 16:50:34 +02:00
sync_timestamp = get_system_time ( ) ;
2017-09-08 16:52:13 +02:00
}
2017-02-13 15:22:25 +01:00
2017-09-08 16:52:13 +02:00
void fill_texture ( gl : : texture * tex )
{
2018-02-10 17:21:16 +01:00
if ( ! synchronized )
2016-02-15 10:50:14 +01:00
{
2017-09-08 16:52:13 +02:00
//LOG_WARNING(RSX, "Request to fill texture rejected because contents were not read");
return ;
}
2017-02-16 19:29:56 +01:00
2017-09-18 19:22:34 +02:00
u32 min_width = std : : min ( ( u16 ) tex - > width ( ) , width ) ;
u32 min_height = std : : min ( ( u16 ) tex - > height ( ) , height ) ;
2016-02-15 10:50:14 +01:00
2018-04-07 12:19:49 +02:00
glBindTexture ( GL_TEXTURE_2D , tex - > id ( ) ) ;
2017-09-08 16:52:13 +02:00
glPixelStorei ( GL_UNPACK_SWAP_BYTES , pack_unpack_swap_bytes ) ;
glBindBuffer ( GL_PIXEL_UNPACK_BUFFER , pbo_id ) ;
2018-04-07 12:19:49 +02:00
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , min_width , min_height , ( GLenum ) format , ( GLenum ) type , nullptr ) ;
2018-04-23 15:13:00 +02:00
glBindBuffer ( GL_PIXEL_UNPACK_BUFFER , GL_NONE ) ;
2017-09-08 16:52:13 +02:00
}
2017-02-13 15:22:25 +01:00
2018-11-01 02:31:12 +01:00
/**
* Flush
*/
2018-12-29 14:28:12 +01:00
void synchronize ( bool blocking , gl : : command_context & cmd )
2017-09-08 16:52:13 +02:00
{
2018-11-01 02:31:12 +01:00
if ( synchronized )
return ;
2018-10-19 00:22:00 +02:00
2018-12-29 14:28:12 +01:00
copy_texture ( cmd , blocking ) ;
2017-10-27 15:52:27 +02:00
2018-11-01 02:31:12 +01:00
if ( blocking )
2017-02-13 15:22:25 +01:00
{
2018-11-01 02:31:12 +01:00
m_fence . wait_for_signal ( ) ;
2017-09-08 16:52:13 +02:00
}
2018-11-01 02:31:12 +01:00
}
2017-02-13 15:22:25 +01:00
2018-11-01 02:31:12 +01:00
void * map_synchronized ( u32 offset , u32 size )
{
AUDIT ( synchronized ) ;
2018-05-10 13:50:32 +02:00
2017-09-08 16:52:13 +02:00
glBindBuffer ( GL_PIXEL_PACK_BUFFER , pbo_id ) ;
2018-11-01 02:31:12 +01:00
return glMapBufferRange ( GL_PIXEL_PACK_BUFFER , offset , size , GL_MAP_READ_BIT ) ;
}
void finish_flush ( )
{
// Free resources
glUnmapBuffer ( GL_PIXEL_PACK_BUFFER ) ;
glBindBuffer ( GL_PIXEL_PACK_BUFFER , GL_NONE ) ;
2016-02-15 10:50:14 +01:00
2018-11-01 02:31:12 +01:00
// Shuffle
2018-02-03 09:37:42 +01:00
bool require_manual_shuffle = false ;
if ( pack_unpack_swap_bytes )
{
if ( type = = gl : : texture : : type : : sbyte | | type = = gl : : texture : : type : : ubyte )
require_manual_shuffle = true ;
}
2018-11-01 02:31:12 +01:00
const auto valid_range = get_confirmed_range_delta ( ) ;
const u32 valid_offset = valid_range . first ;
const u32 valid_length = valid_range . second ;
void * dst = get_ptr ( get_section_base ( ) + valid_offset ) ;
2016-02-15 10:50:14 +01:00
2018-02-03 09:37:42 +01:00
if ( require_manual_shuffle )
{
//byte swapping does not work on byte types, use uint_8_8_8_8 for rgba8 instead to avoid penalty
2018-09-22 02:14:26 +02:00
rsx : : shuffle_texel_data_wzyx < u8 > ( dst , rsx_pitch , width , valid_length / rsx_pitch ) ;
2018-02-03 09:37:42 +01:00
}
2018-04-24 20:04:38 +02:00
else if ( pack_unpack_swap_bytes & & : : gl : : get_driver_caps ( ) . vendor_AMD )
{
2018-11-01 02:31:12 +01:00
2018-04-24 20:04:38 +02:00
//AMD driver bug - cannot use pack_swap_bytes
//Manually byteswap texel data
switch ( type )
{
case texture : : type : : f16 :
case texture : : type : : sshort :
case texture : : type : : ushort :
case texture : : type : : ushort_5_6_5 :
case texture : : type : : ushort_4_4_4_4 :
case texture : : type : : ushort_1_5_5_5_rev :
case texture : : type : : ushort_5_5_5_1 :
{
2018-09-22 02:14:26 +02:00
const u32 num_reps = valid_length / 2 ;
2018-04-24 20:04:38 +02:00
be_t < u16 > * in = ( be_t < u16 > * ) ( dst ) ;
u16 * out = ( u16 * ) dst ;
for ( u32 n = 0 ; n < num_reps ; + + n )
{
out [ n ] = in [ n ] ;
}
break ;
}
case texture : : type : : f32 :
case texture : : type : : sint :
case texture : : type : : uint :
case texture : : type : : uint_10_10_10_2 :
case texture : : type : : uint_24_8 :
case texture : : type : : uint_2_10_10_10_rev :
case texture : : type : : uint_8_8_8_8 :
{
2018-09-22 02:14:26 +02:00
u32 num_reps = valid_length / 4 ;
2018-04-24 20:04:38 +02:00
be_t < u32 > * in = ( be_t < u32 > * ) ( dst ) ;
u32 * out = ( u32 * ) dst ;
for ( u32 n = 0 ; n < num_reps ; + + n )
{
out [ n ] = in [ n ] ;
}
break ;
}
default :
{
LOG_ERROR ( RSX , " Texture type 0x%x is not implemented " HERE , ( u32 ) type ) ;
break ;
}
}
}
2018-11-01 02:31:12 +01:00
}
2018-02-03 09:37:42 +01:00
2018-11-01 02:31:12 +01:00
/**
* Misc
*/
2017-09-08 16:52:13 +02:00
void destroy ( )
{
2018-10-28 14:59:39 +01:00
if ( ! is_locked ( ) & & pbo_id = = 0 & & vram_texture = = nullptr & & m_fence . is_empty ( ) & & managed_texture . get ( ) = = nullptr )
2017-09-08 16:52:13 +02:00
//Already destroyed
return ;
2017-02-13 15:22:25 +01:00
2018-10-28 14:59:39 +01:00
if ( pbo_id ! = 0 )
2017-02-13 15:22:25 +01:00
{
2017-09-08 16:52:13 +02:00
//Destroy pbo cache since vram texture is managed elsewhere
glDeleteBuffers ( 1 , & pbo_id ) ;
2018-04-07 12:19:49 +02:00
scaled_texture . reset ( ) ;
2017-02-13 15:22:25 +01:00
}
2018-10-28 14:59:39 +01:00
managed_texture . reset ( ) ;
2017-03-29 21:27:29 +02:00
2018-04-07 12:19:49 +02:00
vram_texture = nullptr ;
2017-10-23 14:39:24 +02:00
pbo_id = 0 ;
pbo_size = 0 ;
2017-09-21 15:24:42 +02:00
if ( ! m_fence . is_empty ( ) )
2018-10-28 14:59:39 +01:00
{
2017-09-21 15:24:42 +02:00
m_fence . destroy ( ) ;
2018-10-28 14:59:39 +01:00
}
2018-02-09 15:49:37 +01:00
2018-09-22 02:14:26 +02:00
baseclass : : on_section_resources_destroyed ( ) ;
2017-09-08 16:52:13 +02:00
}
2018-02-09 15:49:37 +01:00
2018-10-19 00:22:00 +02:00
bool exists ( ) const
2017-09-08 16:52:13 +02:00
{
2018-09-22 02:14:26 +02:00
return ( vram_texture ! = nullptr ) ;
2017-09-08 16:52:13 +02:00
}
2018-02-09 15:49:37 +01:00
2018-10-19 00:22:00 +02:00
bool is_managed ( ) const
{
return ! exists ( ) | | managed_texture . get ( ) ! = nullptr ;
}
2018-09-22 02:14:26 +02:00
texture : : format get_format ( ) const
2017-09-08 16:52:13 +02:00
{
2018-09-22 02:14:26 +02:00
return format ;
2017-09-08 16:52:13 +02:00
}
2017-03-29 21:27:29 +02:00
2017-09-08 16:52:13 +02:00
bool is_flushed ( ) const
{
return flushed ;
}
2017-03-29 21:27:29 +02:00
2017-09-08 16:52:13 +02:00
bool is_synchronized ( ) const
{
2018-02-10 17:21:16 +01:00
return synchronized ;
2017-09-08 16:52:13 +02:00
}
2017-09-04 12:05:02 +02:00
2017-12-18 10:02:19 +01:00
void set_flushed ( bool state )
2017-09-08 16:52:13 +02:00
{
flushed = state ;
}
bool is_empty ( ) const
{
2018-09-05 22:52:33 +02:00
return vram_texture = = nullptr ;
2017-09-08 16:52:13 +02:00
}
2018-07-17 18:42:51 +02:00
gl : : texture_view * get_view ( u32 remap_encoding , const std : : pair < std : : array < u8 , 4 > , std : : array < u8 , 4 > > & remap )
2018-04-07 12:19:49 +02:00
{
2018-07-17 18:42:51 +02:00
return vram_texture - > get_view ( remap_encoding , remap ) ;
2018-04-07 12:19:49 +02:00
}
gl : : texture * get_raw_texture ( ) const
2017-09-08 16:52:13 +02:00
{
2018-04-07 12:19:49 +02:00
return managed_texture . get ( ) ;
2017-09-08 16:52:13 +02:00
}
2018-07-17 18:42:51 +02:00
gl : : texture_view * get_raw_view ( )
2017-09-08 16:52:13 +02:00
{
2018-07-17 18:42:51 +02:00
return vram_texture - > get_view ( 0xAAE4 , rsx : : default_remap_vector ) ;
2017-09-08 16:52:13 +02:00
}
bool is_depth_texture ( ) const
{
2018-07-26 20:10:25 +02:00
switch ( vram_texture - > get_internal_format ( ) )
{
case gl : : texture : : internal_format : : depth16 :
case gl : : texture : : internal_format : : depth24_stencil8 :
case gl : : texture : : internal_format : : depth32f_stencil8 :
return true ;
default :
return false ;
}
2017-09-08 16:52:13 +02:00
}
bool has_compatible_format ( gl : : texture * tex ) const
{
2018-04-07 12:19:49 +02:00
//TODO
return ( tex - > get_internal_format ( ) = = vram_texture - > get_internal_format ( ) ) ;
}
} ;
2018-10-28 14:59:39 +01:00
class texture_cache : public rsx : : texture_cache < gl : : texture_cache , gl : : texture_cache_traits >
2018-04-07 12:19:49 +02:00
{
private :
2018-10-28 14:59:39 +01:00
using baseclass = rsx : : texture_cache < gl : : texture_cache , gl : : texture_cache_traits > ;
friend baseclass ;
2018-04-07 12:19:49 +02:00
2018-10-28 14:59:39 +01:00
private :
2018-04-07 12:19:49 +02:00
struct discardable_storage
{
std : : unique_ptr < gl : : texture > image ;
std : : unique_ptr < gl : : texture_view > view ;
2017-09-08 16:52:13 +02:00
2018-04-07 12:19:49 +02:00
discardable_storage ( )
{ }
discardable_storage ( std : : unique_ptr < gl : : texture > & tex )
2017-09-04 12:05:02 +02:00
{
2018-04-07 12:19:49 +02:00
image = std : : move ( tex ) ;
}
2018-02-15 19:37:12 +01:00
2018-04-07 12:19:49 +02:00
discardable_storage ( std : : unique_ptr < gl : : texture_view > & _view )
{
view = std : : move ( _view ) ;
2017-09-04 12:05:02 +02:00
}
2017-03-29 21:27:29 +02:00
2018-04-07 12:19:49 +02:00
discardable_storage ( std : : unique_ptr < gl : : texture > & tex , std : : unique_ptr < gl : : texture_view > & _view )
{
image = std : : move ( tex ) ;
view = std : : move ( _view ) ;
}
} ;
2018-02-09 15:49:37 +01:00
2017-02-13 15:22:25 +01:00
private :
2017-03-29 21:27:29 +02:00
blitter m_hw_blitter ;
2018-04-07 12:19:49 +02:00
std : : vector < discardable_storage > m_temporary_surfaces ;
2017-02-16 19:29:56 +01:00
2017-02-13 15:22:25 +01:00
void clear ( )
2016-02-15 10:50:14 +01:00
{
2018-09-22 02:14:26 +02:00
baseclass : : clear ( ) ;
2017-09-08 16:52:13 +02:00
clear_temporary_subresources ( ) ;
2016-02-15 10:50:14 +01:00
}
2018-02-09 15:49:37 +01:00
2017-09-08 16:52:13 +02:00
void clear_temporary_subresources ( )
2016-02-15 10:50:14 +01:00
{
2017-09-08 16:52:13 +02:00
m_temporary_surfaces . resize ( 0 ) ;
2017-02-13 15:22:25 +01:00
}
2018-04-07 12:19:49 +02:00
gl : : texture_view * create_temporary_subresource_impl ( gl : : texture * src , GLenum sized_internal_fmt , GLenum dst_type , u32 gcm_format ,
2018-03-18 12:40:26 +01:00
u16 x , u16 y , u16 width , u16 height , const texture_channel_remap_t & remap , bool copy )
2017-02-16 19:29:56 +01:00
{
2018-02-23 20:49:59 +01:00
if ( sized_internal_fmt = = GL_NONE )
sized_internal_fmt = gl : : get_sized_internal_format ( gcm_format ) ;
2018-04-13 22:59:29 +02:00
gl : : texture : : internal_format ifmt = static_cast < gl : : texture : : internal_format > ( sized_internal_fmt ) ;
if ( src )
2017-09-19 14:46:16 +02:00
{
2018-04-13 22:59:29 +02:00
ifmt = src - > get_internal_format ( ) ;
switch ( ifmt )
{
case gl : : texture : : internal_format : : depth16 :
case gl : : texture : : internal_format : : depth24_stencil8 :
case gl : : texture : : internal_format : : depth32f_stencil8 :
//HACK! Should use typeless transfer instead
sized_internal_fmt = ( GLenum ) ifmt ;
break ;
}
2017-09-19 14:46:16 +02:00
}
2018-11-24 13:54:46 +01:00
std : : unique_ptr < gl : : texture > dst = std : : make_unique < gl : : viewable_image > ( dst_type , width , height , 1 , 1 , sized_internal_fmt ) ;
2017-11-30 19:50:19 +01:00
2018-02-21 11:46:23 +01:00
if ( copy )
{
//Empty GL_ERROR
glGetError ( ) ;
2017-02-16 19:29:56 +01:00
2018-04-07 12:19:49 +02:00
glCopyImageSubData ( src - > id ( ) , GL_TEXTURE_2D , 0 , x , y , 0 ,
dst - > id ( ) , dst_type , 0 , 0 , 0 , 0 , width , height , 1 ) ;
2017-02-16 19:29:56 +01:00
2018-02-21 11:46:23 +01:00
//Check for error
if ( GLenum err = glGetError ( ) )
{
LOG_WARNING ( RSX , " Failed to copy image subresource with GL error 0x%X " , err ) ;
2018-04-07 12:19:49 +02:00
return nullptr ;
2018-02-21 11:46:23 +01:00
}
2017-02-16 19:29:56 +01:00
}
2017-04-04 18:14:36 +02:00
2018-04-13 22:59:29 +02:00
std : : array < GLenum , 4 > swizzle ;
if ( ! src | | ( GLenum ) ifmt ! = sized_internal_fmt )
2018-02-23 20:49:59 +01:00
{
2018-04-13 22:59:29 +02:00
if ( src )
{
//Format mismatch
err_once ( " GL format mismatch (data cast?). Sized ifmt=0x%X vs Src ifmt=0x%X " , sized_internal_fmt , ( GLenum ) ifmt ) ;
}
2018-02-23 20:49:59 +01:00
//Apply base component map onto the new texture if a data cast has been done
2018-04-07 12:19:49 +02:00
swizzle = get_component_mapping ( gcm_format , rsx : : texture_create_flags : : default_component_order ) ;
2018-03-24 12:13:11 +01:00
}
2018-04-13 22:59:29 +02:00
else
{
swizzle = src - > get_native_component_layout ( ) ;
}
2018-02-23 20:49:59 +01:00
2018-03-23 16:05:56 +01:00
if ( memcmp ( remap . first . data ( ) , rsx : : default_remap_vector . first . data ( ) , 4 ) | |
memcmp ( remap . second . data ( ) , rsx : : default_remap_vector . second . data ( ) , 4 ) )
2018-04-07 12:19:49 +02:00
swizzle = apply_swizzle_remap ( swizzle , remap ) ;
2018-03-18 12:40:26 +01:00
2018-04-07 12:19:49 +02:00
auto view = std : : make_unique < gl : : texture_view > ( dst . get ( ) , dst_type , sized_internal_fmt , swizzle . data ( ) ) ;
auto result = view . get ( ) ;
m_temporary_surfaces . push_back ( { dst , view } ) ;
return result ;
2017-02-16 19:29:56 +01:00
}
2017-12-07 13:08:11 +01:00
2018-04-07 12:19:49 +02:00
std : : array < GLenum , 4 > get_component_mapping ( u32 gcm_format , rsx : : texture_create_flags flags )
2017-12-07 13:08:11 +01:00
{
2018-04-22 21:08:53 +02:00
switch ( gcm_format )
{
case CELL_GCM_TEXTURE_DEPTH24_D8 :
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT :
case CELL_GCM_TEXTURE_DEPTH16 :
case CELL_GCM_TEXTURE_DEPTH16_FLOAT :
//Dont bother letting this propagate
return { GL_RED , GL_RED , GL_RED , GL_RED } ;
default :
break ;
}
2017-12-07 13:08:11 +01:00
switch ( flags )
{
case rsx : : texture_create_flags : : default_component_order :
{
2018-04-07 12:19:49 +02:00
return gl : : get_swizzle_remap ( gcm_format ) ;
2017-12-07 13:08:11 +01:00
}
case rsx : : texture_create_flags : : native_component_order :
{
2018-04-07 12:19:49 +02:00
return { GL_ALPHA , GL_RED , GL_GREEN , GL_BLUE } ;
2017-12-07 13:08:11 +01:00
}
case rsx : : texture_create_flags : : swapped_native_component_order :
{
2018-04-07 12:19:49 +02:00
return { GL_BLUE , GL_ALPHA , GL_RED , GL_GREEN } ;
2017-12-07 13:08:11 +01:00
}
2018-04-07 12:19:49 +02:00
default :
fmt : : throw_exception ( " Unknown texture create flags " HERE ) ;
2017-12-07 13:08:11 +01:00
}
}
2018-02-09 15:49:37 +01:00
2017-09-08 16:52:13 +02:00
protected :
2018-02-09 15:49:37 +01:00
2018-12-29 14:28:12 +01:00
gl : : texture_view * create_temporary_subresource_view ( gl : : command_context & , gl : : texture * * src , u32 gcm_format , u16 x , u16 y , u16 w , u16 h ,
2018-03-18 12:40:26 +01:00
const texture_channel_remap_t & remap_vector ) override
2017-02-13 15:22:25 +01:00
{
2018-03-18 12:40:26 +01:00
return create_temporary_subresource_impl ( * src , GL_NONE , GL_TEXTURE_2D , gcm_format , x , y , w , h , remap_vector , true ) ;
2016-02-15 10:50:14 +01:00
}
2018-12-29 14:28:12 +01:00
gl : : texture_view * create_temporary_subresource_view ( gl : : command_context & , gl : : texture * src , u32 gcm_format , u16 x , u16 y , u16 w , u16 h ,
2018-03-18 12:40:26 +01:00
const texture_channel_remap_t & remap_vector ) override
2017-08-13 23:27:19 +02:00
{
2018-04-07 12:19:49 +02:00
return create_temporary_subresource_impl ( src , ( GLenum ) src - > get_internal_format ( ) ,
GL_TEXTURE_2D , gcm_format , x , y , w , h , remap_vector , true ) ;
2017-08-13 23:27:19 +02:00
}
2018-12-29 14:28:12 +01:00
gl : : texture_view * generate_cubemap_from_images ( gl : : command_context & , u32 gcm_format , u16 size , const std : : vector < copy_region_descriptor > & sources , const texture_channel_remap_t & /*remap_vector*/ ) override
2017-11-02 16:54:57 +01:00
{
2017-11-02 19:54:19 +01:00
const GLenum ifmt = gl : : get_sized_internal_format ( gcm_format ) ;
2018-11-24 13:54:46 +01:00
std : : unique_ptr < gl : : texture > dst_image = std : : make_unique < gl : : viewable_image > ( GL_TEXTURE_CUBE_MAP , size , size , 1 , 1 , ifmt ) ;
2018-04-07 12:19:49 +02:00
auto view = std : : make_unique < gl : : texture_view > ( dst_image . get ( ) , GL_TEXTURE_CUBE_MAP , ifmt ) ;
2017-11-02 19:54:19 +01:00
//Empty GL_ERROR
glGetError ( ) ;
2018-03-30 12:28:46 +02:00
for ( const auto & slice : sources )
2017-11-02 19:54:19 +01:00
{
2018-03-30 12:28:46 +02:00
if ( slice . src )
2017-11-03 13:48:27 +01:00
{
2018-04-07 12:19:49 +02:00
glCopyImageSubData ( slice . src - > id ( ) , GL_TEXTURE_2D , 0 , slice . src_x , slice . src_y , 0 ,
dst_image - > id ( ) , GL_TEXTURE_CUBE_MAP , 0 , slice . dst_x , slice . dst_y , slice . dst_z , slice . w , slice . h , 1 ) ;
2018-03-30 12:28:46 +02:00
}
}
if ( GLenum err = glGetError ( ) )
{
LOG_WARNING ( RSX , " Failed to copy image subresource with GL error 0x%X " , err ) ;
2018-04-07 12:19:49 +02:00
return nullptr ;
2018-03-30 12:28:46 +02:00
}
2018-04-07 12:19:49 +02:00
auto result = view . get ( ) ;
m_temporary_surfaces . push_back ( { dst_image , view } ) ;
return result ;
2018-03-30 12:28:46 +02:00
}
2018-12-29 14:28:12 +01:00
gl : : texture_view * generate_3d_from_2d_images ( gl : : command_context & , u32 gcm_format , u16 width , u16 height , u16 depth , const std : : vector < copy_region_descriptor > & sources , const texture_channel_remap_t & /*remap_vector*/ ) override
2018-03-30 12:28:46 +02:00
{
const GLenum ifmt = gl : : get_sized_internal_format ( gcm_format ) ;
2018-11-24 13:54:46 +01:00
std : : unique_ptr < gl : : texture > dst_image = std : : make_unique < gl : : viewable_image > ( GL_TEXTURE_3D , width , height , depth , 1 , ifmt ) ;
2018-04-07 12:19:49 +02:00
auto view = std : : make_unique < gl : : texture_view > ( dst_image . get ( ) , GL_TEXTURE_3D , ifmt ) ;
2018-03-30 12:28:46 +02:00
//Empty GL_ERROR
glGetError ( ) ;
for ( const auto & slice : sources )
{
if ( slice . src )
{
2018-04-07 12:19:49 +02:00
glCopyImageSubData ( slice . src - > id ( ) , GL_TEXTURE_2D , 0 , slice . src_x , slice . src_y , 0 ,
dst_image - > id ( ) , GL_TEXTURE_3D , 0 , slice . dst_x , slice . dst_y , slice . dst_z , slice . w , slice . h , 1 ) ;
2017-11-03 13:48:27 +01:00
}
2017-11-02 19:54:19 +01:00
}
if ( GLenum err = glGetError ( ) )
{
LOG_WARNING ( RSX , " Failed to copy image subresource with GL error 0x%X " , err ) ;
2018-04-07 12:19:49 +02:00
return nullptr ;
2017-11-02 19:54:19 +01:00
}
2018-04-07 12:19:49 +02:00
auto result = view . get ( ) ;
m_temporary_surfaces . push_back ( { dst_image , view } ) ;
return result ;
2017-11-02 16:54:57 +01:00
}
2018-12-29 14:28:12 +01:00
gl : : texture_view * generate_atlas_from_images ( gl : : command_context & , u32 gcm_format , u16 width , u16 height , const std : : vector < copy_region_descriptor > & sections_to_copy ,
2018-03-18 12:40:26 +01:00
const texture_channel_remap_t & remap_vector ) override
2018-02-21 11:46:23 +01:00
{
2018-04-13 22:59:29 +02:00
auto result = create_temporary_subresource_impl ( nullptr , GL_NONE , GL_TEXTURE_2D , gcm_format , 0 , 0 , width , height , remap_vector , false ) ;
2018-02-21 11:46:23 +01:00
for ( const auto & region : sections_to_copy )
{
2018-04-07 12:19:49 +02:00
glCopyImageSubData ( region . src - > id ( ) , GL_TEXTURE_2D , 0 , region . src_x , region . src_y , 0 ,
result - > image ( ) - > id ( ) , GL_TEXTURE_2D , 0 , region . dst_x , region . dst_y , 0 , region . w , region . h , 1 ) ;
2018-02-21 11:46:23 +01:00
}
return result ;
}
2018-12-29 14:28:12 +01:00
void update_image_contents ( gl : : command_context & , gl : : texture_view * dst , gl : : texture * src , u16 width , u16 height ) override
2018-02-21 11:46:23 +01:00
{
2018-04-07 12:19:49 +02:00
glCopyImageSubData ( src - > id ( ) , GL_TEXTURE_2D , 0 , 0 , 0 , 0 ,
dst - > image ( ) - > id ( ) , GL_TEXTURE_2D , 0 , 0 , 0 , 0 , width , height , 1 ) ;
2018-02-21 11:46:23 +01:00
}
2018-12-29 14:28:12 +01:00
cached_texture_section * create_new_texture ( gl : : command_context & , const utils : : address_range & rsx_range , u16 width , u16 height , u16 depth , u16 mipmaps , u16 pitch ,
2018-12-18 18:04:03 +01:00
u32 gcm_format , rsx : : texture_upload_context context , rsx : : texture_dimension_extended type , rsx : : texture_create_flags flags ) override
2016-02-15 10:50:14 +01:00
{
2018-07-17 18:42:51 +02:00
auto image = gl : : create_texture ( gcm_format , width , height , depth , mipmaps , type ) ;
const auto swizzle = get_component_mapping ( gcm_format , flags ) ;
image - > set_native_component_layout ( swizzle ) ;
2017-09-14 13:37:14 +02:00
2018-10-28 14:59:39 +01:00
auto & cached = * find_cached_texture ( rsx_range , true , true , width , height , depth , mipmaps ) ;
2018-09-22 02:14:26 +02:00
ASSERT ( ! cached . is_locked ( ) ) ;
// Prepare section
cached . reset ( rsx_range ) ;
2017-09-14 13:37:14 +02:00
cached . set_view_flags ( flags ) ;
2017-09-18 19:22:34 +02:00
cached . set_context ( context ) ;
2017-11-02 16:54:57 +01:00
cached . set_image_type ( type ) ;
2018-09-22 02:14:26 +02:00
cached . set_gcm_format ( gcm_format ) ;
2018-12-18 18:04:03 +01:00
cached . create_read_only ( image , width , height , depth , mipmaps , pitch ) ;
2018-09-22 02:14:26 +02:00
cached . set_dirty ( false ) ;
2016-03-11 20:25:49 +01:00
2018-02-03 09:37:42 +01:00
if ( context ! = rsx : : texture_upload_context : : blit_engine_dst )
2017-10-28 21:17:27 +02:00
{
2018-10-19 00:22:00 +02:00
AUDIT ( cached . get_memory_read_flags ( ) ! = rsx : : memory_read_flags : : flush_always ) ;
2018-09-22 02:14:26 +02:00
read_only_range = cached . get_min_max ( read_only_range , rsx : : section_bounds : : locked_range ) ; // TODO ruipin: This was outside the if, but is inside the if in Vulkan. Ask kd-11
2017-09-19 14:46:16 +02:00
cached . protect ( utils : : protection : : ro ) ;
2018-02-03 09:37:42 +01:00
}
else
{
//TODO: More tests on byte order
//ARGB8+native+unswizzled is confirmed with Dark Souls II character preview
2018-02-10 17:21:16 +01:00
switch ( gcm_format )
{
case CELL_GCM_TEXTURE_A8R8G8B8 :
2018-02-03 09:37:42 +01:00
{
bool bgra = ( flags = = rsx : : texture_create_flags : : native_component_order ) ;
2018-02-10 17:21:16 +01:00
cached . set_format ( bgra ? gl : : texture : : format : : bgra : gl : : texture : : format : : rgba , gl : : texture : : type : : uint_8_8_8_8 , false ) ;
break ;
2018-02-03 09:37:42 +01:00
}
2018-02-10 17:21:16 +01:00
case CELL_GCM_TEXTURE_R5G6B5 :
2018-02-03 09:37:42 +01:00
{
cached . set_format ( gl : : texture : : format : : rgb , gl : : texture : : type : : ushort_5_6_5 , true ) ;
2018-02-10 17:21:16 +01:00
break ;
}
case CELL_GCM_TEXTURE_DEPTH24_D8 :
{
cached . set_format ( gl : : texture : : format : : depth_stencil , gl : : texture : : type : : uint_24_8 , true ) ;
break ;
}
case CELL_GCM_TEXTURE_DEPTH16 :
{
cached . set_format ( gl : : texture : : format : : depth , gl : : texture : : type : : ushort , true ) ;
break ;
}
default :
fmt : : throw_exception ( " Unexpected gcm format 0x%X " HERE , gcm_format ) ;
2018-02-03 09:37:42 +01:00
}
2018-05-10 13:50:32 +02:00
//NOTE: Protection is handled by the caller
2018-02-03 09:37:42 +01:00
cached . make_flushable ( ) ;
2018-09-22 02:14:26 +02:00
cached . set_dimensions ( width , height , depth , ( rsx_range . length ( ) / height ) ) ;
no_access_range = cached . get_min_max ( no_access_range , rsx : : section_bounds : : locked_range ) ;
2017-10-28 21:17:27 +02:00
}
2017-09-19 14:46:16 +02:00
2018-02-03 09:37:42 +01:00
update_cache_tag ( ) ;
2017-09-08 16:52:13 +02:00
return & cached ;
2016-02-15 10:50:14 +01:00
}
2018-12-29 14:28:12 +01:00
cached_texture_section * upload_image_from_cpu ( gl : : command_context & cmd , const utils : : address_range & rsx_range , u16 width , u16 height , u16 depth , u16 mipmaps , u16 pitch , u32 gcm_format ,
2018-07-17 18:42:51 +02:00
rsx : : texture_upload_context context , const std : : vector < rsx_subresource_layout > & subresource_layout , rsx : : texture_dimension_extended type , bool input_swizzled ) override
2016-02-15 10:50:14 +01:00
{
2018-12-29 14:28:12 +01:00
auto section = create_new_texture ( cmd , rsx_range , width , height , depth , mipmaps , pitch , gcm_format , context , type ,
2018-07-17 18:42:51 +02:00
rsx : : texture_create_flags : : default_component_order ) ;
2017-09-14 13:37:14 +02:00
2018-12-13 11:23:58 +01:00
gl : : upload_texture ( section - > get_raw_texture ( ) - > id ( ) , gcm_format , width , height , depth , mipmaps ,
2018-07-17 18:42:51 +02:00
input_swizzled , type , subresource_layout ) ;
2017-09-08 16:52:13 +02:00
return section ;
2017-02-16 19:29:56 +01:00
}
2017-12-18 10:02:19 +01:00
void enforce_surface_creation_type ( cached_texture_section & section , u32 gcm_format , rsx : : texture_create_flags flags ) override
2017-02-16 19:29:56 +01:00
{
2017-09-14 13:37:14 +02:00
if ( flags = = section . get_view_flags ( ) )
return ;
2018-07-17 18:42:51 +02:00
const auto swizzle = get_component_mapping ( gcm_format , flags ) ;
2018-09-18 20:06:34 +02:00
auto image = static_cast < gl : : viewable_image * > ( section . get_raw_texture ( ) ) ;
verify ( HERE ) , image ! = nullptr ;
image - > set_native_component_layout ( swizzle ) ;
2017-09-14 13:37:14 +02:00
section . set_view_flags ( flags ) ;
2017-12-07 10:09:07 +01:00
}
2018-12-29 14:28:12 +01:00
void insert_texture_barrier ( gl : : command_context & , gl : : texture * ) override
2017-02-13 15:22:25 +01:00
{
2017-09-08 16:52:13 +02:00
auto & caps = gl : : get_driver_caps ( ) ;
2016-02-15 10:50:14 +01:00
2017-09-08 16:52:13 +02:00
if ( caps . ARB_texture_barrier_supported )
glTextureBarrier ( ) ;
else if ( caps . NV_texture_barrier_supported )
glTextureBarrierNV ( ) ;
2017-08-07 23:54:40 +02:00
}
2018-02-23 20:49:59 +01:00
bool render_target_format_is_compatible ( gl : : texture * tex , u32 gcm_format ) override
{
2018-04-07 12:19:49 +02:00
auto ifmt = tex - > get_internal_format ( ) ;
switch ( gcm_format )
2018-02-23 20:49:59 +01:00
{
2018-04-07 12:19:49 +02:00
default :
//TODO
2018-05-18 22:55:37 +02:00
warn_once ( " Format incompatibility detected, reporting failure to force data copy (GL_INTERNAL_FORMAT=0x%X, GCM_FORMAT=0x%X) " , ( u32 ) ifmt , gcm_format ) ;
2018-04-07 12:19:49 +02:00
return false ;
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT :
return ( ifmt = = gl : : texture : : internal_format : : rgba16f ) ;
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT :
return ( ifmt = = gl : : texture : : internal_format : : rgba32f ) ;
case CELL_GCM_TEXTURE_X32_FLOAT :
return ( ifmt = = gl : : texture : : internal_format : : r32f ) ;
case CELL_GCM_TEXTURE_R5G6B5 :
return ( ifmt = = gl : : texture : : internal_format : : r5g6b5 ) ;
case CELL_GCM_TEXTURE_A8R8G8B8 :
return ( ifmt = = gl : : texture : : internal_format : : rgba8 | |
ifmt = = gl : : texture : : internal_format : : depth24_stencil8 | |
ifmt = = gl : : texture : : internal_format : : depth32f_stencil8 ) ;
case CELL_GCM_TEXTURE_B8 :
return ( ifmt = = gl : : texture : : internal_format : : r8 ) ;
case CELL_GCM_TEXTURE_G8B8 :
return ( ifmt = = gl : : texture : : internal_format : : rg8 ) ;
case CELL_GCM_TEXTURE_DEPTH24_D8 :
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT :
return ( ifmt = = gl : : texture : : internal_format : : depth24_stencil8 | |
ifmt = = gl : : texture : : internal_format : : depth32f_stencil8 | |
ifmt = = gl : : texture : : internal_format : : depth_stencil ) ;
case CELL_GCM_TEXTURE_DEPTH16 :
case CELL_GCM_TEXTURE_DEPTH16_FLOAT :
return ( ifmt = = gl : : texture : : internal_format : : depth16 | |
ifmt = = gl : : texture : : internal_format : : depth ) ;
2018-02-23 20:49:59 +01:00
}
}
2017-09-08 16:52:13 +02:00
public :
2016-02-15 10:50:14 +01:00
2018-09-22 02:14:26 +02:00
using baseclass : : texture_cache ;
2016-02-15 10:50:14 +01:00
2017-09-08 16:52:13 +02:00
void initialize ( )
2017-02-16 19:29:56 +01:00
{
2017-09-08 16:52:13 +02:00
m_hw_blitter . init ( ) ;
2017-09-28 20:32:00 +02:00
g_hw_blitter = & m_hw_blitter ;
2016-02-15 10:50:14 +01:00
}
2017-03-29 21:27:29 +02:00
2017-09-08 16:52:13 +02:00
void destroy ( ) override
2017-08-07 23:54:40 +02:00
{
2017-09-08 16:52:13 +02:00
clear ( ) ;
2017-09-28 20:32:00 +02:00
g_hw_blitter = nullptr ;
2017-09-08 16:52:13 +02:00
m_hw_blitter . destroy ( ) ;
2017-08-07 23:54:40 +02:00
}
2017-09-28 20:32:00 +02:00
2017-12-18 10:02:19 +01:00
bool is_depth_texture ( u32 rsx_address , u32 rsx_size ) override
2017-09-04 12:05:02 +02:00
{
2017-09-14 13:37:14 +02:00
reader_lock lock ( m_cache_mutex ) ;
2018-09-22 02:14:26 +02:00
auto & block = m_storage . block_for ( rsx_address ) ;
2017-09-18 19:22:34 +02:00
2018-09-22 02:14:26 +02:00
if ( block . get_locked_count ( ) = = 0 )
return false ;
2017-09-18 19:22:34 +02:00
2018-09-22 02:14:26 +02:00
for ( auto & tex : block )
2017-09-18 19:22:34 +02:00
{
if ( tex . is_dirty ( ) )
continue ;
2018-09-22 02:14:26 +02:00
if ( ! tex . overlaps ( rsx_address , rsx : : section_bounds : : full_range ) )
2017-09-19 14:46:16 +02:00
continue ;
if ( ( rsx_address + rsx_size - tex . get_section_base ( ) ) < = tex . get_section_size ( ) )
return tex . is_depth_texture ( ) ;
}
2017-09-04 12:05:02 +02:00
return false ;
}
2017-09-08 16:52:13 +02:00
void on_frame_end ( ) override
2017-03-29 21:27:29 +02:00
{
2018-09-22 02:14:26 +02:00
if ( m_storage . m_unreleased_texture_objects > = m_max_zombie_objects )
2017-09-04 12:05:02 +02:00
{
2018-09-22 02:14:26 +02:00
purge_unreleased_sections ( ) ;
2017-09-04 12:05:02 +02:00
}
2018-02-09 15:49:37 +01:00
2017-09-08 16:52:13 +02:00
clear_temporary_subresources ( ) ;
2018-10-28 14:59:39 +01:00
baseclass : : on_frame_end ( ) ;
2017-09-08 16:52:13 +02:00
}
2017-03-29 21:27:29 +02:00
2018-12-29 14:28:12 +01:00
bool blit ( gl : : command_context & cmd , rsx : : blit_src_info & src , rsx : : blit_dst_info & dst , bool linear_interpolate , gl_render_targets & m_rtts )
2017-09-08 16:52:13 +02:00
{
2018-12-29 14:28:12 +01:00
auto result = upload_scaled_image ( src , dst , linear_interpolate , cmd , m_rtts , m_hw_blitter ) ;
2018-02-10 17:21:16 +01:00
if ( result . succeeded )
{
2018-02-12 09:26:57 +01:00
if ( result . real_dst_size )
2018-02-10 17:21:16 +01:00
{
2018-02-12 09:26:57 +01:00
gl : : texture : : format fmt ;
if ( ! result . is_depth )
{
fmt = dst . format = = rsx : : blit_engine : : transfer_destination_format : : a8r8g8b8 ?
gl : : texture : : format : : bgra : gl : : texture : : format : : rgba ;
}
else
{
fmt = dst . format = = rsx : : blit_engine : : transfer_destination_format : : a8r8g8b8 ?
gl : : texture : : format : : depth_stencil : gl : : texture : : format : : depth ;
}
2018-12-29 14:28:12 +01:00
flush_if_cache_miss_likely ( cmd , result . to_address_range ( ) ) ;
2018-02-10 17:21:16 +01:00
}
return true ;
}
return false ;
2017-09-08 16:52:13 +02:00
}
2016-02-15 10:50:14 +01:00
} ;
2017-04-04 18:14:36 +02:00
}