diff --git a/rpcs3/Emu/GS/GCM.h b/rpcs3/Emu/GS/GCM.h index 30fdd08517..a66d2955b3 100644 --- a/rpcs3/Emu/GS/GCM.h +++ b/rpcs3/Emu/GS/GCM.h @@ -50,6 +50,24 @@ enum CELL_GCM_LOCATION_MAIN = 1, }; +enum +{ + CELL_GCM_FREQUENCY_MODULO = 1, + CELL_GCM_FREQUENCY_DIVIDE = 0, +}; + +enum CellRescTableElement +{ + CELL_RESC_ELEMENT_HALF = 0, + CELL_RESC_ELEMENT_FLOAT = 1, +}; + +enum +{ + CELL_GCM_FLAT = 0x1D00, + CELL_GCM_SMOOTH = 0x1D01, +}; + // GCM Texture enum { diff --git a/rpcs3/Emu/GS/RSXThread.cpp b/rpcs3/Emu/GS/RSXThread.cpp index 614bdafe85..6eb5d99e58 100644 --- a/rpcs3/Emu/GS/RSXThread.cpp +++ b/rpcs3/Emu/GS/RSXThread.cpp @@ -559,6 +559,14 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u3 } break; + case NV4097_SET_DEPTH_BOUNDS_MAX: + { + m_set_depth_bounds = true; + const u32 a0 = ARGS(0); + m_depth_bounds_max = (float&)a0; + } + break; + // Viewport case NV4097_SET_VIEWPORT_VERTICAL: { @@ -1620,6 +1628,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u3 } break; + case NV4097_SET_FREQUENCY_DIVIDER_OPERATION: + { + m_set_frequency_divider_operation = ARGS(0); + } + break; + case 0x000002c8: case 0x000002d0: case 0x000002d8: diff --git a/rpcs3/Emu/GS/RSXThread.h b/rpcs3/Emu/GS/RSXThread.h index db4f9c3563..d8dc3f6dda 100644 --- a/rpcs3/Emu/GS/RSXThread.h +++ b/rpcs3/Emu/GS/RSXThread.h @@ -408,6 +408,9 @@ public: 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; @@ -490,19 +493,27 @@ protected: void Reset() { + m_set_dither = false; m_set_color_mask = false; m_set_clip = false; - m_set_depth_func = false; - m_set_depth_bounds = 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_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_stencil_mask = false; m_set_stencil_func = false; m_set_stencil_func_ref = false; @@ -517,12 +528,11 @@ protected: m_set_back_stencil_fail = false; m_set_back_stencil_zfail = false; m_set_back_stencil_zpass = false; - m_set_blend_equation = false; - m_set_depth_mask = 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_blend_color = false; m_set_semaphore_offset = false; m_set_fog_mode = false; m_set_fog_params = false; @@ -535,16 +545,21 @@ protected: 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_point_sprite_control = false; m_set_specular = false; m_set_line_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; diff --git a/rpcs3/Emu/SysCalls/Modules/cellResc.cpp b/rpcs3/Emu/SysCalls/Modules/cellResc.cpp index c8a84b13ad..afaba51de3 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellResc.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellResc.cpp @@ -39,8 +39,8 @@ enum static const float PICTURE_SIZE = (1.0f), UV_DELTA_PS = (1.f / 8.f), - UV_DELTA_LB = (1.f / 6.f); - + UV_DELTA_LB = (1.f / 6.f), + XY_DELTA_LB = (1.f / 8.f); struct RescVertex_t { @@ -51,6 +51,7 @@ struct RescVertex_t // Defines #define roundup(x,a) (((x)+(a)-1)&(~((a)-1))) +#define SEVIRITY 80.f struct CCellRescInternal { @@ -58,12 +59,17 @@ struct CCellRescInternal CellRescSrc m_rescSrc[SRC_BUFFER_NUM]; u32 m_dstMode; CellRescDsts m_rescDsts[4], *m_pRescDsts; + CellRescTableElement m_interlaceElement; - u32 m_colorBuffersEA_addr, m_vertexArrayEA_addr, m_fragmentUcodeEA_addr; + u32 m_colorBuffersEA, m_vertexArrayEA, m_fragmentUcodeEA; + u32 m_bufIdFront; s32 m_dstWidth, m_dstHeight, m_dstPitch; u16 m_srcWidthInterlace, m_srcHeightInterlace; u32 m_dstBufInterval, m_dstOffsets[MAX_DST_BUFFER_NUM]; s32 m_nVertex; + u32 m_bufIdFrontPrevDrop, m_bufIdPalMidPrev, m_bufIdPalMidNow; + u32 m_interlaceTableEA; + int m_interlaceTableLength; float m_ratioAdjX, m_ratioAdjY; bool m_bInitialized, m_bNewlyAdjustRatio; @@ -94,6 +100,7 @@ inline bool IsPalDrop() { return (IsPal() && s_rescInternalInstance->m_in inline bool IsPalInterpolate() { return (IsPal() && ((s_rescInternalInstance->m_initConfig.palTemporalMode == CELL_RESC_PAL_60_INTERPOLATE) || (s_rescInternalInstance->m_initConfig.palTemporalMode == CELL_RESC_PAL_60_INTERPOLATE_30_DROP) || (s_rescInternalInstance->m_initConfig.palTemporalMode == CELL_RESC_PAL_60_INTERPOLATE_DROP_FLEXIBLE))); } +inline bool IsNotPalInterpolate() { return !IsPalInterpolate(); } inline int GetNumColorBuffers(){ return IsPalInterpolate() ? 6 : (IsPalDrop() ? 3 : 2); } inline bool IsInterlace() { return s_rescInternalInstance->m_initConfig.interlaceMode == CELL_RESC_INTERLACE_FILTER; } inline bool IsTextureNR() { return !IsInterlace(); } @@ -118,7 +125,7 @@ void BuildupVertexBufferNR() float U_PS0 = UV_CENTER - U_PS; float U_PS1 = UV_CENTER + U_PS; - mem_ptr_t vv(s_rescInternalInstance->m_vertexArrayEA_addr); + mem_ptr_t vv(s_rescInternalInstance->m_vertexArrayEA); if(s_rescInternalInstance->m_dstMode == CELL_RESC_720x480 || s_rescInternalInstance->m_dstMode == CELL_RESC_720x576){ switch((u32)s_rescInternalInstance->m_initConfig.ratioMode){ @@ -194,7 +201,7 @@ void BuildupVertexBufferUN(s32 srcIdx) float U2_FS1 = s_rescInternalInstance->m_dstWidth; float V2_FS1 = s_rescInternalInstance->m_dstHeight; - mem_ptr_t vv(s_rescInternalInstance->m_vertexArrayEA_addr); + mem_ptr_t vv(s_rescInternalInstance->m_vertexArrayEA); if(s_rescInternalInstance->m_dstMode == CELL_RESC_720x480 || s_rescInternalInstance->m_dstMode == CELL_RESC_720x576){ switch((u32)s_rescInternalInstance->m_initConfig.ratioMode){ @@ -360,9 +367,81 @@ bool CheckInitConfig(mem_ptr_t initConfig) void InitMembers() { + s_rescInternalInstance->m_dstMode = (CellRescBufferMode)0; + s_rescInternalInstance->m_interlaceElement = CELL_RESC_ELEMENT_FLOAT; + s_rescInternalInstance->m_colorBuffersEA = NULL; + s_rescInternalInstance->m_vertexArrayEA = NULL; + s_rescInternalInstance->m_fragmentUcodeEA = NULL; + s_rescInternalInstance->m_interlaceTableEA = NULL; + s_rescInternalInstance->m_bufIdFront = 0; + s_rescInternalInstance->m_dstWidth = 0; + s_rescInternalInstance->m_dstHeight = 0; + s_rescInternalInstance->m_dstPitch = 0; + s_rescInternalInstance->m_srcWidthInterlace = 0; + s_rescInternalInstance->m_srcHeightInterlace = 0; + s_rescInternalInstance->m_dstBufInterval = 0; + s_rescInternalInstance->m_nVertex = 0; + s_rescInternalInstance->m_ratioAdjX = 1.f; + s_rescInternalInstance->m_ratioAdjY = 1.f; + s_rescInternalInstance->m_interlaceTableLength = 32; + s_rescInternalInstance->m_bInitialized = false; + s_rescInternalInstance->m_bNewlyAdjustRatio = false; + + //E PAL related variables + //s_rescInternalInstance->m_intrThread50 = 0; + //s_rescInternalInstance->m_lastDummyFlip = 0; + //s_rescInternalInstance->m_lastVsync60 = 0; + //s_rescInternalInstance->m_lastVsync50 = 0; + s_rescInternalInstance->m_bufIdFrontPrevDrop = 2; + s_rescInternalInstance->m_bufIdPalMidPrev = 4; + s_rescInternalInstance->m_bufIdPalMidNow = 5; + //s_rescInternalInstance->m_cgpTvalue = 0; + //s_rescInternalInstance->m_isDummyFlipped = true; + s_rescInternalInstance->m_flexRatio = 0.f; // interpolate + //s_rescInternalInstance->m_commandIdxCaF = 1; + //s_rescInternalInstance->m_rcvdCmdIdx = 0; + + //s_rescInternalInstance->m_lastV60.idx = 0; + //s_rescInternalInstance->m_lastV60.time = Util::GetSystemTime(); + //s_rescInternalInstance->m_lastV50.idx = 0; + //s_rescInternalInstance->m_lastV50.time = Util::GetSystemTime(); + + //s_rescInternalInstance->m_feedback.interval60 = 1; + + for (int i = 0; im_rescSrc[i].format = 0; + s_rescInternalInstance->m_rescSrc[i].pitch = 0; + s_rescInternalInstance->m_rescSrc[i].width = 0; + s_rescInternalInstance->m_rescSrc[i].height = 0; + s_rescInternalInstance->m_rescSrc[i].offset = 0; + } + + for (int i = 0; im_dstOffsets[i] = 0; + } + + /* + for (int i = 0; im_cgParamIndex[i] = 0xFF; + } + { + s_rescInternalInstance->m_rescDsts[0].format = CELL_RESC_SURFACE_A8R8G8B8; + s_rescInternalInstance->m_rescDsts[0].pitch = GcmSysTypePrefix::cellGcmGetTiledPitchSize(720 * 4); + s_rescInternalInstance->m_rescDsts[0].heightAlign = 8; + s_rescInternalInstance->m_rescDsts[1].format = CELL_RESC_SURFACE_A8R8G8B8; + s_rescInternalInstance->m_rescDsts[1].pitch = GcmSysTypePrefix::cellGcmGetTiledPitchSize(720 * 4); + s_rescInternalInstance->m_rescDsts[1].heightAlign = 8; + s_rescInternalInstance->m_rescDsts[2].format = CELL_RESC_SURFACE_A8R8G8B8; + s_rescInternalInstance->m_rescDsts[2].pitch = GcmSysTypePrefix::cellGcmGetTiledPitchSize(1280 * 4); + s_rescInternalInstance->m_rescDsts[2].heightAlign = 8; + s_rescInternalInstance->m_rescDsts[3].format = CELL_RESC_SURFACE_A8R8G8B8; + s_rescInternalInstance->m_rescDsts[3].pitch = GcmSysTypePrefix::cellGcmGetTiledPitchSize(1920 * 4); + s_rescInternalInstance->m_rescDsts[3].heightAlign = 8; + } + */ } -void InitContext(mem_ptr_t& cntxt) +void SetupRsxRenderingStates(mem_ptr_t& cntxt) { //TODO: use cntxt GSLockCurrent lock(GS_LOCK_WAIT_FLUSH); @@ -376,14 +455,13 @@ void InitContext(mem_ptr_t& cntxt) r.m_set_cull_face = false; r.m_set_depth_bounds_test = false; r.m_set_depth_test = false; - //GcmCmdTypePrefix::cellGcmSetPolygonOffsetFillEnable(con, CELL_GCM_FALSE); + r.m_set_poly_offset_fill = false; r.m_set_stencil_test = false; r.m_set_two_sided_stencil_test_enable = false; - //GcmCmdTypePrefix::cellGcmSetPointSpriteControl(con, CELL_GCM_FALSE, 0, 0); + r.m_set_point_sprite_control = false; r.m_set_dither = true; - r.m_set_shade_mode = true; r.m_shade_mode = 0x1D01; - //GcmCmdTypePrefix::cellGcmSetFrequencyDividerOperation(con, 0); - r.m_set_specular = false; + r.m_set_shade_mode = true; r.m_shade_mode = CELL_GCM_SMOOTH; + r.m_set_frequency_divider_operation = CELL_GCM_FREQUENCY_DIVIDE; r.m_set_viewport_horizontal = r.m_set_viewport_vertical = true; r.m_viewport_x = 0; @@ -409,7 +487,7 @@ void InitContext(mem_ptr_t& cntxt) } } -void InitVertex(mem_ptr_t& cntxt) +void SetupVertexArrays(mem_ptr_t& cntxt) { GSLockCurrent lock(GS_LOCK_WAIT_FLUSH); GSRender& r = Emu.GetGSManager().GetRender(); @@ -417,6 +495,51 @@ void InitVertex(mem_ptr_t& cntxt) //TODO } +void SetupSurfaces(mem_ptr_t& cntxt) +{ + bool isMrt; + u32 dstOffset0, dstOffset1; + + if (IsNotPalInterpolate()) { + isMrt = false; + dstOffset0 = s_rescInternalInstance->m_dstOffsets[s_rescInternalInstance->m_bufIdFront]; + dstOffset1 = 0; + } + else { + isMrt = true; + dstOffset0 = s_rescInternalInstance->m_dstOffsets[s_rescInternalInstance->m_bufIdFront]; + dstOffset1 = s_rescInternalInstance->m_dstOffsets[s_rescInternalInstance->m_bufIdPalMidNow]; + } + + GSLockCurrent lock(GS_LOCK_WAIT_FLUSH); + GSRender& r = Emu.GetGSManager().GetRender(); + + r.m_surface_type = CELL_GCM_SURFACE_PITCH; + r.m_surface_antialias = CELL_GCM_SURFACE_CENTER_1; + r.m_surface_color_format = (u8)s_rescInternalInstance->m_pRescDsts->format; + r.m_surface_colour_target = (!isMrt) ? CELL_GCM_SURFACE_TARGET_0 : CELL_GCM_SURFACE_TARGET_MRT1; + //surface.colorLocation[0] = CELL_GCM_LOCATION_LOCAL; + r.m_surface_offset_a = dstOffset0; + r.m_surface_pitch_a = s_rescInternalInstance->m_dstPitch; + //surface.colorLocation[1] = CELL_GCM_LOCATION_LOCAL; + r.m_surface_offset_b = (!isMrt) ? 0 : dstOffset1; + r.m_surface_pitch_b = (!isMrt) ? 64 : s_rescInternalInstance->m_dstPitch; + //surface.colorLocation[2] = CELL_GCM_LOCATION_LOCAL; + r.m_surface_offset_c = 0; + r.m_surface_pitch_c = 64; + //surface.colorLocation[3] = CELL_GCM_LOCATION_LOCAL; + r.m_surface_offset_d = 0; + r.m_surface_pitch_d = 64; + r.m_surface_depth_format = CELL_GCM_SURFACE_Z24S8; + //surface.depthLocation = CELL_GCM_LOCATION_LOCAL; + r.m_surface_offset_z = 0; + r.m_surface_pitch_z = 64; + r.m_surface_width = s_rescInternalInstance->m_dstWidth; + r.m_surface_height = s_rescInternalInstance->m_dstHeight; + //surface.x = 0; + //surface.y = 0; +} + // Module Functions int cellRescInit(mem_ptr_t initConfig) { @@ -616,7 +739,7 @@ int cellRescAdjustAspectRatio(float horizontal, float vertical) s_rescInternalInstance->m_ratioAdjX = horizontal; s_rescInternalInstance->m_ratioAdjY = vertical; - if(s_rescInternalInstance->m_vertexArrayEA_addr) + if(s_rescInternalInstance->m_vertexArrayEA) { if(IsTextureNR()) BuildupVertexBufferNR(); @@ -789,8 +912,14 @@ int cellRescSetConvertAndFlip(mem_ptr_t cntxt, s32 idx) if(!IsTextureNR()) BuildupVertexBufferUN(idx); - InitContext(cntxt); - InitVertex(cntxt); + // Setup GPU internal status + SetupRsxRenderingStates(cntxt); + + // Setup vertex array pointers + SetupVertexArrays(cntxt); + + // Setup surface + SetupSurfaces(cntxt); //TODO: ? @@ -831,12 +960,12 @@ int cellRescSetBufferAddress(mem32_t colorBuffers, mem32_t vertexArray, mem32_t return CELL_RESC_ERROR_BAD_ARGUMENT; } - s_rescInternalInstance->m_colorBuffersEA_addr = colorBuffers.GetAddr(); - s_rescInternalInstance->m_vertexArrayEA_addr = vertexArray.GetAddr(); - s_rescInternalInstance->m_fragmentUcodeEA_addr = fragmentShader.GetAddr(); + s_rescInternalInstance->m_colorBuffersEA = colorBuffers.GetAddr(); + s_rescInternalInstance->m_vertexArrayEA = vertexArray.GetAddr(); + s_rescInternalInstance->m_fragmentUcodeEA = fragmentShader.GetAddr(); MemoryAllocator> dstOffset; - cellGcmAddressToOffset(s_rescInternalInstance->m_colorBuffersEA_addr, dstOffset.GetAddr()); + cellGcmAddressToOffset(s_rescInternalInstance->m_colorBuffersEA, dstOffset.GetAddr()); for(int i=0; i> 23) - 127 + 15; + if (e < 0) + { + return 0; + } + else if (e > 31) + { + e = 31; + } + u32 s = bits & 0x80000000; + u32 m = bits & 0x007fffff; + + return ((s >> 16) & 0x8000) | ((e << 10) & 0x7c00) | ((m >> 13) & 0x03ff); +} + +static void blackman(float window[]) +{ + const float x0 = ((1.f * 2.f*M_PI) / 5.f) - M_PI; + const float x1 = ((2.f * 2.f*M_PI) / 5.f) - M_PI; + const float x2 = ((3.f * 2.f*M_PI) / 5.f) - M_PI; + const float x3 = ((4.f * 2.f*M_PI) / 5.f) - M_PI; + + const float a0 = 0.42f + (0.50f * cosf(x0)) + (0.08f * cosf(2.f*x0)); + const float a1 = 0.42f + (0.50f * cosf(x1)) + (0.08f * cosf(2.f*x1)); + const float a2 = 0.42f + (0.50f * cosf(x2)) + (0.08f * cosf(2.f*x2)); + const float a3 = 0.42f + (0.50f * cosf(x3)) + (0.08f * cosf(2.f*x3)); + + window[0] = ((100.f - SEVIRITY) / 100.f + SEVIRITY / 100.f*a0); + window[1] = ((100.f - SEVIRITY) / 100.f + SEVIRITY / 100.f*a1); + window[2] = ((100.f - SEVIRITY) / 100.f + SEVIRITY / 100.f*a2); + window[3] = ((100.f - SEVIRITY) / 100.f + SEVIRITY / 100.f*a3); +} + +int CreateInterlaceTable(mem32_t ea, float srcH, float dstH, CellRescTableElement depth, int length) +{ + float phi[4], transient[4], *buf32 = (float*)ea.GetAddr(); + float y_fraction; + float bandwidth = 0.5f / (srcH / dstH); + float phi_b = 2.f * M_PI * bandwidth; + float window[4]; + u16 *buf16 = (u16*)ea.GetAddr(); + + blackman(window); + + for (int i = 0; i 1E-10) ? (sinf(phi[0]) / phi[0] * window[0]) : window[0]; + transient[1] = (fabsf(phi[1]) > 1E-10) ? (sinf(phi[1]) / phi[1] * window[1]) : window[1]; + transient[2] = (fabsf(phi[2]) > 1E-10) ? (sinf(phi[2]) / phi[2] * window[2]) : window[2]; + transient[3] = (fabsf(phi[3]) > 1E-10) ? (sinf(phi[3]) / phi[3] * window[3]) : window[3]; + + float total4 = transient[0] + transient[1] + transient[2] + transient[3]; + + if (depth == CELL_RESC_ELEMENT_HALF) + { + buf16[0] = FloatToHalf(transient[0] / total4); + buf16[1] = FloatToHalf(transient[1] / total4); + buf16[2] = FloatToHalf(transient[2] / total4); + buf16[3] = FloatToHalf(transient[3] / total4); + buf16 += 4; + } + else { + buf32[0] = transient[0] / total4; + buf32[1] = transient[1] / total4; + buf32[2] = transient[2] / total4; + buf32[3] = transient[3] / total4; + buf32 += 4; + } + } return CELL_OK; } +int cellRescCreateInterlaceTable(mem32_t ea, float srcH, CellRescTableElement depth, int length) +{ + cellResc->Warning("cellRescCreateInterlaceTable(ea=0x%x, depth = %i, length = %i)", ea.GetAddr(), depth, length); + + if (!s_rescInternalInstance->m_bInitialized) + { + cellResc->Error("cellRescCreateInterlaceTable : CELL_RESC_ERROR_NOT_INITIALIZED"); + return CELL_RESC_ERROR_NOT_INITIALIZED; + } + + if ((!ea.IsGood()) || (srcH <= 0.f) || (!(depth == CELL_RESC_ELEMENT_HALF || depth == CELL_RESC_ELEMENT_FLOAT)) || (length <= 0)) + { + cellResc->Error("cellRescCreateInterlaceTable : CELL_RESC_ERROR_NOT_INITIALIZED"); + return CELL_RESC_ERROR_BAD_ARGUMENT; + } + + if (s_rescInternalInstance->m_dstHeight == 0) + { + cellResc->Error("cellRescCreateInterlaceTable : CELL_RESC_ERROR_BAD_COMBINATION"); + return CELL_RESC_ERROR_BAD_COMBINATION; + } + + float ratioModeCoefficient = (s_rescInternalInstance->m_initConfig.ratioMode != CELL_RESC_LETTERBOX) ? 1.f : (1.f - 2.f * XY_DELTA_LB); + float dstH = s_rescInternalInstance->m_dstHeight * ratioModeCoefficient * s_rescInternalInstance->m_ratioAdjY; + + if (int retValue = CreateInterlaceTable(ea, srcH, dstH, depth, length) == CELL_OK) + { + s_rescInternalInstance->m_interlaceTableEA = ea; + s_rescInternalInstance->m_interlaceElement = depth; + s_rescInternalInstance->m_interlaceTableLength = length; + return CELL_OK; + } + else + { + return retValue; + } +} + void cellResc_init() {