2016-02-15 10:50:14 +01:00
# pragma once
# 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 ) ;
2017-09-28 20:32:00 +02:00
extern blitter * g_hw_blitter ;
class blitter
{
fbo blit_src ;
fbo blit_dst ;
public :
void init ( )
{
blit_src . create ( ) ;
blit_dst . create ( ) ;
}
void destroy ( )
{
blit_dst . remove ( ) ;
blit_src . remove ( ) ;
}
2018-04-07 12:19:49 +02:00
void scale_image ( texture * src , texture * dst , areai src_rect , areai dst_rect , bool linear_interpolation , bool is_depth_copy )
2017-09-28 20:32:00 +02:00
{
s32 old_fbo = 0 ;
glGetIntegerv ( GL_FRAMEBUFFER_BINDING , & old_fbo ) ;
filter interp = linear_interpolation ? filter : : linear : filter : : nearest ;
GLenum attachment = is_depth_copy ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0 ;
blit_src . bind ( ) ;
2018-04-07 12:19:49 +02:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , attachment , GL_TEXTURE_2D , src - > id ( ) , 0 ) ;
2017-09-28 20:32:00 +02:00
blit_src . check ( ) ;
blit_dst . bind ( ) ;
2018-04-07 12:19:49 +02:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , attachment , GL_TEXTURE_2D , dst - > id ( ) , 0 ) ;
2017-09-28 20:32:00 +02:00
blit_dst . check ( ) ;
GLboolean scissor_test_enabled = glIsEnabled ( GL_SCISSOR_TEST ) ;
if ( scissor_test_enabled )
glDisable ( GL_SCISSOR_TEST ) ;
blit_src . blit ( blit_dst , src_rect , dst_rect , is_depth_copy ? buffers : : depth : buffers : : color , interp ) ;
2017-10-02 15:53:27 +02:00
blit_src . bind ( ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , attachment , GL_TEXTURE_2D , GL_NONE , 0 ) ;
blit_dst . bind ( ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , attachment , GL_TEXTURE_2D , GL_NONE , 0 ) ;
2017-09-28 20:32:00 +02:00
if ( scissor_test_enabled )
glEnable ( GL_SCISSOR_TEST ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , old_fbo ) ;
}
} ;
2017-09-08 16:52:13 +02:00
2017-09-18 19:22:34 +02:00
class cached_texture_section : public rsx : : cached_texture_section
2017-02-13 15:22:25 +01:00
{
2017-09-08 16:52:13 +02:00
private :
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-04-07 12:19:49 +02:00
gl : : texture * vram_texture = nullptr ;
std : : unique_ptr < gl : : texture_view > view ;
std : : unique_ptr < gl : : texture > managed_texture ;
std : : unique_ptr < gl : : texture > scaled_texture ;
2017-02-16 19:29:56 +01:00
2017-09-08 16:52:13 +02:00
bool is_depth = false ;
2016-02-15 10:50:14 +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 ) ;
const u32 real_buffer_size = ( resolution_scale < = 1.f ) ? cpu_address_range : ( u32 ) ( resolution_scale * resolution_scale * cpu_address_range ) ;
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 ) ;
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-02-10 09:52:44 +01:00
2018-02-19 13:41:52 +01:00
void reset ( u32 base , u32 size , bool /*flushable*/ = false )
2017-09-08 16:52:13 +02:00
{
2017-10-04 19:54:13 +02:00
rsx : : protection_policy policy = g_cfg . video . strict_rendering_mode ? rsx : : protection_policy : : protect_policy_full_range : rsx : : protection_policy : : protect_policy_conservative ;
2017-09-08 16:52:13 +02:00
rsx : : buffered_section : : reset ( base , size , policy ) ;
2016-02-15 10:50:14 +01:00
2017-09-08 16:52:13 +02:00
flushed = false ;
2018-02-10 17:21:16 +01:00
synchronized = false ;
2017-09-08 16:52:13 +02:00
is_depth = false ;
2017-02-16 19:29:56 +01:00
2018-04-07 12:19:49 +02:00
vram_texture = nullptr ;
managed_texture . reset ( ) ;
view . reset ( ) ;
2017-09-08 16:52:13 +02:00
}
2018-02-09 15:49:37 +01:00
2018-04-07 12:19:49 +02:00
void create ( u16 w , u16 h , u16 depth , u16 mipmaps , gl : : texture_view * _view ,
2017-12-18 10:02:19 +01:00
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 )
{
2017-11-29 15:05:36 +01:00
if ( read_only )
{
2018-04-07 12:19:49 +02:00
managed_texture . reset ( image ) ;
view . reset ( _view ) ;
2017-11-29 15:05:36 +01:00
aa_mode = rsx : : surface_antialiasing : : center_1_sample ;
}
else
{
2018-04-07 12:19:49 +02:00
view . reset ( ) ;
managed_texture . reset ( ) ;
2017-11-29 15:05:36 +01:00
if ( pbo_id = = 0 )
init_buffer ( ) ;
aa_mode = static_cast < gl : : render_target * > ( image ) - > aa_mode ;
}
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 ;
2017-09-08 16:52:13 +02:00
is_depth = false ;
2017-03-29 21:27:29 +02:00
2017-09-18 19:22:34 +02:00
this - > width = w ;
this - > height = h ;
this - > rsx_pitch = rsx_pitch ;
2017-09-22 15:12:10 +02:00
this - > depth = depth ;
this - > mipmaps = mipmaps ;
2017-03-29 21:27:29 +02:00
2018-04-07 12:19:49 +02:00
vram_texture = image ;
2017-09-08 16:52:13 +02:00
set_format ( gl_format , gl_type , swap_bytes ) ;
}
2017-03-29 21:27:29 +02:00
2018-04-07 12:19:49 +02:00
void create_read_only ( gl : : texture * image , gl : : texture_view * _view , u32 width , u32 height , u32 depth , u32 mipmaps )
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 ) ;
view . reset ( _view ) ;
vram_texture = image ;
2017-03-29 21:27:29 +02:00
2017-09-18 19:22:34 +02:00
rsx_pitch = 0 ;
2017-09-08 16:52:13 +02:00
real_pitch = 0 ;
}
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
real_pitch = width * get_pixel_size ( format , type ) ;
}
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-18 19:22:34 +02:00
real_pitch = width * get_pixel_size ( format , type ) ;
2017-09-08 16:52:13 +02:00
}
void set_depth_flag ( bool is_depth_fmt )
{
is_depth = is_depth_fmt ;
}
void set_source ( gl : : texture & source )
{
2018-04-07 12:19:49 +02:00
vram_texture = & source ;
2017-09-08 16:52:13 +02:00
}
2017-02-16 19:29:56 +01:00
2017-09-08 16:52:13 +02:00
void copy_texture ( bool = false )
{
2018-02-03 09:37:42 +01:00
if ( ! pbo_id )
{
init_buffer ( ) ;
}
2018-04-07 12:19:49 +02:00
u32 target_texture = vram_texture - > id ( ) ;
2018-02-03 09:37:42 +01:00
if ( ( rsx : : get_resolution_scale_percent ( ) ! = 100 & & context = = rsx : : texture_upload_context : : framebuffer_storage ) | |
( real_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
}
bool linear_interp = false ; //TODO: Make optional or detect full sized sources
2018-04-07 12:19:49 +02:00
g_hw_blitter - > scale_image ( vram_texture , scaled_texture . get ( ) , src_area , dst_area , linear_interp , is_depth ) ;
target_texture = scaled_texture - > id ( ) ;
2017-10-02 15:53:27 +02:00
}
2017-09-28 20:32:00 +02:00
}
2017-09-08 16:52:13 +02:00
glPixelStorei ( GL_PACK_SWAP_BYTES , pack_unpack_swap_bytes ) ;
2017-10-02 15:53:27 +02:00
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2017-11-29 15:05:36 +01:00
glPixelStorei ( GL_PACK_ROW_LENGTH , 0 ) ;
2017-09-08 16:52:13 +02:00
glBindBuffer ( GL_PIXEL_PACK_BUFFER , pbo_id ) ;
2017-04-04 18:14:36 +02:00
2017-10-03 13:38:00 +02:00
glGetError ( ) ;
2017-09-08 16:52:13 +02:00
if ( get_driver_caps ( ) . EXT_dsa_supported )
2017-09-28 20:32:00 +02:00
glGetTextureImageEXT ( target_texture , GL_TEXTURE_2D , 0 , ( GLenum ) format , ( GLenum ) type , nullptr ) ;
2017-09-08 16:52:13 +02:00
else
2017-09-28 20:32:00 +02:00
glGetTextureImage ( target_texture , 0 , ( GLenum ) format , ( GLenum ) type , pbo_size , nullptr ) ;
2017-04-04 18:14:36 +02:00
2017-10-03 13:38:00 +02:00
if ( GLenum err = glGetError ( ) )
{
bool recovered = false ;
2018-04-07 12:19:49 +02:00
if ( target_texture = = scaled_texture - > id ( ) )
2017-10-03 13:38:00 +02:00
{
if ( get_driver_caps ( ) . EXT_dsa_supported )
2018-04-07 12:19:49 +02:00
glGetTextureImageEXT ( vram_texture - > id ( ) , GL_TEXTURE_2D , 0 , ( GLenum ) format , ( GLenum ) type , nullptr ) ;
2017-10-03 13:38:00 +02:00
else
2018-04-07 12:19:49 +02:00
glGetTextureImage ( vram_texture - > id ( ) , 0 , ( GLenum ) format , ( GLenum ) type , pbo_size , nullptr ) ;
2017-10-03 13:38:00 +02:00
if ( ! glGetError ( ) )
{
recovered = true ;
const u32 min_dimension = cpu_address_range / rsx_pitch ;
LOG_WARNING ( RSX , " Failed to read back a scaled image, but the original texture can be read back. Consider setting min scalable dimension below or equal to %d " , min_dimension ) ;
}
}
2018-02-03 09:37:42 +01:00
if ( ! recovered & & rsx : : get_resolution_scale_percent ( ) ! = 100 & & context = = rsx : : texture_upload_context : : framebuffer_storage )
2017-10-03 13:38:00 +02:00
{
LOG_ERROR ( RSX , " Texture readback failed. Disable resolution scaling to get the 'Write Color Buffers' option to work properly " ) ;
}
}
2017-09-08 16:52:13 +02:00
glBindBuffer ( GL_PIXEL_PACK_BUFFER , 0 ) ;
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 ;
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 ) ;
2017-09-08 16:52:13 +02:00
glBindBuffer ( GL_PIXEL_UNPACK_BUFFER , 0 ) ;
}
2017-02-13 15:22:25 +01:00
2017-09-08 16:52:13 +02:00
bool flush ( )
{
2017-10-27 15:52:27 +02:00
if ( flushed ) return true ; //Already written, ignore
2018-02-10 17:21:16 +01:00
bool result = true ;
if ( ! synchronized )
2017-02-13 15:22:25 +01:00
{
2017-09-08 16:52:13 +02:00
LOG_WARNING ( RSX , " Cache miss at address 0x%X. This is gonna hurt... " , cpu_address_base ) ;
copy_texture ( ) ;
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 , " Nothing to copy; Setting section to readable and moving on... " ) ;
protect ( utils : : protection : : ro ) ;
return false ;
2017-02-13 15:22:25 +01:00
}
2018-02-10 17:21:16 +01:00
result = false ;
2017-09-08 16:52:13 +02:00
}
2017-02-13 15:22:25 +01:00
2017-09-08 16:52:13 +02:00
m_fence . wait_for_signal ( ) ;
flushed = true ;
2017-02-13 15:22:25 +01:00
2017-09-08 16:52:13 +02:00
glBindBuffer ( GL_PIXEL_PACK_BUFFER , pbo_id ) ;
void * data = glMapBufferRange ( GL_PIXEL_PACK_BUFFER , 0 , pbo_size , GL_MAP_READ_BIT ) ;
2018-02-09 15:49:37 +01:00
u8 * dst = vm : : _ptr < u8 > ( cpu_address_base ) ;
2016-02-15 10:50:14 +01:00
2017-09-08 16:52:13 +02:00
//throw if map failed since we'll segfault anyway
verify ( HERE ) , data ! = nullptr ;
2016-02-15 10:50:14 +01:00
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 ;
}
2017-09-28 20:32:00 +02:00
if ( real_pitch > = rsx_pitch | | scaled_texture ! = 0 )
2017-09-08 16:52:13 +02:00
{
memcpy ( dst , data , cpu_address_range ) ;
2016-02-15 10:50:14 +01:00
}
2017-09-08 16:52:13 +02:00
else
2016-02-15 10:50:14 +01:00
{
2017-09-08 16:52:13 +02:00
const u8 pixel_size = get_pixel_size ( format , type ) ;
2017-11-29 17:08:16 +01:00
const u8 samples_u = ( aa_mode = = rsx : : surface_antialiasing : : center_1_sample ) ? 1 : 2 ;
const u8 samples_v = ( aa_mode = = rsx : : surface_antialiasing : : square_centered_4_samples | | aa_mode = = rsx : : surface_antialiasing : : square_rotated_4_samples ) ? 2 : 1 ;
rsx : : scale_image_nearest ( dst , const_cast < const void * > ( data ) , width , height , rsx_pitch , real_pitch , pixel_size , samples_u , samples_v ) ;
2017-09-08 16:52:13 +02:00
}
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
rsx : : shuffle_texel_data_wzyx < u8 > ( dst , rsx_pitch , width , height ) ;
}
2017-09-08 16:52:13 +02:00
glUnmapBuffer ( GL_PIXEL_PACK_BUFFER ) ;
glBindBuffer ( GL_PIXEL_PACK_BUFFER , 0 ) ;
2017-11-29 15:05:36 +01:00
2018-02-10 17:21:16 +01:00
reset_write_statistics ( ) ;
return result ;
2017-09-08 16:52:13 +02:00
}
2016-02-15 10:50:14 +01:00
2018-02-03 09:37:42 +01:00
void reprotect ( utils : : protection prot )
{
flushed = false ;
2018-02-10 17:21:16 +01:00
synchronized = false ;
2018-02-03 09:37:42 +01:00
protect ( prot ) ;
}
2017-09-08 16:52:13 +02:00
void destroy ( )
{
if ( ! locked & & pbo_id = = 0 & & vram_texture = = 0 & & m_fence . is_empty ( ) )
//Already destroyed
return ;
2017-02-13 15:22:25 +01:00
2017-09-08 16:52:13 +02:00
if ( locked )
unprotect ( ) ;
2017-02-13 15:22:25 +01:00
2017-09-08 16:52:13 +02:00
if ( pbo_id = = 0 )
2017-02-13 15:22:25 +01:00
{
2017-09-08 16:52:13 +02:00
//Read-only texture, destroy texture memory
2018-04-07 12:19:49 +02:00
managed_texture . reset ( ) ;
view . reset ( ) ;
2016-02-15 10:50:14 +01:00
}
2017-09-08 16:52:13 +02:00
else
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
}
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 ( ) )
m_fence . destroy ( ) ;
2017-09-08 16:52:13 +02:00
}
2018-02-09 15:49:37 +01:00
2017-09-08 16:52:13 +02:00
texture : : format get_format ( ) const
{
return format ;
}
2018-02-09 15:49:37 +01:00
2017-09-08 16:52:13 +02:00
bool exists ( ) const
{
return vram_texture ! = 0 ;
}
2018-02-09 15:49:37 +01:00
2017-09-08 16:52:13 +02:00
bool is_flushable ( ) const
{
2017-09-15 00:32:23 +02:00
return ( locked & & pbo_id ! = 0 ) ;
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
{
return vram_texture = = 0 ;
}
2018-04-07 12:19:49 +02:00
gl : : texture_view * get_raw_view ( ) const
{
return view . get ( ) ;
}
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-04-07 12:19:49 +02:00
std : : unique_ptr < gl : : texture_view > & get_view ( )
2017-09-08 16:52:13 +02:00
{
2018-04-07 12:19:49 +02:00
return view ;
2017-09-08 16:52:13 +02:00
}
bool is_depth_texture ( ) const
{
return is_depth ;
}
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 ( ) ) ;
}
} ;
class texture_cache : public rsx : : texture_cache < void * , cached_texture_section , gl : : texture * , gl : : texture_view * , gl : : texture , gl : : texture : : format >
{
private :
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
2018-04-07 12:19:49 +02:00
cached_texture_section & create_texture ( gl : : texture * image , gl : : texture_view * view , u32 texaddr , u32 texsize , u32 w , u32 h , u32 depth , u32 mipmaps )
2016-02-15 10:50:14 +01:00
{
2017-09-22 15:12:10 +02:00
cached_texture_section & tex = find_cached_texture ( texaddr , texsize , true , w , h , depth ) ;
2017-03-29 21:27:29 +02:00
tex . reset ( texaddr , texsize , false ) ;
2018-04-07 12:19:49 +02:00
tex . create_read_only ( image , view , w , h , depth , mipmaps ) ;
2017-03-29 21:27:29 +02:00
read_only_range = tex . get_min_max ( read_only_range ) ;
2017-09-08 16:52:13 +02:00
return tex ;
2016-02-15 10:50:14 +01:00
}
2017-02-13 15:22:25 +01:00
void clear ( )
2016-02-15 10:50:14 +01:00
{
2017-09-08 16:52:13 +02:00
for ( auto & address_range : m_cache )
2016-02-15 10:50:14 +01:00
{
2017-09-08 16:52:13 +02:00
auto & range_data = address_range . second ;
for ( auto & tex : range_data . data )
{
tex . destroy ( ) ;
}
2016-02-15 10:50:14 +01:00
2017-09-08 16:52:13 +02:00
range_data . data . resize ( 0 ) ;
2016-02-15 10:50:14 +01:00
}
2017-09-08 16:52:13 +02:00
clear_temporary_subresources ( ) ;
m_unreleased_texture_objects = 0 ;
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-07 12:19:49 +02:00
auto ifmt = src - > get_internal_format ( ) ;
2017-09-19 14:46:16 +02:00
switch ( ifmt )
{
2018-04-07 12:19:49 +02:00
case gl : : texture : : internal_format : : depth16 :
case gl : : texture : : internal_format : : depth24_stencil8 :
case gl : : texture : : internal_format : : depth32f_stencil8 :
sized_internal_fmt = ( GLenum ) ifmt ;
2017-09-19 14:46:16 +02:00
break ;
}
2018-04-07 12:19:49 +02:00
auto dst = std : : make_unique < gl : : texture > ( 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-07 12:19:49 +02:00
std : : array < GLenum , 4 > swizzle = src - > get_native_component_layout ( ) ;
if ( ( GLenum ) ifmt ! = sized_internal_fmt )
2018-02-23 20:49:59 +01:00
{
2018-04-07 12:19:49 +02:00
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-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-02-07 14:25:49 +01:00
//NOTE: Depth textures should always read RRRR
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 :
{
2018-04-07 12:19:49 +02:00
return { GL_RED , GL_RED , GL_RED , GL_RED } ;
2018-02-07 14:25:49 +01:00
}
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
2017-09-08 16:52:13 +02:00
void free_texture_section ( cached_texture_section & tex ) override
2017-02-16 19:29:56 +01:00
{
2017-09-08 16:52:13 +02:00
tex . destroy ( ) ;
2017-02-16 19:29:56 +01:00
}
2018-04-07 12:19:49 +02:00
gl : : texture_view * create_temporary_subresource_view ( void * & , 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-04-07 12:19:49 +02:00
gl : : texture_view * create_temporary_subresource_view ( void * & , 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-04-07 12:19:49 +02:00
gl : : texture_view * generate_cubemap_from_images ( void * & , 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-04-07 12:19:49 +02:00
auto dst_image = std : : make_unique < gl : : texture > ( GL_TEXTURE_CUBE_MAP , size , size , 1 , 1 , ifmt ) ;
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-04-07 12:19:49 +02:00
gl : : texture_view * generate_3d_from_2d_images ( void * & , 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-04-07 12:19:49 +02:00
auto dst_image = std : : make_unique < gl : : texture > ( GL_TEXTURE_3D , width , height , depth , 1 , ifmt ) ;
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-04-07 12:19:49 +02:00
gl : : texture_view * generate_atlas_from_images ( void * & , 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-03-18 12:40:26 +01:00
auto result = create_temporary_subresource_impl ( sections_to_copy . front ( ) . src , 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-04-07 12:19:49 +02:00
void update_image_contents ( void * & , 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
}
2017-12-18 10:02:19 +01:00
cached_texture_section * create_new_texture ( void * & , u32 rsx_address , u32 rsx_size , u16 width , u16 height , u16 depth , u16 mipmaps , u32 gcm_format ,
rsx : : texture_upload_context context , rsx : : texture_dimension_extended type , rsx : : texture_create_flags flags ,
2018-04-07 12:19:49 +02:00
rsx : : texture_colorspace colorspace , const texture_channel_remap_t & remap_vector ) override
2016-02-15 10:50:14 +01:00
{
2017-09-08 16:52:13 +02:00
bool depth_flag = false ;
switch ( gcm_format )
2016-02-15 10:50:14 +01:00
{
2017-09-08 16:52:13 +02:00
case CELL_GCM_TEXTURE_DEPTH24_D8 :
case CELL_GCM_TEXTURE_DEPTH16 :
depth_flag = true ;
break ;
2017-02-13 15:22:25 +01:00
}
2016-02-15 10:50:14 +01:00
2018-04-07 12:19:49 +02:00
auto image = gl : : create_texture ( gcm_format , width , height , depth , mipmaps , type , colorspace ) ;
auto swizzle = get_component_mapping ( gcm_format , flags ) ;
swizzle = gl : : apply_swizzle_remap ( swizzle , remap_vector ) ;
auto view = new gl : : texture_view ( image , swizzle . data ( ) ) ;
2017-09-14 13:37:14 +02:00
2018-04-07 12:19:49 +02:00
auto & cached = create_texture ( image , view , rsx_address , rsx_size , width , height , depth , mipmaps ) ;
2017-02-13 15:22:25 +01:00
cached . set_dirty ( false ) ;
2017-09-08 16:52:13 +02:00
cached . set_depth_flag ( depth_flag ) ;
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-12-07 10:09:07 +01:00
cached . set_sampler_status ( rsx : : texture_sampler_status : : status_uninitialized ) ;
2017-11-02 16:54:57 +01:00
cached . set_image_type ( type ) ;
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
{
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
}
cached . make_flushable ( ) ;
cached . set_dimensions ( width , height , depth , ( rsx_size / height ) ) ;
cached . protect ( utils : : protection : : no ) ;
no_access_range = cached . get_min_max ( no_access_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
}
2017-12-18 10:02:19 +01:00
cached_texture_section * upload_image_from_cpu ( void * & , u32 rsx_address , u16 width , u16 height , u16 depth , u16 mipmaps , u16 pitch , u32 gcm_format ,
2018-03-13 11:46:32 +01:00
rsx : : texture_upload_context context , const std : : vector < rsx_subresource_layout > & subresource_layout , rsx : : texture_dimension_extended type ,
2018-03-18 12:40:26 +01:00
rsx : : texture_colorspace colorspace , bool swizzled , const texture_channel_remap_t & remap_vector ) override
2016-02-15 10:50:14 +01:00
{
2017-09-08 16:52:13 +02:00
void * unused = nullptr ;
2017-09-18 19:22:34 +02:00
auto section = create_new_texture ( unused , rsx_address , pitch * height , width , height , depth , mipmaps , gcm_format , context , type ,
2018-03-13 11:46:32 +01:00
rsx : : texture_create_flags : : default_component_order , colorspace , remap_vector ) ;
2016-02-15 10:50:14 +01:00
2017-12-07 10:09:07 +01:00
bool input_swizzled = swizzled ;
if ( context = = rsx : : texture_upload_context : : blit_engine_src )
{
//Swizzling is ignored for blit engine copy and emulated using remapping
input_swizzled = false ;
section - > set_sampler_status ( rsx : : texture_sampler_status : : status_uninitialized ) ;
}
else
{
//Generic upload - sampler status will be set on upload
section - > set_sampler_status ( rsx : : texture_sampler_status : : status_ready ) ;
}
2017-09-14 13:37:14 +02:00
2018-04-07 12:19:49 +02:00
gl : : upload_texture ( section - > get_raw_texture ( ) - > id ( ) , rsx_address , gcm_format , width , height , depth , mipmaps ,
2018-03-13 11:46:32 +01:00
input_swizzled , type , subresource_layout , remap_vector , false , colorspace ) ;
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-04-07 12:19:49 +02:00
auto swizzle = get_component_mapping ( gcm_format , flags ) ;
auto & view = section . get_view ( ) ;
if ( ! view - > compare_swizzle ( swizzle . data ( ) ) )
{
view . reset ( new gl : : texture_view ( view - > image ( ) , swizzle . data ( ) ) ) ;
}
2017-09-14 13:37:14 +02:00
section . set_view_flags ( flags ) ;
2017-12-07 13:08:11 +01:00
section . set_sampler_status ( rsx : : texture_sampler_status : : status_uninitialized ) ;
2017-02-13 15:22:25 +01:00
}
2016-02-15 10:50:14 +01:00
2018-03-18 12:40:26 +01:00
void set_up_remap_vector ( cached_texture_section & section , const texture_channel_remap_t & remap_vector ) override
2017-12-07 10:09:07 +01:00
{
2018-04-07 12:19:49 +02:00
auto & view = section . get_view ( ) ;
auto swizzle = view - > component_mapping ( ) ;
swizzle = apply_swizzle_remap ( swizzle , remap_vector ) ;
if ( ! view - > compare_swizzle ( swizzle . data ( ) ) )
{
view . reset ( new gl : : texture_view ( view - > image ( ) , swizzle . data ( ) ) ) ;
}
2017-12-07 10:09:07 +01:00
section . set_sampler_status ( rsx : : texture_sampler_status : : status_ready ) ;
}
2018-02-01 08:44:57 +01:00
void insert_texture_barrier ( void * & , 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
err_once ( " Format incompatibility detected, reporting failure to force data copy (GL_INTERNAL_FORMAT=0x%X, GCM_FORMAT=0x%X) " , ( u32 ) ifmt , gcm_format ) ;
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
2017-09-08 16:52:13 +02:00
texture_cache ( ) { }
2016-02-15 10:50:14 +01:00
2017-09-08 16:52:13 +02:00
~ 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 ) ;
2017-09-19 14:46:16 +02:00
auto found = m_cache . find ( get_block_address ( rsx_address ) ) ;
2017-09-18 19:22:34 +02:00
if ( found = = m_cache . end ( ) )
return false ;
if ( found - > second . valid_count = = 0 )
return false ;
for ( auto & tex : found - > second . data )
{
if ( tex . is_dirty ( ) )
continue ;
2017-09-19 14:46:16 +02:00
if ( ! tex . overlaps ( rsx_address , true ) )
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
{
2017-09-08 16:52:13 +02:00
if ( m_unreleased_texture_objects > = m_max_zombie_objects )
2017-09-04 12:05:02 +02:00
{
2017-09-08 16:52:13 +02:00
purge_dirty ( ) ;
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 ( ) ;
2017-11-03 12:16:55 +01:00
m_temporary_subresource_cache . clear ( ) ;
2018-02-11 13:48:36 +01:00
reset_frame_statistics ( ) ;
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 blit ( rsx : : blit_src_info & src , rsx : : blit_dst_info & dst , bool linear_interpolate , gl_render_targets & m_rtts )
{
void * unused = nullptr ;
2018-02-10 17:21:16 +01:00
auto result = upload_scaled_image ( src , dst , linear_interpolate , unused , m_rtts , m_hw_blitter ) ;
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 ;
}
flush_if_cache_miss_likely ( fmt , result . real_dst_address , result . real_dst_size ) ;
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
}