#pragma once #include "GCM.h" #include "RSXTexture.h" #include "RSXVertexProgram.h" #include "RSXFragmentProgram.h" #include #include "Utilities/Semaphore.h" #include "Utilities/Thread.h" #include "Utilities/Timer.h" enum Method { CELL_GCM_METHOD_FLAG_NON_INCREMENT = 0x40000000, CELL_GCM_METHOD_FLAG_JUMP = 0x20000000, CELL_GCM_METHOD_FLAG_CALL = 0x00000002, CELL_GCM_METHOD_FLAG_RETURN = 0x00020000, }; extern u32 methodRegisters[0xffff]; u32 GetAddress(u32 offset, u32 location); struct RSXVertexData { u32 frequency; u32 stride; u32 size; u32 type; u32 addr; u32 constant_count; std::vector data; RSXVertexData(); void Reset(); bool IsEnabled() const { return size > 0; } void Load(u32 start, u32 count, u32 baseOffset, u32 baseIndex); u32 GetTypeSize() const; }; struct RSXIndexArrayData { std::vector m_data; int m_type; u32 m_first; u32 m_count; u32 m_addr; u32 index_max; u32 index_min; RSXIndexArrayData() { Reset(); } void Reset() { m_type = 0; m_first = ~0; m_count = 0; m_addr = 0; index_min = ~0; index_max = 0; m_data.clear(); } }; struct RSXTransformConstant { u32 id; float x, y, z, w; RSXTransformConstant() : x(0.0f) , y(0.0f) , z(0.0f) , w(0.0f) { } RSXTransformConstant(u32 id, float x, float y, float z, float w) : id(id) , x(x) , y(y) , z(z) , w(w) { } }; class RSXThread : protected thread_t { public: static const uint m_textures_count = 16; static const uint m_vertex_count = 32; static const uint m_fragment_count = 32; static const uint m_tiles_count = 15; static const uint m_zculls_count = 8; protected: std::stack m_call_stack; CellGcmControl* m_ctrl; Timer m_timer_sync; public: GcmTileInfo m_tiles[m_tiles_count]; GcmZcullInfo m_zculls[m_zculls_count]; RSXTexture m_textures[m_textures_count]; RSXVertexTexture m_vertex_textures[m_textures_count]; RSXVertexData m_vertex_data[m_vertex_count]; RSXIndexArrayData m_indexed_array; std::vector m_fragment_constants; std::vector m_transform_constants; u32 m_shader_ctrl, m_cur_fragment_prog_num; RSXFragmentProgram m_fragment_progs[m_fragment_count]; RSXFragmentProgram* m_cur_fragment_prog; RSXVertexProgram m_vertex_progs[m_vertex_count]; RSXVertexProgram* m_cur_vertex_prog; public: u32 m_ioAddress, m_ioSize, m_ctrlAddress; int m_flip_status; int m_flip_mode; int m_debug_level; int m_frequency_mode; u32 m_tiles_addr; u32 m_zculls_addr; u32 m_gcm_buffers_addr; u32 m_gcm_buffers_count; u32 m_gcm_current_buffer; u32 m_ctxt_addr; u32 m_report_main_addr; u32 m_label_addr; // DMA u32 dma_report; u32 m_local_mem_addr, m_main_mem_addr; bool m_strict_ordering[0x1000]; public: uint m_draw_mode; u32 m_width; u32 m_height; float m_width_scale; float m_height_scale; u32 m_draw_array_count; u32 m_draw_array_first; double m_fps_limit = 59.94; public: std::mutex m_cs_main; semaphore_t m_sem_flip; u64 m_last_flip_time; vm::ptr m_flip_handler; vm::ptr m_user_handler; u64 m_vblank_count; vm::ptr m_vblank_handler; public: // Dither bool m_set_dither; // Color mask bool m_set_color_mask; bool m_color_mask_r; bool m_color_mask_g; bool m_color_mask_b; bool m_color_mask_a; // Clip bool m_set_clip; float m_clip_min; float m_clip_max; // Depth test bool m_set_depth_test; bool m_set_depth_func; int m_depth_func; bool m_set_depth_mask; u32 m_depth_mask; // Depth bound test bool m_set_depth_bounds_test; bool m_set_depth_bounds; float m_depth_bounds_min; float m_depth_bounds_max; // Primitive restart bool m_set_restart_index; u32 m_restart_index; // Point bool m_set_point_size; bool m_set_point_sprite_control; float m_point_size; u16 m_point_x; u16 m_point_y; // Line smooth bool m_set_line_smooth; // Viewport & scissor bool m_set_viewport_horizontal; bool m_set_viewport_vertical; u16 m_viewport_x; u16 m_viewport_y; u16 m_viewport_w; u16 m_viewport_h; bool m_set_scissor_horizontal; bool m_set_scissor_vertical; u16 m_scissor_x; u16 m_scissor_y; u16 m_scissor_w; u16 m_scissor_h; // Polygon mode/offset bool m_set_poly_smooth; bool m_set_poly_offset_fill; bool m_set_poly_offset_line; bool m_set_poly_offset_point; bool m_set_front_polygon_mode; u32 m_front_polygon_mode; bool m_set_back_polygon_mode; u32 m_back_polygon_mode; bool m_set_poly_offset_mode; float m_poly_offset_scale_factor; float m_poly_offset_bias; // Line/Polygon stipple bool m_set_line_stipple; u16 m_line_stipple_pattern; u16 m_line_stipple_factor; bool m_set_polygon_stipple; u32 m_polygon_stipple_pattern[32]; // Logic Ops bool m_set_logic_op; u32 m_logic_op; // Clearing u32 m_clear_surface_mask; u32 m_clear_surface_z; u8 m_clear_surface_s; u8 m_clear_surface_color_r; u8 m_clear_surface_color_g; u8 m_clear_surface_color_b; u8 m_clear_surface_color_a; u8 m_clear_color_r; u8 m_clear_color_g; u8 m_clear_color_b; u8 m_clear_color_a; u8 m_clear_s; u32 m_clear_z; // Blending bool m_set_blend; bool m_set_blend_dfactor; u16 m_blend_dfactor_rgb; u16 m_blend_dfactor_alpha; bool m_set_blend_sfactor; u16 m_blend_sfactor_rgb; u16 m_blend_sfactor_alpha; bool m_set_blend_equation; u16 m_blend_equation_rgb; u16 m_blend_equation_alpha; bool m_set_blend_color; u8 m_blend_color_r; u8 m_blend_color_g; u8 m_blend_color_b; u8 m_blend_color_a; bool m_set_blend_mrt1; bool m_set_blend_mrt2; bool m_set_blend_mrt3; // Stencil Test bool m_set_stencil_test; bool m_set_stencil_mask; u32 m_stencil_mask; bool m_set_stencil_func; u32 m_stencil_func; bool m_set_stencil_func_ref; u32 m_stencil_func_ref; bool m_set_stencil_func_mask; u32 m_stencil_func_mask; bool m_set_stencil_fail; u32 m_stencil_fail; bool m_set_stencil_zfail; u32 m_stencil_zfail; bool m_set_stencil_zpass; u32 m_stencil_zpass; bool m_set_two_sided_stencil_test_enable; bool m_set_two_side_light_enable; bool m_set_back_stencil_mask; u32 m_back_stencil_mask; bool m_set_back_stencil_func; u32 m_back_stencil_func; bool m_set_back_stencil_func_ref; u32 m_back_stencil_func_ref; bool m_set_back_stencil_func_mask; u32 m_back_stencil_func_mask; bool m_set_back_stencil_fail; u32 m_back_stencil_fail; bool m_set_back_stencil_zfail; u32 m_back_stencil_zfail; bool m_set_back_stencil_zpass; u32 m_back_stencil_zpass; bool m_set_stencil_op_fail; // Line width bool m_set_line_width; float m_line_width; // Shader mode bool m_set_shade_mode; u32 m_shade_mode; // Lighting bool m_set_specular; // Color u32 m_color_format; u16 m_color_format_src_pitch; u16 m_color_format_dst_pitch; u32 m_color_conv; u32 m_color_conv_fmt; u32 m_color_conv_op; s16 m_color_conv_clip_x; s16 m_color_conv_clip_y; u16 m_color_conv_clip_w; u16 m_color_conv_clip_h; s16 m_color_conv_out_x; s16 m_color_conv_out_y; u16 m_color_conv_out_w; u16 m_color_conv_out_h; s32 m_color_conv_dsdx; s32 m_color_conv_dtdy; // Semaphore // PGRAPH u32 m_PGRAPH_semaphore_offset; //PFIFO u32 m_PFIFO_semaphore_offset; u32 m_PFIFO_semaphore_release_value; // Fog bool m_set_fog_mode; u32 m_fog_mode; bool m_set_fog_params; float m_fog_param0; float m_fog_param1; // Clip plane bool m_set_clip_plane; bool m_clip_plane_0; bool m_clip_plane_1; bool m_clip_plane_2; bool m_clip_plane_3; bool m_clip_plane_4; bool m_clip_plane_5; // Surface bool m_set_surface_format; u8 m_surface_color_format; u8 m_surface_depth_format; u8 m_surface_type; u8 m_surface_antialias; u8 m_surface_width; u8 m_surface_height; bool m_set_surface_clip_horizontal; u16 m_surface_clip_x; u16 m_surface_clip_w; bool m_set_surface_clip_vertical; u16 m_surface_clip_y; u16 m_surface_clip_h; u32 m_surface_pitch_a; u32 m_surface_pitch_b; u32 m_surface_pitch_c; u32 m_surface_pitch_d; u32 m_surface_pitch_z; u32 m_surface_offset_a; u32 m_surface_offset_b; u32 m_surface_offset_c; u32 m_surface_offset_d; u32 m_surface_offset_z; u32 m_surface_color_target; // DMA context bool m_set_context_dma_color_a; u32 m_context_dma_color_a; bool m_set_context_dma_color_b; u32 m_context_dma_color_b; bool m_set_context_dma_color_c; u32 m_context_dma_color_c; bool m_set_context_dma_color_d; u32 m_context_dma_color_d; bool m_set_context_dma_z; u32 m_context_dma_z; u32 m_context_surface; u32 m_context_dma_img_src; u32 m_context_dma_img_dst; u32 m_context_dma_buffer_in_src; u32 m_context_dma_buffer_in_dst; u32 m_dst_offset; // Swizzle2D? u16 m_swizzle_format; u8 m_swizzle_width; u8 m_swizzle_height; u32 m_swizzle_offset; // Cull face bool m_set_cull_face; u32 m_cull_face; // Alpha test bool m_set_alpha_test; bool m_set_alpha_func; u32 m_alpha_func; bool m_set_alpha_ref; float m_alpha_ref; // Shader u16 m_shader_window_height; u8 m_shader_window_origin; u16 m_shader_window_pixel_centers; // Vertex Data u32 m_vertex_data_base_offset; u32 m_vertex_data_base_index; // Front face bool m_set_front_face; u32 m_front_face; // Frequency divider u32 m_set_frequency_divider_operation; u8 m_begin_end; bool m_read_buffer; std::set m_used_gcm_commands; protected: RSXThread() : m_ctrl(nullptr) , m_shader_ctrl(0x40) , m_flip_status(0) , m_flip_mode(CELL_GCM_DISPLAY_VSYNC) , m_debug_level(CELL_GCM_DEBUG_LEVEL0) , m_frequency_mode(CELL_GCM_DISPLAY_FREQUENCY_DISABLE) , m_report_main_addr(0) , m_main_mem_addr(0) , m_local_mem_addr(0) , m_draw_mode(0) , m_draw_array_count(0) , m_draw_array_first(~0) , m_gcm_current_buffer(0) , m_read_buffer(true) { m_flip_handler.set(0); m_vblank_handler.set(0); m_user_handler.set(0); m_set_depth_test = false; m_set_alpha_test = false; m_set_depth_bounds_test = false; m_set_blend = false; m_set_blend_mrt1 = false; m_set_blend_mrt2 = false; m_set_blend_mrt3 = false; m_set_logic_op = false; m_set_cull_face = false; m_set_dither = false; m_set_stencil_test = false; m_set_scissor_horizontal = false; m_set_scissor_vertical = false; m_set_line_smooth = false; m_set_poly_smooth = false; m_set_point_sprite_control = false; m_set_specular = false; m_set_two_sided_stencil_test_enable = false; m_set_two_side_light_enable = false; m_set_surface_clip_horizontal = false; m_set_surface_clip_vertical = false; m_set_poly_offset_fill = false; m_set_poly_offset_line = false; m_set_poly_offset_point = false; m_set_restart_index = false; m_set_line_stipple = false; m_set_polygon_stipple = false; // Default value // TODO: Check against the default value on PS3 m_clear_color_r = 0; m_clear_color_g = 0; m_clear_color_b = 0; m_clear_color_a = 0; m_clear_z = 0xffffff; m_clear_s = 0; m_poly_offset_scale_factor = 0.0; m_poly_offset_bias = 0.0; m_restart_index = 0xffffffff; m_front_polygon_mode = 0x1b02; // GL_FILL m_back_polygon_mode = 0x1b02; // GL_FILL m_front_face = 0x0901; // GL_CCW m_cull_face = 0x0405; // GL_BACK m_alpha_func = 0x0207; // GL_ALWAYS m_alpha_ref = 0.0f; m_logic_op = 0x1503; // GL_COPY m_shade_mode = 0x1D01; // GL_SMOOTH m_depth_mask = 1; m_depth_func = 0x0201; // GL_LESS m_depth_bounds_min = 0.0; m_depth_bounds_max = 1.0; m_clip_min = 0.0; m_clip_max = 1.0; m_blend_equation_rgb = 0x8006; // GL_FUNC_ADD m_blend_equation_alpha = 0x8006; // GL_FUNC_ADD m_blend_sfactor_rgb = 1; // GL_ONE m_blend_dfactor_rgb = 0; // GL_ZERO m_blend_sfactor_alpha = 1; // GL_ONE m_blend_dfactor_alpha = 0; // GL_ZERO m_point_x = 0; m_point_y = 0; m_point_size = 1.0; m_line_width = 1.0; m_line_stipple_pattern = 0xffff; m_line_stipple_factor = 1; m_vertex_data_base_offset = 0; m_vertex_data_base_index = 0; // Construct Stipple Pattern for (size_t i = 0; i < 32; i++) { m_polygon_stipple_pattern[i] = 0xFFFFFFFF; } // Construct Textures for (int i = 0; i < 16; i++) { m_textures[i] = RSXTexture(i); } Reset(); } virtual ~RSXThread() override { if (joinable()) { throw EXCEPTION("Thread not joined"); } } void Reset() { m_set_dither = false; m_set_color_mask = false; m_set_clip = false; m_set_depth_test = false; m_set_depth_func = false; m_set_depth_mask = false; m_set_depth_bounds_test = false; m_set_depth_bounds = false; m_set_viewport_horizontal = false; m_set_viewport_vertical = false; m_set_scissor_horizontal = false; m_set_scissor_vertical = false; m_set_front_polygon_mode = false; m_set_back_polygon_mode = false; m_set_blend = false; m_set_blend_mrt1 = false; m_set_blend_mrt2 = false; m_set_blend_mrt3 = false; m_set_blend_sfactor = false; m_set_blend_dfactor = false; m_set_blend_equation = false; m_set_blend_color = false; m_set_stencil_test = false; m_set_two_sided_stencil_test_enable = false; m_set_two_side_light_enable = false; m_set_stencil_mask = false; m_set_stencil_func = false; m_set_stencil_func_ref = false; m_set_stencil_func_mask = false; m_set_stencil_fail = false; m_set_stencil_zfail = false; m_set_stencil_zpass = false; m_set_back_stencil_mask = false; m_set_back_stencil_func = false; m_set_back_stencil_func_ref = false; m_set_back_stencil_func_mask = false; m_set_back_stencil_fail = false; m_set_back_stencil_zfail = false; m_set_back_stencil_zpass = false; m_set_stencil_op_fail = false; m_set_point_sprite_control = false; m_set_point_size = false; m_set_line_width = false; m_set_line_smooth = false; m_set_shade_mode = false; m_set_fog_mode = false; m_set_fog_params = false; m_set_clip_plane = false; m_set_context_dma_color_a = false; m_set_context_dma_color_b = false; m_set_context_dma_color_c = false; m_set_context_dma_color_d = false; m_set_context_dma_z = false; m_set_cull_face = false; m_set_front_face = false; m_set_alpha_test = false; m_set_alpha_func = false; m_set_alpha_ref = false; m_set_poly_smooth = false; m_set_poly_offset_fill = false; m_set_poly_offset_line = false; m_set_poly_offset_point = false; m_set_poly_offset_mode = false; m_set_restart_index = false; m_set_specular = false; m_set_line_stipple = false; m_set_polygon_stipple = false; m_set_logic_op = false; m_set_surface_format = false; m_set_surface_clip_horizontal = false; m_set_surface_clip_vertical = false; m_clear_surface_mask = 0; m_begin_end = 0; for (uint i = 0; i < m_textures_count; ++i) { m_textures[i].Init(); } } void Begin(u32 draw_mode); void End(); u32 OutOfArgsCount(const uint x, const u32 cmd, const u32 count, const u32 args_addr); void DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const u32 count); virtual void OnInit() = 0; virtual void OnInitThread() = 0; virtual void OnExitThread() = 0; virtual void OnReset() = 0; /** * This member is called when the backend is expected to render a draw call, either * indexed or not. */ virtual void Draw() = 0; /** * This member is called when the backend is expected to clear a target surface. */ virtual void Clear(u32 cmd) = 0; /** * This member is called when the backend is expected to present a target surface in * either local or main memory. */ virtual void Flip() = 0; /** * This member is called when RSXThread parse a TEXTURE_READ_SEMAPHORE_RELEASE * command. * Backend is expected to write value at offset when current draw textures aren't * needed anymore by the GPU and can be modified. */ virtual void semaphorePGRAPHTextureReadRelease(u32 offset, u32 value) = 0; /** * This member is called when RSXThread parse a BACK_END_WRITE_SEMAPHORE_RELEASE * command. * Backend is expected to write value at offset when current draw call has completed * and render surface can be used. */ virtual void semaphorePGRAPHBackendRelease(u32 offset, u32 value) = 0; /** * This member is called when RSXThread parse a SEMAPHORE_ACQUIRE command. * Backend and associated GPU is expected to wait that memory at offset is the same * as value. In particular buffer/texture buffers value can change while backend is * waiting. */ virtual void semaphorePFIFOAcquire(u32 offset, u32 value) = 0; void LoadVertexData(u32 first, u32 count) { for (u32 i = 0; i < m_vertex_count; ++i) { if (!m_vertex_data[i].IsEnabled()) continue; m_vertex_data[i].Load(first, count, m_vertex_data_base_offset, m_vertex_data_base_index); } } virtual void Task(); public: void Init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress); u32 ReadIO32(u32 addr); void WriteIO32(u32 addr, u32 value); };