2012-11-15 00:39:56 +01:00
# include "stdafx.h"
2016-02-01 22:50:02 +01:00
# include "Utilities/Config.h"
2014-06-02 19:27:24 +02:00
# include "Emu/Memory/Memory.h"
2015-10-26 22:09:31 +01:00
# include "GLGSRender.h"
2016-10-18 09:57:28 +02:00
# include "GLVertexProgram.h"
2016-01-05 22:29:49 +01:00
# include "../rsx_methods.h"
2016-01-12 00:54:07 +01:00
# include "../Common/BufferUtils.h"
2016-06-20 23:38:38 +02:00
# include "../rsx_utils.h"
2012-11-15 00:39:56 +01:00
2016-02-01 22:50:02 +01:00
extern cfg : : bool_entry g_cfg_rsx_debug_output ;
2016-06-12 11:05:22 +02:00
extern cfg : : bool_entry g_cfg_rsx_overlay ;
2016-10-18 09:57:28 +02:00
extern cfg : : bool_entry g_cfg_rsx_gl_legacy_buffers ;
2016-02-01 22:50:02 +01:00
2013-08-27 17:18:01 +02:00
# define DUMP_VERTEX_DATA 0
2012-11-15 00:39:56 +01:00
2016-01-13 17:40:10 +01:00
namespace
{
2016-01-20 18:12:48 +01:00
u32 get_max_depth_value ( rsx : : surface_depth_format format )
2016-01-13 17:40:10 +01:00
{
switch ( format )
{
2016-01-20 18:12:48 +01:00
case rsx : : surface_depth_format : : z16 : return 0xFFFF ;
case rsx : : surface_depth_format : : z24s8 : return 0xFFFFFF ;
2016-01-13 17:40:10 +01:00
}
2016-08-08 18:01:06 +02:00
fmt : : throw_exception ( " Unknown depth format " HERE ) ;
2016-06-30 06:46:25 +02:00
}
2016-01-13 17:40:10 +01:00
}
2015-10-11 22:00:51 +02:00
GLGSRender : : GLGSRender ( ) : GSRender ( frame_type : : OpenGL )
2015-10-04 00:45:26 +02:00
{
2016-08-26 16:23:23 +02:00
shaders_cache . load ( rsx : : old_shaders_cache : : shader_language : : glsl ) ;
2015-10-11 22:00:51 +02:00
}
2014-08-23 02:16:54 +02:00
2015-10-11 22:00:51 +02:00
u32 GLGSRender : : enable ( u32 condition , u32 cap )
{
if ( condition )
2014-08-23 02:16:54 +02:00
{
2015-10-11 22:00:51 +02:00
glEnable ( cap ) ;
2014-08-23 02:16:54 +02:00
}
else
{
2015-10-11 22:00:51 +02:00
glDisable ( cap ) ;
2014-08-23 02:16:54 +02:00
}
2015-10-11 22:00:51 +02:00
return condition ;
2014-08-23 02:16:54 +02:00
}
2015-10-11 22:00:51 +02:00
u32 GLGSRender : : enable ( u32 condition , u32 cap , u32 index )
2014-08-23 02:16:54 +02:00
{
2015-10-11 22:00:51 +02:00
if ( condition )
{
glEnablei ( cap , index ) ;
}
else
{
glDisablei ( cap , index ) ;
}
return condition ;
2014-08-23 02:16:54 +02:00
}
2015-10-11 22:00:51 +02:00
extern CellGcmContextData current_context ;
2016-06-26 23:37:02 +02:00
namespace
{
2016-07-19 13:06:01 +02:00
GLenum comparison_op ( rsx : : comparison_function op )
2016-06-26 23:37:02 +02:00
{
switch ( op )
{
2016-07-19 13:06:01 +02:00
case rsx : : comparison_function : : never : return GL_NEVER ;
case rsx : : comparison_function : : less : return GL_LESS ;
case rsx : : comparison_function : : equal : return GL_EQUAL ;
case rsx : : comparison_function : : less_or_equal : return GL_LEQUAL ;
case rsx : : comparison_function : : greater : return GL_GREATER ;
case rsx : : comparison_function : : not_equal : return GL_NOTEQUAL ;
case rsx : : comparison_function : : greater_or_equal : return GL_GEQUAL ;
case rsx : : comparison_function : : always : return GL_ALWAYS ;
2016-06-26 23:37:02 +02:00
}
throw ;
}
GLenum stencil_op ( rsx : : stencil_op op )
{
switch ( op )
{
2017-01-23 19:59:54 +01:00
case rsx : : stencil_op : : invert : return GL_INVERT ;
2016-06-26 23:37:02 +02:00
case rsx : : stencil_op : : keep : return GL_KEEP ;
case rsx : : stencil_op : : zero : return GL_ZERO ;
case rsx : : stencil_op : : replace : return GL_REPLACE ;
case rsx : : stencil_op : : incr : return GL_INCR ;
case rsx : : stencil_op : : decr : return GL_DECR ;
case rsx : : stencil_op : : incr_wrap : return GL_INCR_WRAP ;
case rsx : : stencil_op : : decr_wrap : return GL_DECR_WRAP ;
}
throw ;
}
GLenum blend_equation ( rsx : : blend_equation op )
{
switch ( op )
{
// Note : maybe add is signed on gl
case rsx : : blend_equation : : add : return GL_FUNC_ADD ;
case rsx : : blend_equation : : min : return GL_MIN ;
case rsx : : blend_equation : : max : return GL_MAX ;
case rsx : : blend_equation : : substract : return GL_FUNC_SUBTRACT ;
case rsx : : blend_equation : : reverse_substract : return GL_FUNC_REVERSE_SUBTRACT ;
case rsx : : blend_equation : : reverse_substract_signed : throw " unsupported " ;
case rsx : : blend_equation : : add_signed : throw " unsupported " ;
case rsx : : blend_equation : : reverse_add_signed : throw " unsupported " ;
}
throw ;
}
GLenum blend_factor ( rsx : : blend_factor op )
{
switch ( op )
{
case rsx : : blend_factor : : zero : return GL_ZERO ;
case rsx : : blend_factor : : one : return GL_ONE ;
case rsx : : blend_factor : : src_color : return GL_SRC_COLOR ;
case rsx : : blend_factor : : one_minus_src_color : return GL_ONE_MINUS_SRC_COLOR ;
case rsx : : blend_factor : : dst_color : return GL_DST_COLOR ;
case rsx : : blend_factor : : one_minus_dst_color : return GL_ONE_MINUS_DST_COLOR ;
case rsx : : blend_factor : : src_alpha : return GL_SRC_ALPHA ;
case rsx : : blend_factor : : one_minus_src_alpha : return GL_ONE_MINUS_SRC_ALPHA ;
case rsx : : blend_factor : : dst_alpha : return GL_DST_ALPHA ;
case rsx : : blend_factor : : one_minus_dst_alpha : return GL_ONE_MINUS_DST_ALPHA ;
case rsx : : blend_factor : : src_alpha_saturate : return GL_SRC_ALPHA_SATURATE ;
case rsx : : blend_factor : : constant_color : return GL_CONSTANT_COLOR ;
case rsx : : blend_factor : : one_minus_constant_color : return GL_ONE_MINUS_CONSTANT_COLOR ;
case rsx : : blend_factor : : constant_alpha : return GL_CONSTANT_ALPHA ;
case rsx : : blend_factor : : one_minus_constant_alpha : return GL_ONE_MINUS_CONSTANT_ALPHA ;
}
throw ;
}
GLenum logic_op ( rsx : : logic_op op )
{
switch ( op )
{
case rsx : : logic_op : : logic_clear : return GL_CLEAR ;
case rsx : : logic_op : : logic_and : return GL_AND ;
case rsx : : logic_op : : logic_and_reverse : return GL_AND_REVERSE ;
case rsx : : logic_op : : logic_copy : return GL_COPY ;
case rsx : : logic_op : : logic_and_inverted : return GL_AND_INVERTED ;
case rsx : : logic_op : : logic_noop : return GL_NOOP ;
case rsx : : logic_op : : logic_xor : return GL_XOR ;
2016-08-26 16:23:23 +02:00
case rsx : : logic_op : : logic_or : return GL_OR ;
2016-06-26 23:37:02 +02:00
case rsx : : logic_op : : logic_nor : return GL_NOR ;
case rsx : : logic_op : : logic_equiv : return GL_EQUIV ;
case rsx : : logic_op : : logic_invert : return GL_INVERT ;
case rsx : : logic_op : : logic_or_reverse : return GL_OR_REVERSE ;
case rsx : : logic_op : : logic_copy_inverted : return GL_COPY_INVERTED ;
case rsx : : logic_op : : logic_or_inverted : return GL_OR_INVERTED ;
case rsx : : logic_op : : logic_nand : return GL_NAND ;
case rsx : : logic_op : : logic_set : return GL_SET ;
}
throw ;
}
GLenum front_face ( rsx : : front_face op )
{
2016-09-27 09:34:01 +02:00
bool invert = ( rsx : : method_registers . shader_window_origin ( ) = = rsx : : window_origin : : bottom ) ;
2016-07-12 22:10:26 +02:00
2016-06-26 23:37:02 +02:00
switch ( op )
{
2016-09-27 09:34:01 +02:00
case rsx : : front_face : : cw : return ( invert ? GL_CCW : GL_CW ) ;
case rsx : : front_face : : ccw : return ( invert ? GL_CW : GL_CCW ) ;
2016-06-26 23:37:02 +02:00
}
throw ;
}
GLenum cull_face ( rsx : : cull_face op )
{
2016-09-27 09:34:01 +02:00
bool invert = ( rsx : : method_registers . shader_window_origin ( ) = = rsx : : window_origin : : top ) ;
2016-06-26 23:37:02 +02:00
switch ( op )
{
2016-09-27 09:34:01 +02:00
case rsx : : cull_face : : front : return ( invert ? GL_BACK : GL_FRONT ) ;
case rsx : : cull_face : : back : return ( invert ? GL_FRONT : GL_BACK ) ;
2016-06-26 23:37:02 +02:00
case rsx : : cull_face : : front_and_back : return GL_FRONT_AND_BACK ;
}
throw ;
}
}
2015-10-11 22:00:51 +02:00
void GLGSRender : : begin ( )
2015-10-04 00:45:26 +02:00
{
2015-10-11 22:00:51 +02:00
rsx : : thread : : begin ( ) ;
init_buffers ( ) ;
2017-02-04 15:44:40 +01:00
if ( ! draw_fbo . check ( ) )
return ;
2017-01-29 00:00:49 +01:00
std : : chrono : : time_point < steady_clock > then = steady_clock : : now ( ) ;
2016-06-12 11:05:22 +02:00
2016-06-26 23:37:02 +02:00
bool color_mask_b = rsx : : method_registers . color_mask_b ( ) ;
bool color_mask_g = rsx : : method_registers . color_mask_g ( ) ;
bool color_mask_r = rsx : : method_registers . color_mask_r ( ) ;
bool color_mask_a = rsx : : method_registers . color_mask_a ( ) ;
2015-10-11 22:00:51 +02:00
__glcheck glColorMask ( color_mask_r , color_mask_g , color_mask_b , color_mask_a ) ;
2016-06-26 23:37:02 +02:00
__glcheck glDepthMask ( rsx : : method_registers . depth_write_enabled ( ) ) ;
__glcheck glStencilMask ( rsx : : method_registers . stencil_mask ( ) ) ;
2015-10-11 22:00:51 +02:00
2016-06-26 23:37:02 +02:00
if ( __glcheck enable ( rsx : : method_registers . depth_test_enabled ( ) , GL_DEPTH_TEST ) )
2015-10-11 22:00:51 +02:00
{
2016-07-19 13:06:01 +02:00
__glcheck glDepthFunc ( comparison_op ( rsx : : method_registers . depth_func ( ) ) ) ;
2016-06-26 23:37:02 +02:00
__glcheck glDepthMask ( rsx : : method_registers . depth_write_enabled ( ) ) ;
2015-10-11 22:00:51 +02:00
}
2015-10-04 00:45:26 +02:00
2016-06-26 23:37:02 +02:00
if ( glDepthBoundsEXT & & ( __glcheck enable ( rsx : : method_registers . depth_bounds_test_enabled ( ) , GL_DEPTH_BOUNDS_TEST_EXT ) ) )
2015-10-04 00:45:26 +02:00
{
2016-06-26 23:37:02 +02:00
__glcheck glDepthBoundsEXT ( rsx : : method_registers . depth_bounds_min ( ) , rsx : : method_registers . depth_bounds_max ( ) ) ;
2015-10-11 22:00:51 +02:00
}
2014-08-23 02:16:54 +02:00
2016-06-26 23:37:02 +02:00
__glcheck glDepthRange ( rsx : : method_registers . clip_min ( ) , rsx : : method_registers . clip_max ( ) ) ;
__glcheck enable ( rsx : : method_registers . dither_enabled ( ) , GL_DITHER ) ;
2014-08-23 02:16:54 +02:00
2016-06-26 23:37:02 +02:00
if ( __glcheck enable ( rsx : : method_registers . blend_enabled ( ) , GL_BLEND ) )
2015-10-11 22:00:51 +02:00
{
2016-06-26 23:37:02 +02:00
__glcheck glBlendFuncSeparate ( blend_factor ( rsx : : method_registers . blend_func_sfactor_rgb ( ) ) ,
blend_factor ( rsx : : method_registers . blend_func_dfactor_rgb ( ) ) ,
blend_factor ( rsx : : method_registers . blend_func_sfactor_a ( ) ) ,
blend_factor ( rsx : : method_registers . blend_func_dfactor_a ( ) ) ) ;
2015-10-11 22:00:51 +02:00
2017-01-08 08:34:10 +01:00
auto blend_colors = rsx : : get_constant_blend_colors ( ) ;
__glcheck glBlendColor ( blend_colors [ 0 ] , blend_colors [ 1 ] , blend_colors [ 2 ] , blend_colors [ 3 ] ) ;
2014-08-23 02:16:54 +02:00
2016-06-26 23:37:02 +02:00
__glcheck glBlendEquationSeparate ( blend_equation ( rsx : : method_registers . blend_equation_rgb ( ) ) ,
blend_equation ( rsx : : method_registers . blend_equation_a ( ) ) ) ;
2015-10-11 22:00:51 +02:00
}
2016-08-26 16:23:23 +02:00
2016-06-26 23:37:02 +02:00
if ( __glcheck enable ( rsx : : method_registers . stencil_test_enabled ( ) , GL_STENCIL_TEST ) )
{
2016-07-19 13:06:01 +02:00
__glcheck glStencilFunc ( comparison_op ( rsx : : method_registers . stencil_func ( ) ) , rsx : : method_registers . stencil_func_ref ( ) ,
2016-06-26 23:37:02 +02:00
rsx : : method_registers . stencil_func_mask ( ) ) ;
__glcheck glStencilOp ( stencil_op ( rsx : : method_registers . stencil_op_fail ( ) ) , stencil_op ( rsx : : method_registers . stencil_op_zfail ( ) ) ,
stencil_op ( rsx : : method_registers . stencil_op_zpass ( ) ) ) ;
if ( rsx : : method_registers . two_sided_stencil_test_enabled ( ) ) {
__glcheck glStencilMaskSeparate ( GL_BACK , rsx : : method_registers . back_stencil_mask ( ) ) ;
2016-07-19 13:06:01 +02:00
__glcheck glStencilFuncSeparate ( GL_BACK , comparison_op ( rsx : : method_registers . back_stencil_func ( ) ) ,
2016-06-26 23:37:02 +02:00
rsx : : method_registers . back_stencil_func_ref ( ) , rsx : : method_registers . back_stencil_func_mask ( ) ) ;
__glcheck glStencilOpSeparate ( GL_BACK , stencil_op ( rsx : : method_registers . back_stencil_op_fail ( ) ) ,
stencil_op ( rsx : : method_registers . back_stencil_op_zfail ( ) ) , stencil_op ( rsx : : method_registers . back_stencil_op_zpass ( ) ) ) ;
2015-12-01 14:54:15 +01:00
}
2015-10-11 22:00:51 +02:00
}
2016-06-26 23:37:02 +02:00
__glcheck enable ( rsx : : method_registers . blend_enabled_surface_1 ( ) , GL_BLEND , 1 ) ;
__glcheck enable ( rsx : : method_registers . blend_enabled_surface_2 ( ) , GL_BLEND , 2 ) ;
__glcheck enable ( rsx : : method_registers . blend_enabled_surface_3 ( ) , GL_BLEND , 3 ) ;
2016-08-26 16:23:23 +02:00
2016-06-26 23:37:02 +02:00
if ( __glcheck enable ( rsx : : method_registers . logic_op_enabled ( ) , GL_COLOR_LOGIC_OP ) )
2015-10-11 22:00:51 +02:00
{
2016-06-26 23:37:02 +02:00
__glcheck glLogicOp ( logic_op ( rsx : : method_registers . logic_operation ( ) ) ) ;
2014-08-23 02:16:54 +02:00
}
2016-06-26 23:37:02 +02:00
__glcheck glLineWidth ( rsx : : method_registers . line_width ( ) ) ;
__glcheck enable ( rsx : : method_registers . line_smooth_enabled ( ) , GL_LINE_SMOOTH ) ;
2015-10-11 22:00:51 +02:00
//TODO
//NV4097_SET_ANISO_SPREAD
2016-06-26 23:37:02 +02:00
__glcheck enable ( rsx : : method_registers . poly_offset_point_enabled ( ) , GL_POLYGON_OFFSET_POINT ) ;
__glcheck enable ( rsx : : method_registers . poly_offset_line_enabled ( ) , GL_POLYGON_OFFSET_LINE ) ;
__glcheck enable ( rsx : : method_registers . poly_offset_fill_enabled ( ) , GL_POLYGON_OFFSET_FILL ) ;
2015-10-11 22:00:51 +02:00
2016-06-26 23:37:02 +02:00
__glcheck glPolygonOffset ( rsx : : method_registers . poly_offset_scale ( ) ,
rsx : : method_registers . poly_offset_bias ( ) ) ;
2015-10-11 22:00:51 +02:00
//NV4097_SET_SPECULAR_ENABLE
//NV4097_SET_TWO_SIDE_LIGHT_EN
//NV4097_SET_FLAT_SHADE_OP
//NV4097_SET_EDGE_FLAG
2016-06-26 23:37:02 +02:00
if ( __glcheck enable ( rsx : : method_registers . cull_face_enabled ( ) , GL_CULL_FACE ) )
2015-10-11 22:00:51 +02:00
{
2016-06-26 23:37:02 +02:00
__glcheck glCullFace ( cull_face ( rsx : : method_registers . cull_face_mode ( ) ) ) ;
2015-10-11 22:00:51 +02:00
}
2015-10-04 00:45:26 +02:00
2016-06-26 23:37:02 +02:00
__glcheck glFrontFace ( front_face ( rsx : : method_registers . front_face_mode ( ) ) ) ;
2016-01-06 00:15:35 +01:00
2015-10-11 22:00:51 +02:00
//NV4097_SET_COLOR_KEY_COLOR
//NV4097_SET_SHADER_CONTROL
//NV4097_SET_ZMIN_MAX_CONTROL
//NV4097_SET_ANTI_ALIASING_CONTROL
//NV4097_SET_CLIP_ID_TEST_ENABLE
2015-10-04 00:45:26 +02:00
2017-04-25 12:32:39 +02:00
__glcheck enable ( true , GL_CLIP_DISTANCE0 + 0 ) ;
__glcheck enable ( true , GL_CLIP_DISTANCE0 + 1 ) ;
__glcheck enable ( true , GL_CLIP_DISTANCE0 + 2 ) ;
__glcheck enable ( true , GL_CLIP_DISTANCE0 + 3 ) ;
__glcheck enable ( true , GL_CLIP_DISTANCE0 + 4 ) ;
__glcheck enable ( true , GL_CLIP_DISTANCE0 + 5 ) ;
2017-01-29 00:00:49 +01:00
std : : chrono : : time_point < steady_clock > now = steady_clock : : now ( ) ;
2016-06-20 23:38:38 +02:00
m_begin_time + = ( u32 ) std : : chrono : : duration_cast < std : : chrono : : microseconds > ( now - then ) . count ( ) ;
2015-01-31 14:01:34 +01:00
}
2016-03-29 18:43:37 +02:00
namespace
{
2016-09-19 03:25:49 +02:00
GLenum get_gl_target_for_texture ( const rsx : : fragment_texture & tex )
2016-03-29 18:43:37 +02:00
{
switch ( tex . get_extended_texture_dimension ( ) )
{
case rsx : : texture_dimension_extended : : texture_dimension_1d : return GL_TEXTURE_1D ;
case rsx : : texture_dimension_extended : : texture_dimension_2d : return GL_TEXTURE_2D ;
case rsx : : texture_dimension_extended : : texture_dimension_cubemap : return GL_TEXTURE_CUBE_MAP ;
case rsx : : texture_dimension_extended : : texture_dimension_3d : return GL_TEXTURE_3D ;
}
2016-08-08 18:01:06 +02:00
fmt : : throw_exception ( " Unknown texture target " HERE ) ;
2016-03-29 18:43:37 +02:00
}
2016-06-28 11:58:44 +02:00
GLenum get_gl_target_for_texture ( const rsx : : vertex_texture & tex )
{
switch ( tex . get_extended_texture_dimension ( ) )
{
case rsx : : texture_dimension_extended : : texture_dimension_1d : return GL_TEXTURE_1D ;
case rsx : : texture_dimension_extended : : texture_dimension_2d : return GL_TEXTURE_2D ;
case rsx : : texture_dimension_extended : : texture_dimension_cubemap : return GL_TEXTURE_CUBE_MAP ;
case rsx : : texture_dimension_extended : : texture_dimension_3d : return GL_TEXTURE_3D ;
}
2016-08-08 18:01:06 +02:00
fmt : : throw_exception ( " Unknown texture target " HERE ) ;
2016-06-28 11:58:44 +02:00
}
2016-03-29 18:43:37 +02:00
}
2015-10-11 22:00:51 +02:00
void GLGSRender : : end ( )
{
2017-02-04 15:44:40 +01:00
if ( ! draw_fbo | | ! draw_fbo . check ( ) )
2015-10-11 22:00:51 +02:00
{
rsx : : thread : : end ( ) ;
return ;
}
2015-10-09 20:04:20 +02:00
2017-03-25 22:59:57 +01:00
std : : chrono : : time_point < steady_clock > program_start = steady_clock : : now ( ) ;
//Load program here since it is dependent on vertex state
load_program ( ) ;
std : : chrono : : time_point < steady_clock > program_stop = steady_clock : : now ( ) ;
m_begin_time + = ( u32 ) std : : chrono : : duration_cast < std : : chrono : : microseconds > ( program_stop - program_start ) . count ( ) ;
2016-10-18 09:57:28 +02:00
if ( manually_flush_ring_buffers )
{
//Use approximations to reseve space. This path is mostly for debug purposes anyway
u32 approx_vertex_count = rsx : : method_registers . current_draw_clause . get_elements_count ( ) ;
u32 approx_working_buffer_size = approx_vertex_count * 256 ;
//Allocate 256K heap if we have no approximation at this time (inlined array)
m_attrib_ring_buffer - > reserve_storage_on_heap ( std : : max ( approx_working_buffer_size , 256 * 1024U ) ) ;
m_index_ring_buffer - > reserve_storage_on_heap ( 16 * 1024 ) ;
}
2016-07-22 01:31:58 +02:00
//Check if depth buffer is bound and valid
//If ds is not initialized clear it; it seems new depth textures should have depth cleared
gl : : render_target * ds = std : : get < 1 > ( m_rtts . m_bound_depth_stencil ) ;
if ( ds & & ! ds - > cleared ( ) )
{
glDepthMask ( GL_TRUE ) ;
glClearDepth ( 1.f ) ;
2016-08-26 16:23:23 +02:00
2016-07-22 01:31:58 +02:00
glClear ( GL_DEPTH_BUFFER_BIT ) ;
glDepthMask ( rsx : : method_registers . depth_write_enabled ( ) ) ;
ds - > set_cleared ( ) ;
}
2017-01-29 00:00:49 +01:00
std : : chrono : : time_point < steady_clock > textures_start = steady_clock : : now ( ) ;
2016-10-11 02:55:42 +02:00
2016-08-26 16:23:23 +02:00
//Setup textures
2017-03-29 21:27:29 +02:00
//Setting unused texture to 0 is not needed, but makes program validation happy if we choose to enforce it
2016-08-26 16:23:23 +02:00
for ( int i = 0 ; i < rsx : : limits : : fragment_textures_count ; + + i )
2015-10-11 22:00:51 +02:00
{
2016-08-26 16:23:23 +02:00
int location ;
2016-10-11 02:55:42 +02:00
if ( ! rsx : : method_registers . fragment_textures [ i ] . enabled ( ) )
2016-06-16 19:19:45 +02:00
{
2016-10-11 02:55:42 +02:00
glActiveTexture ( GL_TEXTURE0 + i ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
continue ;
}
2016-08-26 16:23:23 +02:00
2016-10-11 02:55:42 +02:00
if ( m_program - > uniforms . has_location ( " tex " + std : : to_string ( i ) , & location ) )
{
2016-08-26 16:23:23 +02:00
m_gl_textures [ i ] . set_target ( get_gl_target_for_texture ( rsx : : method_registers . fragment_textures [ i ] ) ) ;
__glcheck m_gl_texture_cache . upload_texture ( i , rsx : : method_registers . fragment_textures [ i ] , m_gl_textures [ i ] , m_rtts ) ;
2017-03-29 21:27:29 +02:00
__glcheck m_gl_sampler_states [ i ] . apply ( rsx : : method_registers . fragment_textures [ i ] ) ;
2015-10-11 22:00:51 +02:00
}
2013-06-30 10:46:29 +02:00
}
2016-09-20 16:23:56 +02:00
//Vertex textures
for ( int i = 0 ; i < rsx : : limits : : vertex_textures_count ; + + i )
{
int texture_index = i + rsx : : limits : : fragment_textures_count ;
int location ;
2016-10-11 02:55:42 +02:00
if ( ! rsx : : method_registers . vertex_textures [ i ] . enabled ( ) )
2016-09-20 16:23:56 +02:00
{
2016-10-11 02:55:42 +02:00
glActiveTexture ( GL_TEXTURE0 + texture_index ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
continue ;
}
2016-09-20 16:23:56 +02:00
2016-10-11 02:55:42 +02:00
if ( m_program - > uniforms . has_location ( " vtex " + std : : to_string ( i ) , & location ) )
{
2016-09-20 16:23:56 +02:00
m_gl_vertex_textures [ i ] . set_target ( get_gl_target_for_texture ( rsx : : method_registers . vertex_textures [ i ] ) ) ;
__glcheck m_gl_texture_cache . upload_texture ( texture_index , rsx : : method_registers . vertex_textures [ i ] , m_gl_vertex_textures [ i ] , m_rtts ) ;
}
}
2017-01-29 00:00:49 +01:00
std : : chrono : : time_point < steady_clock > textures_end = steady_clock : : now ( ) ;
2016-10-11 02:55:42 +02:00
m_textures_upload_time + = ( u32 ) std : : chrono : : duration_cast < std : : chrono : : microseconds > ( textures_end - textures_start ) . count ( ) ;
2016-08-10 16:52:35 +02:00
u32 vertex_draw_count ;
std : : optional < std : : tuple < GLenum , u32 > > indexed_draw_info ;
2016-08-26 16:23:23 +02:00
std : : tie ( vertex_draw_count , indexed_draw_info ) = set_vertex_buffer ( ) ;
2016-06-12 11:05:22 +02:00
m_vao . bind ( ) ;
2017-01-29 00:00:49 +01:00
std : : chrono : : time_point < steady_clock > draw_start = steady_clock : : now ( ) ;
2015-12-23 22:25:02 +01:00
2016-06-11 21:51:34 +02:00
if ( g_cfg_rsx_debug_output )
2016-06-20 23:38:38 +02:00
{
2016-06-11 21:51:34 +02:00
m_program - > validate ( ) ;
2016-06-20 23:38:38 +02:00
}
2016-02-02 19:41:39 +01:00
2016-10-18 09:57:28 +02:00
if ( manually_flush_ring_buffers )
{
m_attrib_ring_buffer - > unmap ( ) ;
m_index_ring_buffer - > unmap ( ) ;
}
2016-08-10 16:52:35 +02:00
if ( indexed_draw_info )
2015-10-11 22:00:51 +02:00
{
2016-09-20 16:23:56 +02:00
if ( __glcheck enable ( rsx : : method_registers . restart_index_enabled ( ) , GL_PRIMITIVE_RESTART ) )
{
GLenum index_type = std : : get < 0 > ( indexed_draw_info . value ( ) ) ;
__glcheck glPrimitiveRestartIndex ( ( index_type = = GL_UNSIGNED_SHORT ) ? 0xffff : 0xffffffff ) ;
}
2016-08-10 16:52:35 +02:00
__glcheck glDrawElements ( gl : : draw_mode ( rsx : : method_registers . current_draw_clause . primitive ) , vertex_draw_count , std : : get < 0 > ( indexed_draw_info . value ( ) ) , ( GLvoid * ) ( std : : ptrdiff_t ) std : : get < 1 > ( indexed_draw_info . value ( ) ) ) ;
2016-03-01 21:42:46 +01:00
}
2016-01-12 00:54:07 +01:00
else
{
2016-08-04 19:59:50 +02:00
draw_fbo . draw_arrays ( rsx : : method_registers . current_draw_clause . primitive , vertex_draw_count ) ;
2015-10-04 00:45:26 +02:00
}
2015-10-11 22:00:51 +02:00
2017-02-16 19:29:56 +01:00
m_attrib_ring_buffer - > notify ( ) ;
m_index_ring_buffer - > notify ( ) ;
2017-03-11 10:07:26 +01:00
m_scale_offset_buffer - > notify ( ) ;
m_fragment_constants_buffer - > notify ( ) ;
m_transform_constants_buffer - > notify ( ) ;
2017-02-16 19:29:56 +01:00
2017-01-29 00:00:49 +01:00
std : : chrono : : time_point < steady_clock > draw_end = steady_clock : : now ( ) ;
2016-10-11 02:55:42 +02:00
m_draw_time + = ( u32 ) std : : chrono : : duration_cast < std : : chrono : : microseconds > ( draw_end - draw_start ) . count ( ) ;
2016-06-12 11:05:22 +02:00
2017-02-16 19:29:56 +01:00
m_draw_calls + + ;
synchronize_buffers ( ) ;
2015-10-11 22:00:51 +02:00
rsx : : thread : : end ( ) ;
2015-10-09 20:04:20 +02:00
}
2014-08-18 16:37:23 +02:00
2016-01-06 00:15:35 +01:00
void GLGSRender : : set_viewport ( )
{
2016-09-26 14:21:17 +02:00
//NOTE: scale offset matrix already contains the viewport transformation
glViewport ( 0 , 0 , rsx : : method_registers . surface_clip_width ( ) , rsx : : method_registers . surface_clip_height ( ) ) ;
2016-01-06 00:15:35 +01:00
2016-06-26 23:37:02 +02:00
u16 scissor_x = rsx : : method_registers . scissor_origin_x ( ) ;
u16 scissor_w = rsx : : method_registers . scissor_width ( ) ;
u16 scissor_y = rsx : : method_registers . scissor_origin_y ( ) ;
u16 scissor_h = rsx : : method_registers . scissor_height ( ) ;
2016-01-06 00:15:35 +01:00
2016-09-26 14:21:17 +02:00
//NOTE: window origin does not affect scissor region (probably only affects viewport matrix; already applied)
//See LIMBO [NPUB-30373] which uses shader window origin = top
__glcheck glScissor ( scissor_x , scissor_y , scissor_w , scissor_h ) ;
2016-01-06 00:15:35 +01:00
glEnable ( GL_SCISSOR_TEST ) ;
}
2015-11-26 09:06:29 +01:00
void GLGSRender : : on_init_thread ( )
2015-10-09 20:04:20 +02:00
{
2015-11-26 09:06:29 +01:00
GSRender : : on_init_thread ( ) ;
2015-10-11 22:00:51 +02:00
gl : : init ( ) ;
2017-04-04 18:14:36 +02:00
2016-02-01 22:50:02 +01:00
if ( g_cfg_rsx_debug_output )
2016-03-22 22:26:37 +01:00
gl : : enable_debugging ( ) ;
2017-04-04 18:14:36 +02:00
2016-01-12 22:57:16 +01:00
LOG_NOTICE ( RSX , " %s " , ( const char * ) glGetString ( GL_VERSION ) ) ;
LOG_NOTICE ( RSX , " %s " , ( const char * ) glGetString ( GL_SHADING_LANGUAGE_VERSION ) ) ;
LOG_NOTICE ( RSX , " %s " , ( const char * ) glGetString ( GL_VENDOR ) ) ;
2015-10-11 22:00:51 +02:00
2017-04-04 18:14:36 +02:00
auto gl_caps = gl : : get_driver_caps ( ) ;
if ( ! gl_caps . ARB_texture_buffer_supported )
{
fmt : : throw_exception ( " Failed to initialize OpenGL renderer. ARB_texture_buffer_object is required but not supported by your GPU " ) ;
}
if ( ! gl_caps . ARB_dsa_supported & & ! gl_caps . EXT_dsa_supported )
{
fmt : : throw_exception ( " Failed to initialize OpenGL renderer. ARB_direct_state_access or EXT_direct_state_access is required but not supported by your GPU " ) ;
}
//Use industry standard resource alignment values as defaults
m_uniform_buffer_offset_align = 256 ;
m_min_texbuffer_alignment = 256 ;
2015-10-11 22:00:51 +02:00
glEnable ( GL_VERTEX_PROGRAM_POINT_SIZE ) ;
2016-06-20 23:38:38 +02:00
glGetIntegerv ( GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT , & m_uniform_buffer_offset_align ) ;
2016-06-12 17:54:15 +02:00
glGetIntegerv ( GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT , & m_min_texbuffer_alignment ) ;
2015-10-14 00:45:18 +02:00
m_vao . create ( ) ;
2016-01-28 18:01:10 +01:00
2017-04-04 18:14:36 +02:00
const u32 texture_index_offset = rsx : : limits : : fragment_textures_count + rsx : : limits : : vertex_textures_count ;
2016-10-18 09:57:28 +02:00
for ( int index = 0 ; index < rsx : : limits : : vertex_count ; + + index )
2016-01-28 18:01:10 +01:00
{
2016-10-18 09:57:28 +02:00
auto & tex = m_gl_attrib_buffers [ index ] ;
2016-06-11 21:51:34 +02:00
tex . create ( ) ;
tex . set_target ( gl : : texture : : target : : textureBuffer ) ;
2016-10-18 09:57:28 +02:00
glActiveTexture ( GL_TEXTURE0 + texture_index_offset + index ) ;
tex . bind ( ) ;
2016-01-28 18:01:10 +01:00
}
2016-02-15 10:50:14 +01:00
2017-04-04 18:14:36 +02:00
if ( ! gl_caps . ARB_buffer_storage_supported )
{
LOG_WARNING ( RSX , " Forcing use of legacy OpenGL buffers because ARB_buffer_storage is not supported " ) ;
g_cfg_rsx_gl_legacy_buffers = true ;
}
2016-10-18 09:57:28 +02:00
if ( g_cfg_rsx_gl_legacy_buffers )
{
LOG_WARNING ( RSX , " Using legacy openGL buffers. " ) ;
manually_flush_ring_buffers = true ;
2016-06-12 11:05:22 +02:00
2016-10-18 09:57:28 +02:00
m_attrib_ring_buffer . reset ( new gl : : legacy_ring_buffer ( ) ) ;
2017-03-11 10:07:26 +01:00
m_transform_constants_buffer . reset ( new gl : : legacy_ring_buffer ( ) ) ;
m_fragment_constants_buffer . reset ( new gl : : legacy_ring_buffer ( ) ) ;
m_scale_offset_buffer . reset ( new gl : : legacy_ring_buffer ( ) ) ;
2016-10-18 09:57:28 +02:00
m_index_ring_buffer . reset ( new gl : : legacy_ring_buffer ( ) ) ;
}
else
{
m_attrib_ring_buffer . reset ( new gl : : ring_buffer ( ) ) ;
2017-03-11 10:07:26 +01:00
m_transform_constants_buffer . reset ( new gl : : ring_buffer ( ) ) ;
m_fragment_constants_buffer . reset ( new gl : : ring_buffer ( ) ) ;
m_scale_offset_buffer . reset ( new gl : : ring_buffer ( ) ) ;
2016-10-18 09:57:28 +02:00
m_index_ring_buffer . reset ( new gl : : ring_buffer ( ) ) ;
}
m_attrib_ring_buffer - > create ( gl : : buffer : : target : : texture , 256 * 0x100000 ) ;
2017-03-11 10:07:26 +01:00
m_index_ring_buffer - > create ( gl : : buffer : : target : : element_array , 64 * 0x100000 ) ;
m_transform_constants_buffer - > create ( gl : : buffer : : target : : uniform , 16 * 0x100000 ) ;
m_fragment_constants_buffer - > create ( gl : : buffer : : target : : uniform , 16 * 0x100000 ) ;
m_scale_offset_buffer - > create ( gl : : buffer : : target : : uniform , 16 * 0x100000 ) ;
2016-10-18 09:57:28 +02:00
m_vao . element_array_buffer = * m_index_ring_buffer ;
2016-10-20 05:20:45 +02:00
if ( g_cfg_rsx_overlay )
2017-04-04 18:14:36 +02:00
{
if ( gl_caps . ARB_shader_draw_parameters_supported )
{
m_text_printer . init ( ) ;
m_text_printer . set_enabled ( true ) ;
}
}
2017-02-16 19:29:56 +01:00
2017-03-29 21:27:29 +02:00
for ( int i = 0 ; i < rsx : : limits : : fragment_textures_count ; + + i )
{
m_gl_sampler_states [ i ] . create ( ) ;
m_gl_sampler_states [ i ] . bind ( i ) ;
}
2017-02-16 19:29:56 +01:00
m_gl_texture_cache . initialize ( this ) ;
2015-10-09 20:04:20 +02:00
}
2015-11-26 09:06:29 +01:00
void GLGSRender : : on_exit ( )
2015-10-09 20:04:20 +02:00
{
2015-10-11 22:00:51 +02:00
glDisable ( GL_VERTEX_PROGRAM_POINT_SIZE ) ;
2015-10-04 00:45:26 +02:00
2016-08-26 16:23:23 +02:00
m_prog_buffer . clear ( ) ;
2015-10-04 00:45:26 +02:00
2015-10-11 22:00:51 +02:00
if ( draw_fbo )
2016-06-26 14:47:48 +02:00
{
2015-10-11 22:00:51 +02:00
draw_fbo . remove ( ) ;
2016-06-26 14:47:48 +02:00
}
2015-10-04 00:45:26 +02:00
2015-10-11 22:00:51 +02:00
if ( m_flip_fbo )
2016-06-26 14:47:48 +02:00
{
2015-10-11 22:00:51 +02:00
m_flip_fbo . remove ( ) ;
2016-06-26 14:47:48 +02:00
}
2015-10-04 00:45:26 +02:00
2015-10-11 22:00:51 +02:00
if ( m_flip_tex_color )
2016-06-26 14:47:48 +02:00
{
2015-10-11 22:00:51 +02:00
m_flip_tex_color . remove ( ) ;
2016-06-26 14:47:48 +02:00
}
2015-10-14 00:45:18 +02:00
if ( m_vao )
2016-06-26 14:47:48 +02:00
{
2015-10-14 00:45:18 +02:00
m_vao . remove ( ) ;
2016-06-26 14:47:48 +02:00
}
2015-10-14 02:15:23 +02:00
2016-06-11 21:51:34 +02:00
for ( gl : : texture & tex : m_gl_attrib_buffers )
2016-01-28 18:01:10 +01:00
{
2016-06-11 21:51:34 +02:00
tex . remove ( ) ;
2016-01-28 18:01:10 +01:00
}
2016-06-11 21:51:34 +02:00
2017-03-29 21:27:29 +02:00
for ( auto & sampler : m_gl_sampler_states )
{
sampler . remove ( ) ;
}
2017-04-17 23:30:34 +02:00
if ( m_attrib_ring_buffer )
{
m_attrib_ring_buffer - > remove ( ) ;
}
if ( m_transform_constants_buffer )
{
m_transform_constants_buffer - > remove ( ) ;
}
if ( m_fragment_constants_buffer )
{
m_fragment_constants_buffer - > remove ( ) ;
}
if ( m_scale_offset_buffer )
{
m_scale_offset_buffer - > remove ( ) ;
}
if ( m_index_ring_buffer )
{
m_index_ring_buffer - > remove ( ) ;
}
2016-07-20 14:16:19 +02:00
2016-10-11 02:55:42 +02:00
m_text_printer . close ( ) ;
2017-02-16 19:29:56 +01:00
m_gl_texture_cache . close ( ) ;
2016-10-11 02:55:42 +02:00
2016-07-20 14:16:19 +02:00
return GSRender : : on_exit ( ) ;
2012-11-15 00:39:56 +01:00
}
2017-02-16 19:29:56 +01:00
void GLGSRender : : clear_surface ( u32 arg )
2013-11-09 22:29:49 +01:00
{
2016-06-26 23:37:02 +02:00
if ( rsx : : method_registers . surface_color_target ( ) = = rsx : : surface_target : : none ) return ;
2015-10-11 22:00:51 +02:00
if ( ( arg & 0xf3 ) = = 0 )
2015-10-09 20:04:20 +02:00
{
2015-10-11 22:00:51 +02:00
//do nothing
2015-10-09 20:04:20 +02:00
return ;
}
2014-08-18 16:37:23 +02:00
2015-10-11 22:00:51 +02:00
GLbitfield mask = 0 ;
2016-06-26 23:37:02 +02:00
rsx : : surface_depth_format surface_depth_format = rsx : : method_registers . surface_depth_fmt ( ) ;
2016-06-20 23:38:38 +02:00
2015-10-11 22:00:51 +02:00
if ( arg & 0x1 )
2015-10-09 20:04:20 +02:00
{
2016-01-13 17:40:10 +01:00
u32 max_depth_value = get_max_depth_value ( surface_depth_format ) ;
2017-03-26 13:51:25 +02:00
u32 clear_depth = rsx : : method_registers . z_clear_value ( surface_depth_format = = rsx : : surface_depth_format : : z24s8 ) ;
2014-02-16 09:56:58 +01:00
2015-10-11 22:00:51 +02:00
glDepthMask ( GL_TRUE ) ;
glClearDepth ( double ( clear_depth ) / max_depth_value ) ;
mask | = GLenum ( gl : : buffers : : depth ) ;
2017-02-16 19:29:56 +01:00
gl : : render_target * ds = std : : get < 1 > ( m_rtts . m_bound_depth_stencil ) ;
if ( ds & & ! ds - > cleared ( ) )
ds - > set_cleared ( ) ;
2015-10-11 22:00:51 +02:00
}
2014-02-16 09:56:58 +01:00
2016-06-26 14:47:48 +02:00
if ( surface_depth_format = = rsx : : surface_depth_format : : z24s8 & & ( arg & 0x2 ) )
2015-10-09 20:04:20 +02:00
{
2016-06-26 23:37:02 +02:00
u8 clear_stencil = rsx : : method_registers . stencil_clear_value ( ) ;
2014-02-16 09:56:58 +01:00
2016-06-26 23:37:02 +02:00
__glcheck glStencilMask ( rsx : : method_registers . stencil_mask ( ) ) ;
2015-10-11 22:00:51 +02:00
glClearStencil ( clear_stencil ) ;
2015-10-04 00:45:26 +02:00
2015-10-11 22:00:51 +02:00
mask | = GLenum ( gl : : buffers : : stencil ) ;
}
if ( arg & 0xf0 )
{
2016-06-26 23:37:02 +02:00
u8 clear_a = rsx : : method_registers . clear_color_a ( ) ;
u8 clear_r = rsx : : method_registers . clear_color_r ( ) ;
u8 clear_g = rsx : : method_registers . clear_color_g ( ) ;
u8 clear_b = rsx : : method_registers . clear_color_b ( ) ;
2015-10-04 00:45:26 +02:00
2015-10-11 22:00:51 +02:00
glColorMask ( ( ( arg & 0x20 ) ? 1 : 0 ) , ( ( arg & 0x40 ) ? 1 : 0 ) , ( ( arg & 0x80 ) ? 1 : 0 ) , ( ( arg & 0x10 ) ? 1 : 0 ) ) ;
glClearColor ( clear_r / 255.f , clear_g / 255.f , clear_b / 255.f , clear_a / 255.f ) ;
2015-10-04 00:45:26 +02:00
2015-10-11 22:00:51 +02:00
mask | = GLenum ( gl : : buffers : : color ) ;
}
2015-10-04 00:45:26 +02:00
2016-01-06 00:15:35 +01:00
glClear ( mask ) ;
2013-11-09 22:29:49 +01:00
}
2013-08-26 16:18:59 +02:00
2015-11-26 09:06:29 +01:00
bool GLGSRender : : do_method ( u32 cmd , u32 arg )
2015-10-11 22:00:51 +02:00
{
2016-07-22 01:31:58 +02:00
switch ( cmd )
{
case NV4097_CLEAR_SURFACE :
2017-02-27 13:50:00 +01:00
{
2017-02-16 19:29:56 +01:00
init_buffers ( true ) ;
2017-02-27 13:50:00 +01:00
synchronize_buffers ( ) ;
clear_surface ( arg ) ;
2017-02-16 19:29:56 +01:00
return true ;
2017-02-27 13:50:00 +01:00
}
2017-02-16 19:29:56 +01:00
case NV4097_TEXTURE_READ_SEMAPHORE_RELEASE :
case NV4097_BACK_END_WRITE_SEMAPHORE_RELEASE :
flush_draw_buffers = true ;
return true ;
2016-07-22 01:31:58 +02:00
}
2017-02-16 19:29:56 +01:00
return false ;
2015-10-09 20:04:20 +02:00
}
2015-10-04 00:45:26 +02:00
2015-10-11 22:00:51 +02:00
bool GLGSRender : : load_program ( )
2015-10-09 20:04:20 +02:00
{
2017-02-16 19:29:56 +01:00
auto rtt_lookup_func = [ this ] ( u32 texaddr , rsx : : fragment_texture & tex , bool is_depth ) - > std : : tuple < bool , u16 >
2017-02-10 10:08:46 +01:00
{
gl : : render_target * surface = nullptr ;
if ( ! is_depth )
surface = m_rtts . get_texture_from_render_target_if_applicable ( texaddr ) ;
else
surface = m_rtts . get_texture_from_depth_stencil_if_applicable ( texaddr ) ;
2017-02-16 19:29:56 +01:00
if ( ! surface )
{
auto rsc = m_rtts . get_surface_subresource_if_applicable ( texaddr , 0 , 0 , tex . pitch ( ) ) ;
if ( ! rsc . surface | | rsc . is_depth_surface ! = is_depth )
return std : : make_tuple ( false , 0 ) ;
surface = rsc . surface ;
}
2017-02-10 10:08:46 +01:00
return std : : make_tuple ( true , surface - > get_native_pitch ( ) ) ;
} ;
2016-08-26 16:23:23 +02:00
RSXVertexProgram vertex_program = get_current_vertex_program ( ) ;
2017-02-10 10:08:46 +01:00
RSXFragmentProgram fragment_program = get_current_fragment_program ( rtt_lookup_func ) ;
u32 unnormalized_rtts = 0 ;
2015-10-04 00:45:26 +02:00
2016-10-18 09:57:28 +02:00
for ( auto & vtx : vertex_program . rsx_vertex_inputs )
{
auto & array_info = rsx : : method_registers . vertex_arrays_info [ vtx . location ] ;
if ( array_info . type ( ) = = rsx : : vertex_base_type : : s1 | |
array_info . type ( ) = = rsx : : vertex_base_type : : cmp )
{
//Some vendors do not support GL_x_SNORM buffer textures
verify ( HERE ) , vtx . flags = = 0 ;
vtx . flags | = GL_VP_FORCE_ATTRIB_SCALING | GL_VP_ATTRIB_S16_INT ;
}
}
auto old_program = m_program ;
2016-08-26 16:23:23 +02:00
m_program = & m_prog_buffer . getGraphicPipelineState ( vertex_program , fragment_program , nullptr ) ;
m_program - > use ( ) ;
2016-02-13 11:26:07 +01:00
2016-08-27 08:12:44 +02:00
u8 * buf ;
2016-06-12 11:05:22 +02:00
u32 scale_offset_offset ;
u32 vertex_constants_offset ;
u32 fragment_constants_offset ;
2016-02-13 11:26:07 +01:00
2017-03-11 10:07:26 +01:00
const u32 fragment_constants_size = m_prog_buffer . get_fragment_constants_buffer_size ( fragment_program ) ;
const u32 fragment_buffer_size = fragment_constants_size + ( 17 * 4 * sizeof ( float ) ) ;
if ( manually_flush_ring_buffers )
{
m_scale_offset_buffer - > reserve_storage_on_heap ( 512 ) ;
m_fragment_constants_buffer - > reserve_storage_on_heap ( align ( fragment_buffer_size , 256 ) ) ;
if ( m_transform_constants_dirty ) m_transform_constants_buffer - > reserve_storage_on_heap ( 8192 ) ;
}
2016-08-26 16:23:23 +02:00
// Scale offset
2017-03-11 10:07:26 +01:00
auto mapping = m_scale_offset_buffer - > alloc_from_heap ( 512 , m_uniform_buffer_offset_align ) ;
2016-08-27 08:12:44 +02:00
buf = static_cast < u8 * > ( mapping . first ) ;
scale_offset_offset = mapping . second ;
2017-04-25 12:32:39 +02:00
fill_scale_offset_data ( buf , false , true ) ;
fill_user_clip_data ( ( char * ) buf + 64 ) ;
2016-08-27 08:12:44 +02:00
2017-03-11 10:07:26 +01:00
if ( m_transform_constants_dirty )
{
// Vertex constants
mapping = m_transform_constants_buffer - > alloc_from_heap ( 8192 , m_uniform_buffer_offset_align ) ;
buf = static_cast < u8 * > ( mapping . first ) ;
vertex_constants_offset = mapping . second ;
fill_vertex_program_constants_data ( buf ) ;
* ( reinterpret_cast < u32 * > ( buf + ( 468 * 4 * sizeof ( float ) ) ) ) = rsx : : method_registers . transform_branch_bits ( ) ;
}
2016-08-26 16:23:23 +02:00
// Fragment constants
2017-03-11 10:07:26 +01:00
mapping = m_fragment_constants_buffer - > alloc_from_heap ( fragment_buffer_size , m_uniform_buffer_offset_align ) ;
2017-02-10 10:08:46 +01:00
buf = static_cast < u8 * > ( mapping . first ) ;
fragment_constants_offset = mapping . second ;
2016-06-20 23:38:38 +02:00
if ( fragment_constants_size )
2016-08-27 08:12:44 +02:00
m_prog_buffer . fill_fragment_constants_buffer ( { reinterpret_cast < float * > ( buf ) , gsl : : narrow < int > ( fragment_constants_size ) } , fragment_program ) ;
2017-04-04 18:14:36 +02:00
2017-02-10 10:08:46 +01:00
// Fragment state
fill_fragment_state_buffer ( buf + fragment_constants_size , fragment_program ) ;
2016-06-12 11:05:22 +02:00
2017-03-11 10:07:26 +01:00
m_scale_offset_buffer - > bind_range ( 0 , scale_offset_offset , 512 ) ;
m_fragment_constants_buffer - > bind_range ( 2 , fragment_constants_offset , fragment_buffer_size ) ;
if ( m_transform_constants_dirty ) m_transform_constants_buffer - > bind_range ( 1 , vertex_constants_offset , 8192 ) ;
2016-06-27 00:52:08 +02:00
2016-10-18 09:57:28 +02:00
if ( manually_flush_ring_buffers )
2017-03-11 10:07:26 +01:00
{
m_scale_offset_buffer - > unmap ( ) ;
m_fragment_constants_buffer - > unmap ( ) ;
2017-04-04 18:14:36 +02:00
2017-03-11 10:07:26 +01:00
if ( m_transform_constants_dirty ) m_transform_constants_buffer - > unmap ( ) ;
}
2016-10-18 09:57:28 +02:00
2017-03-11 10:07:26 +01:00
m_transform_constants_dirty = false ;
2015-10-11 22:00:51 +02:00
return true ;
2013-11-09 22:29:49 +01:00
}
2013-11-03 20:23:16 +01:00
2015-10-11 22:00:51 +02:00
void GLGSRender : : flip ( int buffer )
{
u32 buffer_width = gcm_buffers [ buffer ] . width ;
u32 buffer_height = gcm_buffers [ buffer ] . height ;
u32 buffer_pitch = gcm_buffers [ buffer ] . pitch ;
2016-01-05 21:55:43 +01:00
2016-06-15 05:19:20 +02:00
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
glDisable ( GL_SCISSOR_TEST ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_STENCIL_TEST ) ;
2016-06-26 14:47:48 +02:00
2016-01-05 21:55:43 +01:00
rsx : : tiled_region buffer_region = get_tiled_address ( gcm_buffers [ buffer ] . offset , CELL_GCM_LOCATION_LOCAL ) ;
2016-06-26 14:47:48 +02:00
u32 absolute_address = buffer_region . address + buffer_region . base ;
gl : : texture * render_target_texture = m_rtts . get_texture_from_render_target_if_applicable ( absolute_address ) ;
2015-10-11 22:00:51 +02:00
2016-06-26 14:47:48 +02:00
__glcheck m_flip_fbo . recreate ( ) ;
m_flip_fbo . bind ( ) ;
2015-10-09 20:04:20 +02:00
2016-06-26 14:47:48 +02:00
auto * flip_fbo = & m_flip_fbo ;
if ( render_target_texture )
{
__glcheck m_flip_fbo . color = * render_target_texture ;
__glcheck m_flip_fbo . read_buffer ( m_flip_fbo . color ) ;
}
else if ( draw_fbo )
{
//HACK! it's here, because textures cache isn't implemented correctly!
flip_fbo = & draw_fbo ;
}
else
2015-10-09 20:04:20 +02:00
{
2015-10-11 22:00:51 +02:00
if ( ! m_flip_tex_color | | m_flip_tex_color . size ( ) ! = sizei { ( int ) buffer_width , ( int ) buffer_height } )
2015-10-09 20:04:20 +02:00
{
2015-10-11 22:00:51 +02:00
m_flip_tex_color . recreate ( gl : : texture : : target : : texture2D ) ;
2015-10-09 20:04:20 +02:00
2015-10-11 22:00:51 +02:00
__glcheck m_flip_tex_color . config ( )
. size ( { ( int ) buffer_width , ( int ) buffer_height } )
. type ( gl : : texture : : type : : uint_8_8_8_8 )
. format ( gl : : texture : : format : : bgra ) ;
2015-10-09 20:04:20 +02:00
2016-01-05 21:55:43 +01:00
m_flip_tex_color . pixel_unpack_settings ( ) . aligment ( 1 ) . row_length ( buffer_pitch / 4 ) ;
2013-11-09 22:29:49 +01:00
}
2016-01-05 21:55:43 +01:00
if ( buffer_region . tile )
{
2016-04-25 12:49:12 +02:00
std : : unique_ptr < u8 [ ] > temp ( new u8 [ buffer_height * buffer_pitch ] ) ;
2016-01-05 21:55:43 +01:00
buffer_region . read ( temp . get ( ) , buffer_width , buffer_height , buffer_pitch ) ;
__glcheck m_flip_tex_color . copy_from ( temp . get ( ) , gl : : texture : : format : : bgra , gl : : texture : : type : : uint_8_8_8_8 ) ;
}
else
{
__glcheck m_flip_tex_color . copy_from ( buffer_region . ptr , gl : : texture : : format : : bgra , gl : : texture : : type : : uint_8_8_8_8 ) ;
}
2016-06-26 14:47:48 +02:00
m_flip_fbo . color = m_flip_tex_color ;
__glcheck m_flip_fbo . read_buffer ( m_flip_fbo . color ) ;
2015-01-31 14:01:34 +01:00
}
2014-05-22 19:39:56 +02:00
2015-10-11 22:00:51 +02:00
areai screen_area = coordi ( { } , { ( int ) buffer_width , ( int ) buffer_height } ) ;
2013-12-08 01:09:16 +01:00
2015-10-11 22:00:51 +02:00
coordi aspect_ratio ;
2015-01-31 14:01:34 +01:00
2017-02-16 19:29:56 +01:00
sizei csize ( m_frame - > client_width ( ) , m_frame - > client_height ( ) ) ;
sizei new_size = csize ;
2015-01-31 14:01:34 +01:00
2017-02-16 19:29:56 +01:00
const double aq = ( double ) buffer_width / buffer_height ;
const double rq = ( double ) new_size . width / new_size . height ;
const double q = aq / rq ;
2014-02-16 09:56:58 +01:00
2017-02-16 19:29:56 +01:00
if ( q > 1.0 )
{
new_size . height = int ( new_size . height / q ) ;
aspect_ratio . y = ( csize . height - new_size . height ) / 2 ;
2015-10-11 22:00:51 +02:00
}
2017-02-16 19:29:56 +01:00
else if ( q < 1.0 )
2014-02-16 09:56:58 +01:00
{
2017-02-16 19:29:56 +01:00
new_size . width = int ( new_size . width * q ) ;
aspect_ratio . x = ( csize . width - new_size . width ) / 2 ;
2014-02-16 09:56:58 +01:00
}
2015-10-09 20:04:20 +02:00
2017-02-16 19:29:56 +01:00
aspect_ratio . size = new_size ;
2015-10-11 22:00:51 +02:00
gl : : screen . clear ( gl : : buffers : : color_depth_stencil ) ;
2015-10-09 20:04:20 +02:00
2017-03-29 21:27:29 +02:00
__glcheck flip_fbo - > blit ( gl : : screen , screen_area , areai ( aspect_ratio ) . flipped_vertical ( ) , gl : : buffers : : color , gl : : filter : : linear ) ;
2015-01-31 14:01:34 +01:00
2016-06-12 11:05:22 +02:00
if ( g_cfg_rsx_overlay )
{
2016-10-11 02:55:42 +02:00
gl : : screen . bind ( ) ;
glViewport ( 0 , 0 , m_frame - > client_width ( ) , m_frame - > client_height ( ) ) ;
2017-04-04 18:14:36 +02:00
2016-10-11 02:55:42 +02:00
m_text_printer . print_text ( 0 , 0 , m_frame - > client_width ( ) , m_frame - > client_height ( ) , " draw calls: " + std : : to_string ( m_draw_calls ) ) ;
m_text_printer . print_text ( 0 , 18 , m_frame - > client_width ( ) , m_frame - > client_height ( ) , " draw call setup: " + std : : to_string ( m_begin_time ) + " us " ) ;
m_text_printer . print_text ( 0 , 36 , m_frame - > client_width ( ) , m_frame - > client_height ( ) , " vertex upload time: " + std : : to_string ( m_vertex_upload_time ) + " us " ) ;
m_text_printer . print_text ( 0 , 54 , m_frame - > client_width ( ) , m_frame - > client_height ( ) , " textures upload time: " + std : : to_string ( m_textures_upload_time ) + " us " ) ;
m_text_printer . print_text ( 0 , 72 , m_frame - > client_width ( ) , m_frame - > client_height ( ) , " draw call execution: " + std : : to_string ( m_draw_time ) + " us " ) ;
2016-06-12 11:05:22 +02:00
}
2016-10-11 02:55:42 +02:00
m_frame - > flip ( m_context ) ;
2016-06-12 11:05:22 +02:00
m_draw_calls = 0 ;
m_begin_time = 0 ;
m_draw_time = 0 ;
m_vertex_upload_time = 0 ;
2016-10-11 02:55:42 +02:00
m_textures_upload_time = 0 ;
2016-03-09 19:11:22 +01:00
2017-02-16 19:29:56 +01:00
m_gl_texture_cache . clear_temporary_surfaces ( ) ;
2016-03-09 19:11:22 +01:00
for ( auto & tex : m_rtts . invalidated_resources )
{
tex - > remove ( ) ;
}
m_rtts . invalidated_resources . clear ( ) ;
2014-02-16 09:56:58 +01:00
}
2015-10-09 20:04:20 +02:00
2015-10-11 22:00:51 +02:00
u64 GLGSRender : : timestamp ( ) const
2015-10-09 20:04:20 +02:00
{
2015-10-11 22:00:51 +02:00
GLint64 result ;
glGetInteger64v ( GL_TIMESTAMP , & result ) ;
return result ;
2015-09-26 22:46:04 +02:00
}
2016-02-15 10:50:14 +01:00
bool GLGSRender : : on_access_violation ( u32 address , bool is_writing )
{
2017-02-13 15:22:25 +01:00
if ( is_writing )
return m_gl_texture_cache . mark_as_dirty ( address ) ;
else
return m_gl_texture_cache . flush_section ( address ) ;
2016-08-27 08:12:44 +02:00
}
2017-02-16 19:29:56 +01:00
void GLGSRender : : do_local_task ( )
{
std : : lock_guard < std : : mutex > lock ( queue_guard ) ;
2017-02-27 21:53:34 +01:00
work_queue . remove_if ( [ ] ( work_item & q ) { return q . received ; } ) ;
2017-02-16 19:29:56 +01:00
for ( work_item & q : work_queue )
{
2017-03-10 14:27:38 +01:00
if ( q . processed ) continue ;
2017-02-16 19:29:56 +01:00
std : : unique_lock < std : : mutex > lock ( q . guard_mutex ) ;
2017-03-10 14:27:38 +01:00
//Check if the suggested section is valid
if ( ! q . section_to_flush - > is_flushed ( ) )
{
q . section_to_flush - > flush ( ) ;
q . result = true ;
}
else
{
2017-03-13 18:58:35 +01:00
//Another thread has unlocked this memory region already
//Return success
q . result = true ;
2017-03-10 14:27:38 +01:00
}
2017-02-16 19:29:56 +01:00
q . processed = true ;
//Notify thread waiting on this
lock . unlock ( ) ;
q . cv . notify_one ( ) ;
}
}
2017-03-29 21:27:29 +02:00
work_item & GLGSRender : : post_flush_request ( u32 address , gl : : texture_cache : : cached_texture_section * section )
2017-02-16 19:29:56 +01:00
{
std : : lock_guard < std : : mutex > lock ( queue_guard ) ;
work_queue . emplace_back ( ) ;
work_item & result = work_queue . back ( ) ;
result . address_to_flush = address ;
2017-03-10 14:27:38 +01:00
result . section_to_flush = section ;
2017-02-16 19:29:56 +01:00
return result ;
}
void GLGSRender : : synchronize_buffers ( )
{
if ( flush_draw_buffers )
{
write_buffers ( ) ;
flush_draw_buffers = false ;
}
}
2017-03-29 21:27:29 +02:00
bool GLGSRender : : scaled_image_from_memory ( rsx : : blit_src_info & src , rsx : : blit_dst_info & dst , bool interpolate )
{
return m_gl_texture_cache . upload_scaled_image ( src , dst , interpolate , m_rtts ) ;
}