diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 991f63ec35..1d3e6144e0 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -137,23 +137,42 @@ std::vector fmt::split(const std::string& source, std::initializer_ std::string fmt::merge(std::vector source, const std::string& separator) { - std::string result; - - for (auto &s : source) + if (!source.size()) { - result += s + separator; + return ""; } - return result; + std::string result; + + for (int i = 0; i < source.size() - 1; ++i) + { + result += source[i] + separator; + } + + return result + source[source.size() - 1]; } std::string fmt::merge(std::initializer_list> sources, const std::string& separator) { + if (!sources.size()) + { + return ""; + } + std::string result; + bool first = true; for (auto &v : sources) { - result += fmt::merge(v, separator); + if (first) + { + result = fmt::merge(v, separator); + first = false; + } + else + { + result += separator + fmt::merge(v, separator); + } } return result; @@ -164,4 +183,4 @@ std::string fmt::tolower(std::string source) std::transform(source.begin(), source.end(), source.begin(), ::tolower); return source; -} \ No newline at end of file +} diff --git a/asmjit b/asmjit index 1318c9aff7..48da90ded7 160000 --- a/asmjit +++ b/asmjit @@ -1 +1 @@ -Subproject commit 1318c9aff7137b30aec7dee2ababb2b313ae0f06 +Subproject commit 48da90ded775fa2ba0fd3f15522890ad631ad6de diff --git a/ffmpeg b/ffmpeg index 352fdfbbfa..79a2d7a9f7 160000 --- a/ffmpeg +++ b/ffmpeg @@ -1 +1 @@ -Subproject commit 352fdfbbfa6d7b26142f00b43d7e1802a03c68a8 +Subproject commit 79a2d7a9f780ad27d1622010cb1cb8396c3701e9 diff --git a/rpcs3/Crypto/unpkg.cpp b/rpcs3/Crypto/unpkg.cpp index 39f4bf99a8..5d7846046f 100644 --- a/rpcs3/Crypto/unpkg.cpp +++ b/rpcs3/Crypto/unpkg.cpp @@ -43,13 +43,13 @@ bool CheckHeader(rFile& pkg_f, PKGHeader* m_header) } if (m_header->pkg_size != pkg_f.Length()) { - LOG_ERROR(LOADER, "PKG: File size mismatch."); - return false; + LOG_WARNING(LOADER, "PKG: File size mismatch."); + //return false; } if (m_header->data_size + m_header->data_offset + 0x60 != pkg_f.Length()) { - LOG_ERROR(LOADER, "PKG: Data size mismatch."); - return false; + LOG_WARNING(LOADER, "PKG: Data size mismatch."); + //return false; } return true; diff --git a/rpcs3/Emu/Audio/cellAudio.h b/rpcs3/Emu/Audio/cellAudio.h index ff6e463065..b448dcfe16 100644 --- a/rpcs3/Emu/Audio/cellAudio.h +++ b/rpcs3/Emu/Audio/cellAudio.h @@ -82,6 +82,8 @@ struct AudioPortConfig u64 attr; u64 tag; u64 counter; // copy of global counter + u32 addr; + u32 read_index_addr; }; struct AudioConfig //custom structure diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp index 2ee3133bf0..493d1896cc 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ b/rpcs3/Emu/CPU/CPUThreadManager.cpp @@ -133,7 +133,7 @@ void CPUThreadManager::Exec() { std::lock_guard lock(m_mtx_thread); - for(u32 i=0; iExec(); } diff --git a/rpcs3/Emu/Cell/SPURecompilerCore.cpp b/rpcs3/Emu/Cell/SPURecompilerCore.cpp index c5edf35a7b..8d733bd8b4 100644 --- a/rpcs3/Emu/Cell/SPURecompilerCore.cpp +++ b/rpcs3/Emu/Cell/SPURecompilerCore.cpp @@ -25,7 +25,7 @@ SPURecompilerCore::SPURecompilerCore(SPUThread& cpu) memset(entry, 0, sizeof(entry)); X86CpuInfo inf; X86CpuUtil::detect(&inf); - if (!inf.hasFeature(kX86CpuFeatureSse41)) + if (!inf.hasFeature(kX86CpuFeatureSSE4_1)) { LOG_ERROR(SPU, "SPU JIT requires SSE4.1 instruction set support"); Emu.Pause(); diff --git a/rpcs3/Emu/FS/VFS.cpp b/rpcs3/Emu/FS/VFS.cpp index d963d9c91f..01489759a6 100644 --- a/rpcs3/Emu/FS/VFS.cpp +++ b/rpcs3/Emu/FS/VFS.cpp @@ -32,21 +32,12 @@ std::string simplify_path(const std::string& path, bool is_dir) { std::vector path_blocks = simplify_path_blocks(path); - std::string result; - if (path_blocks.empty()) - return result; + return ""; - if (is_dir) - { - result = fmt::merge(path_blocks, "/"); - } - else - { - result = fmt::merge(std::vector(path_blocks.begin(), path_blocks.end() - 1), "/") + path_blocks[path_blocks.size() - 1]; - } + std::string result = fmt::merge(path_blocks, "/"); - return result; + return is_dir ? result + "/" : result; } VFS::~VFS() diff --git a/rpcs3/Emu/FS/vfsLocalFile.cpp b/rpcs3/Emu/FS/vfsLocalFile.cpp index aea1e02e0c..0e716c40af 100644 --- a/rpcs3/Emu/FS/vfsLocalFile.cpp +++ b/rpcs3/Emu/FS/vfsLocalFile.cpp @@ -75,7 +75,12 @@ bool vfsLocalFile::Create(const std::string& path) if(m != '/' && m != '\\' && !rExists(path)) // ??? { rFile f; - return f.Create(path); + if (!f.Create(path)) { + LOG_NOTICE(HLE, "vfsLocalFile::Create: couldn't create file"); + return false; + } + else + return true; } return true; diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index f72d5f9350..984aa82eee 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -6,9 +6,9 @@ void GLFragmentDecompilerThread::SetDst(std::string code, bool append_mask) { - if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return; + if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return; - switch(src1.scale) + switch (src1.scale) { case 0: break; case 1: code = "(" + code + " * 2.0)"; break; @@ -21,27 +21,39 @@ void GLFragmentDecompilerThread::SetDst(std::string code, bool append_mask) default: LOG_ERROR(RSX, "Bad scale: %d", fmt::by_value(src1.scale)); Emu.Pause(); - break; + break; } - if(dst.saturate) + if (dst.saturate) { code = "clamp(" + code + ", 0.0, 1.0)"; } - std::string dest; + code += (append_mask ? "$m" : ""); + + if (dst.no_dest) + { + if (dst.set_cond) + { + AddCode("$ifcond " + m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + code + ";"); + } + else + { + AddCode("$ifcond " + code + ";"); + } + + return; + } + + std::string dest = AddReg(dst.dest_reg, dst.fp16) + "$m"; + + AddCodeCond(Format(dest), code); + //AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";")); if (dst.set_cond) { - dest += m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = "; + AddCode(m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + dest + ";"); } - - if (!dst.no_dest) - { - dest += AddReg(dst.dest_reg, dst.fp16) + "$m = "; - } - - AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";")); } void GLFragmentDecompilerThread::AddCode(const std::string& code) @@ -58,17 +70,17 @@ std::string GLFragmentDecompilerThread::GetMask() 'x', 'y', 'z', 'w', }; - if(dst.mask_x) ret += dst_mask[0]; - if(dst.mask_y) ret += dst_mask[1]; - if(dst.mask_z) ret += dst_mask[2]; - if(dst.mask_w) ret += dst_mask[3]; + if (dst.mask_x) ret += dst_mask[0]; + if (dst.mask_y) ret += dst_mask[1]; + if (dst.mask_z) ret += dst_mask[2]; + if (dst.mask_w) ret += dst_mask[3]; return ret.empty() || strncmp(ret.c_str(), dst_mask, 4) == 0 ? "" : ("." + ret); } std::string GLFragmentDecompilerThread::AddReg(u32 index, int fp16) { - return m_parr.AddParam(PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), "vec4(0.0, 0.0, 0.0, 0.0)"); + return m_parr.AddParam(PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), "vec4(0.0)"); } bool GLFragmentDecompilerThread::HasReg(u32 index, int fp16) @@ -79,13 +91,13 @@ bool GLFragmentDecompilerThread::HasReg(u32 index, int fp16) std::string GLFragmentDecompilerThread::AddCond() { - return m_parr.AddParam(PARAM_NONE , "vec4", "cc" + std::to_string(src0.cond_reg_index)); + return m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_reg_index)); } std::string GLFragmentDecompilerThread::AddConst() { std::string name = std::string("fc") + std::to_string(m_size + 4 * 4); - if(m_parr.HasParam(PARAM_UNIFORM, "vec4", name)) + if (m_parr.HasParam(PARAM_UNIFORM, "vec4", name)) { return name; } @@ -118,11 +130,11 @@ std::string GLFragmentDecompilerThread::Format(const std::string& code) { "$t", std::bind(std::mem_fn(&GLFragmentDecompilerThread::AddTex), this) }, { "$m", std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetMask), this) }, { "$ifcond ", [this]() -> std::string - { - const std::string& cond = GetCond(); - if (cond == "true") return ""; - return "if(" + cond + ") "; - } + { + const std::string& cond = GetCond(); + if (cond == "true") return ""; + return "if(" + cond + ") "; + } }, { "$cond", std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetCond), this) }, { "$c", std::bind(std::mem_fn(&GLFragmentDecompilerThread::AddConst), this) } @@ -179,15 +191,83 @@ std::string GLFragmentDecompilerThread::GetCond() return "any(" + cond + "(" + AddCond() + swizzle + ", vec4(0.0)))"; } +void GLFragmentDecompilerThread::AddCodeCond(const std::string& dst, const std::string& src) +{ + if (src0.exec_if_gr && src0.exec_if_lt && src0.exec_if_eq) + { + AddCode(dst + " = " + src + ";"); + return; + } + + if (!src0.exec_if_gr && !src0.exec_if_lt && !src0.exec_if_eq) + { + AddCode("//" + dst + " = " + src + ";"); + return; + } + + static const char f[4] = { 'x', 'y', 'z', 'w' }; + + std::string swizzle, cond; + swizzle += f[src0.cond_swizzle_x]; + swizzle += f[src0.cond_swizzle_y]; + swizzle += f[src0.cond_swizzle_z]; + swizzle += f[src0.cond_swizzle_w]; + swizzle = swizzle == "xyzw" ? "" : "." + swizzle; + + if (src0.exec_if_gr && src0.exec_if_eq) + { + cond = "greaterThanEqual"; + } + else if (src0.exec_if_lt && src0.exec_if_eq) + { + cond = "lessThanEqual"; + } + else if (src0.exec_if_gr && src0.exec_if_lt) + { + cond = "notEqual"; + } + else if (src0.exec_if_gr) + { + cond = "greaterThan"; + } + else if (src0.exec_if_lt) + { + cond = "lessThan"; + } + else //if(src0.exec_if_eq) + { + cond = "equal"; + } + + cond = cond + "(" + AddCond() + swizzle + ", vec4(0.0))"; + + ShaderVar dst_var(dst); + dst_var.symplify(); + + //const char *c_mask = f; + + if (dst_var.swizzles[0].length() == 1) + { + AddCode("if (" + cond + ".x) " + dst + " = vec4(" + src + ").x;"); + } + else + { + for (int i = 0; i < dst_var.swizzles[0].length(); ++i) + { + AddCode("if (" + cond + "." + f[i] + ") " + dst + "." + f[i] + " = " + src + "." + f[i] + ";"); + } + } +} + template std::string GLFragmentDecompilerThread::GetSRC(T src) { std::string ret; - switch(src.reg_type) + switch (src.reg_type) { case 0: //tmp ret += AddReg(src.tmp_reg_index, src.fp16); - break; + break; case 1: //input { @@ -200,11 +280,11 @@ template std::string GLFragmentDecompilerThread::GetSRC(T src) "ssa" }; - switch(dst.src_attr_reg_num) + switch (dst.src_attr_reg_num) { case 0x00: ret += reg_table[0]; break; default: - if(dst.src_attr_reg_num < sizeof(reg_table)/sizeof(reg_table[0])) + if (dst.src_attr_reg_num < sizeof(reg_table) / sizeof(reg_table[0])) { ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[dst.src_attr_reg_num]); } @@ -214,22 +294,22 @@ template std::string GLFragmentDecompilerThread::GetSRC(T src) ret += m_parr.AddParam(PARAM_IN, "vec4", "unk"); Emu.Pause(); } - break; + break; } } break; case 2: //const ret += AddConst(); - break; + break; default: LOG_ERROR(RSX, "Bad src type %d", fmt::by_value(src.reg_type)); Emu.Pause(); - break; + break; } - static const char f[4] = {'x', 'y', 'z', 'w'}; + static const char f[4] = { 'x', 'y', 'z', 'w' }; std::string swizzle = ""; swizzle += f[src.swizzle_x]; @@ -237,10 +317,10 @@ template std::string GLFragmentDecompilerThread::GetSRC(T src) swizzle += f[src.swizzle_z]; swizzle += f[src.swizzle_w]; - if(strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle; + if (strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle; - if(src.abs) ret = "abs(" + ret + ")"; - if(src.neg) ret = "-" + ret; + if (src.abs) ret = "abs(" + ret + ")"; + if (src.neg) ret = "-" + ret; return ret; } @@ -251,10 +331,9 @@ std::string GLFragmentDecompilerThread::BuildCode() const std::pair table[] = { { "ocol0", m_ctrl & 0x40 ? "r0" : "h0" }, - { "ocol1", m_ctrl & 0x40 ? "r2" : "h2" }, - { "ocol2", m_ctrl & 0x40 ? "r3" : "h4" }, - { "ocol3", m_ctrl & 0x40 ? "r4" : "h6" }, - { "ocol4", m_ctrl & 0x40 ? "r5" : "h8" }, + { "ocol1", m_ctrl & 0x40 ? "r2" : "h4" }, + { "ocol2", m_ctrl & 0x40 ? "r3" : "h6" }, + { "ocol3", m_ctrl & 0x40 ? "r4" : "h8" }, }; for (int i = 0; i < sizeof(table) / sizeof(*table); ++i) @@ -263,7 +342,7 @@ std::string GLFragmentDecompilerThread::BuildCode() AddCode(m_parr.AddParam(PARAM_OUT, "vec4", table[i].first, i) + " = " + table[i].second + ";"); } - if (m_ctrl & 0xe) main += "\tgl_FragDepth = r1.z;\n"; + if (m_ctrl & 0xe) main += m_ctrl & 0x40 ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h2.z;\n"; std::string p; @@ -285,7 +364,16 @@ void GLFragmentDecompilerThread::Task() m_loop_count = 0; m_code_level = 1; - while(true) + enum + { + FORCE_NONE, + FORCE_SCT, + FORCE_SCB, + }; + + int forced_unit = FORCE_NONE; + + while (true) { for (auto finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size); finded != m_end_offsets.end(); @@ -318,164 +406,195 @@ void GLFragmentDecompilerThread::Task() const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6); - switch(opcode) + auto SCT = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break; + case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); break; + case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1))"); break; + case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break; + case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break; + case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break; + case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break; + case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break; + case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break; + case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break; + case RSX_FP_OPCODE_MOV: SetDst("$0"); break; + case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break; + case RSX_FP_OPCODE_RCP: SetDst("1 / $0"); break; + case RSX_FP_OPCODE_RSQ: SetDst("inversesqrt(abs($0))"); break; + case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break; + case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break; + case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break; + case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break; + case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break; + case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break; + + default: + return false; + } + + return true; + }; + + auto SCB = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break; + case RSX_FP_OPCODE_COS: SetDst("cos($0)"); break; + case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break; + case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break; + case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break; + case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break; + case RSX_FP_OPCODE_DST: SetDst("vec4(distance($0, $1))"); break; + case RSX_FP_OPCODE_EX2: SetDst("exp2($0)"); break; + case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); break; + case RSX_FP_OPCODE_FRC: SetDst("fract($0)"); break; + case RSX_FP_OPCODE_LIF: SetDst("vec4(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); break; + case RSX_FP_OPCODE_LG2: SetDst("log2($0)"); break; + case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break; + case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break; + case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break; + case RSX_FP_OPCODE_MOV: SetDst("$0"); break; + case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break; + case RSX_FP_OPCODE_PK2: LOG_ERROR(RSX, "Unimplemented SCB instruction: PK2"); break; + case RSX_FP_OPCODE_PK4: LOG_ERROR(RSX, "Unimplemented SCB instruction: PK4"); break; + case RSX_FP_OPCODE_PK16: LOG_ERROR(RSX, "Unimplemented SCB instruction: PK16"); break; + case RSX_FP_OPCODE_PKB: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKB"); break; + case RSX_FP_OPCODE_PKG: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKG"); break; + case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break; + case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break; + case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break; + case RSX_FP_OPCODE_SIN: SetDst("sin($0)"); break; + case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break; + case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break; + case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break; + + default: + return false; + } + + return true; + }; + + auto TEX_SRB = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_DDX: SetDst("dFdx($0)"); break; + case RSX_FP_OPCODE_DDY: SetDst("dFdy($0)"); break; + case RSX_FP_OPCODE_NRM: SetDst("normalize($0)"); break; + case RSX_FP_OPCODE_TEX: SetDst("texture($t, $0.xy)"); break; + case RSX_FP_OPCODE_TXP: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXP"); break; + case RSX_FP_OPCODE_TXD: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXD"); break; + case RSX_FP_OPCODE_TXB: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXB"); break; + case RSX_FP_OPCODE_TXL: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXL"); break; + case RSX_FP_OPCODE_UP2: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UP2"); break; + case RSX_FP_OPCODE_UP4: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UP4"); break; + case RSX_FP_OPCODE_UP16: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UP16"); break; + case RSX_FP_OPCODE_UPB: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPB"); break; + case RSX_FP_OPCODE_UPG: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPG"); break; + + default: + return false; + } + + return true; + }; + + auto SIP = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_BRK: SetDst("break"); break; + case RSX_FP_OPCODE_CAL: LOG_ERROR(RSX, "Unimplemented SIP instruction: CAL"); break; + case RSX_FP_OPCODE_FENCT: forced_unit = FORCE_SCT; break; + case RSX_FP_OPCODE_FENCB: forced_unit = FORCE_SCB; break; + case RSX_FP_OPCODE_IFE: + AddCode("if($cond)"); + m_else_offsets.push_back(src1.else_offset << 2); + m_end_offsets.push_back(src2.end_offset << 2); + AddCode("{"); + m_code_level++; + break; + case RSX_FP_OPCODE_LOOP: + if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) + { + AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); + } + else + { + AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); + m_loop_count++; + m_end_offsets.push_back(src2.end_offset << 2); + AddCode("{"); + m_code_level++; + } + break; + case RSX_FP_OPCODE_REP: + if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) + { + AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); + } + else + { + AddCode(fmt::Format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); + m_loop_count++; + m_end_offsets.push_back(src2.end_offset << 2); + AddCode("{"); + m_code_level++; + } + break; + case RSX_FP_OPCODE_RET: SetDst("return"); break; + + default: + return false; + } + + return true; + }; + + switch (opcode) { case RSX_FP_OPCODE_NOP: break; - case RSX_FP_OPCODE_MOV: SetDst("$0"); break; - case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break; - case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break; - case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break; - case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break; - case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break; - case RSX_FP_OPCODE_DST: SetDst("vec4(distance($0, $1))"); break; - case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break; - case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break; - case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break; - case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break; - case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break; - case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break; - case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break; - case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break; - case RSX_FP_OPCODE_FRC: SetDst("fract($0)"); break; - case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); break; case RSX_FP_OPCODE_KIL: SetDst("discard", false); break; - case RSX_FP_OPCODE_PK4: - LOG_ERROR(RSX, "Unimplemented fp_opcode PK4"); - break; - case RSX_FP_OPCODE_UP4: - LOG_ERROR(RSX, "Unimplemented fp_opcode UP4"); - break; - case RSX_FP_OPCODE_DDX: SetDst("dFdx($0)"); break; - case RSX_FP_OPCODE_DDY: SetDst("dFdy($0)"); break; - case RSX_FP_OPCODE_TEX: SetDst("texture($t, $0.xy)"); break; - case RSX_FP_OPCODE_TXP: - LOG_ERROR(RSX, "Unimplemented fp_opcode TXP"); - break; - case RSX_FP_OPCODE_TXD: - LOG_ERROR(RSX, "Unimplemented fp_opcode TXD"); - break; - case RSX_FP_OPCODE_RCP: SetDst("(1 / $0)"); break; - case RSX_FP_OPCODE_RSQ: SetDst("inversesqrt(abs($0))"); break; - case RSX_FP_OPCODE_EX2: SetDst("exp2($0)"); break; - case RSX_FP_OPCODE_LG2: SetDst("log2($0)"); break; - case RSX_FP_OPCODE_LIT: SetDst("vec4(1.0, $0.x, ($0.x > 0 ? exp2($0.w * log2($0.y)) : 0.0), 1.0)"); break; - case RSX_FP_OPCODE_LRP: SetDst("($0 * ($1 - $2) + $2)"); break; - case RSX_FP_OPCODE_STR: SetDst("vec4(equal($0, vec4(1.0)))"); break; - case RSX_FP_OPCODE_SFL: SetDst("vec4(equal($0, vec4(0.0)))"); break; - case RSX_FP_OPCODE_COS: SetDst("cos($0)"); break; - case RSX_FP_OPCODE_SIN: SetDst("sin($0)"); break; - case RSX_FP_OPCODE_PK2: - LOG_ERROR(RSX, "Unimplemented fp_opcode PK2"); - break; - case RSX_FP_OPCODE_UP2: - LOG_ERROR(RSX, "Unimplemented fp_opcode UP2"); - break; - case RSX_FP_OPCODE_POW: SetDst("pow($0, $1)"); break; - case RSX_FP_OPCODE_PKB: - LOG_ERROR(RSX, "Unimplemented fp_opcode PKB"); - break; - case RSX_FP_OPCODE_UPB: - LOG_ERROR(RSX, "Unimplemented fp_opcode UPB"); - break; - case RSX_FP_OPCODE_PK16: - LOG_ERROR(RSX, "Unimplemented fp_opcode PK16"); - break; - case RSX_FP_OPCODE_UP16: - LOG_ERROR(RSX, "Unimplemented fp_opcode UP16"); - break; - case RSX_FP_OPCODE_BEM: - LOG_ERROR(RSX, "Unimplemented fp_opcode BEM"); - break; - case RSX_FP_OPCODE_PKG: - LOG_ERROR(RSX, "Unimplemented fp_opcode PKG"); - break; - case RSX_FP_OPCODE_UPG: - LOG_ERROR(RSX, "Unimplemented fp_opcode UPG"); - break; - case RSX_FP_OPCODE_DP2A: SetDst("($0.x * $1.x + $0.y * $1.y + $2.x)"); break; - case RSX_FP_OPCODE_TXL: break; - LOG_ERROR(RSX, "Unimplemented fp_opcode TXL"); - break; - case RSX_FP_OPCODE_TXB: break; - LOG_ERROR(RSX, "Unimplemented fp_opcode TXB"); - break; - case RSX_FP_OPCODE_TEXBEM: - LOG_ERROR(RSX, "Unimplemented fp_opcode TEXBEM"); - break; - case RSX_FP_OPCODE_TXPBEM: - LOG_ERROR(RSX, "Unimplemented fp_opcode TXPBEM"); - break; - case RSX_FP_OPCODE_BEMLUM: - LOG_ERROR(RSX, "Unimplemented fp_opcode BEMLUM"); - break; - case RSX_FP_OPCODE_REFL: SetDst("($0 - 2.0 * $1 * dot($0, $1))"); break; - case RSX_FP_OPCODE_TIMESWTEX: - LOG_ERROR(RSX, "Unimplemented fp_opcode TIMESWTEX"); - break; - case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break; - case RSX_FP_OPCODE_NRM: SetDst("normalize($0.xyz)"); break; - case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); break; - case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1))"); break; - case RSX_FP_OPCODE_LIF: SetDst("vec4(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); break; - case RSX_FP_OPCODE_FENCT: break; - case RSX_FP_OPCODE_FENCB: break; - case RSX_FP_OPCODE_BRK: SetDst("break"); break; - case RSX_FP_OPCODE_CAL: - LOG_ERROR(RSX, "Unimplemented fp_opcode CAL"); - break; - case RSX_FP_OPCODE_IFE: - AddCode("if($cond)"); - m_else_offsets.push_back(src1.else_offset << 2); - m_end_offsets.push_back(src2.end_offset << 2); - AddCode("{"); - m_code_level++; - break; - - case RSX_FP_OPCODE_LOOP: - if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) - { - AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); - } - else - { - AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); - m_loop_count++; - m_end_offsets.push_back(src2.end_offset << 2); - AddCode("{"); - m_code_level++; - } - break; - case RSX_FP_OPCODE_REP: - if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) - { - AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); - } - else - { - AddCode(fmt::Format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); - m_loop_count++; - m_end_offsets.push_back(src2.end_offset << 2); - AddCode("{"); - m_code_level++; - } - break; - case RSX_FP_OPCODE_RET: - SetDst("return"); - break; default: - LOG_ERROR(RSX, "Unknown fp opcode 0x%x (inst %d)", opcode, m_size / (4 * 4)); - Emu.Pause(); - break; + if (forced_unit == FORCE_NONE) + { + if (SIP()) break; + if (SCT()) break; + if (TEX_SRB()) break; + if (SCB()) break; + } + else if (forced_unit == FORCE_SCT) + { + forced_unit = FORCE_NONE; + if (SCT()) break; + } + else if (forced_unit == FORCE_SCB) + { + forced_unit = FORCE_NONE; + if (SCB()) break; + } + + LOG_ERROR(RSX, "Unknown/illegal instruction: 0x%x (forced unit %d)", opcode, forced_unit); + break; } m_size += m_offset; - if(dst.end) break; + if (dst.end) break; assert(m_offset % sizeof(u32) == 0); data += m_offset / sizeof(u32); @@ -488,7 +607,7 @@ void GLFragmentDecompilerThread::Task() m_parr.params.clear(); } -GLShaderProgram::GLShaderProgram() +GLShaderProgram::GLShaderProgram() : m_decompiler_thread(nullptr) , m_id(0) { @@ -496,14 +615,14 @@ GLShaderProgram::GLShaderProgram() GLShaderProgram::~GLShaderProgram() { - if(m_decompiler_thread) + if (m_decompiler_thread) { Wait(); - if(m_decompiler_thread->IsAlive()) + if (m_decompiler_thread->IsAlive()) { m_decompiler_thread->Stop(); } - + delete m_decompiler_thread; m_decompiler_thread = nullptr; } @@ -513,7 +632,7 @@ GLShaderProgram::~GLShaderProgram() void GLShaderProgram::Wait() { - if(m_decompiler_thread && m_decompiler_thread->IsAlive()) + if (m_decompiler_thread && m_decompiler_thread->IsAlive()) { m_decompiler_thread->Join(); } @@ -527,14 +646,14 @@ void GLShaderProgram::Decompile(RSXShaderProgram& prog) void GLShaderProgram::DecompileAsync(RSXShaderProgram& prog) { - if(m_decompiler_thread) + if (m_decompiler_thread) { Wait(); - if(m_decompiler_thread->IsAlive()) + if (m_decompiler_thread->IsAlive()) { m_decompiler_thread->Stop(); } - + delete m_decompiler_thread; m_decompiler_thread = nullptr; } diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h index f05dfc30e0..9666035d07 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h @@ -155,6 +155,7 @@ struct GLFragmentDecompilerThread : public ThreadBase std::string AddTex(); std::string Format(const std::string& code); + void AddCodeCond(const std::string& dst, const std::string& src); std::string GetCond(); template std::string GetSRC(T src); std::string BuildCode(); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 9e9fdd70de..a2c202f0c8 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -425,7 +425,7 @@ void GLTexture::Init(RSXTexture& tex) free(unswizzledPixels); } - break; break; + break; case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN): { @@ -450,7 +450,7 @@ void GLTexture::Init(RSXTexture& tex) free(unswizzledPixels); } - break; break; + break; default: LOG_ERROR(RSX, "Init tex error: Bad tex format (0x%x | %s | 0x%x)", format, (is_swizzled ? "swizzled" : "linear"), tex.GetFormat() & 0x40); @@ -984,7 +984,7 @@ void GLGSRender::EnableVertexData(bool indexed_draw) LOG_ERROR(RSX, "GLGSRender::EnableVertexData: Bad vertex data type (%d)!", m_vertex_data[i].type); } - if(0 && !m_vertex_data[i].addr) + if(!m_vertex_data[i].addr) { switch(m_vertex_data[i].type) { @@ -1647,6 +1647,21 @@ void GLGSRender::InitDrawBuffers() LOG_ERROR(RSX, "Bad surface color target: %d", m_surface_color_target); break; } + + if (m_read_buffer) + { + u32 format = GL_BGRA; + CellGcmDisplayInfo* buffers = vm::get_ptr(m_gcm_buffers_addr); + u32 addr = GetAddress(buffers[m_gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL); + + if (Memory.IsGoodAddr(addr)) + { + u32 width = buffers[m_gcm_current_buffer].width; + u32 height = buffers[m_gcm_current_buffer].height; + + glDrawPixels(width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, vm::get_ptr(addr)); + } + } } void GLGSRender::ExecCMD(u32 cmd) @@ -1721,24 +1736,6 @@ void GLGSRender::ExecCMD() checkForGlError("glColorMask"); } - if (!m_indexed_array.m_count && !m_draw_array_count) - { - u32 min_vertex_size = ~0; - for(auto &i : m_vertex_data) - { - if (!i.size) - continue; - - u32 vertex_size = i.data.size() / (i.size * i.GetTypeSize()); - - if (min_vertex_size > vertex_size) - min_vertex_size = vertex_size; - } - - m_draw_array_count = min_vertex_size; - m_draw_array_first = 0; - } - Enable(m_set_depth_test, GL_DEPTH_TEST); Enable(m_set_alpha_test, GL_ALPHA_TEST); Enable(m_set_depth_bounds_test, GL_DEPTH_BOUNDS_TEST_EXT); @@ -1995,6 +1992,20 @@ void GLGSRender::ExecCMD() checkForGlError(fmt::Format("m_gl_textures[%d].Init", i)); } + for (u32 i = 0; i < m_textures_count; ++i) + { + if (!m_vertex_textures[i].IsEnabled()) continue; + + glActiveTexture(GL_TEXTURE0 + m_textures_count + i); + checkForGlError("glActiveTexture"); + m_gl_vertex_textures[i].Create(); + m_gl_vertex_textures[i].Bind(); + checkForGlError(fmt::Format("m_gl_vertex_textures[%d].Bind", i)); + m_program.SetTex(i); + m_gl_vertex_textures[i].Init(m_vertex_textures[i]); + checkForGlError(fmt::Format("m_gl_vertex_textures[%d].Init", i)); + } + m_vao.Bind(); if(m_indexed_array.m_count) { diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index a598404c8a..b89484fb87 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -148,6 +148,7 @@ private: GLVertexProgram m_vertex_prog; GLTexture m_gl_textures[m_textures_count]; + GLTexture m_gl_vertex_textures[m_textures_count]; GLvao m_vao; GLvbo m_vbo; diff --git a/rpcs3/Emu/RSX/GL/GLProgram.cpp b/rpcs3/Emu/RSX/GL/GLProgram.cpp index e7e7fdaa0a..32f9d709bd 100644 --- a/rpcs3/Emu/RSX/GL/GLProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLProgram.cpp @@ -98,6 +98,13 @@ void GLProgram::SetTex(u32 index) checkForGlError(fmt::Format("SetTex(%u - %d - %d)", id, index, loc)); } +void GLProgram::SetVTex(u32 index) +{ + int loc = GetLocation(fmt::Format("vtex%u", index)); + glProgramUniform1i(id, loc, index); + checkForGlError(fmt::Format("SetVTex(%u - %d - %d)", id, index, loc)); +} + void GLProgram::Delete() { if(!IsCreated()) return; diff --git a/rpcs3/Emu/RSX/GL/GLProgram.h b/rpcs3/Emu/RSX/GL/GLProgram.h index 321a2e3cf5..076b3ce01f 100644 --- a/rpcs3/Emu/RSX/GL/GLProgram.h +++ b/rpcs3/Emu/RSX/GL/GLProgram.h @@ -24,5 +24,6 @@ public: void Use(); void UnUse(); void SetTex(u32 index); + void SetVTex(u32 index); void Delete(); }; diff --git a/rpcs3/Emu/RSX/GL/GLShaderParam.h b/rpcs3/Emu/RSX/GL/GLShaderParam.h index 80fa5a3dec..f90402eda0 100644 --- a/rpcs3/Emu/RSX/GL/GLShaderParam.h +++ b/rpcs3/Emu/RSX/GL/GLShaderParam.h @@ -1,5 +1,6 @@ #pragma once #include "OpenGL.h" +#include enum GLParamFlag { @@ -41,9 +42,9 @@ struct GLParamType bool SearchName(const std::string& name) { - for(u32 i=0; iSearchName(name)) t->items.emplace_back(name, -1, value); + if (!t->SearchName(name)) t->items.emplace_back(name, -1, value); } else { @@ -125,9 +126,9 @@ struct GLParamArray type = GetParamFlag(flag) + type; GLParamType* t = SearchParam(type); - if(t) + if (t) { - if(!t->SearchName(name)) t->items.emplace_back(name, location); + if (!t->SearchName(name)) t->items.emplace_back(name, location); } else { @@ -139,3 +140,90 @@ struct GLParamArray return name; } }; + +class ShaderVar +{ +public: + std::string name; + std::vector swizzles; + + ShaderVar() = default; + ShaderVar(const std::string& var) + { + auto var_blocks = fmt::split(var, { "." }); + + if (var_blocks.size() == 0) + { + assert(0); + } + + name = var_blocks[0]; + + if (var_blocks.size() == 1) + { + swizzles.push_back("xyzw"); + } + else + { + swizzles = std::vector(var_blocks.begin() + 1, var_blocks.end()); + } + } + + int get_vector_size() const + { + return swizzles[swizzles.size() - 1].length(); + } + + ShaderVar& symplify() + { + std::unordered_map swizzle; + + static std::unordered_map pos_to_swizzle = + { + { 0, 'x' }, + { 1, 'y' }, + { 2, 'z' }, + { 3, 'w' } + }; + + for (auto &i : pos_to_swizzle) + { + swizzle[i.second] = swizzles[0].length() > i.first ? swizzles[0][i.first] : 0; + } + + for (int i = 1; i < swizzles.size(); ++i) + { + std::unordered_map new_swizzle; + + for (auto &sw : pos_to_swizzle) + { + new_swizzle[sw.second] = swizzle[swizzles[i].length() <= sw.first ? '\0' : swizzles[i][sw.first]]; + } + + swizzle = new_swizzle; + } + + swizzles.clear(); + std::string new_swizzle; + + for (auto &i : pos_to_swizzle) + { + if (swizzle[i.second] != '\0') + new_swizzle += swizzle[i.second]; + } + + swizzles.push_back(new_swizzle); + + return *this; + } + + std::string get() const + { + if (swizzles.size() == 1 && swizzles[0] == "xyzw") + { + return name; + } + + return name + "." + fmt::merge({ swizzles }, "."); + } +}; \ No newline at end of file diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp index fffaf8f42a..186c70ed29 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp @@ -8,19 +8,19 @@ std::string GLVertexDecompilerThread::GetMask(bool is_sca) { std::string ret; - if(is_sca) + if (is_sca) { - if(d3.sca_writemask_x) ret += "x"; - if(d3.sca_writemask_y) ret += "y"; - if(d3.sca_writemask_z) ret += "z"; - if(d3.sca_writemask_w) ret += "w"; + if (d3.sca_writemask_x) ret += "x"; + if (d3.sca_writemask_y) ret += "y"; + if (d3.sca_writemask_z) ret += "z"; + if (d3.sca_writemask_w) ret += "w"; } else { - if(d3.vec_writemask_x) ret += "x"; - if(d3.vec_writemask_y) ret += "y"; - if(d3.vec_writemask_z) ret += "z"; - if(d3.vec_writemask_w) ret += "w"; + if (d3.vec_writemask_x) ret += "x"; + if (d3.vec_writemask_y) ret += "y"; + if (d3.vec_writemask_z) ret += "z"; + if (d3.vec_writemask_w) ret += "w"; } return ret.empty() || ret == "xyzw" ? "" : ("." + ret); @@ -40,17 +40,17 @@ std::string GLVertexDecompilerThread::GetDST(bool isSca) { std::string ret; - switch(isSca ? 0x1f : d3.dst) + switch (isSca ? 0x1f : d3.dst) { case 0x1f: ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("tmp") + std::to_string(isSca ? d3.sca_dst_tmp : d0.dst_tmp)); - break; + break; default: if (d3.dst > 15) LOG_ERROR(RSX, "dst index out of range: %u", d3.dst); ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? "vec4(0.0f, 0.0f, 0.0f, 1.0f)" : "vec4(0.0)"); - break; + break; } return ret; @@ -58,7 +58,7 @@ std::string GLVertexDecompilerThread::GetDST(bool isSca) std::string GLVertexDecompilerThread::GetSRC(const u32 n) { - static const std::string reg_table[] = + static const std::string reg_table[] = { "in_pos", "in_weight", "in_normal", "in_diff_color", "in_spec_color", @@ -70,13 +70,13 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n) std::string ret; - switch(src[n].reg_type) + switch (src[n].reg_type) { case 1: //temp ret += m_parr.AddParam(PARAM_NONE, "vec4", "tmp" + std::to_string(src[n].tmp_src)); - break; + break; case 2: //input - if (d1.input_src < (sizeof(reg_table)/sizeof(reg_table[0]))) + if (d1.input_src < (sizeof(reg_table) / sizeof(reg_table[0]))) { ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[d1.input_src], d1.input_src); } @@ -85,16 +85,16 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n) LOG_ERROR(RSX, "Bad input src num: %d", fmt::by_value(d1.input_src)); ret += m_parr.AddParam(PARAM_IN, "vec4", "in_unk", d1.input_src); } - break; + break; case 3: //const m_parr.AddParam(PARAM_UNIFORM, "vec4", std::string("vc[468]")); ret += std::string("vc[") + std::to_string(d1.const_src) + (d3.index_const ? " + " + AddAddrReg() : "") + "]"; - break; + break; default: LOG_ERROR(RSX, "Bad src%u reg type: %d", n, fmt::by_value(src[n].reg_type)); Emu.Pause(); - break; + break; } static const std::string f = "xyzw"; @@ -106,26 +106,26 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n) swizzle += f[src[n].swz_z]; swizzle += f[src[n].swz_w]; - if(swizzle != f) ret += '.' + swizzle; + if (swizzle != f) ret += '.' + swizzle; bool abs; - - switch(n) + + switch (n) { case 0: abs = d0.src0_abs; break; case 1: abs = d0.src1_abs; break; case 2: abs = d0.src2_abs; break; } - - if(abs) ret = "abs(" + ret + ")"; - if(src[n].neg) ret = "-" + ret; + + if (abs) ret = "abs(" + ret + ")"; + if (src[n].neg) ret = "-" + ret; return ret; } void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value) { - if(d0.cond == 0) return; + if (d0.cond == 0) return; enum { @@ -138,12 +138,12 @@ void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value) value += mask; - if(is_sca && d0.vec_result) + if (is_sca && d0.vec_result) { - value = "vec4(" + value + ")" + mask; + //value = "vec4(" + value + ")"; } - if(d0.staturate) + if (d0.staturate) { value = "clamp(" + value + ", 0.0, 1.0)"; } @@ -152,22 +152,20 @@ void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value) if (d0.cond_update_enable_0 && d0.cond_update_enable_1) { - dest += m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(d0.cond_reg_sel_1), "vec4(0.0)") + mask + " = "; + dest = m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(d0.cond_reg_sel_1), "vec4(0.0)") + mask; } - - if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f)) + else if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f)) { - dest += GetDST(is_sca) + mask + " = "; + dest = GetDST(is_sca) + mask; } - std::string code; + //std::string code; + //if (d0.cond_test_enable) + // code += "$ifcond "; + //code += dest + value; + //AddCode(code + ";"); - if (d0.cond_test_enable) - code += "$ifcond "; - - code += dest + value; - - AddCode(code + ";"); + AddCodeCond(Format(dest), value); } std::string GLVertexDecompilerThread::GetFunc() @@ -188,6 +186,11 @@ std::string GLVertexDecompilerThread::GetFunc() return name + "()"; } +std::string GLVertexDecompilerThread::GetTex() +{ + return m_parr.AddParam(PARAM_UNIFORM, "sampler2D", std::string("vtex") + std::to_string(/*?.tex_num*/0)); +} + std::string GLVertexDecompilerThread::Format(const std::string& code) { const std::pair> repl_list[] = @@ -200,14 +203,16 @@ std::string GLVertexDecompilerThread::Format(const std::string& code) { "$am", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrMask), this) }, { "$a", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrReg), this) }, - { "$fa", [this]()->std::string {return std::to_string(GetAddr()); } }, + { "$t", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetTex), this) }, + + { "$fa", [this]()->std::string { return std::to_string(GetAddr()); } }, { "$f()", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetFunc), this) }, { "$ifcond ", [this]() -> std::string - { - const std::string& cond = GetCond(); - if (cond == "true") return ""; - return "if(" + cond + ") "; - } + { + const std::string& cond = GetCond(); + if (cond == "true") return ""; + return "if(" + cond + ") "; + } }, { "$cond", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetCond), this) } }; @@ -252,6 +257,70 @@ std::string GLVertexDecompilerThread::GetCond() return fmt::Format("any(%s(cc%d%s, vec4(0.0)%s))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str(), swizzle.c_str()); } +void GLVertexDecompilerThread::AddCodeCond(const std::string& dst, const std::string& src) +{ + enum + { + lt = 0x1, + eq = 0x2, + gt = 0x4, + }; + + + if (!d0.cond_test_enable || d0.cond == (lt | gt | eq)) + { + AddCode(dst + " = " + src + ";"); + return; + } + + if (d0.cond == 0) + { + AddCode("//" + dst + " = " + src + ";"); + return; + } + + static const char* cond_string_table[(lt | gt | eq) + 1] = + { + "error", + "lessThan", + "equal", + "lessThanEqual", + "greaterThan", + "notEqual", + "greaterThanEqual", + "error" + }; + + static const char f[4] = { 'x', 'y', 'z', 'w' }; + + std::string swizzle; + swizzle += f[d0.mask_x]; + swizzle += f[d0.mask_y]; + swizzle += f[d0.mask_z]; + swizzle += f[d0.mask_w]; + + swizzle = swizzle == "xyzw" ? "" : "." + swizzle; + + std::string cond = fmt::Format("%s(cc%d%s, vec4(0.0))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str()); + + ShaderVar dst_var(dst); + dst_var.symplify(); + + //const char *c_mask = f; + + if (dst_var.swizzles[0].length() == 1) + { + AddCode("if (" + cond + ".x) " + dst + " = vec4(" + src + ").x;"); + } + else + { + for (int i = 0; i < dst_var.swizzles[0].length(); ++i) + { + AddCode("if (" + cond + "." + f[i] + ") " + dst + "." + f[i] + " = " + src + "." + f[i] + ";"); + } + } +} + std::string GLVertexDecompilerThread::AddAddrMask() { @@ -290,21 +359,21 @@ std::string GLVertexDecompilerThread::BuildFuncBody(const FuncInfo& func) { std::string result; - for(uint i=func.offset; i0; --i) + for (int i = m_funcs.size() - 1; i > 0; --i) { fp += fmt::Format("void %s();\n", m_funcs[i].name.c_str()); } @@ -423,7 +492,7 @@ std::string GLVertexDecompilerThread::BuildCode() f += fmt::Format("\nvoid %s()\n{\n%s}\n", m_funcs[1].name.c_str(), main_body.c_str()); - for(uint i=2; i 0 ? exp2($s.w * log2($s.y)) : 0.0), 1.0)"); break; + case RSX_SCA_OPCODE_LIT: SetDSTSca("vec4(1.0, $s.x, ($s.x > 0.0 ? exp($s.w * log2($s.y)) : 0.0), 1.0)"); break; case RSX_SCA_OPCODE_BRA: { AddCode("$if ($cond)"); @@ -599,33 +668,33 @@ void GLVertexDecompilerThread::Task() break; case RSX_SCA_OPCODE_CAL: // works same as BRI - AddCode("$ifcond $f(); //CAL"); + AddCode("$ifcond $f(); //CAL"); break; - case RSX_SCA_OPCODE_CLI: + case RSX_SCA_OPCODE_CLI: // works same as BRI - AddCode("$ifcond $f(); //CLI"); + AddCode("$ifcond $f(); //CLI"); break; case RSX_SCA_OPCODE_RET: // works like BRI but shorter (RET o[1].x(TR);) - AddCode("$ifcond return;"); + AddCode("$ifcond return;"); break; case RSX_SCA_OPCODE_LG2: SetDSTSca("log2($s)"); break; case RSX_SCA_OPCODE_EX2: SetDSTSca("exp2($s)"); break; case RSX_SCA_OPCODE_SIN: SetDSTSca("sin($s)"); break; case RSX_SCA_OPCODE_COS: SetDSTSca("cos($s)"); break; - case RSX_SCA_OPCODE_BRB: + case RSX_SCA_OPCODE_BRB: // works differently (BRB o[1].x !b0, L0;) LOG_ERROR(RSX, "Unimplemented sca_opcode BRB"); break; - case RSX_SCA_OPCODE_CLB: break; + case RSX_SCA_OPCODE_CLB: break; // works same as BRB LOG_ERROR(RSX, "Unimplemented sca_opcode CLB"); break; - case RSX_SCA_OPCODE_PSH: break; + case RSX_SCA_OPCODE_PSH: break; // works differently (PSH o[1].x A0;) LOG_ERROR(RSX, "Unimplemented sca_opcode PSH"); break; - case RSX_SCA_OPCODE_POP: break; + case RSX_SCA_OPCODE_POP: break; // works differently (POP o[1].x;) LOG_ERROR(RSX, "Unimplemented sca_opcode POP"); break; @@ -634,7 +703,7 @@ void GLVertexDecompilerThread::Task() AddCode(fmt::Format("//Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode))); LOG_ERROR(RSX, "Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode)); Emu.Pause(); - break; + break; } switch (d1.vec_opcode) @@ -662,12 +731,13 @@ void GLVertexDecompilerThread::Task() case RSX_VEC_OPCODE_SNE: SetDSTVec("vec4(notEqual($0, $1))"); break; case RSX_VEC_OPCODE_STR: SetDSTVec("vec4(equal($0, vec4(1.0)))"); break; case RSX_VEC_OPCODE_SSG: SetDSTVec("sign($0)"); break; + case RSX_VEC_OPCODE_TEX: SetDSTVec("texture($t, $0.xy)"); break; default: AddCode(fmt::Format("//Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode))); LOG_ERROR(RSX, "Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode)); Emu.Pause(); - break; + break; } if (d3.end) @@ -710,10 +780,10 @@ GLVertexProgram::GLVertexProgram() GLVertexProgram::~GLVertexProgram() { - if(m_decompiler_thread) + if (m_decompiler_thread) { Wait(); - if(m_decompiler_thread->IsAlive()) + if (m_decompiler_thread->IsAlive()) { m_decompiler_thread->Stop(); } @@ -727,7 +797,7 @@ GLVertexProgram::~GLVertexProgram() void GLVertexProgram::Wait() { - if(m_decompiler_thread && m_decompiler_thread->IsAlive()) + if (m_decompiler_thread && m_decompiler_thread->IsAlive()) { m_decompiler_thread->Join(); } @@ -759,7 +829,7 @@ void GLVertexProgram::DecompileAsync(RSXVertexProgram& prog) void GLVertexProgram::Compile() { - if(id) glDeleteShader(id); + if (id) glDeleteShader(id); id = glCreateShader(GL_VERTEX_SHADER); @@ -768,16 +838,16 @@ void GLVertexProgram::Compile() glShaderSource(id, 1, &str, &strlen); glCompileShader(id); - + GLint r = GL_FALSE; glGetShaderiv(id, GL_COMPILE_STATUS, &r); - if(r != GL_TRUE) + if (r != GL_TRUE) { glGetShaderiv(id, GL_INFO_LOG_LENGTH, &r); - if(r) + if (r) { - char* buf = new char[r+1](); + char* buf = new char[r + 1](); GLsizei len; glGetShaderInfoLog(id, r, &len, buf); LOG_ERROR(RSX, "Failed to compile vertex shader: %s", buf); @@ -796,7 +866,7 @@ void GLVertexProgram::Delete() parr.params.clear(); shader.clear(); - if(id) + if (id) { if (Emu.IsStopped()) { diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.h b/rpcs3/Emu/RSX/GL/GLVertexProgram.h index af8a666200..de4c3d07cd 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.h +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.h @@ -54,6 +54,7 @@ enum vec_opcode RSX_VEC_OPCODE_SNE = 0x14, RSX_VEC_OPCODE_STR = 0x15, RSX_VEC_OPCODE_SSG = 0x16, + RSX_VEC_OPCODE_TEX = 0x19, }; struct GLVertexDecompilerThread : public ThreadBase @@ -237,12 +238,14 @@ struct GLVertexDecompilerThread : public ThreadBase std::string GetDST(bool is_sca = false); std::string GetSRC(const u32 n); std::string GetFunc(); + std::string GetTex(); std::string GetCond(); std::string AddAddrMask(); std::string AddAddrReg(); u32 GetAddr(); std::string Format(const std::string& code); + void AddCodeCond(const std::string& dst, const std::string& src); void AddCode(const std::string& code); void SetDST(bool is_sca, std::string value); void SetDSTVec(const std::string& code); diff --git a/rpcs3/Emu/RSX/RSXTexture.cpp b/rpcs3/Emu/RSX/RSXTexture.cpp index 6904da2420..7a21e076d3 100644 --- a/rpcs3/Emu/RSX/RSXTexture.cpp +++ b/rpcs3/Emu/RSX/RSXTexture.cpp @@ -210,3 +210,206 @@ void RSXTexture::SetControl3(u16 depth, u32 pitch) m_depth = depth; m_pitch = pitch; } + +RSXVertexTexture::RSXVertexTexture() : RSXTexture() +{ +} + +RSXVertexTexture::RSXVertexTexture(u8 index) : RSXTexture(index) +{ +} + +void RSXVertexTexture::Init() +{ + // Offset + methodRegisters[NV4097_SET_VERTEX_TEXTURE_OFFSET + (m_index * 32)] = 0; + + // Format + methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] = 0; + + // Address + methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] = + ((/*wraps*/1) | ((/*anisoBias*/0) << 4) | ((/*wrapt*/1) << 8) | ((/*unsignedRemap*/0) << 12) | + ((/*wrapr*/3) << 16) | ((/*gamma*/0) << 20) | ((/*signedRemap*/0) << 24) | ((/*zfunc*/0) << 28)); + + // Control0 + methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] = + (((/*alphakill*/0) << 2) | (/*maxaniso*/0) << 4) | ((/*maxlod*/0xc00) << 7) | ((/*minlod*/0) << 19) | ((/*enable*/0) << 31); + + // Control1 + //methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL1 + (m_index * 32)] = 0xE4; + + // Filter + methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] = + ((/*bias*/0) | ((/*conv*/1) << 13) | ((/*min*/5) << 16) | ((/*mag*/2) << 24) + | ((/*as*/0) << 28) | ((/*rs*/0) << 29) | ((/*gs*/0) << 30) | ((/*bs*/0) << 31)); + + // Image Rect + methodRegisters[NV4097_SET_VERTEX_TEXTURE_IMAGE_RECT + (m_index * 32)] = (/*height*/1) | ((/*width*/1) << 16); + + // Border Color + methodRegisters[NV4097_SET_VERTEX_TEXTURE_BORDER_COLOR + (m_index * 32)] = 0; +} + +u32 RSXVertexTexture::GetOffset() const +{ + return methodRegisters[NV4097_SET_VERTEX_TEXTURE_OFFSET + (m_index * 32)]; +} + +u8 RSXVertexTexture::GetLocation() const +{ + return (methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] & 0x3) - 1; +} + +bool RSXVertexTexture::isCubemap() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 2) & 0x1); +} + +u8 RSXVertexTexture::GetBorderType() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 3) & 0x1); +} + +u8 RSXVertexTexture::GetDimension() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 4) & 0xf); +} + +u8 RSXVertexTexture::GetFormat() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 8) & 0xff); +} + +u16 RSXVertexTexture::GetMipmap() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 16) & 0xffff); +} + +u8 RSXVertexTexture::GetWrapS() const +{ + return 1; + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)]) & 0xf); +} + +u8 RSXVertexTexture::GetWrapT() const +{ + return 1; + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 8) & 0xf); +} + +u8 RSXVertexTexture::GetWrapR() const +{ + return 1; + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 16) & 0xf); +} + +u8 RSXVertexTexture::GetUnsignedRemap() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 12) & 0xf); +} + +u8 RSXVertexTexture::GetZfunc() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 28) & 0xf); +} + +u8 RSXVertexTexture::GetGamma() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 20) & 0xf); +} + +u8 RSXVertexTexture::GetAnisoBias() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 4) & 0xf); +} + +u8 RSXVertexTexture::GetSignedRemap() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 24) & 0xf); +} + +bool RSXVertexTexture::IsEnabled() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 31) & 0x1); +} + +u16 RSXVertexTexture::GetMinLOD() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 19) & 0xfff); +} + +u16 RSXVertexTexture::GetMaxLOD() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 7) & 0xfff); +} + +u8 RSXVertexTexture::GetMaxAniso() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 4) & 0x7); +} + +bool RSXVertexTexture::IsAlphaKillEnabled() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 2) & 0x1); +} + +u32 RSXVertexTexture::GetRemap() const +{ + return 0 | (1 << 2) | (2 << 4) | (3 << 6);//(methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL1 + (m_index * 32)]); +} + +u16 RSXVertexTexture::GetBias() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)]) & 0x1fff); +} + +u8 RSXVertexTexture::GetMinFilter() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 16) & 0x7); +} + +u8 RSXVertexTexture::GetMagFilter() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 24) & 0x7); +} + +u8 RSXVertexTexture::GetConvolutionFilter() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 13) & 0xf); +} + +bool RSXVertexTexture::isASigned() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 28) & 0x1); +} + +bool RSXVertexTexture::isRSigned() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 29) & 0x1); +} + +bool RSXVertexTexture::isGSigned() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 30) & 0x1); +} + +bool RSXVertexTexture::isBSigned() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 31) & 0x1); +} + +u16 RSXVertexTexture::GetWidth() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_IMAGE_RECT + (m_index * 32)] >> 16) & 0xffff); +} + +u16 RSXVertexTexture::GetHeight() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_IMAGE_RECT + (m_index * 32)]) & 0xffff); +} + +u32 RSXVertexTexture::GetBorderColor() const +{ + return methodRegisters[NV4097_SET_VERTEX_TEXTURE_BORDER_COLOR + (m_index * 32)]; +} \ No newline at end of file diff --git a/rpcs3/Emu/RSX/RSXTexture.h b/rpcs3/Emu/RSX/RSXTexture.h index d5db3480fb..c595dba082 100644 --- a/rpcs3/Emu/RSX/RSXTexture.h +++ b/rpcs3/Emu/RSX/RSXTexture.h @@ -2,6 +2,7 @@ class RSXTexture { +protected: u8 m_index; public: @@ -11,6 +12,64 @@ public: public: RSXTexture(); RSXTexture(u8 index); + virtual void Init(); + + // Offset + virtual u32 GetOffset() const; + + // Format + virtual u8 GetLocation() const; + virtual bool isCubemap() const; + virtual u8 GetBorderType() const; + virtual u8 GetDimension() const; + virtual u8 GetFormat() const; + virtual u16 GetMipmap() const; + + // Address + virtual u8 GetWrapS() const; + virtual u8 GetWrapT() const; + virtual u8 GetWrapR() const; + virtual u8 GetUnsignedRemap() const; + virtual u8 GetZfunc() const; + virtual u8 GetGamma() const; + virtual u8 GetAnisoBias() const; + virtual u8 GetSignedRemap() const; + + // Control0 + virtual bool IsEnabled() const; + virtual u16 GetMinLOD() const; + virtual u16 GetMaxLOD() const; + virtual u8 GetMaxAniso() const; + virtual bool IsAlphaKillEnabled() const; + + // Control1 + virtual u32 GetRemap() const; + + // Filter + virtual u16 GetBias() const; + virtual u8 GetMinFilter() const; + virtual u8 GetMagFilter() const; + virtual u8 GetConvolutionFilter() const; + virtual bool isASigned() const; + virtual bool isRSigned() const; + virtual bool isGSigned() const; + virtual bool isBSigned() const; + + // Image Rect + virtual u16 GetWidth() const; + virtual u16 GetHeight() const; + + // Border Color + virtual u32 GetBorderColor() const; + + void SetControl3(u16 depth, u32 pitch); +}; + +class RSXVertexTexture : public RSXTexture +{ +public: + RSXVertexTexture(); + RSXVertexTexture(u8 index); void Init(); // Offset @@ -60,6 +119,4 @@ public: // Border Color u32 GetBorderColor() const; - - void SetControl3(u16 depth, u32 pitch); -}; +}; \ No newline at end of file diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 0ec87d8cad..caa0481f1d 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -14,34 +14,42 @@ u32 methodRegisters[0xffff]; -void RSXThread::nativeRescale(float width, float height) +void RSXThread::NativeRescale(float width, float height) { switch (Ini.GSResolution.GetValue()) { case 1: // 1920x1080 window size + { m_width_scale = 1920 / width * 2.0f; m_height_scale = 1080 / height * 2.0f; m_width = 1920; m_height = 1080; - break; + } + break; case 2: // 1280x720 window size + { m_width_scale = 1280 / width * 2.0f; m_height_scale = 720 / height * 2.0f; m_width = 1280; m_height = 720; - break; + } + break; case 4: // 720x480 window size + { m_width_scale = 720 / width * 2.0f; m_height_scale = 480 / height * 2.0f; m_width = 720; m_height = 480; - break; + } + break; case 5: // 720x576 window size + { m_width_scale = 720 / width * 2.0f; m_height_scale = 576 / height * 2.0f; m_width = 720; m_height = 576; - break; + } + break; } } @@ -49,7 +57,7 @@ u32 GetAddress(u32 offset, u32 location) { u32 res = 0; - switch(location) + switch (location) { case CELL_GCM_LOCATION_LOCAL: { @@ -95,28 +103,28 @@ RSXVertexData::RSXVertexData() void RSXVertexData::Reset() { - //frequency = 0; - //stride = 0; - //size = 0; - //type = 0; - //addr = 0; + frequency = 0; + stride = 0; + size = 0; + type = 0; + addr = 0; data.clear(); } void RSXVertexData::Load(u32 start, u32 count, u32 baseOffset, u32 baseIndex=0) { - if(!addr) return; + if (!addr) return; const u32 tsize = GetTypeSize(); data.resize((start + count) * tsize * size); - for(u32 i=start; i(addr + baseOffset + stride * (i + baseIndex)); u8* dst = &data[i * tsize * size]; - switch(tsize) + switch (tsize) { case 1: { @@ -128,7 +136,7 @@ void RSXVertexData::Load(u32 start, u32 count, u32 baseOffset, u32 baseIndex=0) { const u16* c_src = (const u16*)src; u16* c_dst = (u16*)dst; - for(u32 j=0; j::make(args_addr); std::string debug = GetMethodName(cmd); debug += "("; - for(u32 i=0; i> 20; + tex.SetControl3(depth, pitch); + } + break; + // Vertex data - case_16(NV4097_SET_VERTEX_DATA4UB_M, 4): + case_16(NV4097_SET_VERTEX_DATA4UB_M, 4) { const u32 a0 = ARGS(0); u8 v0 = a0; @@ -401,7 +413,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const u8 v2 = a0 >> 16; u8 v3 = a0 >> 24; - //m_vertex_data[index].Reset(); + m_vertex_data[index].Reset(); m_vertex_data[index].size = 4; m_vertex_data[index].type = CELL_GCM_VERTEX_UB; m_vertex_data[index].data.push_back(v0); @@ -412,7 +424,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const } break; - case_16(NV4097_SET_VERTEX_DATA2F_M, 8): + case_16(NV4097_SET_VERTEX_DATA2F_M, 8) { const u32 a0 = ARGS(0); const u32 a1 = ARGS(1); @@ -420,7 +432,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const float v0 = (float&)a0; float v1 = (float&)a1; - //m_vertex_data[index].Reset(); + m_vertex_data[index].Reset(); m_vertex_data[index].type = CELL_GCM_VERTEX_F; m_vertex_data[index].size = 2; u32 pos = m_vertex_data[index].data.size(); @@ -432,7 +444,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const } break; - case_16(NV4097_SET_VERTEX_DATA4F_M, 16): + case_16(NV4097_SET_VERTEX_DATA4F_M, 16) { const u32 a0 = ARGS(0); const u32 a1 = ARGS(1); @@ -444,7 +456,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const float v2 = (float&)a2; float v3 = (float&)a3; - //m_vertex_data[index].Reset(); + m_vertex_data[index].Reset(); m_vertex_data[index].type = CELL_GCM_VERTEX_F; m_vertex_data[index].size = 4; u32 pos = m_vertex_data[index].data.size(); @@ -458,7 +470,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const } break; - case_16(NV4097_SET_VERTEX_DATA_ARRAY_OFFSET, 4): + case_16(NV4097_SET_VERTEX_DATA_ARRAY_OFFSET, 4) { const u32 addr = GetAddress(ARGS(0) & 0x7fffffff, ARGS(0) >> 31); CMD_LOG("num=%d, addr=0x%x", index, addr); @@ -469,7 +481,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const } break; - case_16(NV4097_SET_VERTEX_DATA_ARRAY_FORMAT, 4): + case_16(NV4097_SET_VERTEX_DATA_ARRAY_FORMAT, 4) { const u32 a0 = ARGS(0); u16 frequency = a0 >> 16; @@ -493,7 +505,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_VERTEX_ATTRIB_INPUT_MASK: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_VERTEX_ATTRIB_INPUT_MASK: 0x%x", ARGS(0)); + } //VertexData[0].prog.attributeInputMask = ARGS(0); } @@ -502,7 +516,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK: 0x%x", ARGS(0)); + } //VertexData[0].prog.attributeOutputMask = ARGS(0); //FragmentData.prog.attributeInputMask = ARGS(0)/* & ~0x20*/; @@ -525,7 +541,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_COLOR_MASK_MRT: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_COLOR_MASK_MRT: 0x%x", ARGS(0)); + } } break; @@ -629,7 +647,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_BLEND_COLOR2: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_BLEND_COLOR2: 0x % x", ARGS(0)); + } } break; @@ -644,7 +664,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_REDUCE_DST_COLOR: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_REDUCE_DST_COLOR: 0x%x", ARGS(0)); + } } break; @@ -820,8 +842,8 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const { u32 a0 = ARGS(0); - if(a0 & 0x01) m_clear_surface_z = m_clear_z; - if(a0 & 0x02) m_clear_surface_s = m_clear_s; + if (a0 & 0x01) m_clear_surface_z = m_clear_z; + if (a0 & 0x02) m_clear_surface_s = m_clear_s; m_clear_surface_mask |= a0 & 0x3; } @@ -831,12 +853,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const { const u32 a0 = ARGS(0); - if(a0 & 0x01) m_clear_surface_z = m_clear_z; - if(a0 & 0x02) m_clear_surface_s = m_clear_s; - if(a0 & 0x10) m_clear_surface_color_r = m_clear_color_r; - if(a0 & 0x20) m_clear_surface_color_g = m_clear_color_g; - if(a0 & 0x40) m_clear_surface_color_b = m_clear_color_b; - if(a0 & 0x80) m_clear_surface_color_a = m_clear_color_a; + if (a0 & 0x01) m_clear_surface_z = m_clear_z; + if (a0 & 0x02) m_clear_surface_s = m_clear_s; + if (a0 & 0x10) m_clear_surface_color_r = m_clear_color_r; + if (a0 & 0x20) m_clear_surface_color_g = m_clear_color_g; + if (a0 & 0x40) m_clear_surface_color_b = m_clear_color_b; + if (a0 & 0x80) m_clear_surface_color_a = m_clear_color_a; m_clear_surface_mask = a0; ExecCMD(NV4097_CLEAR_SURFACE); @@ -864,21 +886,25 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_CLEAR_RECT_HORIZONTAL: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_CLEAR_RECT_HORIZONTAL: 0x%x", ARGS(0)); + } } break; case NV4097_SET_CLEAR_RECT_VERTICAL: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_CLEAR_RECT_VERTICAL: 0x%x", ARGS(0)); + } } break; // Arrays case NV4097_DRAW_ARRAYS: { - for(u32 c=0; c> 24) + 1; - if(first < m_indexed_array.m_first) m_indexed_array.m_first = first; + if (first < m_indexed_array.m_first) m_indexed_array.m_first = first; - for(u32 i=first; i<_count; ++i) + for (u32 i = first; i < _count; ++i) { u32 index; - switch(m_indexed_array.m_type) + switch (m_indexed_array.m_type) { case 0: { @@ -940,8 +966,8 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const break; } - if(index < m_indexed_array.index_min) m_indexed_array.index_min = index; - if(index > m_indexed_array.index_max) m_indexed_array.index_max = index; + if (index < m_indexed_array.index_min) m_indexed_array.index_min = index; + if (index > m_indexed_array.index_max) m_indexed_array.index_max = index; } m_indexed_array.m_count += _count; @@ -971,10 +997,29 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const const u32 a0 = ARGS(0); //LOG_WARNING(RSX, "NV4097_SET_BEGIN_END: 0x%x", a0); + if (!m_indexed_array.m_count && !m_draw_array_count) + { + u32 min_vertex_size = ~0; + for (auto &i : m_vertex_data) + { + if (!i.size) + continue; - m_read_buffer = false; + u32 vertex_size = i.data.size() / (i.size * i.GetTypeSize()); - if(a0) + if (min_vertex_size > vertex_size) + { + min_vertex_size = vertex_size; + } + } + + m_draw_array_count = min_vertex_size; + m_draw_array_first = 0; + } + + m_read_buffer = Ini.GSReadColorBuffer.GetValue() || (!m_indexed_array.m_count && !m_draw_array_count); + + if (a0) { Begin(a0); } @@ -1029,10 +1074,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const if (count == 2) { - const u32 start = ARGS(1); - if (start) + if (ARGS(1)) { - LOG_WARNING(RSX, "NV4097_SET_TRANSFORM_PROGRAM_LOAD: start = %d", start); + LOG_WARNING(RSX, "NV4097_SET_TRANSFORM_PROGRAM_LOAD: start = %d", ARGS(0)); } } } @@ -1040,51 +1084,51 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_TRANSFORM_PROGRAM_START: { - const u32 start = ARGS(0); - if (start) + if (ARGS(0)) { - LOG_WARNING(RSX, "NV4097_SET_TRANSFORM_PROGRAM_START: start = %d", start); + LOG_WARNING(RSX, "NV4097_SET_TRANSFORM_PROGRAM_START: start = %d", ARGS(0)); } } break; - case_32(NV4097_SET_TRANSFORM_PROGRAM, 4): + case_32(NV4097_SET_TRANSFORM_PROGRAM, 4) { //LOG_WARNING(RSX, "NV4097_SET_TRANSFORM_PROGRAM[%d](%d)", index, count); - if(!m_cur_vertex_prog) + if (!m_cur_vertex_prog) { LOG_WARNING(RSX, "NV4097_SET_TRANSFORM_PROGRAM: m_cur_vertex_prog == NULL"); break; } - for(u32 i=0; idata.push_back(ARGS(i)); + for (u32 i = 0; i < count; ++i) m_cur_vertex_prog->data.push_back(ARGS(i)); } break; case NV4097_SET_TRANSFORM_TIMEOUT: - + { // TODO: // (cmd)[1] = CELL_GCM_ENDIAN_SWAP((count) | ((registerCount) << 16)); \ - if(!m_cur_vertex_prog) + if (!m_cur_vertex_prog) { LOG_WARNING(RSX, "NV4097_SET_TRANSFORM_TIMEOUT: m_cur_vertex_prog == NULL"); break; } //m_cur_vertex_prog->Decompile(); + } break; case NV4097_SET_TRANSFORM_CONSTANT_LOAD: { - if((count - 1) % 4) + if ((count - 1) % 4) { CMD_LOG("NV4097_SET_TRANSFORM_CONSTANT_LOAD [%d]", count); break; } - for(u32 id = ARGS(0), i = 1; i= 2) + if (count >= 2) { m_set_stencil_func_ref = true; m_stencil_func_ref = ARGS(1); - if(count >= 3) + if (count >= 3) { m_set_stencil_func_mask = true; m_stencil_func_mask = ARGS(2); @@ -1210,12 +1258,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_set_stencil_fail = true; m_stencil_fail = ARGS(0); - if(count >= 2) + if (count >= 2) { m_set_stencil_zfail = true; m_stencil_zfail = ARGS(1); - if(count >= 3) + if (count >= 3) { m_set_stencil_zpass = true; m_stencil_zpass = ARGS(2); @@ -1236,12 +1284,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_set_back_stencil_func = true; m_back_stencil_func = ARGS(0); - if(count >= 2) + if (count >= 2) { m_set_back_stencil_func_ref = true; m_back_stencil_func_ref = ARGS(1); - if(count >= 3) + if (count >= 3) { m_set_back_stencil_func_mask = true; m_back_stencil_func_mask = ARGS(2); @@ -1269,12 +1317,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_set_stencil_fail = true; m_stencil_fail = ARGS(0); - if(count >= 2) + if (count >= 2) { m_set_back_stencil_zfail = true; m_back_stencil_zfail = ARGS(1); - if(count >= 3) + if (count >= 3) { m_set_back_stencil_zpass = true; m_back_stencil_zpass = ARGS(2); @@ -1286,7 +1334,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_SCULL_CONTROL: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_SCULL_CONTROL: 0x%x", ARGS(0)); + } //This is stencil culling , nothing to do with stencil masking on regular color or depth buffer //const u32 a0 = ARGS(0); @@ -1324,7 +1374,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_POINT_PARAMS_ENABLE: { if (ARGS(0)) + { LOG_ERROR(RSX, "NV4097_SET_POINT_PARAMS_ENABLE: 0x%x", ARGS(0)); + } } break; @@ -1351,7 +1403,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_scissor_x = ARGS(0) & 0xffff; m_scissor_w = ARGS(0) >> 16; - if(count == 2) + if (count == 2) { m_set_scissor_vertical = true; m_scissor_y = ARGS(1) & 0xffff; @@ -1394,7 +1446,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_height = buffers[m_gcm_current_buffer].height; // Rescale native resolution to fit 1080p/720p/480p/576p window size - nativeRescale((float)m_width, (float)m_height); + NativeRescale((float)m_width, (float)m_height); } break; @@ -1509,7 +1561,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_set_context_dma_color_c = true; m_context_dma_color_c = ARGS(0); - if(count > 1) + if (count > 1) { m_set_context_dma_color_d = true; m_context_dma_color_d = ARGS(1); @@ -1534,14 +1586,18 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_CONTEXT_DMA_SEMAPHORE: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_CONTEXT_DMA_SEMAPHORE: 0x%x", ARGS(0)); + } } break; case NV4097_SET_CONTEXT_DMA_NOTIFIES: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_CONTEXT_DMA_NOTIFIES: 0x%x", ARGS(0)); + } } break; @@ -1553,7 +1609,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_surface_clip_x = a0; m_surface_clip_w = a0 >> 16; - if(count == 2) + if (count == 2) { const u32 a1 = ARGS(1); m_set_surface_clip_vertical = true; @@ -1652,7 +1708,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_ZCULL_CONTROL0: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_ZCULL_CONTROL0: 0x%x", ARGS(0)); + } //m_set_depth_func = true; //m_depth_func = ARGS(0) >> 4; @@ -1662,7 +1720,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_ZCULL_CONTROL1: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_ZCULL_CONTROL1: 0x%x", ARGS(0)); + } //m_set_depth_func = true; //m_depth_func = ARGS(0) >> 4; @@ -1672,14 +1732,18 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_ZCULL_STATS_ENABLE: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_SET_ZCULL_STATS_ENABLE: 0x%x", ARGS(0)); + } } break; case NV4097_ZCULL_SYNC: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV4097_ZCULL_SYNC: 0x%x", ARGS(0)); + } } break; @@ -1774,17 +1838,16 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const const u8 cullNearFarEnable = ARGS(0) & 0xf; const u8 zclampEnable = (ARGS(0) >> 4) & 0xf; const u8 cullIgnoreW = (ARGS(0) >> 8) & 0xf; - LOG_WARNING(RSX, "TODO: NV4097_SET_ZMIN_MAX_CONTROL: cullNearFarEnable=%d, zclampEnable=%d, cullIgnoreW=%d", - cullNearFarEnable, zclampEnable, cullIgnoreW); + LOG_WARNING(RSX, "TODO: NV4097_SET_ZMIN_MAX_CONTROL: cullNearFarEnable=%d, zclampEnable=%d, cullIgnoreW=%d", cullNearFarEnable, zclampEnable, cullIgnoreW); } break; - // Windows Clipping + // Windows Clipping (Doesn't seem to be relevant?) case NV4097_SET_WINDOW_OFFSET: { const u16 x = ARGS(0); const u16 y = ARGS(0) >> 16; - LOG_WARNING(RSX, "TODO: NV4097_SET_WINDOW_OFFSET: x=%d, y=%d", x, y); + //LOG_WARNING(RSX, "TODO: NV4097_SET_WINDOW_OFFSET: x=%d, y=%d", x, y); } break; @@ -1854,6 +1917,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const if (!offset) { + // } else { @@ -1865,14 +1929,18 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV0039_PITCH_IN: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV0039_PITCH_IN: 0x%x", ARGS(0)); + } } break; case NV0039_BUFFER_NOTIFY: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV0039_BUFFER_NOTIFY: 0x%x", ARGS(0)); + } } break; @@ -1901,7 +1969,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV309E_SET_CONTEXT_DMA_IMAGE: { if (ARGS(0)) + { LOG_WARNING(RSX, "NV309E_SET_CONTEXT_DMA_IMAGE: 0x%x", ARGS(0)); + } } break; @@ -1943,21 +2013,21 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const c.y = (float&)a; } - if(count >= 3) + if (count >= 3) { u32 a = ARGS(2); a = a << 16 | a >> 16; c.z = (float&)a; } - if(count >= 4) + if (count >= 4) { u32 a = ARGS(3); a = a << 16 | a >> 16; c.w = (float&)a; } - if(count >= 5) + if (count >= 5) { LOG_WARNING(RSX, "NV308A_COLOR: count = %d", count); } @@ -2004,9 +2074,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const LOG_WARNING(RSX, "*** m_dst_offset=0x%x, m_color: conv_in_h=0x%x, format_src_pitch=0x%x, conv_in_x=0x%x, conv_in_y=0x%x, conv_out_x=0x%x, conv_out_y=0x%x", m_dst_offset, m_color_conv_in_h, m_color_format_src_pitch, m_color_conv_in_x, m_color_conv_in_y, m_color_conv_out_x, m_color_conv_out_y); - for(u16 y=0; y lock(m_cs_main); - inc=1; + inc = 1; u32 get = m_ctrl->get.read_sync(); u32 put = m_ctrl->put.read_sync(); - if(put == get || !Emu.IsRunning()) + if (put == get || !Emu.IsRunning()) { - if(put == get) + if (put == get) { - if(m_flip_status == 0) + if (m_flip_status == 0) + { m_sem_flip.post_and_wait(); + } m_sem_flush.post_and_wait(); } @@ -2250,52 +2322,54 @@ void RSXThread::Task() continue; } - //ConLog.Write("addr = 0x%x", m_ioAddress + get); + const u32 cmd = ReadIO32(get); const u32 count = (cmd >> 18) & 0x7ff; - //if(cmd == 0) continue; if (Ini.RSXLogging.GetValue()) + { LOG_NOTICE(Log::RSX, "%s (cmd=0x%x)", GetMethodName(cmd & 0xffff).c_str(), cmd); + } - //LOG_NOTICE(Log::RSX, "put=0x%x, get=0x%x, cmd=0x%x (%s)", put, get, cmd, GetMethodName(cmd & 0xffff).c_str()); - - if(cmd & CELL_GCM_METHOD_FLAG_JUMP) + if (cmd & CELL_GCM_METHOD_FLAG_JUMP) { u32 offs = cmd & 0x1fffffff; - //LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put); + //LOG_WARNING(RSX, "RSX: jump cmd (0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put); m_ctrl->get.exchange(be_t::make(offs)); continue; } - if(cmd & CELL_GCM_METHOD_FLAG_CALL) + + if (cmd & CELL_GCM_METHOD_FLAG_CALL) { m_call_stack.push(get + 4); u32 offs = cmd & ~3; - //u32 addr = offs; - //LOG_WARNING(RSX, "rsx call(0x%x) #0x%x - 0x%x", offs, cmd, get); + //LOG_WARNING(RSX, "RSX: call cmd (0x%x) #0x%x - 0x%x", offs, cmd, get); m_ctrl->get.exchange(be_t::make(offs)); continue; } - if(cmd == CELL_GCM_METHOD_FLAG_RETURN) + + if (cmd == CELL_GCM_METHOD_FLAG_RETURN) { //LOG_WARNING(RSX, "rsx return!"); u32 get = m_call_stack.top(); m_call_stack.pop(); - //LOG_WARNING(RSX, "rsx return(0x%x)", get); + //LOG_WARNING(RSX, "RSX: return cmd (0x%x)", get); m_ctrl->get.exchange(be_t::make(get)); continue; } - if(cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT) + + if (cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT) { - //LOG_WARNING(RSX, "non increment cmd! 0x%x", cmd); + //LOG_WARNING(RSX,"RSX: non-increment cmd! 0x%x", cmd); inc = 0; } else { - //LOG_WARNING(RSX, "increment cmd! 0x%x", cmd); + //LOG_WARNING(RSX, "RSX: increment cmd! 0x%x", cmd); + inc++; } - if(cmd == 0) //nop + if (cmd == 0) //nop { m_ctrl->get.atomic_op([](be_t& value) { @@ -2306,7 +2380,7 @@ void RSXThread::Task() auto args = vm::ptr::make((u32)Memory.RSXIOMem.RealAddr(get + 4)); - for(u32 i=0; i #include "Utilities/SSemaphore.h" #include "Utilities/Thread.h" +#include "Utilities/Timer.h" enum Method { @@ -101,11 +102,14 @@ public: protected: std::stack m_call_stack; CellGcmControl* m_ctrl; + Timer m_timer_sync; + double m_fps_limit = 59.94; 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; @@ -515,12 +519,14 @@ protected: 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++) + for (int i = 0; i < 16; i++) { m_textures[i] = RSXTexture(i); } @@ -607,7 +613,7 @@ protected: m_clear_surface_mask = 0; m_begin_end = 0; - for(uint i=0; i __noinline void Notice(const char* fmt, Targs... args) const { - LogOutput(LogNotice, " : ", fmt::Format(fmt, args...)); + LogOutput(LogNotice, ": ", fmt::Format(fmt, args...)); } template __forceinline void Log(const char* fmt, Targs... args) const diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 17bc618472..3448ef7701 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -526,6 +526,8 @@ int cellAudioPortOpen(vm::ptr audioParam, vm::ptr portN port.channel = (u8)audioParam->nChannel; port.block = (u8)audioParam->nBlock; port.attr = audioParam->attr; + port.addr = m_config.m_buffer + (128 * 1024 * i); + port.read_index_addr = m_config.m_indexes + (sizeof(u64) * i); if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL) { port.level = audioParam->level; @@ -578,8 +580,8 @@ int cellAudioGetPortConfig(u32 portNum, vm::ptr portConfig) portConfig->nChannel = port.channel; portConfig->nBlock = port.block; portConfig->portSize = port.channel * port.block * 256 * sizeof(float); - portConfig->portAddr = m_config.m_buffer + (128 * 1024 * portNum); // 0x20020000 - portConfig->readIndexAddr = m_config.m_indexes + (sizeof(u64) * portNum); // 0x20010010 on ps3 + portConfig->portAddr = port.addr; // 0x20020000 + portConfig->readIndexAddr = port.read_index_addr; // 0x20010010 on ps3 cellAudio->Log("*** port config: nChannel=%d, nBlock=%d, portSize=0x%x, portAddr=0x%x, readIndexAddr=0x%x", (u32)portConfig->nChannel, (u32)portConfig->nBlock, (u32)portConfig->portSize, (u32)portConfig->portAddr, (u32)portConfig->readIndexAddr); @@ -730,6 +732,28 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) int cellAudioSetPortLevel(u32 portNum, float level) { cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level); + + AudioPortConfig& port = m_config.m_ports[portNum]; + + if (portNum >= m_config.AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (!port.m_is_audio_port_opened) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (!port.m_is_audio_port_started) + { + return CELL_AUDIO_ERROR_PORT_NOT_RUN; + } + + std::lock_guard lock(audioMutex); + + port.level = level; // TODO + return CELL_OK; } @@ -839,21 +863,94 @@ int cellAudioRemoveNotifyEventQueueEx(u64 key, u32 iFlags) return CELL_OK; } -int cellAudioAddData(u32 portNum, vm::ptr> src, u32 samples, float volume) +int cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) { cellAudio->Todo("cellAudioAddData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); + + AudioPortConfig& port = m_config.m_ports[portNum]; + + if (portNum >= m_config.AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (!port.m_is_audio_port_opened) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (!port.m_is_audio_port_started) + { + return CELL_AUDIO_ERROR_PORT_NOT_RUN; + } + + std::lock_guard lock(audioMutex); + + //u32 addr = port.addr; + //for (u32 i = 0; i < samples; i++) + //{ + // vm::write32(addr, src[i]); + // addr += port.channel * port.block * sizeof(float); + //} + + m_config.m_buffer = src.addr(); // TODO: write data from src in selected port + return CELL_OK; } int cellAudioAdd2chData(u32 portNum, vm::ptr> src, u32 samples, float volume) { cellAudio->Todo("cellAudioAdd2chData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); + + AudioPortConfig& port = m_config.m_ports[portNum]; + + if (portNum >= m_config.AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (!port.m_is_audio_port_opened) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (!port.m_is_audio_port_started) + { + return CELL_AUDIO_ERROR_PORT_NOT_RUN; + } + + std::lock_guard lock(audioMutex); + + m_config.m_buffer = src.addr(); // TODO + return CELL_OK; } int cellAudioAdd6chData(u32 portNum, vm::ptr> src, float volume) { cellAudio->Todo("cellAudioAdd6chData(portNum=0x%x, src_addr=0x%x, volume=%f)", portNum, src.addr(), volume); + + AudioPortConfig& port = m_config.m_ports[portNum]; + + if (portNum >= m_config.AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (!port.m_is_audio_port_opened) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (!port.m_is_audio_port_started) + { + return CELL_AUDIO_ERROR_PORT_NOT_RUN; + } + + std::lock_guard lock(audioMutex); + + m_config.m_buffer = src.addr(); // TODO + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp index 2f6b5a5bd0..c8e0b87038 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp @@ -195,7 +195,7 @@ u64 cellGcmGetTimeStampLocation(u32 index, u32 location) } if (location == CELL_GCM_LOCATION_MAIN) { - if (index >= 1024*1024) { + if (index >= 1024 * 1024) { cellGcmSys->Error("cellGcmGetTimeStampLocation: Wrong main index (%d)", index); return 0; } @@ -300,7 +300,7 @@ u32 cellGcmGetTiledPitchSize(u32 size) { cellGcmSys->Log("cellGcmGetTiledPitchSize(size=%d)", size); - for (size_t i=0; i < sizeof(tiled_pitches)/sizeof(tiled_pitches[0]) - 1; i++) { + for (size_t i=0; i < sizeof(tiled_pitches) / sizeof(tiled_pitches[0]) - 1; i++) { if (tiled_pitches[i] < size && size <= tiled_pitches[i+1]) { return tiled_pitches[i+1]; } @@ -369,7 +369,7 @@ s32 _cellGcmInitBody(vm::ptr context, u32 cmdSize, u32 ioSiz u32 ctx_begin = ioAddress/* + 0x1000*/; u32 ctx_size = 0x6ffc; current_context.begin = ctx_begin; - current_context.end = ctx_begin + ctx_size; + current_context.end = ctx_begin + ctx_size - 4; current_context.current = current_context.begin; current_context.callback.set(be_t::make(Emu.GetRSXCallback() - 4)); @@ -805,8 +805,7 @@ s32 cellGcmAddressToOffset(u64 address, vm::ptr> offset) cellGcmSys->Log("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.addr()); // Address not on main memory or local memory - if (!address || address >= 0xD0000000) { - cellGcmSys->Error("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.addr()); + if (address >= 0xD0000000) { return CELL_GCM_ERROR_FAILURE; } @@ -1170,12 +1169,16 @@ s32 cellGcmCallback(vm::ptr context, u32 count) { cellGcmSys->Log("cellGcmCallback(context_addr=0x%x, count=0x%x)", context.addr(), count); - GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH); - if (1) { auto& ctrl = vm::get_ref(gcm_info.control_addr); be_t res = be_t::make(context->current - context->begin - ctrl.put.read_relaxed()); + + if (res != 0) + { + GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH); + } + memmove(vm::get_ptr(context->begin), vm::get_ptr(context->current - res), res); context->current = context->begin + res; diff --git a/rpcs3/cellMic.h b/rpcs3/Emu/SysCalls/Modules/cellMic.h similarity index 100% rename from rpcs3/cellMic.h rename to rpcs3/Emu/SysCalls/Modules/cellMic.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.h b/rpcs3/Emu/SysCalls/Modules/cellPamf.h index 13a051285c..33904beb97 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.h +++ b/rpcs3/Emu/SysCalls/Modules/cellPamf.h @@ -391,3 +391,5 @@ struct CellPamfReader }; static_assert(sizeof(CellPamfReader) == 128, "Invalid CellPamfReader size"); + +s32 cellPamfReaderInitialize(vm::ptr pSelf, vm::ptr pAddr, u64 fileSize, u32 attribute); \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellSail.cpp b/rpcs3/Emu/SysCalls/Modules/cellSail.cpp index b4d1eba987..9e5ee1fc73 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSail.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSail.cpp @@ -1,8 +1,10 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/SysCalls/Modules.h" +#include "Emu/FS/vfsFile.h" #include "cellSail.h" +#include "cellPamf.h" Module *cellSail = nullptr; @@ -11,6 +13,7 @@ int cellSailMemAllocatorInitialize(vm::ptr pSelf, vm::ptr< cellSail->Warning("cellSailMemAllocatorInitialize(pSelf_addr=0x%x, pCallbacks_addr=0x%x)", pSelf.addr(), pCallbacks.addr()); pSelf->callbacks = pCallbacks; + // TODO: Create a cellSail thread return CELL_OK; } @@ -91,9 +94,22 @@ int cellSailDescriptorIsAutoSelection(vm::ptr pSelf) return CELL_OK; } -int cellSailDescriptorCreateDatabase() +int cellSailDescriptorCreateDatabase(vm::ptr pSelf, vm::ptr pDatabase, be_t size, be_t arg) { - UNIMPLEMENTED_FUNC(cellSail); + cellSail->Warning("cellSailDescriptorCreateDatabase(pSelf=0x%x, pDatabase=0x%x, size=0x%x, arg=0x%x", pSelf.addr(), pDatabase.addr(), size, arg); + + switch ((s32)pSelf->streamType) { + case CELL_SAIL_STREAM_PAMF: + { + u32 addr = pSelf->internalData[1]; + auto ptr = vm::ptr::make(addr); + memcpy(pDatabase.get_ptr(), ptr.get_ptr(), sizeof(CellPamfReader)); + break; + } + default: + cellSail->Error("Unhandled stream type: %d", pSelf->streamType); + } + return CELL_OK; } @@ -616,28 +632,52 @@ int cellSailPlayerAddDescriptor(vm::ptr pSelf, vm::ptr pSelf, s32 streamType, vm::ptr pMediaInfo, vm::ptr pUri, vm::ptr ppDesc) +int cellSailPlayerCreateDescriptor(vm::ptr pSelf, s32 streamType, vm::ptr pMediaInfo, vm::ptr pUri, vm::ptr ppDesc) { - cellSail->Todo("cellSailPlayerCreateDescriptor(pSelf_addr=0x%x, streamType=%d, pMediaInfo_addr=0x%x, pUri_addr=0x%x, ppDesc_addr=0x%x)", pSelf.addr(), streamType, + cellSail->Warning("cellSailPlayerCreateDescriptor(pSelf_addr=0x%x, streamType=%d, pMediaInfo_addr=0x%x, pUri_addr=0x%x, ppDesc_addr=0x%x)", pSelf.addr(), streamType, pMediaInfo.addr(), pUri.addr(), ppDesc.addr()); - //cellSail->Todo("Descriptor: %i", sizeof(CellSailDescriptor)); - //cellSail->Todo("Player: %i", sizeof(CellSailPlayer)); + u32 descriptorAddress = Memory.Alloc(sizeof(CellSailDescriptor), 1); + auto descriptor = vm::ptr::make(descriptorAddress); + *ppDesc = descriptorAddress; + descriptor->streamType = streamType; + descriptor->registered = false; - // TODO: Let the game allocate memory for the descriptor, setup the descriptor and pass it back to the game - - //CellSailDescriptor *pDesc = new CellSailDescriptor(); - //u32 descriptorAddress = pSelf->allocator->callbacks->pAlloc(pSelf->allocator->pArg, sizeof(CellSailDescriptor), sizeof(CellSailDescriptor)); - u32 descriptorAddress = Memory.Alloc(sizeof(CellSailDescriptor), sizeof(CellSailDescriptor)); - cellSail->Error("Address: 0x%x", descriptorAddress); - //vm::ptr descriptor = vm::ptr::make(Memory.RealToVirtualAddr(&descriptorAddress)); - vm::ptr descriptor = vm::ptr::make(descriptorAddress); - //descriptor->streamType = streamType; - //descriptor->registered = false; - - pSelf->descriptors = 0; + //pSelf->descriptors = 0; pSelf->repeatMode = 0; - //ppDesc = descriptor; + + switch (streamType) + { + case CELL_SAIL_STREAM_PAMF: + { + std::string uri = pUri.get_ptr(); + if (uri.substr(0, 12) == "x-cell-fs://") { + std::string path = uri.substr(12); + vfsFile f; + if (f.Open(path)) { + u64 size = f.GetSize(); + u32 buf_ = Memory.Alloc(size, 1); + auto bufPtr = vm::ptr::make(buf_); + PamfHeader *buf = const_cast(bufPtr.get_ptr()); + assert(f.Read(buf, size) == size); + u32 sp_ = Memory.Alloc(sizeof(CellPamfReader), 1); + auto sp = vm::ptr::make(sp_); + u32 r = cellPamfReaderInitialize(sp, bufPtr, size, 0); + + descriptor->internalData[0] = buf_; + descriptor->internalData[1] = sp_; + } + else + cellSail->Warning("Couldn't open PAMF: %s", uri.c_str()); + + } + else + cellSail->Warning("Unhandled uri: %s", uri.c_str()); + break; + } + default: + cellSail->Error("Unhandled stream type: %d", streamType); + } //cellSail->Todo("pSelf_addr=0x%x, pDesc_addr=0x%x", pSelf.addr(), descriptor.addr()); //cellSailPlayerAddDescriptor(pSelf, ppDesc); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSail.h b/rpcs3/Emu/SysCalls/Modules/cellSail.h index eb518f110d..d0244fed6d 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSail.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSail.h @@ -679,8 +679,8 @@ typedef void(*CellSailPlayerFuncNotified)(u32 pArg, vm::ptr event struct CellSailMemAllocatorFuncs { - CellSailMemAllocatorFuncAlloc pAlloc; - CellSailMemAllocatorFuncFree pFree; + vm::ptr pAlloc; + vm::ptr pFree; }; struct CellSailMemAllocator @@ -691,8 +691,8 @@ struct CellSailMemAllocator struct CellSailFuture { - u32 mutex_id; - u32 cond_id; + be_t mutex_id; + be_t cond_id; volatile be_t flags; be_t result; be_t userParam; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp index 79cfb5e18a..9e79e0015c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp @@ -10,6 +10,14 @@ #include "Loader/PSF.h" #include "cellSaveData.h" +#ifdef _WIN32 + #include + #undef CreateFile +#else + #include + #include +#endif + extern Module *cellSysutil; // Auxiliary Classes @@ -39,7 +47,6 @@ public: } }; - // Auxiliary Functions u64 getSaveDataSize(const std::string& dirName) { @@ -69,6 +76,28 @@ void addSaveDataEntry(std::vector& saveEntries, const std::string std::string localPath; Emu.GetVFS().GetDevice(saveDir + "/ICON0.PNG", localPath); + u64 atime = 0; + u64 mtime = 0; + u64 ctime = 0; + + cellSysutil->Error("Running _stat in cellSaveData. Please report this to a RPCS3 developer!"); + + std::string pathy; + + Emu.GetVFS().GetDevice("dev_hdd0", pathy); + + struct stat buf; + int result = stat((pathy.substr(0, pathy.length() - 9) + f.GetPath()).c_str(), &buf); + + if (result != 0) + cellSysutil->Error("_stat failed! (%s)", (pathy.substr(0, pathy.length() - 9) + f.GetPath()).c_str()); + else + { + atime = buf.st_atime; + mtime = buf.st_mtime; + ctime = buf.st_ctime; + } + SaveDataEntry saveEntry; saveEntry.dirName = psf.GetString("SAVEDATA_DIRECTORY"); saveEntry.listParam = psf.GetString("SAVEDATA_LIST_PARAM"); @@ -76,9 +105,9 @@ void addSaveDataEntry(std::vector& saveEntries, const std::string saveEntry.subtitle = psf.GetString("SUB_TITLE"); saveEntry.details = psf.GetString("DETAIL"); saveEntry.sizeKB = (u32)(getSaveDataSize(saveDir) / 1024); - saveEntry.st_atime_ = 0; // TODO - saveEntry.st_mtime_ = 0; // TODO - saveEntry.st_ctime_ = 0; // TODO + saveEntry.st_atime_ = atime; + saveEntry.st_mtime_ = mtime; + saveEntry.st_ctime_ = ctime; saveEntry.iconBuf = NULL; // TODO: Here should be the PNG buffer saveEntry.iconBufSize = 0; // TODO: Size of the PNG file saveEntry.isNew = false; @@ -112,7 +141,7 @@ void setSaveDataList(std::vector& saveEntries, vm::ptrdirName == (char*)fixedList[j].dirName) { @@ -215,11 +244,11 @@ void getSaveDataStat(SaveDataEntry entry, vm::ptr statGet) } } - // TODO: Fix the crash - // statGet's fileList doesn't seem to be initiliazed properly, when called by cellSaveDataAutoSave2, thus causing a crash during memcpy. - statGet->fileList = vm::bptr::make(be_t::make((u32)Memory.Alloc(sizeof(CellSaveDataFileStat) * (u32)fileEntries.size(), sizeof(CellSaveDataFileStat)))); - for (u32 i = 0; i < fileEntries.size(); i++) - memcpy(&statGet->fileList[i], &fileEntries[i], sizeof(CellSaveDataFileStat)); + statGet->fileList = vm::ptr::make((u32)Memory.Alloc(sizeof(CellSaveDataFileStat) * fileEntries.size(), 8)); + for (u32 i = 0; i < fileEntries.size(); i++) { + CellSaveDataFileStat *dst = &statGet->fileList[i]; + memcpy(dst, &fileEntries[i], sizeof(CellSaveDataFileStat)); + } } s32 modifySaveDataFiles(vm::ptr funcFile, vm::ptr result, const std::string& saveDataDir) @@ -238,7 +267,7 @@ s32 modifySaveDataFiles(vm::ptr funcFile, vm::ptrError("modifySaveDataFiles: CellSaveDataFileCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. return CELL_SAVEDATA_ERROR_CBRESULT; } - if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) { + if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM) { break; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp index aa7458e940..5afa9e72dc 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp @@ -286,13 +286,13 @@ int cellVideoOutGetNumberOfDevice(u32 videoOut) int cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 aspect, u32 option) { - cellSysutil->Warning("cellVideoOutGetResolutionAvailability(videoOut=%d, resolutionId=0x%x, option_addr=0x%x, aspect=0x%x, option=0x%x)", + cellSysutil->Warning("cellVideoOutGetResolutionAvailability(videoOut=%d, resolutionId=0x%x, option_addr=0x%x, aspect=%d, option=%d)", videoOut, resolutionId, aspect, option); - if(!ResolutionIdToNum(resolutionId)) - { - return CELL_EINVAL; - } + if (!Ini.GS3DTV.GetValue() && (resolutionId == CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING || resolutionId == CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING || + resolutionId == CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING || resolutionId == CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING || + resolutionId == CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING)) + return 0; switch(videoOut) { diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp b/rpcs3/Emu/SysCalls/Modules/sceNp.cpp index ab3645a1cb..a05edc415c 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sceNp.cpp @@ -116,17 +116,16 @@ int npDrmIsAvailable(u32 k_licensee_addr, vm::ptr drm_path) std::string rap_path("/dev_hdd0/home/" + pf_str + "/exdata/"); // Search dev_usb000 for a compatible RAP file. - vfsDir *raps_dir = new vfsDir(rap_path); - if (!raps_dir->IsOpened()) + vfsDir raps_dir(rap_path); + if (!raps_dir.IsOpened()) sceNp->Warning("npDrmIsAvailable: Can't find RAP file for DRM!"); else { - const std::vector &entries = raps_dir->GetEntries(); - for (auto &entry : entries) + for (const DirEntryInfo *entry : raps_dir) { - if (entry.name.find(titleID) != std::string::npos) + if (entry->name.find(titleID) != std::string::npos) { - rap_path += entry.name; + rap_path += entry->name; break; } } diff --git a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp index d9be37b585..4852d04dff 100644 --- a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp +++ b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp @@ -5,6 +5,14 @@ #include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/CB_FUNC.h" +#ifdef _WIN32 + #include + #undef CreateFile +#else + #include + #include +#endif + #include "Emu/FS/VFS.h" #include "Emu/FS/vfsFile.h" #include "Emu/FS/vfsDir.h" @@ -234,16 +242,48 @@ s32 cellFsStat(vm::ptr path, vm::ptr sb) const std::string _path = path.get_ptr(); + u32 mode = 0; + s32 uid = 0; + s32 gid = 0; + u64 atime = 0; + u64 mtime = 0; + u64 ctime = 0; + u64 size = 0; + + std::string real_path; + + Emu.GetVFS().GetDevice(_path, real_path); + + struct stat buf; + + if (int result = stat(real_path.c_str(), &buf)) + { + sys_fs->Error("_stat failed! (%s)", real_path.c_str()); + } + else + { + mode = buf.st_mode; + uid = buf.st_uid; + gid = buf.st_gid; + atime = buf.st_atime; + mtime = buf.st_mtime; + ctime = buf.st_ctime; + size = buf.st_size; + } + sb->st_mode = CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR | CELL_FS_S_IRGRP | CELL_FS_S_IWGRP | CELL_FS_S_IXGRP | CELL_FS_S_IROTH | CELL_FS_S_IWOTH | CELL_FS_S_IXOTH; - sb->st_uid = 0; - sb->st_gid = 0; - sb->st_atime_ = 0; //TODO - sb->st_mtime_ = 0; //TODO - sb->st_ctime_ = 0; //TODO + if (sb->st_mode == mode) + sys_fs->Error("Mode is the same. Report this to a RPCS3 developer! (%d)", mode); + + sb->st_uid = uid; + sb->st_gid = gid; + sb->st_atime_ = atime; + sb->st_mtime_ = mtime; + sb->st_ctime_ = ctime; sb->st_blksize = 4096; { @@ -265,6 +305,9 @@ s32 cellFsStat(vm::ptr path, vm::ptr sb) } } + if (sb->st_size == size && size != 0) + sys_fs->Error("Size is the same. Report this to a RPCS3 developer! (%d)", size); + sys_fs->Warning("cellFsStat: \"%s\" not found.", path.get_ptr()); return CELL_ENOENT; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_process.cpp b/rpcs3/Emu/SysCalls/lv2/sys_process.cpp index e42d34cf1a..24a1753dae 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_process.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_process.cpp @@ -109,8 +109,11 @@ void sys_game_process_exitspawn(vm::ptr path, u32 argv_addr, u32 env device = 0; else if (_path.substr(1, 8) == "dev_hdd1") device = 1; + else if (_path.substr(1, 8) == "dev_bdvd") + device = 2; - Emu.BootGame(_path.c_str(), true, device); + if (device != 0) + Emu.BootGame(_path.c_str(), true, device); return; } @@ -188,6 +191,8 @@ void sys_game_process_exitspawn2(vm::ptr path, u32 argv_addr, u32 en device = 0; else if (_path.substr(1, 8) == "dev_hdd1") device = 1; + else if (_path.substr(1, 8) == "dev_bdvd") + device = 2; Emu.BootGame(_path.c_str(), true, device); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 9c01efad0c..cbc70bdc3c 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -102,6 +102,11 @@ void Emulator::SetTitleID(const std::string& id) m_title_id = id; } +void Emulator::SetTitle(const std::string& title) +{ + m_title = title; +} + void Emulator::CheckStatus() { //auto& threads = GetCPU().GetThreads(); @@ -150,7 +155,7 @@ bool Emulator::BootGame(const std::string& path, bool direct, int device) "/BOOT.BIN", "/PS3_GAME/USRDIR/EBOOT.BIN", "/USRDIR/EBOOT.BIN", - "/EBOOT.BIN", + "/EBOOT.BIN" }; auto curpath = path; @@ -177,6 +182,8 @@ bool Emulator::BootGame(const std::string& path, bool direct, int device) Emu.GetVFS().GetDevice("dev_hdd0", pathy); else if (device == 1) Emu.GetVFS().GetDevice("dev_hdd1", pathy); + else if (device == 2) + Emu.GetVFS().GetDevice("dev_bdvd", pathy); curpath = pathy.substr(0, pathy.length() - 9) + path; @@ -237,6 +244,9 @@ void Emulator::Load() LOG_NOTICE(LOADER, "Title: %s", title.c_str()); LOG_NOTICE(LOADER, "Serial: %s", title_id.c_str()); + title.length() ? SetTitle(title) : SetTitle(m_path); + SetTitleID(title_id); + // bdvd inserting imitation vfsFile f1("/app_home/../dev_bdvd.path"); if (f1.IsOpened()) diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 7b8689bc5a..99a0225e6a 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -114,6 +114,7 @@ public: std::string m_elf_path; std::string m_emu_path; std::string m_title_id; + std::string m_title; s32 m_sdk_version; Emulator(); @@ -122,6 +123,7 @@ public: void Init(); void SetPath(const std::string& path, const std::string& elf_path = ""); void SetTitleID(const std::string& id); + void SetTitle(const std::string& title); std::string GetPath() const { @@ -133,6 +135,16 @@ public: return m_emu_path; } + std::string GetTitleID() const + { + return m_title_id; + } + + std::string GetTitle() const + { + return m_title; + } + void SetEmulatorPath(const std::string& path) { m_emu_path = path; diff --git a/rpcs3/Gui/GLGSFrame.cpp b/rpcs3/Gui/GLGSFrame.cpp index 8a0fc1aab7..c3f34c14eb 100644 --- a/rpcs3/Gui/GLGSFrame.cpp +++ b/rpcs3/Gui/GLGSFrame.cpp @@ -1,5 +1,6 @@ #include "stdafx_gui.h" #include "Emu/Memory/Memory.h" +#include "Emu/System.h" #include "GLGSFrame.h" #include "Utilities/Timer.h" @@ -61,10 +62,12 @@ void GLGSFrame::Flip(void* context) canvas->SwapBuffers(); m_frames++; + const std::string sub_title = Emu.GetTitle() += Emu.GetTitleID().length() ? " [" + Emu.GetTitleID() + "] | " : " | "; + if (fps_t.GetElapsedTimeInSec() >= 0.5) { // can freeze on exit - SetTitle(wxString::Format("FPS: %.2f", (double)m_frames / fps_t.GetElapsedTimeInSec())); + SetTitle(sub_title + wxString::Format("FPS: %.2f", (double)m_frames / fps_t.GetElapsedTimeInSec())); m_frames = 0; fps_t.Start(); } diff --git a/rpcs3/Gui/GameViewer.h b/rpcs3/Gui/GameViewer.h index 21c90077b3..b0b968b7e9 100644 --- a/rpcs3/Gui/GameViewer.h +++ b/rpcs3/Gui/GameViewer.h @@ -157,7 +157,7 @@ public: { list->DeleteAllItems(); list->SetImageList(m_img_list, wxIMAGE_LIST_SMALL); - for(int c=0; cGetColumnCount(); ++c) + for(int c=1; cGetColumnCount(); ++c) { Column* col = GetColumnByPos(c); @@ -175,7 +175,6 @@ public: list->SetItemData(i, i); } list->SetItem(i, c, fmt::FromUTF8(col->data[i])); - list->SetItem(i, 0, wxEmptyString); // don't insert icon path list->SetItemColumnImage(i, 0, m_icon_indexes[i]); } } diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index 6c096cda47..595d207423 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -20,6 +20,7 @@ #include "Gui/KernelExplorer.h" #include "Gui/MemoryViewer.h" #include "Gui/RSXDebugger.h" +#include "Gui/MemoryStringSearcher.h" #include "Gui/LLEModulesManager.h" #include @@ -51,6 +52,7 @@ enum IDs id_tools_kernel_explorer, id_tools_memory_viewer, id_tools_rsx_debugger, + id_tools_string_search, id_help_about, id_update_dbg, }; @@ -112,6 +114,7 @@ MainFrame::MainFrame() menu_tools->Append(id_tools_kernel_explorer, "&Kernel Explorer")->Enable(false); menu_tools->Append(id_tools_memory_viewer, "&Memory Viewer")->Enable(false); menu_tools->Append(id_tools_rsx_debugger, "&RSX Debugger")->Enable(false); + menu_tools->Append(id_tools_string_search, "&String Search")->Enable(false); wxMenu* menu_help = new wxMenu(); menubar->Append(menu_help, "&Help"); @@ -151,6 +154,7 @@ MainFrame::MainFrame() Bind(wxEVT_MENU, &MainFrame::OpenKernelExplorer, this, id_tools_kernel_explorer); Bind(wxEVT_MENU, &MainFrame::OpenMemoryViewer, this, id_tools_memory_viewer); Bind(wxEVT_MENU, &MainFrame::OpenRSXDebugger, this, id_tools_rsx_debugger); + Bind(wxEVT_MENU, &MainFrame::OpenStringSearch, this, id_tools_string_search); Bind(wxEVT_MENU, &MainFrame::AboutDialogHandler, this, id_help_about); @@ -342,7 +346,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxDialog diag(this, wxID_ANY, "Settings", wxDefaultPosition); static const u32 width = 425; - static const u32 height = 400; + static const u32 height = 460; // Settings panels wxNotebook* nb_config = new wxNotebook(&diag, wxID_ANY, wxPoint(6,6), wxSize(width, height)); @@ -378,6 +382,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxStaticBoxSizer* s_round_gs_render = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Render")); wxStaticBoxSizer* s_round_gs_res = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Default resolution")); wxStaticBoxSizer* s_round_gs_aspect = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Default aspect ratio")); + wxStaticBoxSizer* s_round_gs_frame_limit = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Frame limit")); // Input / Output wxStaticBoxSizer* s_round_io_pad_handler = new wxStaticBoxSizer(wxVERTICAL, p_io, _("Pad Handler")); @@ -402,6 +407,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxComboBox* cbox_gs_render = new wxComboBox(p_graphics, wxID_ANY); wxComboBox* cbox_gs_resolution = new wxComboBox(p_graphics, wxID_ANY); wxComboBox* cbox_gs_aspect = new wxComboBox(p_graphics, wxID_ANY); + wxComboBox* cbox_gs_frame_limit = new wxComboBox(p_graphics, wxID_ANY); wxComboBox* cbox_pad_handler = new wxComboBox(p_io, wxID_ANY); wxComboBox* cbox_keyboard_handler = new wxComboBox(p_io, wxID_ANY); wxComboBox* cbox_mouse_handler = new wxComboBox(p_io, wxID_ANY); @@ -414,6 +420,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxCheckBox* chbox_gs_log_prog = new wxCheckBox(p_graphics, wxID_ANY, "Log vertex/fragment programs"); wxCheckBox* chbox_gs_dump_depth = new wxCheckBox(p_graphics, wxID_ANY, "Write Depth Buffer"); wxCheckBox* chbox_gs_dump_color = new wxCheckBox(p_graphics, wxID_ANY, "Write Color Buffers"); + wxCheckBox* chbox_gs_read_color = new wxCheckBox(p_graphics, wxID_ANY, "Read Color Buffer"); wxCheckBox* chbox_gs_vsync = new wxCheckBox(p_graphics, wxID_ANY, "VSync"); wxCheckBox* chbox_gs_3dmonitor = new wxCheckBox(p_graphics, wxID_ANY, "3D Monitor"); wxCheckBox* chbox_audio_dump = new wxCheckBox(p_audio, wxID_ANY, "Dump to file"); @@ -447,6 +454,9 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) cbox_gs_aspect->Append("4:3"); cbox_gs_aspect->Append("16:9"); + for (auto item : { "Off", "50", "59.94", "30", "60", "Auto" }) + cbox_gs_frame_limit->Append(item); + cbox_pad_handler->Append("Null"); cbox_pad_handler->Append("Windows"); #if defined (_WIN32) @@ -501,6 +511,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) chbox_gs_log_prog ->SetValue(Ini.GSLogPrograms.GetValue()); chbox_gs_dump_depth ->SetValue(Ini.GSDumpDepthBuffer.GetValue()); chbox_gs_dump_color ->SetValue(Ini.GSDumpColorBuffers.GetValue()); + chbox_gs_read_color ->SetValue(Ini.GSReadColorBuffer.GetValue()); chbox_gs_vsync ->SetValue(Ini.GSVSyncEnable.GetValue()); chbox_gs_3dmonitor ->SetValue(Ini.GS3DTV.GetValue()); chbox_audio_dump ->SetValue(Ini.AudioDumpToFile.GetValue()); @@ -521,6 +532,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) cbox_gs_render ->SetSelection(Ini.GSRenderMode.GetValue()); cbox_gs_resolution ->SetSelection(ResolutionIdToNum(Ini.GSResolution.GetValue()) - 1); cbox_gs_aspect ->SetSelection(Ini.GSAspectRatio.GetValue() - 1); + cbox_gs_frame_limit ->SetSelection(Ini.GSFrameLimit.GetValue()); cbox_pad_handler ->SetSelection(Ini.PadHandlerMode.GetValue()); cbox_keyboard_handler->SetSelection(Ini.KeyboardHandlerMode.GetValue()); cbox_mouse_handler ->SetSelection(Ini.MouseHandlerMode.GetValue()); @@ -543,6 +555,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) s_round_gs_render->Add(cbox_gs_render, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs_res->Add(cbox_gs_resolution, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs_aspect->Add(cbox_gs_aspect, wxSizerFlags().Border(wxALL, 5).Expand()); + s_round_gs_frame_limit->Add(cbox_gs_frame_limit, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_io_pad_handler->Add(cbox_pad_handler, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_io_keyboard_handler->Add(cbox_keyboard_handler, wxSizerFlags().Border(wxALL, 5).Expand()); @@ -565,9 +578,11 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) s_subpanel_graphics->Add(s_round_gs_render, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(s_round_gs_res, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(s_round_gs_aspect, wxSizerFlags().Border(wxALL, 5).Expand()); + s_subpanel_graphics->Add(s_round_gs_frame_limit, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_log_prog, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_dump_depth, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_dump_color, wxSizerFlags().Border(wxALL, 5).Expand()); + s_subpanel_graphics->Add(chbox_gs_read_color, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_vsync, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_3dmonitor, wxSizerFlags().Border(wxALL, 5).Expand()); @@ -625,9 +640,11 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) Ini.GSRenderMode.SetValue(cbox_gs_render->GetSelection()); Ini.GSResolution.SetValue(ResolutionNumToId(cbox_gs_resolution->GetSelection() + 1)); Ini.GSAspectRatio.SetValue(cbox_gs_aspect->GetSelection() + 1); + Ini.GSFrameLimit.SetValue(cbox_gs_frame_limit->GetSelection()); Ini.GSLogPrograms.SetValue(chbox_gs_log_prog->GetValue()); Ini.GSDumpDepthBuffer.SetValue(chbox_gs_dump_depth->GetValue()); Ini.GSDumpColorBuffers.SetValue(chbox_gs_dump_color->GetValue()); + Ini.GSReadColorBuffer.SetValue(chbox_gs_read_color->GetValue()); Ini.GSVSyncEnable.SetValue(chbox_gs_vsync->GetValue()); Ini.GS3DTV.SetValue(chbox_gs_3dmonitor->GetValue()); Ini.PadHandlerMode.SetValue(cbox_pad_handler->GetSelection()); @@ -707,6 +724,10 @@ void MainFrame::OpenRSXDebugger(wxCommandEvent& WXUNUSED(event)) (new RSXDebugger(this)) -> Show(); } +void MainFrame::OpenStringSearch(wxCommandEvent& WXUNUSED(event)) +{ + (new MemoryStringSearcher(this)) -> Show(); +} void MainFrame::AboutDialogHandler(wxCommandEvent& WXUNUSED(event)) { @@ -805,9 +826,12 @@ void MainFrame::UpdateUI(wxCommandEvent& event) wxMenuItem& kernel_explorer = *menubar.FindItem(id_tools_kernel_explorer); wxMenuItem& memory_viewer = *menubar.FindItem(id_tools_memory_viewer); wxMenuItem& rsx_debugger = *menubar.FindItem(id_tools_rsx_debugger); + wxMenuItem& string_search = *menubar.FindItem(id_tools_string_search); kernel_explorer.Enable(!is_stopped); memory_viewer.Enable(!is_stopped); rsx_debugger.Enable(!is_stopped); + string_search.Enable(!is_stopped); + //m_aui_mgr.Update(); diff --git a/rpcs3/Gui/MainFrame.h b/rpcs3/Gui/MainFrame.h index 359e932c6a..3de2d38e6a 100644 --- a/rpcs3/Gui/MainFrame.h +++ b/rpcs3/Gui/MainFrame.h @@ -45,6 +45,7 @@ private: void OpenKernelExplorer(wxCommandEvent& evt); void OpenMemoryViewer(wxCommandEvent& evt); void OpenRSXDebugger(wxCommandEvent& evt); + void OpenStringSearch(wxCommandEvent& evt); void OpenFnIdGenerator(wxCommandEvent& evt); void AboutDialogHandler(wxCommandEvent& event); void UpdateUI(wxCommandEvent& event); diff --git a/rpcs3/Gui/MemoryStringSearcher.cpp b/rpcs3/Gui/MemoryStringSearcher.cpp new file mode 100644 index 0000000000..8676d57371 --- /dev/null +++ b/rpcs3/Gui/MemoryStringSearcher.cpp @@ -0,0 +1,74 @@ +#include "stdafx_gui.h" +#include "rpcs3/Ini.h" +#include "Utilities/rPlatform.h" +#include "Utilities/Log.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" + +#include "MemoryStringSearcher.h" +#include "Emu/RSX/sysutil_video.h" +#include "Emu/RSX/GSManager.h" +//#include "Emu/RSX/GCM.h" + +#include + +MemoryStringSearcher::MemoryStringSearcher(wxWindow* parent) + : wxFrame(parent, wxID_ANY, "String Searcher", wxDefaultPosition, wxSize(545, 64)) + , exit(false) +{ + this->SetBackgroundColour(wxColour(240,240,240)); + //wxBoxSizer* s_panel = new wxBoxSizer(wxHORIZONTAL); + + //Tools + //wxBoxSizer* s_tools = new wxBoxSizer(wxVERTICAL); + + //Tabs + //wxNotebook* nb_rsx = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(482,475)); + + s_panel = new wxBoxSizer(wxHORIZONTAL); + t_addr = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(482, -1)); + b_search = new wxButton(this, wxID_ANY, "Search", wxPoint(482, 0), wxSize(40, -1)); + b_search->Bind(wxEVT_BUTTON, &MemoryStringSearcher::Search, this); + s_panel->Add(t_addr); + s_panel->Add(b_search); +}; + +void MemoryStringSearcher::Search(wxCommandEvent& event) +{ + const wxString wstr = t_addr->GetValue(); + const char *str = wstr.c_str(); + const u32 len = wstr.length(); + + LOG_NOTICE(GENERAL, "Searching for string %s", str); + + // Search the address space for the string + u32 strIndex = 0; + u32 numFound = 0; + for (u32 addr = Memory.MainMem.GetStartAddr(); addr < Memory.MainMem.GetEndAddr(); addr++) { + if (!Memory.IsGoodAddr(addr)) { + strIndex = 0; + continue; + } + + u8 byte = vm::read8(addr); + if (byte == str[strIndex]) { + if (strIndex == len) { + // Found it + LOG_NOTICE(GENERAL, "Found @ %04x", addr - len); + numFound++; + strIndex = 0; + continue; + } + + strIndex++; + } + else + strIndex = 0; + + if (addr % (1024 * 1024 * 64) == 0) { // Log every 64mb + LOG_NOTICE(GENERAL, "Searching %04x ...", addr); + } + } + + LOG_NOTICE(GENERAL, "Search completed (found %d matches)", numFound); +} \ No newline at end of file diff --git a/rpcs3/Gui/MemoryStringSearcher.h b/rpcs3/Gui/MemoryStringSearcher.h new file mode 100644 index 0000000000..f0928afe2d --- /dev/null +++ b/rpcs3/Gui/MemoryStringSearcher.h @@ -0,0 +1,19 @@ +#pragma once +#include + +class MemoryStringSearcher : public wxFrame +{ + wxTextCtrl* t_addr; + wxBoxSizer* s_panel; + wxButton* b_search; + +public: + bool exit; + MemoryStringSearcher(wxWindow* parent); + ~MemoryStringSearcher() + { + exit = true; + } + + void Search(wxCommandEvent& event); +}; diff --git a/rpcs3/Gui/MemoryViewer.cpp b/rpcs3/Gui/MemoryViewer.cpp index 73b57c835e..59f3917713 100644 --- a/rpcs3/Gui/MemoryViewer.cpp +++ b/rpcs3/Gui/MemoryViewer.cpp @@ -22,12 +22,12 @@ MemoryViewerPanel::MemoryViewerPanel(wxWindow* parent) wxStaticBoxSizer* s_tools_mem = new wxStaticBoxSizer(wxHORIZONTAL, this, "Memory Viewer Options"); wxStaticBoxSizer* s_tools_mem_addr = new wxStaticBoxSizer(wxHORIZONTAL, this, "Address"); - t_addr = new wxTextCtrl(this, wxID_ANY, "00000000", wxDefaultPosition, wxSize(60,-1)); + t_addr = new wxTextCtrl(this, wxID_ANY, "00000000", wxDefaultPosition, wxSize(60, -1)); t_addr->SetMaxLength(8); s_tools_mem_addr->Add(t_addr); wxStaticBoxSizer* s_tools_mem_bytes = new wxStaticBoxSizer(wxHORIZONTAL, this, "Bytes"); - sc_bytes = new wxSpinCtrl(this, wxID_ANY, "16", wxDefaultPosition, wxSize(44,-1)); + sc_bytes = new wxSpinCtrl(this, wxID_ANY, "16", wxDefaultPosition, wxSize(44, -1)); sc_bytes->SetRange(1, 16); s_tools_mem_bytes->Add(sc_bytes); @@ -49,8 +49,8 @@ MemoryViewerPanel::MemoryViewerPanel(wxWindow* parent) wxStaticBoxSizer* s_tools_img = new wxStaticBoxSizer(wxHORIZONTAL, this, "Raw Image Preview"); wxStaticBoxSizer* s_tools_img_size = new wxStaticBoxSizer(wxHORIZONTAL, this, "Size"); - sc_img_size_x = new wxSpinCtrl(this, wxID_ANY, "256", wxDefaultPosition, wxSize(60,-1)); - sc_img_size_y = new wxSpinCtrl(this, wxID_ANY, "256", wxDefaultPosition, wxSize(60,-1)); + sc_img_size_x = new wxSpinCtrl(this, wxID_ANY, "256", wxDefaultPosition, wxSize(60, -1)); + sc_img_size_y = new wxSpinCtrl(this, wxID_ANY, "256", wxDefaultPosition, wxSize(60, -1)); s_tools_img_size->Add(sc_img_size_x); s_tools_img_size->Add(new wxStaticText(this, wxID_ANY, " x ")); s_tools_img_size->Add(sc_img_size_y); @@ -72,7 +72,7 @@ MemoryViewerPanel::MemoryViewerPanel(wxWindow* parent) //Tools: Run tools wxStaticBoxSizer* s_tools_buttons = new wxStaticBoxSizer(wxVERTICAL, this, "Tools"); - wxButton* b_img = new wxButton(this, wxID_ANY, "View\nimage", wxDefaultPosition, wxSize(52,-1)); + wxButton* b_img = new wxButton(this, wxID_ANY, "View\nimage", wxDefaultPosition, wxSize(52, -1)); s_tools_buttons->Add(b_img); //Tools: Tools = Memory Viewer Options + Raw Image Preview Options + Buttons @@ -108,8 +108,8 @@ MemoryViewerPanel::MemoryViewerPanel(wxWindow* parent) //Memory Panel: Set size of the wxTextCtrl's int x, y; t_mem_hex->GetTextExtent(wxT("T"), &x, &y); - t_mem_hex->SetMinSize(wxSize(x * 3*m_colcount + 6, 228)); - t_mem_hex->SetMaxSize(wxSize(x * 3*m_colcount + 6, 228)); + t_mem_hex->SetMinSize(wxSize(x * 3 * m_colcount + 6, 228)); + t_mem_hex->SetMaxSize(wxSize(x * 3 * m_colcount + 6, 228)); t_mem_ascii->SetMinSize(wxSize(x * m_colcount + 6, 228)); t_mem_ascii->SetMaxSize(wxSize(x * m_colcount + 6, 228)); @@ -156,8 +156,8 @@ void MemoryViewerPanel::OnChangeToolsBytes(wxCommandEvent& event) int x, y; t_mem_hex->GetTextExtent(wxT("T"), &x, &y); - t_mem_hex->SetMinSize(wxSize(x * 3*m_colcount + 6, 228)); - t_mem_hex->SetMaxSize(wxSize(x * 3*m_colcount + 6, 228)); + t_mem_hex->SetMinSize(wxSize(x * 3 * m_colcount + 6, 228)); + t_mem_hex->SetMaxSize(wxSize(x * 3 * m_colcount + 6, 228)); t_mem_ascii->SetMinSize(wxSize(x * m_colcount + 6, 228)); t_mem_ascii->SetMaxSize(wxSize(x * m_colcount + 6, 228)); this->Layout(); @@ -242,43 +242,43 @@ void MemoryViewerPanel::ShowImage(wxWindow* parent, u32 addr, int mode, u32 widt break; case(1): // ARGB - for (u32 y=0; y GSRenderMode; IniEntry GSResolution; IniEntry GSAspectRatio; + IniEntry GSFrameLimit; IniEntry GSLogPrograms; IniEntry GSDumpColorBuffers; IniEntry GSDumpDepthBuffer; + IniEntry GSReadColorBuffer; IniEntry GSVSyncEnable; IniEntry GS3DTV; @@ -179,9 +181,11 @@ public: GSRenderMode.Init("GS_RenderMode", path); GSResolution.Init("GS_Resolution", path); GSAspectRatio.Init("GS_AspectRatio", path); + GSFrameLimit.Init("GS_FrameLimit", path); GSLogPrograms.Init("GS_LogPrograms", path); GSDumpColorBuffers.Init("GS_DumpColorBuffers", path); GSDumpDepthBuffer.Init("GS_DumpDepthBuffer", path); + GSReadColorBuffer.Init("GS_GSReadColorBuffer", path); GSVSyncEnable.Init("GS_VSyncEnable", path); GS3DTV.Init("GS_3DTV", path); @@ -250,9 +254,11 @@ public: GSRenderMode.Load(1); GSResolution.Load(4); GSAspectRatio.Load(2); + GSFrameLimit.Load(0); GSLogPrograms.Load(false); GSDumpColorBuffers.Load(false); GSDumpDepthBuffer.Load(false); + GSReadColorBuffer.Load(false); GSVSyncEnable.Load(false); GS3DTV.Load(false); @@ -322,9 +328,11 @@ public: GSRenderMode.Save(); GSResolution.Save(); GSAspectRatio.Save(); + GSFrameLimit.Save(); GSLogPrograms.Save(); GSDumpColorBuffers.Save(); GSDumpDepthBuffer.Save(); + GSReadColorBuffer.Save(); GSVSyncEnable.Save(); GS3DTV.Save(); diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index cbfb8a0317..31925d4b57 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -55,7 +55,7 @@ namespace loader { m_shdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum); m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_shoff : m_ehdr.data_be.e_shoff)); - size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum) * sizeof(phdr); + size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum) * sizeof(shdr); if (m_stream->Read(m_shdrs.data(), size) != size) return broken_file; @@ -284,4 +284,4 @@ namespace loader return ok; } } -} \ No newline at end of file +} diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 48e253c667..dcaf0010f5 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -281,7 +281,6 @@ - @@ -419,8 +418,9 @@ - + + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 5004d39614..01b67c4ce8 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -69,16 +69,16 @@ {1d9e6fc4-9a79-4329-a8b5-081e24822aaa} - + {6674e2ab-90cd-47de-a852-d21643ab18c2} - + {fadb4b36-57af-4583-891d-d22ff369e266} - + {4adca4fa-b90f-4662-9eb0-1d29cf3cd2eb} - + {6f1da5b2-52c5-416b-9b5c-b9897bc1b300} @@ -546,37 +546,37 @@ Emu\SysCalls\Modules - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX Emu\SysCalls\lv2 @@ -742,6 +742,9 @@ Emu\SysCalls\Modules + + Emu\SysCalls\Modules + Emu\SysCalls\Modules @@ -1112,58 +1115,58 @@ Emu\SysCalls - GPU\RSX\Null + Emu\GPU\RSX\Null - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX Emu\SysCalls\lv2 @@ -1240,9 +1243,6 @@ Crypto - - Emu\SysCalls\Modules - Emu\CPU\Cell diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index d762f00bd4..6eb8cbc46b 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -3,6 +3,7 @@ #include "Emu/System.h" #include "rpcs3.h" #include "Ini.h" +#include "Utilities/Log.h" #include "Gui/ConLogFrame.h" #include "Emu/GameInfo.h" @@ -42,6 +43,163 @@ Rpcs3App* TheApp; std::string simplify_path(const std::string& path, bool is_dir); +typedef be_t CGprofile; +typedef int CGbool; +typedef be_t CGresource; +typedef be_t CGenum; +typedef be_t CGtype; + +typedef be_t CgBinaryOffset; +typedef CgBinaryOffset CgBinaryEmbeddedConstantOffset; +typedef CgBinaryOffset CgBinaryFloatOffset; +typedef CgBinaryOffset CgBinaryStringOffset; +typedef CgBinaryOffset CgBinaryParameterOffset; + +// a few typedefs +typedef struct CgBinaryParameter CgBinaryParameter; +typedef struct CgBinaryEmbeddedConstant CgBinaryEmbeddedConstant; +typedef struct CgBinaryVertexProgram CgBinaryVertexProgram; +typedef struct CgBinaryFragmentProgram CgBinaryFragmentProgram; +typedef struct CgBinaryProgram CgBinaryProgram; + +// fragment programs have their constants embedded in the microcode +struct CgBinaryEmbeddedConstant +{ + be_t ucodeCount; // occurances + be_t ucodeOffset[1]; // offsets that need to be patched follow +}; + +// describe a binary program parameter (CgParameter is opaque) +struct CgBinaryParameter +{ + CGtype type; // cgGetParameterType() + CGresource res; // cgGetParameterResource() + CGenum var; // cgGetParameterVariability() + be_t resIndex; // cgGetParameterResourceIndex() + CgBinaryStringOffset name; // cgGetParameterName() + CgBinaryFloatOffset defaultValue; // default constant value + CgBinaryEmbeddedConstantOffset embeddedConst; // embedded constant information + CgBinaryStringOffset semantic; // cgGetParameterSemantic() + CGenum direction; // cgGetParameterDirection() + be_t paramno; // 0..n: cgGetParameterIndex() -1: globals + CGbool isReferenced; // cgIsParameterReferenced() + CGbool isShared; // cgIsParameterShared() +}; + +// attributes needed for vshaders +struct CgBinaryVertexProgram +{ + be_t instructionCount; // #instructions + be_t instructionSlot; // load address (indexed reads!) + be_t registerCount; // R registers count + be_t attributeInputMask; // attributes vs reads from + be_t attributeOutputMask; // attributes vs writes (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits) + be_t userClipMask; // user clip plane enables (for SET_USER_CLIP_PLANE_CONTROL) +}; + +typedef enum { + CgBinaryPTTNone = 0, + CgBinaryPTT2x16 = 1, + CgBinaryPTT1x32 = 2, +} CgBinaryPartialTexType; + +// attributes needed for pshaders +struct CgBinaryFragmentProgram +{ + be_t instructionCount; // #instructions + be_t attributeInputMask; // attributes fp reads (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits) + be_t partialTexType; // texid 0..15 use two bits each marking whether the texture format requires partial load: see CgBinaryPartialTexType + be_t texCoordsInputMask; // tex coords used by frag prog. (tex is bit n) + be_t texCoords2D; // tex coords that are 2d (tex is bit n) + be_t texCoordsCentroid; // tex coords that are centroid (tex is bit n) + unsigned char registerCount; // R registers count + unsigned char outputFromH0; // final color from R0 or H0 + unsigned char depthReplace; // fp generated z epth value + unsigned char pixelKill; // fp uses kill operations +}; + +#include "Emu/RSX/GL/GLFragmentProgram.h" +#include "Emu/RSX/GL/GLVertexProgram.h" +// defines a binary program -- *all* address/offsets are relative to the begining of CgBinaryProgram +struct CgBinaryProgram +{ + // vertex/pixel shader identification (BE/LE as well) + CGprofile profile; + + // binary revision (used to verify binary and driver structs match) + be_t binaryFormatRevision; + + // total size of this struct including profile and totalSize field! + be_t totalSize; + + // parameter usually queried using cgGet[First/Next]LeafParameter + be_t parameterCount; + CgBinaryParameterOffset parameterArray; + + // depending on profile points to a CgBinaryVertexProgram or CgBinaryFragmentProgram struct + CgBinaryOffset program; + + // raw ucode data + be_t ucodeSize; + CgBinaryOffset ucode; + + // variable length data follows + unsigned char data[1]; +}; + +void compile_shader(std::string path) +{ + ShaderVar var("r0.yz.x"); + var.symplify(); + LOG_ERROR(GENERAL, var.get().c_str()); + + u32 ptr; + { + wxFile f(path); + + if (!f.IsOpened()) + return; + + size_t size = f.Length(); + vm::ps3::init(); + ptr = vm::alloc(size); + f.Read(vm::get_ptr(ptr), size); + f.Close(); + } + + CgBinaryProgram& prog = vm::get_ref(ptr); + LOG_ERROR(GENERAL, "%d - %x", (u32)prog.profile, (u32)prog.binaryFormatRevision); + + std::string shader; + GLParamArray param_array; + u32 size; + + if (prog.profile == 7004) + { + CgBinaryFragmentProgram& fprog = vm::get_ref(ptr + prog.program); + + u32 ctrl = (fprog.outputFromH0 ? 0 : 0x40) | (fprog.depthReplace ? 0xe : 0); + + GLFragmentDecompilerThread(shader, param_array, ptr + prog.ucode, size, ctrl).Task(); + } + else + { + CgBinaryVertexProgram& vprog = vm::get_ref(ptr + prog.program); + + std::vector data; + be_t* vdata = vm::get_ptr>(ptr + prog.ucode); + for (u32 i = 0; i < prog.ucodeSize; ++i, ++vdata) + { + data.push_back(vdata[i]); + } + + GLVertexDecompilerThread(data, shader, param_array).Task(); + } + + LOG_ERROR(GENERAL, shader.c_str()); + vm::close(); +} + bool Rpcs3App::OnInit() { SetSendDbgCommandCallback([](DbgCommand id, CPUThread* t) @@ -140,6 +298,9 @@ bool Rpcs3App::OnInit() OnArguments(); + //compile_shader("compile_shader0.spo"); + //compile_shader("compile_shader1.spo"); + return true; } @@ -181,9 +342,9 @@ Rpcs3App::Rpcs3App() timeBeginPeriod(1); #endif - #if defined(__unix__) && !defined(__APPLE__) +#if defined(__unix__) && !defined(__APPLE__) XInitThreads(); - #endif +#endif } GameInfo CurGameInfo; diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 946b6cb66e..44c219a587 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -175,6 +175,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 5fce1aa362..71062a8296 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -93,6 +93,9 @@ Gui + + Gui +