@ -3,6 +3,7 @@
# include "common/log.h"
# include "common/state_wrapper.h"
# include "cpu_core.h"
# include "gpu_sw_backend.h"
# include "pgxp.h"
# include "settings.h"
# include "system.h"
@ -34,7 +35,14 @@ GPU_HW::GPU_HW() : GPU()
m_vram_ptr = m_vram_shadow . data ( ) ;
}
GPU_HW : : ~ GPU_HW ( ) = default ;
GPU_HW : : ~ GPU_HW ( )
{
if ( m_sw_renderer )
{
m_sw_renderer - > Shutdown ( ) ;
m_sw_renderer . reset ( ) ;
}
}
bool GPU_HW : : Initialize ( HostDisplay * host_display )
{
@ -82,6 +90,9 @@ bool GPU_HW::Initialize(HostDisplay* host_display)
}
m_pgxp_depth_buffer = g_settings . UsingPGXPDepthBuffer ( ) ;
UpdateSoftwareRenderer ( false ) ;
PrintSettingsToLog ( ) ;
return true ;
}
@ -93,6 +104,8 @@ void GPU_HW::Reset(bool clear_vram)
m_batch_current_vertex_ptr = m_batch_start_vertex_ptr ;
m_vram_shadow . fill ( 0 ) ;
if ( m_sw_renderer )
m_sw_renderer - > Reset ( clear_vram ) ;
m_batch = { } ;
m_batch_ubo_data = { } ;
@ -180,6 +193,8 @@ void GPU_HW::UpdateHWSettings(bool* framebuffer_changed, bool* shaders_changed)
ClearDepthBuffer ( ) ;
}
UpdateSoftwareRenderer ( true ) ;
PrintSettingsToLog ( ) ;
}
@ -248,6 +263,7 @@ void GPU_HW::PrintSettingsToLog()
Log_InfoPrintf ( " Using UV limits: %s " , m_using_uv_limits ? " YES " : " NO " ) ;
Log_InfoPrintf ( " Depth buffer: %s " , m_pgxp_depth_buffer ? " YES " : " NO " ) ;
Log_InfoPrintf ( " Downsampling: %s " , Settings : : GetDownsampleModeDisplayName ( m_downsample_mode ) ) ;
Log_InfoPrintf ( " Using software renderer for readbacks: %s " , m_sw_renderer ? " YES " : " NO " ) ;
}
void GPU_HW : : UpdateVRAMReadTexture ( )
@ -545,6 +561,7 @@ void GPU_HW::LoadVertices()
const u32 num_vertices = rc . quad_polygon ? 4 : 3 ;
std : : array < BatchVertex , 4 > vertices ;
std : : array < std : : array < s32 , 2 > , 4 > native_vertex_positions ;
std : : array < u16 , 4 > native_texcoords ;
bool valid_w = g_settings . gpu_pgxp_texture_correction ;
for ( u32 i = 0 ; i < num_vertices ; i + + )
{
@ -556,6 +573,7 @@ void GPU_HW::LoadVertices()
const s32 native_y = m_drawing_offset . y + vp . y ;
native_vertex_positions [ i ] [ 0 ] = native_x ;
native_vertex_positions [ i ] [ 1 ] = native_y ;
native_texcoords [ i ] = texcoord ;
vertices [ i ] . Set ( static_cast < float > ( native_x ) , static_cast < float > ( native_y ) , depth , 1.0f , color , texpage ,
texcoord , 0xFFFF0000u ) ;
@ -659,6 +677,23 @@ void GPU_HW::LoadVertices()
AddVertex ( vertices [ 3 ] ) ;
}
}
if ( m_sw_renderer )
{
GPUBackendDrawPolygonCommand * cmd = m_sw_renderer - > NewDrawPolygonCommand ( num_vertices ) ;
FillDrawCommand ( cmd , rc ) ;
for ( u32 i = 0 ; i < num_vertices ; i + + )
{
GPUBackendDrawPolygonCommand : : Vertex * vert = & cmd - > vertices [ i ] ;
vert - > x = native_vertex_positions [ i ] [ 0 ] ;
vert - > y = native_vertex_positions [ i ] [ 1 ] ;
vert - > texcoord = native_texcoords [ i ] ;
vert - > color = vertices [ i ] . color ;
}
m_sw_renderer - > PushCommand ( cmd ) ;
}
}
break ;
@ -754,6 +789,19 @@ void GPU_HW::LoadVertices()
m_vram_dirty_rect . Include ( clip_left , clip_right , clip_top , clip_bottom ) ;
AddDrawRectangleTicks ( clip_right - clip_left , clip_bottom - clip_top , rc . texture_enable , rc . transparency_enable ) ;
if ( m_sw_renderer )
{
GPUBackendDrawRectangleCommand * cmd = m_sw_renderer - > NewDrawRectangleCommand ( ) ;
FillDrawCommand ( cmd , rc ) ;
cmd - > color = color ;
cmd - > x = pos_x ;
cmd - > y = pos_y ;
cmd - > width = static_cast < u16 > ( rectangle_width ) ;
cmd - > height = static_cast < u16 > ( rectangle_height ) ;
cmd - > texcoord = ( static_cast < u16 > ( texcoord_y ) < < 8 ) | static_cast < u16 > ( texcoord_x ) ;
m_sw_renderer - > PushCommand ( cmd ) ;
}
}
break ;
@ -808,6 +856,15 @@ void GPU_HW::LoadVertices()
// TODO: Should we do a PGXP lookup here? Most lines are 2D.
DrawLine ( static_cast < float > ( start_x ) , static_cast < float > ( start_y ) , start_color , static_cast < float > ( end_x ) ,
static_cast < float > ( end_y ) , end_color , depth ) ;
if ( m_sw_renderer )
{
GPUBackendDrawLineCommand * cmd = m_sw_renderer - > NewDrawLineCommand ( 2 ) ;
FillDrawCommand ( cmd , rc ) ;
cmd - > vertices [ 0 ] . Set ( start_x , start_y , start_color ) ;
cmd - > vertices [ 1 ] . Set ( end_x , end_y , end_color ) ;
m_sw_renderer - > PushCommand ( cmd ) ;
}
}
else
{
@ -826,6 +883,18 @@ void GPU_HW::LoadVertices()
s32 start_y = start_vp . y + m_drawing_offset . y ;
u32 start_color = rc . color_for_first_vertex ;
GPUBackendDrawLineCommand * cmd ;
if ( m_sw_renderer )
{
cmd = m_sw_renderer - > NewDrawLineCommand ( num_vertices ) ;
FillDrawCommand ( cmd , rc ) ;
cmd - > vertices [ 0 ] . Set ( start_x , start_y , start_color ) ;
}
else
{
cmd = nullptr ;
}
for ( u32 i = 1 ; i < num_vertices ; i + + )
{
const u32 end_color = shaded ? ( m_blit_buffer [ buffer_pos + + ] & UINT32_C ( 0x00FFFFFF ) ) : start_color ;
@ -859,7 +928,13 @@ void GPU_HW::LoadVertices()
start_x = end_x ;
start_y = end_y ;
start_color = end_color ;
if ( cmd )
cmd - > vertices [ i ] . Set ( end_x , end_y , end_color ) ;
}
if ( cmd )
m_sw_renderer - > PushCommand ( cmd ) ;
}
}
break ;
@ -1017,10 +1092,84 @@ void GPU_HW::ResetBatchVertexDepth()
m_current_depth = 1 ;
}
void GPU_HW : : FillBackendCommandParameters ( GPUBackendCommand * cmd ) const
{
cmd - > params . bits = 0 ;
cmd - > params . check_mask_before_draw = m_GPUSTAT . check_mask_before_draw ;
cmd - > params . set_mask_while_drawing = m_GPUSTAT . set_mask_while_drawing ;
cmd - > params . active_line_lsb = m_crtc_state . active_line_lsb ;
cmd - > params . interlaced_rendering = m_GPUSTAT . SkipDrawingToActiveField ( ) ;
}
void GPU_HW : : FillDrawCommand ( GPUBackendDrawCommand * cmd , GPURenderCommand rc ) const
{
FillBackendCommandParameters ( cmd ) ;
cmd - > rc . bits = rc . bits ;
cmd - > draw_mode . bits = m_draw_mode . mode_reg . bits ;
cmd - > palette . bits = m_draw_mode . palette_reg ;
cmd - > window = m_draw_mode . texture_window ;
}
void GPU_HW : : HandleVRAMReadWithSoftwareRenderer ( u32 x , u32 y , u32 width , u32 height )
{
DebugAssert ( m_sw_renderer ) ;
m_sw_renderer - > Sync ( false ) ;
}
void GPU_HW : : UpdateSoftwareRenderer ( bool copy_vram_from_hw )
{
const bool current_enabled = ( m_sw_renderer ! = nullptr ) ;
const bool new_enabled = g_settings . gpu_use_software_renderer_for_readbacks ;
if ( current_enabled = = new_enabled )
return ;
m_vram_ptr = m_vram_shadow . data ( ) ;
if ( ! new_enabled )
{
if ( m_sw_renderer )
m_sw_renderer - > Shutdown ( ) ;
m_sw_renderer . reset ( ) ;
return ;
}
std : : unique_ptr < GPU_SW_Backend > sw_renderer = std : : make_unique < GPU_SW_Backend > ( ) ;
if ( ! sw_renderer - > Initialize ( true ) )
return ;
// We need to fill in the SW renderer's VRAM with the current state for hot toggles.
if ( copy_vram_from_hw )
{
FlushRender ( ) ;
ReadVRAM ( 0 , 0 , VRAM_WIDTH , VRAM_HEIGHT ) ;
std : : memcpy ( sw_renderer - > GetVRAM ( ) , m_vram_ptr , sizeof ( u16 ) * VRAM_WIDTH * VRAM_HEIGHT ) ;
// Sync the drawing area.
GPUBackendSetDrawingAreaCommand * cmd = sw_renderer - > NewSetDrawingAreaCommand ( ) ;
cmd - > new_area = m_drawing_area ;
sw_renderer - > PushCommand ( cmd ) ;
}
m_sw_renderer = std : : move ( sw_renderer ) ;
m_vram_ptr = m_sw_renderer - > GetVRAM ( ) ;
}
void GPU_HW : : FillVRAM ( u32 x , u32 y , u32 width , u32 height , u32 color )
{
IncludeVRAMDirtyRectangle (
Common : : Rectangle < u32 > : : FromExtents ( x , y , width , height ) . Clamped ( 0 , 0 , VRAM_WIDTH , VRAM_HEIGHT ) ) ;
if ( m_sw_renderer )
{
GPUBackendFillVRAMCommand * cmd = m_sw_renderer - > NewFillVRAMCommand ( ) ;
FillBackendCommandParameters ( cmd ) ;
cmd - > x = static_cast < u16 > ( x ) ;
cmd - > y = static_cast < u16 > ( y ) ;
cmd - > width = static_cast < u16 > ( width ) ;
cmd - > height = static_cast < u16 > ( height ) ;
cmd - > color = color ;
m_sw_renderer - > PushCommand ( cmd ) ;
}
}
void GPU_HW : : UpdateVRAM ( u32 x , u32 y , u32 width , u32 height , const void * data , bool set_mask , bool check_mask )
@ -1033,6 +1182,21 @@ void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, b
// set new vertex counter since we want this to take into consideration previous masked pixels
m_current_depth + + ;
}
if ( m_sw_renderer )
{
const u32 num_words = width * height ;
GPUBackendUpdateVRAMCommand * cmd = m_sw_renderer - > NewUpdateVRAMCommand ( num_words ) ;
FillBackendCommandParameters ( cmd ) ;
cmd - > params . set_mask_while_drawing = set_mask ;
cmd - > params . check_mask_before_draw = check_mask ;
cmd - > x = static_cast < u16 > ( x ) ;
cmd - > y = static_cast < u16 > ( y ) ;
cmd - > width = static_cast < u16 > ( width ) ;
cmd - > height = static_cast < u16 > ( height ) ;
std : : memcpy ( cmd - > data , data , sizeof ( u16 ) * num_words ) ;
m_sw_renderer - > PushCommand ( cmd ) ;
}
}
void GPU_HW : : CopyVRAM ( u32 src_x , u32 src_y , u32 dst_x , u32 dst_y , u32 width , u32 height )
@ -1045,6 +1209,19 @@ void GPU_HW::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32
// set new vertex counter since we want this to take into consideration previous masked pixels
m_current_depth + + ;
}
if ( m_sw_renderer )
{
GPUBackendCopyVRAMCommand * cmd = m_sw_renderer - > NewCopyVRAMCommand ( ) ;
FillBackendCommandParameters ( cmd ) ;
cmd - > src_x = static_cast < u16 > ( src_x ) ;
cmd - > src_y = static_cast < u16 > ( src_y ) ;
cmd - > dst_x = static_cast < u16 > ( dst_x ) ;
cmd - > dst_y = static_cast < u16 > ( dst_y ) ;
cmd - > width = static_cast < u16 > ( width ) ;
cmd - > height = static_cast < u16 > ( height ) ;
m_sw_renderer - > PushCommand ( cmd ) ;
}
}
void GPU_HW : : DispatchRenderCommand ( )
@ -1136,6 +1313,22 @@ void GPU_HW::DispatchRenderCommand()
m_batch_ubo_dirty = true ;
}
if ( m_drawing_area_changed )
{
m_drawing_area_changed = false ;
SetScissorFromDrawingArea ( ) ;
if ( m_pgxp_depth_buffer & & m_last_depth_z < 1.0f )
ClearDepthBuffer ( ) ;
if ( m_sw_renderer )
{
GPUBackendSetDrawingAreaCommand * cmd = m_sw_renderer - > NewSetDrawingAreaCommand ( ) ;
cmd - > new_area = m_drawing_area ;
m_sw_renderer - > PushCommand ( cmd ) ;
}
}
LoadVertices ( ) ;
}
@ -1150,15 +1343,6 @@ void GPU_HW::FlushRender()
if ( vertex_count = = 0 )
return ;
if ( m_drawing_area_changed )
{
m_drawing_area_changed = false ;
SetScissorFromDrawingArea ( ) ;
if ( m_pgxp_depth_buffer & & m_last_depth_z < 1.0f )
ClearDepthBuffer ( ) ;
}
if ( m_batch_ubo_dirty )
{
UploadUniformBuffer ( & m_batch_ubo_data , sizeof ( m_batch_ubo_data ) ) ;