PS5 graphics (#42)

This commit is contained in:
InoriRus 2022-08-16 13:38:38 +03:00
parent e110bd0f63
commit 90acd3d364
46 changed files with 12642 additions and 3962 deletions

View File

@ -1,4 +1,4 @@
version: 0.1.11.build-{build}
version: 0.1.12.build-{build}
image: Visual Studio 2019
environment:
matrix:

View File

@ -82,7 +82,7 @@ if (KYTY_LINKER STREQUAL LD)
set(KYTY_LD_OPTIONS "-Wl,--image-base=0x100000000000")
endif()
project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.1.11)
project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.1.12)
include(src_script.cmake)

View File

@ -41,9 +41,12 @@ enum class ProfilerDirection
void Load(const Scripts::ScriptVar& cfg);
void SetNextGen(bool mode);
uint32_t GetScreenWidth();
uint32_t GetScreenHeight();
bool IsNeo();
bool IsNextGen();
bool VulkanValidationEnabled();
bool ShaderValidationEnabled();

View File

@ -11,6 +11,9 @@
namespace Kyty::Libs::Graphics {
struct Shader;
struct ShaderRegister;
KYTY_SUBSYSTEM_DEFINE(Graphics);
void GraphicsDbgDumpDcb(const char* type, uint32_t num_dw, uint32_t* cmd_buffer);
@ -69,9 +72,7 @@ int KYTY_SYSV_ABI GraphicsUnregisterResource(uint32_t resource_handle);
namespace Gen5 {
struct Shader;
struct CommandBuffer;
struct ShaderRegister;
struct Label;
int KYTY_SYSV_ABI GraphicsInit(uint32_t* state, uint32_t ver);
@ -97,6 +98,7 @@ uint32_t* KYTY_SYSV_ABI GraphicsCbReleaseMem(CommandBuffer* buf, uint8_t action,
uint16_t gds_size, uint8_t interrupt, uint32_t interrupt_ctx_id);
uint32_t* KYTY_SYSV_ABI GraphicsDcbResetQueue(CommandBuffer* buf, uint32_t op, uint32_t state);
uint32_t* KYTY_SYSV_ABI GraphicsDcbWaitUntilSafeForRendering(CommandBuffer* buf, uint32_t video_out_handle, uint32_t display_buffer_index);
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetShRegisterDirect(CommandBuffer* buf, ShaderRegister reg);
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetCxRegistersIndirect(CommandBuffer* buf, const volatile ShaderRegister* regs, uint32_t num_regs);
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetShRegistersIndirect(CommandBuffer* buf, const volatile ShaderRegister* regs, uint32_t num_regs);
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetUcRegistersIndirect(CommandBuffer* buf, const volatile ShaderRegister* regs, uint32_t num_regs);

View File

@ -353,7 +353,7 @@ struct ColorControl
struct ScanModeControl
{
bool msaa_enable = false;
bool vport_scissor_enable = false;
bool vport_scissor_enable = true;
bool line_stipple_enable = false;
};
@ -401,7 +401,7 @@ struct Viewport
struct ScreenViewport
{
Viewport viewports[15];
uint32_t transform_control = 0;
uint32_t transform_control = 1087;
int screen_scissor_left = 0;
int screen_scissor_top = 0;
int screen_scissor_right = 0;

View File

@ -13,7 +13,7 @@ namespace Kyty::Libs::Graphics {
class StorageTextureObject: public GpuObject
{
public:
static constexpr int PARAM_DFMT_NFMT = 0;
static constexpr int PARAM_FORMAT = 0;
static constexpr int PARAM_PITCH = 1;
static constexpr int PARAM_WIDTH_HEIGHT = 2;
static constexpr int PARAM_LEVELS = 3;
@ -21,10 +21,10 @@ public:
static constexpr int PARAM_NEO = 5;
static constexpr int PARAM_SWIZZLE = 6;
StorageTextureObject(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t base_level,
StorageTextureObject(uint8_t dfmt, uint8_t nfmt, uint16_t fmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t base_level,
uint32_t levels, uint32_t tile, bool neo, uint32_t swizzle)
{
params[PARAM_DFMT_NFMT] = (static_cast<uint64_t>(dfmt) << 32u) | nfmt;
params[PARAM_FORMAT] = (static_cast<uint64_t>(fmt) << 16u) | (static_cast<uint64_t>(dfmt) << 8u) | nfmt;
params[PARAM_PITCH] = pitch;
params[PARAM_WIDTH_HEIGHT] = (static_cast<uint64_t>(width) << 32u) | height;
params[PARAM_LEVELS] = (static_cast<uint64_t>(base_level) << 32u) | levels;

View File

@ -13,7 +13,7 @@ namespace Kyty::Libs::Graphics {
class TextureObject: public GpuObject
{
public:
static constexpr int PARAM_DFMT_NFMT = 0;
static constexpr int PARAM_FORMAT = 0;
static constexpr int PARAM_PITCH = 1;
static constexpr int PARAM_WIDTH_HEIGHT = 2;
static constexpr int PARAM_LEVELS = 3;
@ -21,10 +21,10 @@ public:
static constexpr int PARAM_NEO = 5;
static constexpr int PARAM_SWIZZLE = 6;
TextureObject(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t base_level, uint32_t levels,
uint32_t tile, bool neo, uint32_t swizzle)
TextureObject(uint8_t dfmt, uint8_t nfmt, uint16_t fmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t base_level,
uint32_t levels, uint32_t tile, bool neo, uint32_t swizzle)
{
params[PARAM_DFMT_NFMT] = (static_cast<uint64_t>(dfmt) << 32u) | nfmt;
params[PARAM_FORMAT] = (static_cast<uint64_t>(fmt) << 16u) | (static_cast<uint64_t>(dfmt) << 8u) | nfmt;
params[PARAM_PITCH] = pitch;
params[PARAM_WIDTH_HEIGHT] = (static_cast<uint64_t>(width) << 32u) | height;
params[PARAM_LEVELS] = (static_cast<uint64_t>(base_level) << 32u) | levels;

View File

@ -3,6 +3,7 @@
#include "Kyty/Core/Common.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/String8.h"
#include "Kyty/Core/Vector.h"
#include "Emulator/Common.h"
@ -29,7 +30,7 @@ enum class ShaderType
Compute
};
enum class ShaderInstructionType
enum class ShaderInstructionType : uint32_t
{
Unknown,
@ -57,6 +58,8 @@ enum class ShaderInstructionType
SAndB64,
SAndn2B64,
SAndSaveexecB64,
SBfeU32,
SBfeU64,
SBfmB32,
SBranch,
SBufferLoadDword,
@ -84,20 +87,30 @@ enum class ShaderInstructionType
SCselectB32,
SCselectB64,
SEndpgm,
SInstPrefetch,
SLoadDword,
SLoadDwordx2,
SLoadDwordx4,
SLoadDwordx8,
SLoadDwordx16,
SLshl4AddU32,
SLshlB32,
SLshrB32,
SLshlB64,
SLshrB64,
SMovB32,
SMovB64,
SMovkI32,
SMulI32,
SNandB64,
SNorB64,
SOrB32,
SOrB64,
SOrn2B64,
SSendmsg,
SSetpcB64,
SSwappcB64,
SSubI32,
SWaitcnt,
SWqmB64,
SXnorB64,
@ -207,6 +220,12 @@ enum class ShaderInstructionType
VSubrevI32,
VTruncF32,
VXorB32,
FetchX,
FetchXy,
FetchXyz,
FetchXyzw,
ZMax
};
@ -253,6 +272,7 @@ enum FormatByte : uint64_t
Param3, // param3
Param4, // param4
Mrt0, // mrt_color0
Prim, // prim
Off, // off
Compr, // compr
Vm, // vm
@ -292,9 +312,12 @@ enum Format : uint64_t
Param3Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param3, S0, S1, S2, S3}),
Param4Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param4, S0, S1, S2, S3}),
Pos0Vsrc0Vsrc1Vsrc2Vsrc3Done = FormatDefine({Pos0, S0, S1, S2, S3, Done}),
PrimVsrc0OffOffOffDone = FormatDefine({Prim, S0, Off, Off, Off, Done}),
Saddr = FormatDefine({S0A2}),
SdstSbaseSoffset = FormatDefine({D, S0A2, S1}),
Sdst16SvSoffset = FormatDefine({DA16, S0A4, S1}),
Sdst2Ssrc02 = FormatDefine({DA2, S0A2}),
Sdst2Ssrc02Ssrc1 = FormatDefine({DA2, S0A2, S1}),
Sdst2Ssrc02Ssrc12 = FormatDefine({DA2, S0A2, S1A2}),
Sdst2SvSoffset = FormatDefine({DA2, S0A4, S1}),
Sdst4SbaseSoffset = FormatDefine({DA4, S0A2, S1}),
@ -332,6 +355,12 @@ enum Format : uint64_t
} // namespace ShaderInstructionFormat
struct ShaderInstructionTypeFormat
{
ShaderInstructionType type = ShaderInstructionType::Unknown;
ShaderInstructionFormat::Format format = ShaderInstructionFormat::Unknown;
};
enum class ShaderOperandType
{
Unknown,
@ -346,7 +375,8 @@ enum class ShaderOperandType
Scc,
Vgpr,
Sgpr,
M0
M0,
Null
};
union ShaderConstant
@ -387,6 +417,7 @@ struct ShaderInstruction
class ShaderLabel
{
public:
ShaderLabel(uint32_t dst, uint32_t src): m_dst(dst), m_src(src) {}
explicit ShaderLabel(const ShaderInstruction& inst): m_dst(inst.pc + 4 + inst.src[0].constant.i), m_src(inst.pc) {}
~ShaderLabel() = default;
KYTY_CLASS_DEFAULT_COPY(ShaderLabel);
@ -394,7 +425,7 @@ public:
[[nodiscard]] uint32_t GetDst() const { return m_dst; }
[[nodiscard]] uint32_t GetSrc() const { return m_src; }
[[nodiscard]] String ToString() const { return String::FromPrintf("label_%04" PRIx32 "_%04" PRIx32, m_dst, m_src); }
[[nodiscard]] String8 ToString() const { return String8::FromPrintf("label_%04" PRIx32 "_%04" PRIx32, m_dst, m_src); }
void Disable()
{
@ -442,12 +473,14 @@ public:
Vector<ShaderInstruction>& GetInstructions() { return m_instructions; }
[[nodiscard]] const Vector<ShaderLabel>& GetLabels() const { return m_labels; }
Vector<ShaderLabel>& GetLabels() { return m_labels; }
[[nodiscard]] const Vector<ShaderLabel>& GetIndirectLabels() const { return m_indirect_labels; }
Vector<ShaderLabel>& GetIndirectLabels() { return m_indirect_labels; }
[[nodiscard]] const Vector<ShaderDebugPrintf>& GetDebugPrintfs() const { return m_debug_printfs; }
Vector<ShaderDebugPrintf>& GetDebugPrintfs() { return m_debug_printfs; }
[[nodiscard]] String DbgDump() const;
[[nodiscard]] String8 DbgDump() const;
static String DbgInstructionToStr(const ShaderInstruction& inst);
static String8 DbgInstructionToStr(const ShaderInstruction& inst);
[[nodiscard]] ShaderType GetType() const { return m_type; }
void SetType(ShaderType type) { this->m_type = type; }
@ -484,6 +517,7 @@ private:
uint32_t m_crc32 = 0;
Vector<ShaderInstruction> m_instructions;
Vector<ShaderLabel> m_labels;
Vector<ShaderLabel> m_indirect_labels;
ShaderType m_type = ShaderType::Unknown;
Vector<ShaderDebugPrintf> m_debug_printfs;
uint32_t m_vs_embedded_id = 0;
@ -516,15 +550,22 @@ struct ShaderBufferResource
{
uint32_t fields[4] = {0};
void UpdateAddress(uint64_t gpu_addr)
void UpdateAddress44(uint64_t gpu_addr)
{
auto lo = static_cast<uint32_t>(gpu_addr & 0xffffffffu);
auto hi = static_cast<uint32_t>(gpu_addr >> 32u);
fields[0] = lo;
fields[1] = (fields[1] & 0xfffff000u) | (hi & 0xfffu);
fields[1] = (fields[1] & 0xfffff000u) | (hi & 0x00000fffu);
}
void UpdateAddress48(uint64_t gpu_addr)
{
auto lo = static_cast<uint32_t>(gpu_addr & 0xffffffffu);
auto hi = static_cast<uint32_t>(gpu_addr >> 32u);
fields[0] = lo;
fields[1] = (fields[1] & 0xffff0000u) | (hi & 0x0000ffffu);
}
[[nodiscard]] uint64_t Base() const { return (fields[0] | (static_cast<uint64_t>(fields[1]) << 32u)) & 0xFFFFFFFFFFFu; }
[[nodiscard]] uint16_t Stride() const { return (fields[1] >> 16u) & 0x3FFFu; }
[[nodiscard]] bool SwizzleEnabled() const { return ((fields[1] >> 31u) & 0x1u) == 1; }
[[nodiscard]] uint32_t NumRecords() const { return fields[2]; }
@ -535,11 +576,16 @@ struct ShaderBufferResource
[[nodiscard]] uint32_t DstSelXY() const { return (fields[3] >> 0u) & 0x3Fu; }
[[nodiscard]] uint32_t DstSelXYZ() const { return (fields[3] >> 0u) & 0x1FFu; }
[[nodiscard]] uint32_t DstSelXYZW() const { return (fields[3] >> 0u) & 0xFFFu; }
[[nodiscard]] uint8_t Nfmt() const { return (fields[3] >> 12u) & 0x7u; }
[[nodiscard]] uint8_t Dfmt() const { return (fields[3] >> 15u) & 0xFu; }
[[nodiscard]] bool AddTid() const { return ((fields[3] >> 23u) & 0x1u) == 1; }
[[nodiscard]] uint8_t MemoryType() const
[[nodiscard]] uint64_t Base48() const { return (fields[0] | (static_cast<uint64_t>(fields[1]) << 32u)) & 0xFFFFFFFFFFFFu; }
[[nodiscard]] uint8_t Format() const { return (fields[3] >> 12u) & 0x7Fu; }
[[nodiscard]] uint8_t OutOfBounds() const { return (fields[3] >> 28u) & 0x3u; }
[[nodiscard]] uint64_t Base44() const { return (fields[0] | (static_cast<uint64_t>(fields[1]) << 32u)) & 0x0FFFFFFFFFFFu; }
[[nodiscard]] uint8_t Nfmt() const { return (fields[3] >> 12u) & 0x7u; }
[[nodiscard]] uint8_t Dfmt() const { return (fields[3] >> 15u) & 0xFu; }
[[nodiscard]] uint8_t MemoryType() const
{
return ((fields[1] >> 7u) & 0x60u) | ((fields[3] >> 25u) & 0x1cu) | ((fields[1] >> 14u) & 0x3u);
}
@ -549,22 +595,23 @@ struct ShaderTextureResource
{
uint32_t fields[8] = {0};
void UpdateAddress(uint64_t gpu_addr)
void UpdateAddress38(uint64_t gpu_addr)
{
auto lo = static_cast<uint32_t>(gpu_addr & 0xffffffffu);
auto hi = static_cast<uint32_t>(gpu_addr >> 32u);
fields[0] = lo;
fields[1] = (fields[1] & 0xffffffc0u) | (hi & 0x3fu);
fields[1] = (fields[1] & 0xffffffc0u) | (hi & 0x0000003fu);
}
void UpdateAddress40(uint64_t gpu_addr)
{
auto lo = static_cast<uint32_t>(gpu_addr & 0xffffffffu);
auto hi = static_cast<uint32_t>(gpu_addr >> 32u);
fields[0] = lo;
fields[1] = (fields[1] & 0xffffff00u) | (hi & 0x000000ffu);
}
[[nodiscard]] uint64_t Base() const { return ((fields[0] | (static_cast<uint64_t>(fields[1]) << 32u)) & 0x3FFFFFFFFFu) << 8u; }
[[nodiscard]] uint16_t MinLod() const { return (fields[1] >> 8u) & 0xFFFu; }
[[nodiscard]] uint8_t Dfmt() const { return (fields[1] >> 20u) & 0x3Fu; }
[[nodiscard]] uint8_t Nfmt() const { return (fields[1] >> 26u) & 0xFu; }
[[nodiscard]] uint16_t Width() const { return (fields[2] >> 0u) & 0x3FFFu; }
[[nodiscard]] uint16_t Height() const { return (fields[2] >> 14u) & 0x3FFFu; }
[[nodiscard]] uint8_t PerfMod() const { return (fields[2] >> 28u) & 0x7u; }
[[nodiscard]] bool Interlaced() const { return ((fields[2] >> 31u) & 0x1u) == 1; }
[[nodiscard]] uint8_t DstSelX() const { return (fields[3] >> 0u) & 0x7u; }
[[nodiscard]] uint8_t DstSelY() const { return (fields[3] >> 3u) & 0x7u; }
[[nodiscard]] uint8_t DstSelZ() const { return (fields[3] >> 6u) & 0x7u; }
@ -574,19 +621,49 @@ struct ShaderTextureResource
[[nodiscard]] uint32_t DstSelXYZW() const { return (fields[3] >> 0u) & 0xFFFu; }
[[nodiscard]] uint8_t BaseLevel() const { return (fields[3] >> 12u) & 0xFu; }
[[nodiscard]] uint8_t LastLevel() const { return (fields[3] >> 16u) & 0xFu; }
[[nodiscard]] uint8_t TilingIdx() const { return (fields[3] >> 20u) & 0x1Fu; }
[[nodiscard]] bool Pow2Pad() const { return ((fields[3] >> 25u) & 0x1u) == 1; }
[[nodiscard]] uint8_t TileMode() const { return (fields[3] >> 20u) & 0x1Fu; }
[[nodiscard]] uint8_t Type() const { return (fields[3] >> 28u) & 0xFu; }
[[nodiscard]] uint16_t Depth() const { return (fields[4] >> 0u) & 0x1FFFu; }
[[nodiscard]] uint64_t Base40() const { return ((fields[0] | (static_cast<uint64_t>(fields[1]) << 32u)) & 0xFFFFFFFFFFu) << 8u; }
[[nodiscard]] uint16_t Format() const { return (fields[1] >> 20u) & 0x1FFu; }
[[nodiscard]] uint16_t Width5() const { return ((fields[1] >> 30u) & 0x3u) | (((fields[2] >> 0u) & 0xFFFu) << 2u); }
[[nodiscard]] uint16_t Height5() const { return (fields[2] >> 14u) & 0x3FFFu; }
[[nodiscard]] uint8_t BCSwizzle() const { return (fields[3] >> 25u) & 0x7u; }
[[nodiscard]] uint16_t BaseArray5() const { return (fields[4] >> 16u) & 0x1FFFu; }
[[nodiscard]] uint8_t ArrayPitch() const { return (fields[5] >> 0u) & 0xFu; }
[[nodiscard]] uint8_t MaxMip() const { return (fields[5] >> 4u) & 0xFu; }
[[nodiscard]] uint16_t MinLodWarn5() const { return (fields[5] >> 8u) & 0xFFFu; }
[[nodiscard]] uint8_t PerfMod5() const { return (fields[5] >> 20u) & 0x7u; }
[[nodiscard]] bool CornerSample() const { return ((fields[5] >> 23u) & 0x1u) == 1; }
[[nodiscard]] bool MipStatsCntEn() const { return ((fields[5] >> 25u) & 0x1u) == 1; }
[[nodiscard]] bool PrtDefColor() const { return ((fields[5] >> 26u) & 0x1u) == 1; }
[[nodiscard]] uint8_t MipStatsCntId() const { return (fields[6] >> 0u) & 0xFFu; }
[[nodiscard]] bool MsaaDepth() const { return ((fields[6] >> 10u) & 0x1u) == 1; }
[[nodiscard]] uint8_t MaxUncompBlkSize() const { return (fields[6] >> 15u) & 0x3u; }
[[nodiscard]] uint8_t MaxCompBlkSize() const { return (fields[6] >> 17u) & 0x3u; }
[[nodiscard]] bool MetaPipeAligned() const { return ((fields[6] >> 19u) & 0x1u) == 1; }
[[nodiscard]] bool WriteCompress() const { return ((fields[6] >> 20u) & 0x1u) == 1; }
[[nodiscard]] bool MetaCompress() const { return ((fields[6] >> 21u) & 0x1u) == 1; }
[[nodiscard]] bool DccAlphaPos() const { return ((fields[6] >> 22u) & 0x1u) == 1; }
[[nodiscard]] bool DccColorTransf() const { return ((fields[6] >> 23u) & 0x1u) == 1; }
[[nodiscard]] uint64_t MetaAddr() const { return ((fields[6] >> 24u) & 0xFFu) | (static_cast<uint64_t>(fields[7]) << 8u); }
[[nodiscard]] uint64_t Base38() const { return ((fields[0] | (static_cast<uint64_t>(fields[1]) << 32u)) & 0x3FFFFFFFFFu) << 8u; }
[[nodiscard]] uint8_t Dfmt() const { return (fields[1] >> 20u) & 0x3Fu; }
[[nodiscard]] uint8_t Nfmt() const { return (fields[1] >> 26u) & 0xFu; }
[[nodiscard]] uint16_t Width4() const { return (fields[2] >> 0u) & 0x3FFFu; }
[[nodiscard]] uint16_t Height4() const { return (fields[2] >> 14u) & 0x3FFFu; }
[[nodiscard]] uint8_t PerfMod() const { return (fields[2] >> 28u) & 0x7u; }
[[nodiscard]] bool Interlaced() const { return ((fields[2] >> 31u) & 0x1u) == 1; }
[[nodiscard]] bool Pow2Pad() const { return ((fields[3] >> 25u) & 0x1u) == 1; }
[[nodiscard]] uint16_t Pitch() const { return (fields[4] >> 13u) & 0x3FFFu; }
[[nodiscard]] uint16_t BaseArray() const { return (fields[5] >> 0u) & 0x1FFFu; }
[[nodiscard]] uint16_t LastArray() const { return (fields[5] >> 13u) & 0x1FFFu; }
[[nodiscard]] uint16_t MinLodWarn() const { return (fields[6] >> 0u) & 0xFFFu; }
[[nodiscard]] uint8_t CounterBankId() const { return (fields[6] >> 12u) & 0xFFu; }
[[nodiscard]] bool LodHdwCntEn() const { return ((fields[6] >> 20u) & 0x1u) == 1; }
[[nodiscard]] uint8_t MemoryType() const
[[nodiscard]] uint8_t CounterBankId() const { return (fields[6] >> 12u) & 0xFFu; }
[[nodiscard]] uint8_t MemoryType() const
{
return ((fields[1] >> 6u) & 0x3u) | ((fields[1] >> 30u) << 2u) | ((fields[3] & 0x04000000u) == 0 ? 0x60u : 0x10u);
}
@ -605,7 +682,6 @@ struct ShaderSamplerResource
[[nodiscard]] uint8_t DepthCompareFunc() const { return (fields[0] >> 12u) & 0x7u; }
[[nodiscard]] bool ForceUnormCoords() const { return ((fields[0] >> 15u) & 0x1u) == 1; }
[[nodiscard]] uint8_t AnisoThreshold() const { return (fields[0] >> 16u) & 0x7u; }
[[nodiscard]] bool McCoordTrunc() const { return ((fields[0] >> 19u) & 0x1u) == 1; }
[[nodiscard]] bool ForceDegamma() const { return ((fields[0] >> 20u) & 0x1u) == 1; }
[[nodiscard]] uint8_t AnisoBias() const { return (fields[0] >> 21u) & 0x3Fu; }
[[nodiscard]] bool TruncCoord() const { return ((fields[0] >> 27u) & 0x1u) == 1; }
@ -623,6 +699,13 @@ struct ShaderSamplerResource
[[nodiscard]] uint8_t MipFilter() const { return (fields[2] >> 26u) & 0x3u; }
[[nodiscard]] uint16_t BorderColorPtr() const { return (fields[3] >> 0u) & 0xFFFu; }
[[nodiscard]] uint8_t BorderColorType() const { return (fields[3] >> 30u) & 0x3u; }
[[nodiscard]] bool SkipDegamma() const { return ((fields[0] >> 31u) & 0x1u) == 1; }
[[nodiscard]] bool PointPreclamp() const { return ((fields[3] >> 28u) & 0x1u) == 1; }
[[nodiscard]] bool AnisoOverride() const { return ((fields[3] >> 28u) & 0x1u) == 1; }
[[nodiscard]] bool BlendZeroPrt() const { return ((fields[3] >> 28u) & 0x1u) == 1; }
[[nodiscard]] bool McCoordTrunc() const { return ((fields[0] >> 19u) & 0x1u) == 1; }
};
struct ShaderGdsResource
@ -760,25 +843,24 @@ struct ShaderBindResources
ShaderExtendedResources extended;
};
// struct ShaderBindParameters
//{
// bool textures2d_without_sampler[ShaderTextureResources::RES_MAX] = {};
// int textures2d_sampled_num = 0;
// int textures2d_storage_num = 0;
//};
struct ShaderVertexInputInfo
{
static constexpr int RES_MAX = 16;
ShaderBufferResource resources[RES_MAX];
ShaderVertexDestination resources_dst[RES_MAX];
int resources_num = 0;
bool fetch = false;
ShaderVertexInputBuffer buffers[RES_MAX];
int buffers_num = 0;
int export_count = 0;
ShaderBindResources bind;
int resources_num = 0;
int fetch_shader_reg = 0;
int fetch_attrib_reg = 0;
int fetch_buffer_reg = 0;
int buffers_num = 0;
int export_count = 0;
bool fetch_external = false;
bool fetch_embedded = false;
bool fetch_inline = false;
bool gs_prolog = false;
};
struct ShaderComputeInputInfo
@ -802,23 +884,123 @@ struct ShaderPixelInputInfo
ShaderBindResources bind;
};
void ShaderCalcBindingIndices(ShaderBindResources* bind);
void ShaderGetInputInfoVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegisters* sh, ShaderVertexInputInfo* info);
void ShaderGetInputInfoPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh, const ShaderVertexInputInfo* vs_info,
ShaderPixelInputInfo* ps_info);
void ShaderGetInputInfoCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh, ShaderComputeInputInfo* info);
void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo* info);
void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo* info);
void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo* info);
ShaderId ShaderGetIdVS(const HW::VertexShaderInfo* regs, const ShaderVertexInputInfo* input_info);
ShaderId ShaderGetIdPS(const HW::PixelShaderInfo* regs, const ShaderPixelInputInfo* input_info);
ShaderId ShaderGetIdCS(const HW::ComputeShaderInfo* regs, const ShaderComputeInputInfo* input_info);
ShaderCode ShaderParseVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegisters* sh);
ShaderCode ShaderParsePS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh);
ShaderCode ShaderParseCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh);
// ShaderBindParameters ShaderGetBindParametersVS(const ShaderCode& code, const ShaderVertexInputInfo* input_info);
// ShaderBindParameters ShaderGetBindParametersPS(const ShaderCode& code, const ShaderPixelInputInfo* input_info);
// ShaderBindParameters ShaderGetBindParametersCS(const ShaderCode& code, const ShaderComputeInputInfo* input_info);
struct ShaderSharp
{
uint16_t offset_dw : 15;
uint16_t size : 1;
};
struct ShaderUserData
{
uint16_t* direct_resource_offset;
ShaderSharp* sharp_resource_offset[4];
uint16_t eud_size_dw;
uint16_t srt_size_dw;
uint16_t direct_resource_count;
uint16_t sharp_resource_count[4];
};
struct ShaderRegisterRange
{
uint16_t start;
uint16_t end;
};
struct ShaderDrawModifier
{
uint32_t enbl_start_vertex_offset : 1;
uint32_t enbl_start_index_offset : 1;
uint32_t enbl_start_instance_offset : 1;
uint32_t enbl_draw_index : 1;
uint32_t enbl_user_vgprs : 1;
uint32_t render_target_slice_offset : 3;
uint32_t fuse_draws : 1;
uint32_t compiler_flags : 23;
uint32_t is_default : 1;
uint32_t reserved : 31;
};
struct ShaderRegister
{
uint32_t offset;
uint32_t value;
};
struct ShaderSpecialRegs
{
ShaderRegister ge_cntl;
ShaderRegister vgt_shader_stages_en;
uint32_t dispatch_modifier;
ShaderRegisterRange user_data_range;
ShaderDrawModifier draw_modifier;
ShaderRegister vgt_gs_out_prim_type;
ShaderRegister ge_user_vgpr_en;
};
struct ShaderSemantic
{
uint32_t semantic : 8;
uint32_t hardware_mapping : 8;
uint32_t size_in_elements : 4;
uint32_t is_f16 : 2;
uint32_t is_flat_shaded : 1;
uint32_t is_linear : 1;
uint32_t is_custom : 1;
uint32_t static_vb_index : 1;
uint32_t static_attribute : 1;
uint32_t reserved : 1;
uint32_t default_value : 2;
uint32_t default_value_hi : 2;
};
struct Shader
{
uint32_t file_header;
uint32_t version;
ShaderUserData* user_data;
const volatile void* code;
ShaderRegister* cx_registers;
ShaderRegister* sh_registers;
ShaderSpecialRegs* specials;
ShaderSemantic* input_semantics;
ShaderSemantic* output_semantics;
uint32_t header_size;
uint32_t shader_size;
uint32_t embedded_constant_buffer_size_dqw;
uint32_t target;
uint32_t num_input_semantics;
uint16_t scratch_size_dw_per_thread;
uint16_t num_output_semantics;
uint16_t special_sizes_bytes;
uint8_t type;
uint8_t num_cx_registers;
uint8_t num_sh_registers;
};
struct ShaderMappedData
{
ShaderUserData* user_data = nullptr;
ShaderSemantic* input_semantics = nullptr;
uint32_t num_input_semantics = 0;
};
void ShaderInit();
void ShaderMapUserData(uint64_t addr, const ShaderMappedData& data);
void ShaderCalcBindingIndices(ShaderBindResources* bind);
void ShaderGetInputInfoVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegisters* sh, ShaderVertexInputInfo* info);
void ShaderGetInputInfoPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh, const ShaderVertexInputInfo* vs_info,
ShaderPixelInputInfo* ps_info);
void ShaderGetInputInfoCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh, ShaderComputeInputInfo* info);
void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo* info);
void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo* info);
void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo* info);
ShaderId ShaderGetIdVS(const HW::VertexShaderInfo* regs, const ShaderVertexInputInfo* input_info);
ShaderId ShaderGetIdPS(const HW::PixelShaderInfo* regs, const ShaderPixelInputInfo* input_info);
ShaderId ShaderGetIdCS(const HW::ComputeShaderInfo* regs, const ShaderComputeInputInfo* input_info);
ShaderCode ShaderParseVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegisters* sh);
ShaderCode ShaderParsePS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh);
ShaderCode ShaderParseCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh);
Vector<uint32_t> ShaderRecompileVS(const ShaderCode& code, const ShaderVertexInputInfo* input_info);
Vector<uint32_t> ShaderRecompilePS(const ShaderCode& code, const ShaderPixelInputInfo* input_info);
Vector<uint32_t> ShaderRecompileCS(const ShaderCode& code, const ShaderComputeInputInfo* input_info);

View File

@ -0,0 +1,21 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADERPARSE_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADERPARSE_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/String.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
class ShaderCode;
void ShaderParse(const uint32_t* src, ShaderCode* dst);
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADERPARSE_H_ */

View File

@ -2,7 +2,7 @@
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADERSPIRV_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/String8.h"
#include "Emulator/Common.h"
@ -15,10 +15,10 @@ struct ShaderVertexInputInfo;
struct ShaderPixelInputInfo;
struct ShaderComputeInputInfo;
String SpirvGenerateSource(const ShaderCode& code, const ShaderVertexInputInfo* vs_input_info, const ShaderPixelInputInfo* ps_input_info,
const ShaderComputeInputInfo* cs_input_info);
String SpirvGetEmbeddedVs(uint32_t id);
String SpirvGetEmbeddedPs(uint32_t id);
String8 SpirvGenerateSource(const ShaderCode& code, const ShaderVertexInputInfo* vs_input_info, const ShaderPixelInputInfo* ps_input_info,
const ShaderComputeInputInfo* cs_input_info);
String8 SpirvGetEmbeddedVs(uint32_t id);
String8 SpirvGetEmbeddedPs(uint32_t id);
} // namespace Kyty::Libs::Graphics

View File

@ -43,10 +43,12 @@ void TileConvertTiledToLinear(void* dst, const void* src, TileMode mode, uint32_
uint32_t pitch, uint32_t levels, bool neo);
bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format, uint32_t stencil_format, bool htile, bool neo,
TileSizeAlign* stencil_size, TileSizeAlign* htile_size, TileSizeAlign* depth_size);
bool next_gen, TileSizeAlign* stencil_size, TileSizeAlign* htile_size, TileSizeAlign* depth_size);
void TileGetVideoOutSize(uint32_t width, uint32_t height, uint32_t pitch, bool tile, bool neo, TileSizeAlign* size);
void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, uint32_t tile,
bool neo, TileSizeAlign* total_size, TileSizeOffset* level_sizes, TilePaddedSize* padded_size);
void TileGetTextureSize2(uint32_t format, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, uint32_t tile,
TileSizeAlign* total_size, TileSizeOffset* level_sizes, TilePaddedSize* padded_size);
} // namespace Kyty::Libs::Graphics

View File

@ -12,6 +12,10 @@ namespace Kyty::Libs::LibKernel::Memory {
KYTY_SUBSYSTEM_DEFINE(Memory);
using callback_func_t = void (*)(uintptr_t addr, size_t size);
void RegisterCallbacks(callback_func_t alloc_func, callback_func_t free_func);
int KYTY_SYSV_ABI KernelMapNamedFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags, const char* name);
int KYTY_SYSV_ABI KernelMapFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags);
int KYTY_SYSV_ABI KernelMunmap(uint64_t vaddr, size_t len);

View File

@ -20,6 +20,19 @@ constexpr int OK = 0;
return 0; \
}()
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define POSIX_N_CALL(func) \
[&]() \
{ \
auto result = func; \
if (result < 0) \
{ \
*Posix::GetErrorAddr() = LibKernel::KernelToPosix(static_cast<int>(result)); \
return static_cast<decltype(result)>(-1); \
} \
return result; \
}()
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define POSIX_PTHREAD_CALL(func) \
[&]() \

View File

@ -35,10 +35,12 @@
using n::g_module_version_major; \
using n::g_module_version_minor;
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define LIB_LOAD(name) name(s)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define LIB_CHECK(ids, name) \
if (id == (ids)) \
{ \
name(s); \
LIB_LOAD(name); \
return true; \
}
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
@ -81,6 +83,7 @@ class SymbolDatabase;
namespace Libs {
bool Init(const String& id, Loader::SymbolDatabase* s);
void InitAll(Loader::SymbolDatabase* s);
} // namespace Libs
} // namespace Kyty

View File

@ -60,6 +60,7 @@ public:
uint64_t access_violation_vaddr = 0;
uint64_t exception_address = 0;
uint64_t rbp = 0;
uint32_t exception_win_code = 0;
};
using handler_func_t = void (*)(const ExceptionInfo*);

View File

@ -13,6 +13,7 @@ struct Config
uint32_t screen_width = 1280;
uint32_t screen_height = 720;
bool neo = true;
bool next_gen = false;
bool vulkan_validation_enabled = false;
bool shader_validation_enabled = false;
ShaderOptimizationType shader_optimization_type = ShaderOptimizationType::None;
@ -115,7 +116,7 @@ uint32_t GetScreenHeight()
bool IsNeo()
{
return g_config->neo;
return g_config->neo || g_config->next_gen;
}
bool VulkanValidationEnabled()
@ -193,6 +194,16 @@ String GetPipelineDumpFolder()
return g_config->pipeline_dump_folder;
}
void SetNextGen(bool mode)
{
g_config->next_gen = mode;
}
bool IsNextGen()
{
return g_config->next_gen;
}
} // namespace Kyty::Config
#endif // KYTY_EMU_ENABLED

View File

@ -12,6 +12,7 @@
#include "Emulator/Graphics/Objects/IndexBuffer.h"
#include "Emulator/Graphics/Objects/Label.h"
#include "Emulator/Graphics/Pm4.h"
#include "Emulator/Graphics/Shader.h"
#include "Emulator/Graphics/Tile.h"
#include "Emulator/Graphics/VideoOut.h"
#include "Emulator/Graphics/Window.h"
@ -40,6 +41,7 @@ KYTY_SUBSYSTEM_INIT(Graphics)
LabelInit();
TileInit();
IndexBufferInit();
ShaderInit();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Graphics) {}
@ -755,12 +757,6 @@ namespace Gen5 {
LIB_NAME("Graphics5", "Graphics5");
struct ShaderRegister
{
uint32_t offset;
uint32_t value;
};
struct RegisterDefaultInfo
{
uint32_t type;
@ -778,93 +774,6 @@ struct RegisterDefaults
uint32_t count = 0;
};
struct ShaderSharp
{
uint16_t offset_dw : 15;
uint16_t size : 1;
};
struct ShaderUserData
{
uint16_t* direct_resource_offset;
ShaderSharp* sharp_resource_offset[4];
uint16_t eud_size_dw;
uint16_t srt_size_dw;
uint16_t direct_resource_count;
uint16_t sharp_resource_count[4];
};
struct ShaderRegisterRange
{
uint16_t start;
uint16_t end;
};
struct ShaderDrawModifier
{
uint32_t enbl_start_vertex_offset : 1;
uint32_t enbl_start_index_offset : 1;
uint32_t enbl_start_instance_offset : 1;
uint32_t enbl_draw_index : 1;
uint32_t enbl_user_vgprs : 1;
uint32_t render_target_slice_offset : 3;
uint32_t fuse_draws : 1;
uint32_t compiler_flags : 23;
uint32_t is_default : 1;
uint32_t reserved : 31;
};
struct ShaderSpecialRegs
{
ShaderRegister ge_cntl;
ShaderRegister vgt_shader_stages_en;
uint32_t dispatch_modifier;
ShaderRegisterRange user_data_range;
ShaderDrawModifier draw_modifier;
ShaderRegister vgt_gs_out_prim_type;
ShaderRegister ge_user_vgpr_en;
};
struct ShaderSemantic
{
uint32_t semantic : 8;
uint32_t hardware_mapping : 8;
uint32_t size_in_elements : 4;
uint32_t is_f16 : 2;
uint32_t is_flat_shaded : 1;
uint32_t is_linear : 1;
uint32_t is_custom : 1;
uint32_t static_vb_index : 1;
uint32_t static_attribute : 1;
uint32_t reserved : 1;
uint32_t default_value : 2;
uint32_t default_value_hi : 2;
};
struct Shader
{
uint32_t file_header;
uint32_t version;
ShaderUserData* user_data;
const volatile void* code;
ShaderRegister* cx_registers;
ShaderRegister* sh_registers;
ShaderSpecialRegs* specials;
ShaderSemantic* input_semantics;
ShaderSemantic* output_semantics;
uint32_t header_size;
uint32_t shader_size;
uint32_t embedded_constant_buffer_size_dqw;
uint32_t target;
uint32_t num_input_semantics;
uint16_t scratch_size_dw_per_thread;
uint16_t num_output_semantics;
uint16_t special_sizes_bytes;
uint8_t type;
uint8_t num_cx_registers;
uint8_t num_sh_registers;
};
struct CommandBuffer
{
using Callback = KYTY_SYSV_ABI bool (*)(CommandBuffer*, uint32_t, void*);
@ -1561,6 +1470,17 @@ int KYTY_SYSV_ABI GraphicsCreateShader(Shader** dst, void* header, const volatil
auto base = reinterpret_cast<uint64_t>(code);
printf("\t base = 0x%016" PRIx64 "\n", base);
ShaderMappedData map;
map.user_data = h->user_data;
map.input_semantics = h->input_semantics;
map.num_input_semantics = h->num_input_semantics;
ShaderMapUserData(base, map);
EXIT_NOT_IMPLEMENTED((base & 0xFFFF0000000000FFull) != 0);
if (h->type == 2 && h->num_sh_registers >= 2 && h->sh_registers[0].offset == Pm4::SPI_SHADER_PGM_LO_ES &&
h->sh_registers[1].offset == Pm4::SPI_SHADER_PGM_HI_ES)
{
@ -1716,6 +1636,7 @@ int KYTY_SYSV_ABI GraphicsCreatePrimState(ShaderRegister* cx_regs, ShaderRegiste
return OK;
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
int KYTY_SYSV_ABI GraphicsCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs, const Shader* ps)
{
PRINT_NAME();
@ -1733,20 +1654,42 @@ int KYTY_SYSV_ABI GraphicsCreateInterpolantMapping(ShaderRegister* regs, const S
EXIT_NOT_IMPLEMENTED(sizeof(ShaderSemantic) != 4);
EXIT_NOT_IMPLEMENTED(ps != nullptr && gs->num_output_semantics != ps->num_input_semantics);
EXIT_NOT_IMPLEMENTED(ps != nullptr && ps->num_output_semantics != 0);
auto* out32 = reinterpret_cast<uint32_t*>(gs->output_semantics);
auto* in32 = (ps != nullptr ? reinterpret_cast<uint32_t*>(ps->input_semantics) : nullptr);
for (int i = 0; i < 32; i++)
for (uint16_t i = 0; i < 32; i++)
{
regs[i].offset = Pm4::SPI_PS_INPUT_CNTL_0 + i;
regs[i].value = 0;
if (i < static_cast<int>(gs->num_output_semantics))
{
EXIT_NOT_IMPLEMENTED(out32[i] != 0x0000000f);
EXIT_NOT_IMPLEMENTED(in32 != nullptr && out32[i] != in32[i]);
regs[i].value = i;
EXIT_NOT_IMPLEMENTED(gs->output_semantics[i].semantic != 15 + i);
EXIT_NOT_IMPLEMENTED(gs->output_semantics[i].hardware_mapping != i);
EXIT_NOT_IMPLEMENTED(gs->output_semantics[i].size_in_elements != 0);
EXIT_NOT_IMPLEMENTED(gs->output_semantics[i].is_f16 != 0);
EXIT_NOT_IMPLEMENTED(gs->output_semantics[i].is_flat_shaded != 0);
EXIT_NOT_IMPLEMENTED(gs->output_semantics[i].is_linear != 0);
EXIT_NOT_IMPLEMENTED(gs->output_semantics[i].is_custom != 0);
EXIT_NOT_IMPLEMENTED(gs->output_semantics[i].static_vb_index != 0);
EXIT_NOT_IMPLEMENTED(gs->output_semantics[i].static_attribute != 0);
EXIT_NOT_IMPLEMENTED(gs->output_semantics[i].default_value != 0);
EXIT_NOT_IMPLEMENTED(gs->output_semantics[i].default_value_hi != 0);
bool flat = false;
if (ps != nullptr)
{
EXIT_NOT_IMPLEMENTED(ps->input_semantics[i].semantic != gs->output_semantics[i].semantic);
EXIT_NOT_IMPLEMENTED(ps->input_semantics[i].hardware_mapping != 0);
EXIT_NOT_IMPLEMENTED(ps->input_semantics[i].size_in_elements != 0);
EXIT_NOT_IMPLEMENTED(ps->input_semantics[i].is_f16 != 0);
EXIT_NOT_IMPLEMENTED(ps->input_semantics[i].is_linear != 0);
EXIT_NOT_IMPLEMENTED(ps->input_semantics[i].is_custom != 0);
EXIT_NOT_IMPLEMENTED(ps->input_semantics[i].static_vb_index != 0);
EXIT_NOT_IMPLEMENTED(ps->input_semantics[i].static_attribute != 0);
EXIT_NOT_IMPLEMENTED(ps->input_semantics[i].default_value != 0);
EXIT_NOT_IMPLEMENTED(ps->input_semantics[i].default_value_hi != 0);
flat = ps->input_semantics[i].is_flat_shaded != 0;
}
regs[i].value = i | (flat ? 0x400u : 0u);
}
}
@ -1837,7 +1780,7 @@ uint32_t* KYTY_SYSV_ABI GraphicsCbReleaseMem(CommandBuffer* buf, uint8_t action,
EXIT_NOT_IMPLEMENTED(buf == nullptr);
EXIT_NOT_IMPLEMENTED(dst != 1);
EXIT_NOT_IMPLEMENTED(data_sel != 2);
EXIT_NOT_IMPLEMENTED(data_sel != 2 && data_sel != 3);
EXIT_NOT_IMPLEMENTED(gds_offset != 0);
EXIT_NOT_IMPLEMENTED(gds_size != 1);
EXIT_NOT_IMPLEMENTED(interrupt != 0);
@ -1851,7 +1794,7 @@ uint32_t* KYTY_SYSV_ABI GraphicsCbReleaseMem(CommandBuffer* buf, uint8_t action,
cmd[0] = KYTY_PM4(7, Pm4::IT_NOP, Pm4::R_RELEASE_MEM);
cmd[1] = action | (static_cast<uint32_t>(cache_policy) << 8u);
cmd[2] = gcr_cntl;
cmd[2] = gcr_cntl | (static_cast<uint32_t>(data_sel) << 16u);
cmd[3] = static_cast<uint32_t>(reinterpret_cast<uint64_t>(address) & 0xffffffffu);
cmd[4] = static_cast<uint32_t>((reinterpret_cast<uint64_t>(address) >> 32u) & 0xffffffffu);
cmd[5] = static_cast<uint32_t>(data & 0xffffffffu);
@ -1909,6 +1852,25 @@ uint32_t* KYTY_SYSV_ABI GraphicsDcbWaitUntilSafeForRendering(CommandBuffer* buf,
return cmd;
}
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetShRegisterDirect(CommandBuffer* buf, ShaderRegister reg)
{
PRINT_NAME();
EXIT_NOT_IMPLEMENTED(buf == nullptr);
buf->DbgDump();
auto* cmd = buf->AllocateDW(3);
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
cmd[0] = KYTY_PM4(3, Pm4::IT_SET_SH_REG, 0u);
cmd[1] = reg.offset;
cmd[2] = reg.value;
return cmd;
}
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetCxRegistersIndirect(CommandBuffer* buf, const volatile ShaderRegister* regs, uint32_t num_regs)
{
PRINT_NAME();

View File

@ -471,6 +471,7 @@ static void uc_print(const char* func, const HW::UserConfig& uc)
printf("\t GetPrimType() = 0x%08" PRIx32 "\n", uc.GetPrimType());
printf("\t primitive_group_size = 0x%04" PRIx16 "\n", ge_cntl.primitive_group_size);
printf("\t vertex_group_size = 0x%04" PRIx16 "\n", ge_cntl.vertex_group_size);
printf("\t en_user_vgpr1 = %s\n", user_en.vgpr1 ? "true" : "false");
printf("\t en_user_vgpr2 = %s\n", user_en.vgpr2 ? "true" : "false");
printf("\t en_user_vgpr3 = %s\n", user_en.vgpr3 ? "true" : "false");
@ -481,8 +482,8 @@ static void uc_check(const HW::UserConfig& uc)
const auto& ge_cntl = uc.GetGeControl();
const auto& user_en = uc.GetGeUserVgprEn();
EXIT_NOT_IMPLEMENTED(ge_cntl.primitive_group_size != 0x0000);
EXIT_NOT_IMPLEMENTED(ge_cntl.vertex_group_size != 0x0000);
EXIT_NOT_IMPLEMENTED(ge_cntl.primitive_group_size != 0x0000 && ge_cntl.primitive_group_size != 0x0040);
EXIT_NOT_IMPLEMENTED(ge_cntl.vertex_group_size != 0x0000 && ge_cntl.vertex_group_size != 0x0040);
EXIT_NOT_IMPLEMENTED(user_en.vgpr1 != false);
EXIT_NOT_IMPLEMENTED(user_en.vgpr2 != false);
EXIT_NOT_IMPLEMENTED(user_en.vgpr3 != false);
@ -565,11 +566,15 @@ static void rt_check(const HW::RenderTarget& rt)
{
if (rt.base.addr != 0)
{
bool render_to_texture = (rt.attrib.tile_mode == 0x0d);
// EXIT_NOT_IMPLEMENTED(rt.base_addr == 0);
// EXIT_NOT_IMPLEMENTED(rt.pitch_div8_minus1 != 0x000000ef);
// EXIT_NOT_IMPLEMENTED(rt.fmask_pitch_div8_minus1 != 0x000000ef);
// EXIT_NOT_IMPLEMENTED(rt.slice_div64_minus1 != 0x000086ff);
bool ps5 = Config::IsNextGen();
// bool render_to_texture = (rt.attrib.tile_mode == 0x0d);
// EXIT_NOT_IMPLEMENTED(rt.base_addr == 0);
if (ps5)
{
EXIT_NOT_IMPLEMENTED(rt.pitch.pitch_div8_minus1 != 0);
EXIT_NOT_IMPLEMENTED(rt.pitch.fmask_pitch_div8_minus1 != 0);
EXIT_NOT_IMPLEMENTED(rt.slice.slice_div64_minus1 != 0);
}
EXIT_NOT_IMPLEMENTED(rt.view.base_array_slice_index != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.view.last_array_slice_index != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.view.current_mip_level != 0x00000000);
@ -581,7 +586,7 @@ static void rt_check(const HW::RenderTarget& rt)
EXIT_NOT_IMPLEMENTED(rt.info.cmask_fast_clear_enable != false);
EXIT_NOT_IMPLEMENTED(rt.info.dcc_compression_enable != false);
EXIT_NOT_IMPLEMENTED(!render_to_texture && rt.info.neo_mode != Config::IsNeo());
EXIT_NOT_IMPLEMENTED(!(rt.attrib.tile_mode == 0x0d) && rt.info.neo_mode != Config::IsNeo());
EXIT_NOT_IMPLEMENTED(rt.info.cmask_tile_mode != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.info.cmask_tile_mode_neo != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.info.blend_bypass != false);
@ -595,14 +600,27 @@ static void rt_check(const HW::RenderTarget& rt)
// EXIT_NOT_IMPLEMENTED(rt.fmask_tile_mode != 0x0000000a);
EXIT_NOT_IMPLEMENTED(rt.attrib.num_samples != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib.num_fragments != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib2.width != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib2.height != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib2.num_mip_levels != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib3.depth != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib3.tile_mode != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib3.dimension != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib3.cmask_pipe_aligned != false);
EXIT_NOT_IMPLEMENTED(rt.attrib3.dcc_pipe_aligned != false);
if (ps5)
{
EXIT_NOT_IMPLEMENTED(rt.attrib2.width == 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib2.height == 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib2.num_mip_levels != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib3.depth != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib3.tile_mode != 0x0000001b);
EXIT_NOT_IMPLEMENTED(rt.attrib3.dimension != 0x00000001);
EXIT_NOT_IMPLEMENTED(rt.attrib3.cmask_pipe_aligned != true);
EXIT_NOT_IMPLEMENTED(rt.attrib3.dcc_pipe_aligned != true);
} else
{
EXIT_NOT_IMPLEMENTED(rt.attrib2.width != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib2.height != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib2.num_mip_levels != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib3.depth != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib3.tile_mode != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib3.dimension != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.attrib3.cmask_pipe_aligned != false);
EXIT_NOT_IMPLEMENTED(rt.attrib3.dcc_pipe_aligned != false);
}
// EXIT_NOT_IMPLEMENTED(rt.dcc_max_uncompressed_block_size != 0x00000002);
// EXIT_NOT_IMPLEMENTED(rt.dcc.max_compressed_block_size != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.dcc.min_compressed_block_size != 0x00000000);
@ -619,8 +637,11 @@ static void rt_check(const HW::RenderTarget& rt)
EXIT_NOT_IMPLEMENTED(rt.clear_word0.word0 != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.clear_word1.word1 != 0x00000000);
EXIT_NOT_IMPLEMENTED(rt.dcc_addr.addr != 0x0000000000000000);
// EXIT_NOT_IMPLEMENTED(rt.width != 0x00000780);
// EXIT_NOT_IMPLEMENTED(rt.height != 0x00000438);
if (ps5)
{
EXIT_NOT_IMPLEMENTED(rt.size.width != 0);
EXIT_NOT_IMPLEMENTED(rt.size.height != 0);
}
}
}
@ -729,25 +750,46 @@ static void z_check(const HW::DepthRenderTarget& z)
if (z.z_info.format != 0 || z.stencil_info.format != 0)
{
EXIT_NOT_IMPLEMENTED(z.depth_info.addr5_swizzle_mask != 0x00000001);
EXIT_NOT_IMPLEMENTED(z.depth_info.array_mode != 0x00000004);
EXIT_NOT_IMPLEMENTED(z.depth_info.pipe_config != (Config::IsNeo() ? 0x00000012 : 0x0c));
EXIT_NOT_IMPLEMENTED(z.depth_info.bank_width != 0x00000000);
// EXIT_NOT_IMPLEMENTED(z.depth_info.bank_height != (Config::IsNeo() ? 0x00000001 : 2));
// EXIT_NOT_IMPLEMENTED(z.depth_info.macro_tile_aspect != (Config::IsNeo() ? 0x00000000 : 2));
// EXIT_NOT_IMPLEMENTED(z.depth_info.num_banks != (Config::IsNeo() ? 0x00000002 : 3));
bool ps5 = Config::IsNextGen();
if (ps5)
{
EXIT_NOT_IMPLEMENTED(z.depth_info.addr5_swizzle_mask != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.depth_info.array_mode != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.depth_info.pipe_config != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.depth_info.bank_width != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.depth_info.bank_height != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.depth_info.macro_tile_aspect != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.depth_info.num_banks != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.linear != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.full_cache != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.htile_uses_preload_win != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.preload != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.prefetch_width != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.prefetch_height != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.dst_outside_zero_to_one != 0x00000000);
} else
{
EXIT_NOT_IMPLEMENTED(z.depth_info.addr5_swizzle_mask != 0x00000001);
EXIT_NOT_IMPLEMENTED(z.depth_info.array_mode != 0x00000004);
EXIT_NOT_IMPLEMENTED(z.depth_info.pipe_config != (Config::IsNeo() ? 0x00000012 : 0x0c));
EXIT_NOT_IMPLEMENTED(z.depth_info.bank_width != 0x00000000);
// EXIT_NOT_IMPLEMENTED(z.depth_info.bank_height != (Config::IsNeo() ? 0x00000001 : 2));
// EXIT_NOT_IMPLEMENTED(z.depth_info.macro_tile_aspect != (Config::IsNeo() ? 0x00000000 : 2));
// EXIT_NOT_IMPLEMENTED(z.depth_info.num_banks != (Config::IsNeo() ? 0x00000002 : 3));
EXIT_NOT_IMPLEMENTED(z.htile_surface.linear != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.full_cache != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.htile_uses_preload_win != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.preload != 0x00000001);
EXIT_NOT_IMPLEMENTED(z.htile_surface.prefetch_width != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.prefetch_height != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.dst_outside_zero_to_one != 0x00000000);
}
EXIT_NOT_IMPLEMENTED(z.depth_view.slice_start != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.depth_view.slice_max != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.depth_view.current_mip_level != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.depth_view.depth_write_disable != false);
EXIT_NOT_IMPLEMENTED(z.depth_view.stencil_write_disable != false);
EXIT_NOT_IMPLEMENTED(z.htile_surface.linear != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.full_cache != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.htile_uses_preload_win != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.preload != 0x00000001);
EXIT_NOT_IMPLEMENTED(z.htile_surface.prefetch_width != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.prefetch_height != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.htile_surface.dst_outside_zero_to_one != 0x00000000);
EXIT_NOT_IMPLEMENTED(z.z_read_base_addr != z.z_write_base_addr);
EXIT_NOT_IMPLEMENTED(z.stencil_read_base_addr != z.stencil_write_base_addr);
EXIT_NOT_IMPLEMENTED(z.z_write_base_addr == 0);
@ -758,8 +800,13 @@ static void z_check(const HW::DepthRenderTarget& z)
// EXIT_NOT_IMPLEMENTED(z.htile_data_base_addr == 0);
// EXIT_NOT_IMPLEMENTED(z.width != 0x00000780);
// EXIT_NOT_IMPLEMENTED(z.height != 0x00000438);
EXIT_NOT_IMPLEMENTED(z.size.x_max != 0);
EXIT_NOT_IMPLEMENTED(z.size.y_max != 0);
if (ps5)
{
EXIT_NOT_IMPLEMENTED(z.width != 0);
EXIT_NOT_IMPLEMENTED(z.height != 0);
EXIT_NOT_IMPLEMENTED(z.size.x_max == 0);
EXIT_NOT_IMPLEMENTED(z.size.y_max == 0);
}
}
}
@ -1044,14 +1091,23 @@ static void vp_print(const char* func, const HW::ScreenViewport& vp, const HW::S
static void vp_check(const HW::ScreenViewport& vp, const HW::ScanModeControl& smc)
{
bool ps5 = Config::IsNextGen();
EXIT_NOT_IMPLEMENTED(smc.msaa_enable);
// EXIT_NOT_IMPLEMENTED(smc.vport_scissor_enable);
EXIT_NOT_IMPLEMENTED(smc.line_stipple_enable);
bool generic_scissor =
(vp.generic_scissor_left != 0 || vp.generic_scissor_top != 0 || vp.generic_scissor_right != 0 || vp.generic_scissor_bottom != 0);
bool screen_scissor =
(vp.screen_scissor_left != 0 || vp.screen_scissor_top != 0 || vp.screen_scissor_right != 0 || vp.screen_scissor_bottom != 0);
bool viewport_scissor = (vp.viewports[0].viewport_scissor_left != 0 || vp.viewports[0].viewport_scissor_top != 0 ||
vp.viewports[0].viewport_scissor_right != 0 || vp.viewports[0].viewport_scissor_bottom != 0);
EXIT_NOT_IMPLEMENTED(vp.viewports[0].zmin != 0.000000);
EXIT_NOT_IMPLEMENTED(viewport_scissor && (generic_scissor || screen_scissor));
EXIT_NOT_IMPLEMENTED(viewport_scissor && (!smc.vport_scissor_enable));
EXIT_NOT_IMPLEMENTED(vp.viewports[0].zmin > 0.000000);
EXIT_NOT_IMPLEMENTED(vp.viewports[0].zmax != 1.000000);
// EXIT_NOT_IMPLEMENTED(vp.viewports[0].xscale != 960.000000);
// EXIT_NOT_IMPLEMENTED(vp.viewports[0].xoffset != 960.000000);
@ -1068,14 +1124,21 @@ static void vp_check(const HW::ScreenViewport& vp, const HW::ScanModeControl& sm
// EXIT_NOT_IMPLEMENTED(vp.hw_offset_y != 32);
// EXIT_NOT_IMPLEMENTED(fabsf(vp.guard_band_horz_clip - 33.133327f) > 0.001f);
// EXIT_NOT_IMPLEMENTED(fabsf(vp.guard_band_vert_clip - 59.629623f) > 0.001f);
EXIT_NOT_IMPLEMENTED(vp.guard_band_horz_discard != 1.000000);
EXIT_NOT_IMPLEMENTED(vp.guard_band_vert_discard != 1.000000);
if (ps5)
{
EXIT_NOT_IMPLEMENTED(vp.guard_band_horz_discard != 0.0f);
EXIT_NOT_IMPLEMENTED(vp.guard_band_vert_discard != 0.0f);
} else
{
EXIT_NOT_IMPLEMENTED(vp.guard_band_horz_discard != 1.000000);
EXIT_NOT_IMPLEMENTED(vp.guard_band_vert_discard != 1.000000);
}
EXIT_NOT_IMPLEMENTED(vp.generic_scissor_window_offset_enable != false);
EXIT_NOT_IMPLEMENTED(vp.viewports[0].viewport_scissor_left != 0);
EXIT_NOT_IMPLEMENTED(vp.viewports[0].viewport_scissor_top != 0);
EXIT_NOT_IMPLEMENTED(vp.viewports[0].viewport_scissor_right != 0);
EXIT_NOT_IMPLEMENTED(vp.viewports[0].viewport_scissor_bottom != 0);
EXIT_NOT_IMPLEMENTED(vp.viewports[0].viewport_scissor_window_offset_enable != false);
// EXIT_NOT_IMPLEMENTED(vp.viewports[0].viewport_scissor_left != 0);
// EXIT_NOT_IMPLEMENTED(vp.viewports[0].viewport_scissor_top != 0);
// EXIT_NOT_IMPLEMENTED(vp.viewports[0].viewport_scissor_right != 0);
// EXIT_NOT_IMPLEMENTED(vp.viewports[0].viewport_scissor_bottom != 0);
EXIT_NOT_IMPLEMENTED(viewport_scissor && vp.viewports[0].viewport_scissor_window_offset_enable != true);
}
static void hw_check(const HW::Context& hw)
@ -1785,33 +1848,53 @@ uint64_t SamplerCache::GetSamplerId(const ShaderSamplerResource& r)
return m_samplers_size;
}
static void get_input_format(const ShaderBufferResource& res, VkFormat* format, uint32_t* size)
static void get_input_format(const ShaderBufferResource& res, VkFormat* format, uint32_t* size, bool ps5)
{
EXIT_IF(format == nullptr);
EXIT_IF(size == nullptr);
auto nfmt = res.Nfmt();
auto dfmt = res.Dfmt();
if (nfmt == 7 && dfmt == 14)
if (ps5)
{
*format = VK_FORMAT_R32G32B32A32_SFLOAT;
*size = 4;
} else if (nfmt == 7 && dfmt == 13)
{
*format = VK_FORMAT_R32G32B32_SFLOAT;
*size = 3;
} else if (nfmt == 7 && dfmt == 11)
{
*format = VK_FORMAT_R32G32_SFLOAT;
*size = 2;
} else if (nfmt == 0 && dfmt == 10)
{
*format = VK_FORMAT_R8G8B8A8_UNORM;
*size = 4;
auto fmt = res.Format();
if (fmt == 74)
{
*format = VK_FORMAT_R32G32B32_SFLOAT;
*size = 3;
} else if (fmt == 64)
{
*format = VK_FORMAT_R32G32_SFLOAT;
*size = 2;
} else
{
EXIT("unknown format: fmt = %u\n", fmt);
*format = VK_FORMAT_UNDEFINED;
*size = 4;
}
} else
{
EXIT("unknown format: nfmt = %u, dfmt = %u\n", nfmt, dfmt);
*format = VK_FORMAT_UNDEFINED;
*size = 4;
auto nfmt = res.Nfmt();
auto dfmt = res.Dfmt();
if (nfmt == 7 && dfmt == 14)
{
*format = VK_FORMAT_R32G32B32A32_SFLOAT;
*size = 4;
} else if (nfmt == 7 && dfmt == 13)
{
*format = VK_FORMAT_R32G32B32_SFLOAT;
*size = 3;
} else if (nfmt == 7 && dfmt == 11)
{
*format = VK_FORMAT_R32G32_SFLOAT;
*size = 2;
} else if (nfmt == 0 && dfmt == 10)
{
*format = VK_FORMAT_R8G8B8A8_UNORM;
*size = 4;
} else
{
EXIT("unknown format: nfmt = %u, dfmt = %u\n", nfmt, dfmt);
*format = VK_FORMAT_UNDEFINED;
*size = 4;
}
}
}
@ -1952,6 +2035,8 @@ static VulkanPipeline* CreatePipelineInternal(VkRenderPass render_pass, const Sh
VkVertexInputAttributeDescription input_attr[ShaderVertexInputInfo::RES_MAX];
VkVertexInputBindingDescription input_desc[ShaderVertexInputInfo::RES_MAX];
bool gen5 = Config::IsNextGen();
for (int bi = 0; bi < vs_input_info->buffers_num; bi++)
{
const auto& b = vs_input_info->buffers[bi];
@ -1967,10 +2052,14 @@ static VulkanPipeline* CreatePipelineInternal(VkRenderPass render_pass, const Sh
input_attr[index].offset = b.attr_offsets[ai];
uint32_t attr_size = 4;
get_input_format(vs_input_info->resources[index], &input_attr[index].format, &attr_size);
get_input_format(vs_input_info->resources[index], &input_attr[index].format, &attr_size, gen5);
auto registers_num = vs_input_info->resources_dst[index].registers_num;
if (gen5)
{
EXIT_NOT_IMPLEMENTED(vs_input_info->resources[index].OutOfBounds() != 0);
}
EXIT_NOT_IMPLEMENTED(vs_input_info->resources[index].AddTid());
EXIT_NOT_IMPLEMENTED(vs_input_info->resources[index].SwizzleEnabled());
@ -2484,17 +2573,23 @@ VulkanPipeline* PipelineCache::CreatePipeline(VulkanFramebuffer* framebuffer, Re
bool generic_scissor =
(vp.generic_scissor_left != 0 || vp.generic_scissor_top != 0 || vp.generic_scissor_right != 0 || vp.generic_scissor_bottom != 0);
bool viewport_scissor = (vp.viewports[0].viewport_scissor_left != 0 || vp.viewports[0].viewport_scissor_top != 0 ||
vp.viewports[0].viewport_scissor_right != 0 || vp.viewports[0].viewport_scissor_bottom != 0);
p.static_params->viewport_scale[0] = vp.viewports[0].xscale;
p.static_params->viewport_scale[1] = vp.viewports[0].yscale;
p.static_params->viewport_scale[2] = vp.viewports[0].zscale;
p.static_params->viewport_offset[0] = vp.viewports[0].xoffset;
p.static_params->viewport_offset[1] = vp.viewports[0].yoffset;
p.static_params->viewport_offset[2] = vp.viewports[0].zoffset;
p.static_params->scissor_ltrb[0] = (generic_scissor ? vp.generic_scissor_left : vp.screen_scissor_left);
p.static_params->scissor_ltrb[1] = (generic_scissor ? vp.generic_scissor_top : vp.screen_scissor_top);
p.static_params->scissor_ltrb[2] = (generic_scissor ? vp.generic_scissor_right : vp.screen_scissor_right);
p.static_params->scissor_ltrb[3] = (generic_scissor ? vp.generic_scissor_bottom : vp.screen_scissor_bottom);
p.static_params->viewport_scale[0] = vp.viewports[0].xscale;
p.static_params->viewport_scale[1] = vp.viewports[0].yscale;
p.static_params->viewport_scale[2] = vp.viewports[0].zscale;
p.static_params->viewport_offset[0] = vp.viewports[0].xoffset;
p.static_params->viewport_offset[1] = vp.viewports[0].yoffset;
p.static_params->viewport_offset[2] = vp.viewports[0].zoffset;
p.static_params->scissor_ltrb[0] =
(viewport_scissor ? vp.viewports[0].viewport_scissor_left : (generic_scissor ? vp.generic_scissor_left : vp.screen_scissor_left));
p.static_params->scissor_ltrb[1] =
(viewport_scissor ? vp.viewports[0].viewport_scissor_top : (generic_scissor ? vp.generic_scissor_top : vp.screen_scissor_top));
p.static_params->scissor_ltrb[2] = (viewport_scissor ? vp.viewports[0].viewport_scissor_right
: (generic_scissor ? vp.generic_scissor_right : vp.screen_scissor_right));
p.static_params->scissor_ltrb[3] = (viewport_scissor ? vp.viewports[0].viewport_scissor_bottom
: (generic_scissor ? vp.generic_scissor_bottom : vp.screen_scissor_bottom));
p.static_params->topology = topology;
p.static_params->with_depth = (depth->format != VK_FORMAT_UNDEFINED && depth->vulkan_buffer != nullptr);
p.static_params->depth_test_enable = depth->depth_test_enable;
@ -3713,42 +3808,22 @@ static void FindRenderDepthInfo(uint64_t submit_id, CommandBuffer* /*buffer*/, c
EXIT_IF(r == nullptr);
bool neo = Config::IsNeo();
const auto& z = hw.GetDepthRenderTarget();
const auto& rc = hw.GetRenderControl();
const auto& dc = hw.GetDepthControl();
const auto& sc = hw.GetStencilControl();
const auto& sm = hw.GetStencilMask();
const auto& cc = hw.GetColorControl();
const auto& z = hw.GetDepthRenderTarget();
const auto& rc = hw.GetRenderControl();
const auto& dc = hw.GetDepthControl();
const auto& sc = hw.GetStencilControl();
const auto& sm = hw.GetStencilMask();
const auto& cc = hw.GetColorControl();
uint32_t size = 0;
uint32_t pitch = (z.pitch_div8_minus1 + 1) * 8;
TileSizeAlign stencil_size {};
TileSizeAlign htile_size {};
TileSizeAlign depth_size {};
if (z.z_info.format == 3)
{
size = (z.slice_div64_minus1 + 1) * 64 * 4;
} else if (z.z_info.format == 1)
{
size = (z.slice_div64_minus1 + 1) * 64 * 2;
}
bool htile = z.z_info.tile_surface_enable;
bool neo = Config::IsNeo();
bool ps5 = Config::IsNextGen();
bool htile = z.z_info.tile_surface_enable;
bool decompress = htile && (rc.depth_compress_disable || rc.stencil_compress_disable);
if (!TileGetDepthSize(z.width, z.height, pitch, z.z_info.format, z.stencil_info.format, htile, neo, &stencil_size, &htile_size,
&depth_size))
{
depth_size.size = size;
depth_size.align = neo ? 65536 : 32768;
} else
{
EXIT_NOT_IMPLEMENTED(depth_size.size != size);
}
if (dc.z_enable || dc.z_write_enable || dc.stencil_enable || decompress)
{
switch (z.z_info.format * 2 + z.stencil_info.format)
@ -3763,6 +3838,38 @@ static void FindRenderDepthInfo(uint64_t submit_id, CommandBuffer* /*buffer*/, c
}
}
if (r->format != VK_FORMAT_UNDEFINED)
{
if (ps5)
{
bool size_found = TileGetDepthSize(z.size.x_max + 1, z.size.y_max + 1, 0, z.z_info.format, z.stencil_info.format, htile, true,
true, &stencil_size, &htile_size, &depth_size);
EXIT_NOT_IMPLEMENTED(!size_found);
} else
{
uint32_t size = 0;
uint32_t pitch = (z.pitch_div8_minus1 + 1) * 8;
if (z.z_info.format == 3)
{
size = (z.slice_div64_minus1 + 1) * 64 * 4;
} else if (z.z_info.format == 1)
{
size = (z.slice_div64_minus1 + 1) * 64 * 2;
}
if (!TileGetDepthSize(z.width, z.height, pitch, z.z_info.format, z.stencil_info.format, htile, neo, false, &stencil_size,
&htile_size, &depth_size))
{
depth_size.size = size;
depth_size.align = neo ? 65536 : 32768;
} else
{
EXIT_NOT_IMPLEMENTED(depth_size.size != size);
}
}
}
auto stencil_addr_mask = static_cast<uint64_t>(stencil_size.align) - 1;
auto depth_addr_mask = static_cast<uint64_t>(depth_size.align) - 1;
auto htile_addr_mask = static_cast<uint64_t>(htile_size.align) - 1;
@ -3778,8 +3885,8 @@ static void FindRenderDepthInfo(uint64_t submit_id, CommandBuffer* /*buffer*/, c
r->htile_buffer_size = htile_size.size;
r->htile_buffer_vaddr = z.htile_data_base_addr & ~htile_addr_mask;
r->htile_tile_swizzle = z.htile_data_base_addr & htile_addr_mask;
r->width = z.width;
r->height = z.height;
r->width = (ps5 ? z.size.x_max + 1 : z.width);
r->height = (ps5 ? z.size.y_max + 1 : z.height);
r->depth_clear_enable = rc.depth_clear_enable;
r->depth_clear_value = hw.GetDepthClearValue();
r->depth_test_enable = dc.z_enable;
@ -3888,38 +3995,69 @@ static void FindRenderColorInfo(uint64_t submit_id, CommandBuffer* buffer, const
return;
}
auto width = rt.size.width;
auto height = rt.size.height;
auto pitch = (rt.pitch.pitch_div8_minus1 + 1) * 8;
auto size = (rt.slice.slice_div64_minus1 + 1) * 64 * 4;
bool tile = false;
bool write_back = false;
bool ps5 = Config::IsNextGen();
uint32_t width = 0;
uint32_t height = 0;
uint32_t pitch = 0;
uint32_t size = 0;
bool tile = false;
bool write_back = false;
if (ps5)
{
switch (rt.attrib3.tile_mode)
{
case 0x1b:
tile = true;
write_back = false;
break;
default: EXIT("unknown tile mode: %u\n", rt.attrib3.tile_mode);
}
width = rt.attrib2.width + 1;
height = rt.attrib2.height + 1;
pitch = width;
Graphics::TileSizeAlign size32 {};
Graphics::TileGetVideoOutSize(width, height, pitch, tile, true, &size32);
size = size32.size;
EXIT_NOT_IMPLEMENTED(size == 0);
} else
{
switch (rt.attrib.tile_mode)
{
case 0x8:
tile = false;
write_back = false;
break;
case 0x1f:
tile = false;
write_back = true;
break;
case 0xa:
case 0xd:
case 0xe:
tile = true;
write_back = false;
break;
default: EXIT("unknown tile mode: %u\n", rt.attrib.tile_mode);
}
width = rt.size.width;
height = rt.size.height;
pitch = (rt.pitch.pitch_div8_minus1 + 1) * 8;
size = (rt.slice.slice_div64_minus1 + 1) * 64 * 4;
}
auto video_image = VideoOut::VideoOutGetImage(rt.base.addr);
bool render_to_texture = (video_image.image == nullptr);
switch (rt.attrib.tile_mode)
{
case 0x8:
tile = false;
write_back = false;
break;
case 0x1f:
tile = false;
write_back = true;
break;
case 0xa:
case 0xd:
case 0xe:
tile = true;
write_back = false;
break;
default: EXIT("unknown tile mode: %u\n", rt.attrib.tile_mode);
}
if (render_to_texture)
{
RenderTextureFormat rt_format = RenderTextureFormat::Unknown;
@ -3955,8 +4093,8 @@ static void FindRenderColorInfo(uint64_t submit_id, CommandBuffer* buffer, const
r->buffer_size = size;
} else
{
EXIT_NOT_IMPLEMENTED(
!(rt.info.format == 0xa && (rt.info.channel_type == 0x6 || rt.info.channel_type == 0x0) && rt.info.channel_order == 0x1));
EXIT_NOT_IMPLEMENTED(!(rt.info.format == 0xa && (rt.info.channel_type == 0x6 || rt.info.channel_type == 0x0) &&
(rt.info.channel_order == 0x0 || rt.info.channel_order == 0x1)));
// Display buffer
EXIT_NOT_IMPLEMENTED(video_image.buffer_size != size);
@ -3994,6 +4132,7 @@ static void InvalidateMemoryObject(const RenderDepthInfo& r)
}
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
static void PrepareStorageBuffers(uint64_t submit_id, CommandBuffer* buffer, const ShaderStorageResources& storage_buffers,
VulkanBuffer** buffers, uint32_t** sgprs)
{
@ -4003,26 +4142,36 @@ static void PrepareStorageBuffers(uint64_t submit_id, CommandBuffer* buffer, con
EXIT_IF(sgprs == nullptr);
EXIT_IF(*sgprs == nullptr);
bool gen5 = Config::IsNextGen();
for (int i = 0; i < storage_buffers.buffers_num; i++)
{
auto r = storage_buffers.buffers[i];
EXIT_NOT_IMPLEMENTED(r.AddTid());
EXIT_NOT_IMPLEMENTED(r.SwizzleEnabled());
EXIT_NOT_IMPLEMENTED(!((r.Stride() == 4 && r.DstSelXYZW() == DstSel(4, 0, 0, 0) && r.Dfmt() == 4 && r.Nfmt() == 4) ||
(r.Stride() == 4 && r.DstSelXYZW() == DstSel(4, 0, 0, 1) && r.Dfmt() == 4 && r.Nfmt() == 7) ||
(r.Stride() == 8 && r.DstSelXYZW() == DstSel(4, 5, 0, 0) && r.Dfmt() == 11 && r.Nfmt() == 4) ||
(r.Stride() == 16 && r.DstSelXYZW() == DstSel(4, 5, 6, 7) && r.Dfmt() == 14 && r.Nfmt() == 7)));
EXIT_NOT_IMPLEMENTED(!(r.MemoryType() == 0x00 || r.MemoryType() == 0x10 || r.MemoryType() == 0x6d));
auto addr = r.Base();
if (gen5)
{
EXIT_NOT_IMPLEMENTED(r.OutOfBounds() != 0);
EXIT_NOT_IMPLEMENTED(!((r.Stride() == 16 && r.DstSelXYZW() == DstSel(4, 5, 6, 7) && r.Format() == 77)));
} else
{
EXIT_NOT_IMPLEMENTED(!((r.Stride() == 4 && r.DstSelXYZW() == DstSel(4, 0, 0, 0) && r.Dfmt() == 4 && r.Nfmt() == 4) ||
(r.Stride() == 4 && r.DstSelXYZW() == DstSel(4, 0, 0, 1) && r.Dfmt() == 4 && r.Nfmt() == 7) ||
(r.Stride() == 8 && r.DstSelXYZW() == DstSel(4, 5, 0, 0) && r.Dfmt() == 11 && r.Nfmt() == 4) ||
(r.Stride() == 16 && r.DstSelXYZW() == DstSel(4, 5, 6, 7) && r.Dfmt() == 14 && r.Nfmt() == 7)));
EXIT_NOT_IMPLEMENTED(!(r.MemoryType() == 0x00 || r.MemoryType() == 0x10 || r.MemoryType() == 0x6d));
}
auto addr = (gen5 ? r.Base48() : r.Base44());
auto stride = r.Stride();
auto num_records = r.NumRecords();
auto size = stride * num_records;
EXIT_NOT_IMPLEMENTED(size == 0);
EXIT_NOT_IMPLEMENTED((size & 0x3u) != 0);
bool read_only = (r.MemoryType() == 0x10);
bool read_only = (gen5 ? false : (r.MemoryType() == 0x10));
EXIT_NOT_IMPLEMENTED(read_only && !(storage_buffers.usages[i] == ShaderStorageUsage::ReadOnly ||
storage_buffers.usages[i] == ShaderStorageUsage::Constant));
@ -4038,9 +4187,15 @@ static void PrepareStorageBuffers(uint64_t submit_id, CommandBuffer* buffer, con
buffers[i] = buf;
r.UpdateAddress(i);
if (gen5)
{
r.UpdateAddress48(i);
} else
{
r.UpdateAddress44(i);
}
EXIT_NOT_IMPLEMENTED((r.Base() >> 32u) != 0);
EXIT_NOT_IMPLEMENTED(((gen5 ? r.Base48() : r.Base44()) >> 32u) != 0);
(*sgprs)[0] = r.fields[0];
(*sgprs)[1] = r.fields[1];
@ -4065,48 +4220,83 @@ static void PrepareTextures(uint64_t submit_id, CommandBuffer* buffer, const Sha
int index_sampled = 0;
int index_storage = 0;
bool gen5 = Config::IsNextGen();
for (int i = 0; i < textures.textures_num; i++)
{
auto r = textures.desc[i].texture;
EXIT_NOT_IMPLEMENTED(r.Base() == 0);
if (gen5)
{
EXIT_NOT_IMPLEMENTED(!(r.TileMode() == 0));
EXIT_NOT_IMPLEMENTED(r.Format() != 56);
EXIT_NOT_IMPLEMENTED(r.PerfMod5() != 7 && r.PerfMod5() != 0);
EXIT_NOT_IMPLEMENTED(r.BCSwizzle() != 0);
EXIT_NOT_IMPLEMENTED(r.BaseArray5() != 0);
EXIT_NOT_IMPLEMENTED(r.ArrayPitch() != 0);
EXIT_NOT_IMPLEMENTED(r.MaxMip() != 0);
EXIT_NOT_IMPLEMENTED(r.MinLodWarn5() != 0);
EXIT_NOT_IMPLEMENTED(r.MipStatsCntId() != 0);
EXIT_NOT_IMPLEMENTED(r.MipStatsCntEn() != false);
EXIT_NOT_IMPLEMENTED(r.CornerSample() != false);
EXIT_NOT_IMPLEMENTED(r.PrtDefColor() != false);
EXIT_NOT_IMPLEMENTED(r.MsaaDepth() != false);
EXIT_NOT_IMPLEMENTED(r.MaxUncompBlkSize() != 0);
EXIT_NOT_IMPLEMENTED(r.MaxCompBlkSize() != 0);
EXIT_NOT_IMPLEMENTED(r.MetaPipeAligned() != false);
EXIT_NOT_IMPLEMENTED(r.WriteCompress() != false);
EXIT_NOT_IMPLEMENTED(r.MetaCompress() != false);
EXIT_NOT_IMPLEMENTED(r.DccAlphaPos() != false);
EXIT_NOT_IMPLEMENTED(r.DccColorTransf() != false);
EXIT_NOT_IMPLEMENTED(r.MetaAddr() != 0);
} else
{
EXIT_NOT_IMPLEMENTED(r.Dfmt() != 1 && r.Dfmt() != 10 && r.Dfmt() != 37 && r.Dfmt() != 4 && r.Dfmt() != 35 && r.Dfmt() != 3 &&
r.Dfmt() != 36);
EXIT_NOT_IMPLEMENTED(r.Nfmt() != 9 && r.Nfmt() != 0 && r.Nfmt() != 7);
EXIT_NOT_IMPLEMENTED(r.PerfMod() != 7 && r.PerfMod() != 0);
EXIT_NOT_IMPLEMENTED(r.Interlaced() != false);
EXIT_NOT_IMPLEMENTED(!(r.TileMode() == 8 || r.TileMode() == 13 || r.TileMode() == 14 || r.TileMode() == 2 ||
r.TileMode() == 10 || r.TileMode() == 31));
EXIT_NOT_IMPLEMENTED(r.BaseArray() != 0);
EXIT_NOT_IMPLEMENTED(r.LastArray() != 0);
EXIT_NOT_IMPLEMENTED(r.MinLodWarn() != 0);
EXIT_NOT_IMPLEMENTED(r.CounterBankId() != 0);
EXIT_NOT_IMPLEMENTED(r.LodHdwCntEn() != false);
EXIT_NOT_IMPLEMENTED(r.MemoryType() != 0x10 && r.MemoryType() != 0x6d);
}
EXIT_NOT_IMPLEMENTED((gen5 ? r.Base40() : r.Base38()) == 0);
EXIT_NOT_IMPLEMENTED(r.MinLod() != 0);
EXIT_NOT_IMPLEMENTED(r.Dfmt() != 1 && r.Dfmt() != 10 && r.Dfmt() != 37 && r.Dfmt() != 4 && r.Dfmt() != 35 && r.Dfmt() != 3 &&
r.Dfmt() != 36);
EXIT_NOT_IMPLEMENTED(r.Nfmt() != 9 && r.Nfmt() != 0 && r.Nfmt() != 7);
EXIT_NOT_IMPLEMENTED(r.PerfMod() != 7 && r.PerfMod() != 0);
EXIT_NOT_IMPLEMENTED(r.Interlaced() != false);
EXIT_NOT_IMPLEMENTED(!(r.TilingIdx() == 8 || r.TilingIdx() == 13 || r.TilingIdx() == 14 || r.TilingIdx() == 2 ||
r.TilingIdx() == 10 || r.TilingIdx() == 31));
EXIT_NOT_IMPLEMENTED(r.Type() != 9);
EXIT_NOT_IMPLEMENTED(r.Depth() != 0);
EXIT_NOT_IMPLEMENTED(r.BaseArray() != 0);
EXIT_NOT_IMPLEMENTED(r.LastArray() != 0);
EXIT_NOT_IMPLEMENTED(r.MinLodWarn() != 0);
EXIT_NOT_IMPLEMENTED(r.CounterBankId() != 0);
EXIT_NOT_IMPLEMENTED(r.LodHdwCntEn() != false);
EXIT_NOT_IMPLEMENTED(r.MemoryType() != 0x10 && r.MemoryType() != 0x6d);
bool read_only = (r.MemoryType() == 0x10);
bool read_only = (gen5 ? false : (r.MemoryType() == 0x10));
EXIT_NOT_IMPLEMENTED(read_only && !(textures.desc[i].usage == ShaderTextureUsage::ReadOnly));
TileSizeAlign size {};
auto addr = r.Base();
auto addr = (gen5 ? r.Base40() : r.Base38());
bool neo = Config::IsNeo();
auto width = r.Width() + 1;
auto height = r.Height() + 1;
auto pitch = r.Pitch() + 1;
auto width = (gen5 ? r.Width5() : r.Width4()) + 1;
auto height = (gen5 ? r.Height5() : r.Height4()) + 1;
auto pitch = (gen5 ? width : r.Pitch() + 1);
auto base_level = r.BaseLevel();
auto levels = r.LastLevel() + 1;
auto tile = r.TilingIdx();
auto dfmt = r.Dfmt();
auto nfmt = r.Nfmt();
auto tile = r.TileMode();
auto dfmt = (gen5 ? 0 : r.Dfmt());
auto nfmt = (gen5 ? 0 : r.Nfmt());
auto fmt = (gen5 ? r.Format() : 0);
uint32_t swizzle = r.DstSelXYZW();
bool check_depth_texture = (tile == 2);
bool check_depth_texture = (!gen5 && tile == 2);
TileGetTextureSize(dfmt, nfmt, width, height, pitch, levels, tile, neo, &size, nullptr, nullptr);
if (gen5)
{
TileGetTextureSize2(fmt, width, height, pitch, levels, tile, &size, nullptr, nullptr);
} else
{
TileGetTextureSize(dfmt, nfmt, width, height, pitch, levels, tile, neo, &size, nullptr, nullptr);
}
EXIT_NOT_IMPLEMENTED(size.size == 0);
EXIT_NOT_IMPLEMENTED((addr & (static_cast<uint64_t>(size.align) - 1u)) != 0);
@ -4149,14 +4339,14 @@ static void PrepareTextures(uint64_t submit_id, CommandBuffer* buffer, const Sha
{
EXIT_NOT_IMPLEMENTED(textures.desc[i].usage != ShaderTextureUsage::ReadWrite);
StorageTextureObject vulkan_texture_info(dfmt, nfmt, width, height, pitch, base_level, levels, tile, neo, swizzle);
StorageTextureObject vulkan_texture_info(dfmt, nfmt, fmt, width, height, pitch, base_level, levels, tile, neo, swizzle);
tex = static_cast<StorageTextureVulkanImage*>(
GpuMemoryCreateObject(submit_id, g_render_ctx->GetGraphicCtx(), buffer, addr, size.size, vulkan_texture_info));
} else
{
EXIT_NOT_IMPLEMENTED(textures.desc[i].usage != ShaderTextureUsage::ReadOnly);
if (tile == 10)
if (!gen5 && tile == 10)
{
RenderTextureFormat rt_format = RenderTextureFormat::Unknown;
if (dfmt == 10 && nfmt == 0)
@ -4169,7 +4359,7 @@ static void PrepareTextures(uint64_t submit_id, CommandBuffer* buffer, const Sha
submit_id, g_render_ctx->GetGraphicCtx(), buffer, addr, size.size, vulkan_buffer_info));
} else
{
TextureObject vulkan_texture_info(dfmt, nfmt, width, height, pitch, base_level, levels, tile, neo, swizzle);
TextureObject vulkan_texture_info(dfmt, nfmt, fmt, width, height, pitch, base_level, levels, tile, neo, swizzle);
tex = static_cast<TextureVulkanImage*>(
GpuMemoryCreateObject(submit_id, g_render_ctx->GetGraphicCtx(), buffer, addr, size.size, vulkan_texture_info));
}
@ -4181,17 +4371,29 @@ static void PrepareTextures(uint64_t submit_id, CommandBuffer* buffer, const Sha
if (textures.desc[i].textures2d_without_sampler)
{
images_storage[index_storage] = tex;
r.UpdateAddress(index_storage);
if (gen5)
{
r.UpdateAddress40(index_storage);
} else
{
r.UpdateAddress38(index_storage);
}
index_storage++;
} else
{
images_sampled[index_sampled] = tex;
images_sampled_view[index_sampled] = (depth_texture ? VulkanImage::VIEW_DEPTH_TEXTURE : view_type);
r.UpdateAddress(index_sampled);
if (gen5)
{
r.UpdateAddress40(index_sampled);
} else
{
r.UpdateAddress38(index_sampled);
}
index_sampled++;
}
EXIT_NOT_IMPLEMENTED((r.Base() >> 32u) != 0);
EXIT_NOT_IMPLEMENTED(((gen5 ? r.Base40() : r.Base38()) >> 32u) != 0);
(*sgprs)[0] = r.fields[0];
(*sgprs)[1] = r.fields[1];
@ -4215,6 +4417,8 @@ static void PrepareSamplers(const ShaderSamplerResources& samplers, uint64_t* sa
EXIT_IF(sgprs == nullptr);
EXIT_IF(*sgprs == nullptr);
bool gen5 = Config::IsNextGen();
for (int i = 0; i < samplers.samplers_num; i++)
{
auto r = samplers.samplers[i];
@ -4226,8 +4430,12 @@ static void PrepareSamplers(const ShaderSamplerResources& samplers, uint64_t* sa
EXIT_NOT_IMPLEMENTED(r.DepthCompareFunc() != 0);
EXIT_NOT_IMPLEMENTED(r.ForceUnormCoords() != false);
EXIT_NOT_IMPLEMENTED(r.AnisoThreshold() != 0);
EXIT_NOT_IMPLEMENTED(r.McCoordTrunc() != false);
EXIT_NOT_IMPLEMENTED(!gen5 && r.McCoordTrunc() != false);
EXIT_NOT_IMPLEMENTED(r.ForceDegamma() != false);
EXIT_NOT_IMPLEMENTED(gen5 && r.SkipDegamma() != false);
EXIT_NOT_IMPLEMENTED(gen5 && r.PointPreclamp() != false);
EXIT_NOT_IMPLEMENTED(gen5 && r.AnisoOverride() != false);
EXIT_NOT_IMPLEMENTED(gen5 && r.BlendZeroPrt() != false);
EXIT_NOT_IMPLEMENTED(r.AnisoBias() != 0);
EXIT_NOT_IMPLEMENTED(r.TruncCoord() != false);
EXIT_NOT_IMPLEMENTED(r.DisableCubeWrap() != false);
@ -4457,7 +4665,7 @@ void GraphicsRenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Cont
hw_print(*ctx);
hw_check(*ctx);
EXIT_NOT_IMPLEMENTED(ctx->GetShaderStages() != 0);
EXIT_NOT_IMPLEMENTED(ctx->GetShaderStages() != 0 && ctx->GetShaderStages() != 0x02002000);
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
@ -4605,7 +4813,7 @@ void GraphicsRenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::
printf("\t flags = 0x%08" PRIx32 "\n", flags);
EXIT_NOT_IMPLEMENTED(flags != 0);
EXIT_NOT_IMPLEMENTED(ctx->GetShaderStages() != 0);
EXIT_NOT_IMPLEMENTED(ctx->GetShaderStages() != 0 && ctx->GetShaderStages() != 0x02002000);
RenderDepthInfo depth_info;
FindRenderDepthInfo(submit_id, buffer, *ctx, &depth_info);

View File

@ -5,6 +5,7 @@
#include "Kyty/Core/String.h"
#include "Kyty/Core/Threads.h"
#include "Emulator/Config.h"
#include "Emulator/Graphics/AsyncJob.h"
#include "Emulator/Graphics/GraphicContext.h"
#include "Emulator/Graphics/Graphics.h"
@ -309,7 +310,7 @@ private:
CommandProcessor* m_compute_cp[8] = {};
ComputeRing* m_compute_ring[64] = {};
int m_done_num = 0;
std::atomic_int m_done_num = 0;
};
using hw_ctx_parser_func_t = uint32_t (*)(KYTY_HW_CTX_PARSER_ARGS);
@ -452,7 +453,7 @@ bool Gpu::AreSubmitsAllowed()
int Gpu::GetFrameNum()
{
Core::LockGuard lock(m_mutex);
// Core::LockGuard lock(m_mutex);
return m_done_num;
}
@ -1179,7 +1180,8 @@ void CommandProcessor::WriteAtEndOfPipe64(uint32_t cache_policy, uint32_t event_
cache_action == 0x38 && source64 && !with_interrupt)
{
GraphicsRenderWriteAtEndOfPipeWithWriteBack64(m_sumbit_id, m_buffer[m_current_buffer], static_cast<uint64_t*>(dst_gpu_addr), value);
} else if (eop_event_type == 0x04 && cache_action == 0x00 && event_index == 0x05 && source_counter && !with_interrupt)
} else if (((eop_event_type == 0x04 && event_index == 0x05) || (eop_event_type == 0x28 && event_index == 0x00)) &&
cache_action == 0x00 && source_counter && !with_interrupt)
{
GraphicsRenderWriteAtEndOfPipeClockCounter(m_sumbit_id, m_buffer[m_current_buffer], static_cast<uint64_t*>(dst_gpu_addr));
} else if ((eop_event_type == 0x04 && event_index == 0x05) && cache_action == 0x00 && source64 && with_interrupt)
@ -1581,6 +1583,11 @@ KYTY_HW_CTX_PARSER(hw_ctx_set_color_info)
r.cmask_tile_mode_neo = KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, CMASK_ADDR_TYPE);
r.neo_mode = KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, ALT_TILE_MODE) != 0;
if (!r.neo_mode && Config::IsNextGen())
{
r.neo_mode = true;
}
cp->GetCtx()->SetColorInfo(param, r);
return 1;
@ -1957,6 +1964,11 @@ KYTY_HW_CTX_PARSER(hw_ctx_set_render_target)
info.cmask_tile_mode_neo = KYTY_PM4_GET(buffer[4], CB_COLOR0_INFO, CMASK_ADDR_TYPE);
info.neo_mode = KYTY_PM4_GET(buffer[4], CB_COLOR0_INFO, ALT_TILE_MODE) != 0;
if (!info.neo_mode && Config::IsNextGen())
{
info.neo_mode = true;
}
// attrib.force_dest_alpha_to_one = (buffer[5] & 0x20000u) != 0;
// attrib.tile_mode = buffer[5] & 0x1fu;
// attrib.fmask_tile_mode = (buffer[5] >> 5u) & 0x1fu;
@ -3223,21 +3235,39 @@ KYTY_CP_OP_PARSER(cp_op_release_mem)
if (custom)
{
uint32_t gcr_cntl = buffer[1];
uint32_t gcr_cntl = buffer[1] & 0xffffu;
uint32_t data_sel = (buffer[1] >> 16u) & 0xffu;
EXIT_NOT_IMPLEMENTED(gcr_cntl != 0x200);
EXIT_NOT_IMPLEMENTED((buffer[0] >> 8u) != 0x3);
EXIT_NOT_IMPLEMENTED(data_sel != 2 && data_sel != 3);
if (gcr_cntl == 0x200)
if (data_sel == 2)
{
cache_action = 0x38;
}
EXIT_NOT_IMPLEMENTED(gcr_cntl != 0x0200);
EXIT_NOT_IMPLEMENTED((buffer[0] >> 8u) != 0x3);
cache_policy = 0;
event_index = 0;
event_write_dest = 0;
event_write_source = 2;
interrupt_selector = 0;
if (gcr_cntl == 0x200)
{
cache_action = 0x38;
}
cache_policy = 0;
event_index = 0;
event_write_dest = 0;
event_write_source = 2;
interrupt_selector = 0;
} else if (data_sel == 3)
{
EXIT_NOT_IMPLEMENTED(gcr_cntl != 0x0000);
EXIT_NOT_IMPLEMENTED((buffer[0] >> 8u) != 0x0);
cache_action = 0x00;
cache_policy = 0;
event_index = 0;
event_write_dest = 0;
event_write_source = 4;
interrupt_selector = 0;
}
}
cp->WriteAtEndOfPipe64(cache_policy, event_write_dest, eop_event_type, cache_action, event_index, event_write_source, dst_gpu_addr,
@ -3513,6 +3543,10 @@ static void graphics_init_jmp_tables_cx_indirect()
info.dcc_compression_enable = KYTY_PM4_GET(value, CB_COLOR0_INFO, DCC_ENABLE) != 0;
info.cmask_tile_mode_neo = KYTY_PM4_GET(value, CB_COLOR0_INFO, CMASK_ADDR_TYPE);
info.neo_mode = KYTY_PM4_GET(value, CB_COLOR0_INFO, ALT_TILE_MODE) != 0;
if (!info.neo_mode && Config::IsNextGen())
{
info.neo_mode = true;
}
cp->GetCtx()->SetColorInfo(slot, info);
};
}

View File

@ -17,21 +17,27 @@
namespace Kyty::Libs::Graphics {
static VkFormat get_texture_format(uint32_t dfmt, uint32_t nfmt)
static VkFormat get_texture_format(uint32_t dfmt, uint32_t nfmt, uint32_t fmt)
{
if (nfmt == 9 && dfmt == 10)
if (fmt == 0)
{
return VK_FORMAT_R8G8B8A8_SRGB;
}
if (nfmt == 0 && dfmt == 10)
if (nfmt == 9 && dfmt == 10)
{
return VK_FORMAT_R8G8B8A8_SRGB;
}
if (nfmt == 0 && dfmt == 10)
{
return VK_FORMAT_R8G8B8A8_UNORM;
}
if (nfmt == 9 && dfmt == 37)
{
return VK_FORMAT_BC3_SRGB_BLOCK;
}
EXIT("unknown format: nfmt = %u, dfmt = %u\n", nfmt, dfmt);
} else
{
return VK_FORMAT_R8G8B8A8_UNORM;
EXIT("unknown format: fmt = %u\n", fmt);
}
if (nfmt == 9 && dfmt == 37)
{
return VK_FORMAT_BC3_SRGB_BLOCK;
}
EXIT("unknown format: nfmt = %u, dfmt = %u\n", nfmt, dfmt);
return VK_FORMAT_UNDEFINED;
}
@ -130,8 +136,9 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj,
auto* vk_obj = static_cast<StorageTextureVulkanImage*>(obj);
auto tile = params[StorageTextureObject::PARAM_TILE];
auto dfmt = params[StorageTextureObject::PARAM_DFMT_NFMT] >> 32u;
auto nfmt = params[StorageTextureObject::PARAM_DFMT_NFMT] & 0xffffffffu;
auto fmt = (params[StorageTextureObject::PARAM_FORMAT] >> 16u) & 0xffffu;
auto dfmt = (params[StorageTextureObject::PARAM_FORMAT] >> 8u) & 0xffu;
auto nfmt = (params[StorageTextureObject::PARAM_FORMAT]) & 0xffu;
auto width = params[StorageTextureObject::PARAM_WIDTH_HEIGHT] >> 32u;
auto height = params[StorageTextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu;
// auto base_level = params[StorageTextureObject::PARAM_LEVELS] >> 32u;
@ -147,7 +154,13 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj,
TileSizeOffset level_sizes[16];
TileGetTextureSize(dfmt, nfmt, width, height, pitch, levels, tile, neo, nullptr, level_sizes, nullptr);
if (fmt != 0)
{
TileGetTextureSize2(fmt, width, height, pitch, levels, tile, nullptr, level_sizes, nullptr);
} else
{
TileGetTextureSize(dfmt, nfmt, width, height, pitch, levels, tile, neo, nullptr, level_sizes, nullptr);
}
// dbg_test_mipmaps(ctx, VK_FORMAT_BC3_SRGB_BLOCK, 512, 512);
@ -187,6 +200,7 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj,
if (tile == 13)
{
// EXIT_NOT_IMPLEMENTED(pitch != width);
EXIT_NOT_IMPLEMENTED(fmt != 0);
auto* temp_buf = new uint8_t[*size];
TileConvertTiledToLinear(temp_buf, reinterpret_cast<void*>(*vaddr), TileMode::TextureTiled, dfmt, nfmt, width, height, pitch,
levels, neo);
@ -208,8 +222,9 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint
EXIT_IF(ctx == nullptr);
EXIT_IF(params == nullptr);
auto dfmt = params[StorageTextureObject::PARAM_DFMT_NFMT] >> 32u;
auto nfmt = params[StorageTextureObject::PARAM_DFMT_NFMT] & 0xffffffffu;
auto fmt = (params[StorageTextureObject::PARAM_FORMAT] >> 16u) & 0xffffu;
auto dfmt = (params[StorageTextureObject::PARAM_FORMAT] >> 8u) & 0xffu;
auto nfmt = (params[StorageTextureObject::PARAM_FORMAT]) & 0xffu;
auto width = params[StorageTextureObject::PARAM_WIDTH_HEIGHT] >> 32u;
auto height = params[StorageTextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu;
auto base_level = params[StorageTextureObject::PARAM_LEVELS] >> 32u;
@ -227,7 +242,7 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint
components.b = get_swizzle(GetDstSel(swizzle, 2));
components.a = get_swizzle(GetDstSel(swizzle, 3));
auto pixel_format = get_texture_format(dfmt, nfmt);
auto pixel_format = get_texture_format(dfmt, nfmt, fmt);
EXIT_NOT_IMPLEMENTED(pixel_format == VK_FORMAT_UNDEFINED);
EXIT_NOT_IMPLEMENTED(width == 0);
@ -336,7 +351,7 @@ static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* mem)
bool StorageTextureObject::Equal(const uint64_t* other) const
{
return (params[PARAM_DFMT_NFMT] == other[PARAM_DFMT_NFMT] && params[PARAM_PITCH] == other[PARAM_PITCH] &&
return (params[PARAM_FORMAT] == other[PARAM_FORMAT] && params[PARAM_PITCH] == other[PARAM_PITCH] &&
params[PARAM_WIDTH_HEIGHT] == other[PARAM_WIDTH_HEIGHT] && params[PARAM_LEVELS] == other[PARAM_LEVELS] &&
params[PARAM_TILE] == other[PARAM_TILE] && params[PARAM_NEO] == other[PARAM_NEO] &&
params[PARAM_SWIZZLE] == other[PARAM_SWIZZLE]);

View File

@ -17,41 +17,51 @@
namespace Kyty::Libs::Graphics {
static VkFormat get_texture_format(uint32_t dfmt, uint32_t nfmt)
static VkFormat get_texture_format(uint32_t dfmt, uint32_t nfmt, uint32_t fmt)
{
if (nfmt == 9 && dfmt == 10)
if (fmt == 0)
{
return VK_FORMAT_R8G8B8A8_SRGB;
}
if (nfmt == 0 && dfmt == 10)
if (nfmt == 9 && dfmt == 10)
{
return VK_FORMAT_R8G8B8A8_SRGB;
}
if (nfmt == 0 && dfmt == 10)
{
return VK_FORMAT_R8G8B8A8_UNORM;
}
if (nfmt == 0 && dfmt == 1)
{
return VK_FORMAT_R8_UNORM;
}
if (nfmt == 0 && dfmt == 3)
{
return VK_FORMAT_R8G8_UNORM;
}
if (nfmt == 9 && dfmt == 37)
{
return VK_FORMAT_BC3_SRGB_BLOCK;
}
if (nfmt == 0 && dfmt == 37)
{
return VK_FORMAT_BC3_UNORM_BLOCK;
}
if (nfmt == 0 && dfmt == 36)
{
return VK_FORMAT_BC2_UNORM_BLOCK;
}
if (nfmt == 0 && dfmt == 35)
{
return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
}
EXIT("unknown format: nfmt = %u, dfmt = %u\n", nfmt, dfmt);
} else
{
return VK_FORMAT_R8G8B8A8_UNORM;
if (fmt == 56)
{
return VK_FORMAT_R8G8B8A8_UNORM;
}
EXIT("unknown format: fmt = %u\n", fmt);
}
if (nfmt == 0 && dfmt == 1)
{
return VK_FORMAT_R8_UNORM;
}
if (nfmt == 0 && dfmt == 3)
{
return VK_FORMAT_R8G8_UNORM;
}
if (nfmt == 9 && dfmt == 37)
{
return VK_FORMAT_BC3_SRGB_BLOCK;
}
if (nfmt == 0 && dfmt == 37)
{
return VK_FORMAT_BC3_UNORM_BLOCK;
}
if (nfmt == 0 && dfmt == 36)
{
return VK_FORMAT_BC2_UNORM_BLOCK;
}
if (nfmt == 0 && dfmt == 35)
{
return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
}
EXIT("unknown format: nfmt = %u, dfmt = %u\n", nfmt, dfmt);
return VK_FORMAT_UNDEFINED;
}
@ -150,8 +160,9 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj,
auto* vk_obj = static_cast<TextureVulkanImage*>(obj);
auto tile = params[TextureObject::PARAM_TILE];
auto dfmt = params[TextureObject::PARAM_DFMT_NFMT] >> 32u;
auto nfmt = params[TextureObject::PARAM_DFMT_NFMT] & 0xffffffffu;
auto fmt = (params[TextureObject::PARAM_FORMAT] >> 16u) & 0xffffu;
auto dfmt = (params[TextureObject::PARAM_FORMAT] >> 8u) & 0xffu;
auto nfmt = (params[TextureObject::PARAM_FORMAT]) & 0xffu;
auto width = params[TextureObject::PARAM_WIDTH_HEIGHT] >> 32u;
auto height = params[TextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu;
auto levels = params[TextureObject::PARAM_LEVELS] & 0xffffffffu;
@ -162,11 +173,19 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj,
EXIT_NOT_IMPLEMENTED(levels >= 16);
EXIT_NOT_IMPLEMENTED(tile != 8 && tile != 13);
TileSizeOffset level_sizes[16];
TileGetTextureSize(dfmt, nfmt, width, height, pitch, levels, tile, neo, nullptr, level_sizes, nullptr);
if (fmt != 0)
{
EXIT_NOT_IMPLEMENTED(tile != 0);
TileGetTextureSize2(fmt, width, height, pitch, levels, tile, nullptr, level_sizes, nullptr);
} else
{
EXIT_NOT_IMPLEMENTED(tile != 8 && tile != 13);
TileGetTextureSize(dfmt, nfmt, width, height, pitch, levels, tile, neo, nullptr, level_sizes, nullptr);
}
// dbg_test_mipmaps(ctx, VK_FORMAT_BC3_SRGB_BLOCK, 512, 512);
@ -201,17 +220,27 @@ static void update_func(GraphicContext* ctx, const uint64_t* params, void* obj,
}
}
if (tile == 13)
if (fmt == 0)
{
// EXIT_NOT_IMPLEMENTED(pitch != width);
auto* temp_buf = new uint8_t[*size];
TileConvertTiledToLinear(temp_buf, reinterpret_cast<void*>(*vaddr), TileMode::TextureTiled, dfmt, nfmt, width, height, pitch,
levels, neo);
UtilFillImage(ctx, vk_obj, temp_buf, *size, regions, static_cast<uint64_t>(vk_layout));
delete[] temp_buf;
} else if (tile == 8)
if (tile == 13)
{
// EXIT_NOT_IMPLEMENTED(pitch != width);
EXIT_NOT_IMPLEMENTED(fmt != 0);
auto* temp_buf = new uint8_t[*size];
TileConvertTiledToLinear(temp_buf, reinterpret_cast<void*>(*vaddr), TileMode::TextureTiled, dfmt, nfmt, width, height, pitch,
levels, neo);
UtilFillImage(ctx, vk_obj, temp_buf, *size, regions, static_cast<uint64_t>(vk_layout));
delete[] temp_buf;
} else if (tile == 8)
{
UtilFillImage(ctx, vk_obj, reinterpret_cast<void*>(*vaddr), *size, regions, static_cast<uint64_t>(vk_layout));
}
} else
{
UtilFillImage(ctx, vk_obj, reinterpret_cast<void*>(*vaddr), *size, regions, static_cast<uint64_t>(vk_layout));
if (tile == 0)
{
UtilFillImage(ctx, vk_obj, reinterpret_cast<void*>(*vaddr), *size, regions, static_cast<uint64_t>(vk_layout));
}
}
}
@ -392,8 +421,9 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint
EXIT_IF(ctx == nullptr);
EXIT_IF(params == nullptr);
auto dfmt = params[TextureObject::PARAM_DFMT_NFMT] >> 32u;
auto nfmt = params[TextureObject::PARAM_DFMT_NFMT] & 0xffffffffu;
auto fmt = (params[TextureObject::PARAM_FORMAT] >> 16u) & 0xffffu;
auto dfmt = (params[TextureObject::PARAM_FORMAT] >> 8u) & 0xffu;
auto nfmt = (params[TextureObject::PARAM_FORMAT]) & 0xffu;
auto width = params[TextureObject::PARAM_WIDTH_HEIGHT] >> 32u;
auto height = params[TextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu;
auto base_level = params[TextureObject::PARAM_LEVELS] >> 32u;
@ -409,7 +439,7 @@ static void* create_func(GraphicContext* ctx, const uint64_t* params, const uint
components.b = get_swizzle(GetDstSel(swizzle, 2));
components.a = get_swizzle(GetDstSel(swizzle, 3));
auto pixel_format = get_texture_format(dfmt, nfmt);
auto pixel_format = get_texture_format(dfmt, nfmt, fmt);
EXIT_NOT_IMPLEMENTED(pixel_format == VK_FORMAT_UNDEFINED);
EXIT_NOT_IMPLEMENTED(width == 0);
@ -504,8 +534,9 @@ static void* create2_func(GraphicContext* ctx, CommandBuffer* buffer, const uint
EXIT_IF(ctx == nullptr);
EXIT_IF(params == nullptr);
auto dfmt = params[TextureObject::PARAM_DFMT_NFMT] >> 32u;
auto nfmt = params[TextureObject::PARAM_DFMT_NFMT] & 0xffffffffu;
auto fmt = (params[TextureObject::PARAM_FORMAT] >> 16u) & 0xffffu;
auto dfmt = (params[TextureObject::PARAM_FORMAT] >> 8u) & 0xffu;
auto nfmt = (params[TextureObject::PARAM_FORMAT]) & 0xffu;
auto width = params[TextureObject::PARAM_WIDTH_HEIGHT] >> 32u;
auto height = params[TextureObject::PARAM_WIDTH_HEIGHT] & 0xffffffffu;
auto base_level = params[TextureObject::PARAM_LEVELS] >> 32u;
@ -521,7 +552,7 @@ static void* create2_func(GraphicContext* ctx, CommandBuffer* buffer, const uint
components.b = get_swizzle(GetDstSel(swizzle, 2));
components.a = get_swizzle(GetDstSel(swizzle, 3));
auto pixel_format = get_texture_format(dfmt, nfmt);
auto pixel_format = get_texture_format(dfmt, nfmt, fmt);
EXIT_NOT_IMPLEMENTED(pixel_format == VK_FORMAT_UNDEFINED);
EXIT_NOT_IMPLEMENTED(width == 0);
@ -628,7 +659,7 @@ static void delete_func(GraphicContext* ctx, void* obj, VulkanMemory* mem)
bool TextureObject::Equal(const uint64_t* other) const
{
return (params[PARAM_DFMT_NFMT] == other[PARAM_DFMT_NFMT] && params[PARAM_PITCH] == other[PARAM_PITCH] &&
return (params[PARAM_FORMAT] == other[PARAM_FORMAT] && params[PARAM_PITCH] == other[PARAM_PITCH] &&
params[PARAM_WIDTH_HEIGHT] == other[PARAM_WIDTH_HEIGHT] && params[PARAM_LEVELS] == other[PARAM_LEVELS] &&
params[PARAM_TILE] == other[PARAM_TILE] && params[PARAM_NEO] == other[PARAM_NEO] &&
params[PARAM_SWIZZLE] == other[PARAM_SWIZZLE]);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -501,7 +501,7 @@ void TileConvertTiledToLinear(void* dst, const void* src, TileMode mode, uint32_
}
bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format, uint32_t stencil_format, bool htile, bool neo,
TileSizeAlign* stencil_size, TileSizeAlign* htile_size, TileSizeAlign* depth_size)
bool next_gen, TileSizeAlign* stencil_size, TileSizeAlign* htile_size, TileSizeAlign* depth_size)
{
struct DepthInfo
{
@ -585,11 +585,53 @@ bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t
{1280, 720, 1, 1, false, true, 1280, {983040, 32768}, {0, 0}, {1966080, 65536}},
};
static const DepthInfo infos_next_gen[] = {
{3840, 2160, 3, 0, true, true, 3840, {0, 0}, {655360, 32768}, {33423360, 65536}},
{3840, 2160, 3, 0, false, true, 3840, {0, 0}, {0, 0}, {33423360, 65536}},
{1920, 1080, 3, 0, true, true, 1920, {0, 0}, {196608, 32768}, {8847360, 65536}},
{1920, 1080, 3, 0, false, true, 1920, {0, 0}, {0, 0}, {8847360, 65536}},
{1280, 720, 3, 0, true, true, 1280, {0, 0}, {131072, 32768}, {3932160, 65536}},
{1280, 720, 3, 0, false, true, 1280, {0, 0}, {0, 0}, {3932160, 65536}},
{3840, 2160, 1, 0, true, true, 3840, {0, 0}, {655360, 32768}, {16711680, 65536}},
{3840, 2160, 1, 0, false, true, 3840, {0, 0}, {0, 0}, {16711680, 65536}},
{1920, 1080, 1, 0, true, true, 2048, {0, 0}, {196608, 32768}, {4718592, 65536}},
{1920, 1080, 1, 0, false, true, 2048, {0, 0}, {0, 0}, {4718592, 65536}},
{1280, 720, 1, 0, true, true, 1280, {0, 0}, {131072, 32768}, {1966080, 65536}},
{1280, 720, 1, 0, false, true, 1280, {0, 0}, {0, 0}, {1966080, 65536}},
{3840, 2160, 3, 1, true, true, 3840, {8847360, 65536}, {655360, 32768}, {33423360, 65536}},
{3840, 2160, 3, 1, false, true, 3840, {8847360, 65536}, {0, 0}, {33423360, 65536}},
{1920, 1080, 3, 1, true, true, 1920, {2621440, 65536}, {196608, 32768}, {8847360, 65536}},
{1920, 1080, 3, 1, false, true, 1920, {2621440, 65536}, {0, 0}, {8847360, 65536}},
{1280, 720, 3, 1, true, true, 1280, {983040, 65536}, {131072, 32768}, {3932160, 65536}},
{1280, 720, 3, 1, false, true, 1280, {983040, 65536}, {0, 0}, {3932160, 65536}},
{3840, 2160, 1, 1, true, true, 3840, {8847360, 65536}, {655360, 32768}, {16711680, 65536}},
{3840, 2160, 1, 1, false, true, 3840, {8847360, 65536}, {0, 0}, {16711680, 65536}},
{1920, 1080, 1, 1, true, true, 2048, {2621440, 65536}, {196608, 32768}, {4718592, 65536}},
{1920, 1080, 1, 1, false, true, 2048, {2621440, 65536}, {0, 0}, {4718592, 65536}},
{1280, 720, 1, 1, true, true, 1280, {983040, 65536}, {131072, 32768}, {1966080, 65536}},
{1280, 720, 1, 1, false, true, 1280, {983040, 65536}, {0, 0}, {1966080, 65536}},
};
EXIT_IF(depth_size == nullptr);
EXIT_IF(htile_size == nullptr);
EXIT_IF(stencil_size == nullptr);
if (neo)
if (next_gen)
{
EXIT_IF(pitch != 0);
EXIT_IF(!neo);
for (const auto& i: infos_next_gen)
{
if (i.width == width && i.height == height /*&& i.pitch == pitch*/ && i.tile == htile && i.z_format == z_format &&
i.stencil_format == stencil_format)
{
*depth_size = i.depth;
*htile_size = i.htile;
*stencil_size = i.stencil;
return true;
}
}
} else if (neo)
{
for (const auto& i: infos_neo)
{
@ -719,6 +761,12 @@ struct TextureInfoSize
uint32_t mipmap_size = 0;
};
struct TextureInfoSize2
{
uint32_t mipmap_offset = 0;
uint32_t mipmap_size = 0;
};
struct TextureInfo
{
uint32_t dfmt = 0;
@ -733,6 +781,21 @@ struct TextureInfo
TextureInfoPadded padded[16];
};
struct TextureInfo2
{
uint32_t fmt = 0;
uint32_t width = 0;
uint32_t height = 0;
uint32_t pitch = 0;
uint32_t levels = 0;
uint32_t tile = 0;
uint32_t total_size = 0;
uint32_t total_align = 0;
TextureInfoSize2 size[16];
TextureInfoPadded padded[16];
};
#include "Tables/TileTextureInfo_0_56.inc"
#include "Tables/TileTextureInfo_10_10_0.inc"
#include "Tables/TileTextureInfo_13_10_0.inc"
#include "Tables/TileTextureInfo_13_10_9.inc"
@ -759,6 +822,8 @@ static const TextureInfo* g_info_map_8_1_0[16][16][16][2] = {};
static const TextureInfo* g_info_map_8_10_0[16][16][16][2] = {};
static const TextureInfo* g_info_map_8_10_9[16][16][16][2] = {};
static const TextureInfo2* g_info_map_0_56[16][16][16][16] = {};
template <class Map>
static void init_map(Map& map, const TextureInfo* info, int num)
{
@ -786,7 +851,41 @@ static void init_map(Map& map, const TextureInfo* info, int num)
auto h = IntLog2(i.height);
auto p = IntLog2(i.pitch);
auto n = i.neo ? 1 : 0;
EXIT_IF(w > 16 || h > 16 || p > 16 || n > 2);
EXIT_IF(w >= 16 || h >= 16 || p >= 16 || n >= 2);
EXIT_IF(map[w][h][p][n] != nullptr);
map[w][h][p][n] = &i;
}
}
}
template <class Map>
static void init_map2(Map& map, const TextureInfo2* info, int num)
{
for (int w = 0; w < 16; w++)
{
for (int h = 0; h < 16; h++)
{
for (int p = 0; p < 16; p++)
{
for (int n = 0; n < 16; n++)
{
map[w][h][p][n] = nullptr;
}
}
}
}
for (int index = 0; index < num; index++)
{
const auto& i = info[index];
if (!(i.width == 0 && i.height == 0 && i.pitch == 0))
{
EXIT_IF(!(IsPowerOfTwo(i.width) && IsPowerOfTwo(i.height) && IsPowerOfTwo(i.pitch)));
auto w = IntLog2(i.width);
auto h = IntLog2(i.height);
auto p = IntLog2(i.pitch);
auto n = i.levels;
EXIT_IF(w >= 16 || h >= 16 || p >= 16 || n >= 16);
EXIT_IF(map[w][h][p][n] != nullptr);
map[w][h][p][n] = &i;
}
@ -796,15 +895,20 @@ static void init_map(Map& map, const TextureInfo* info, int num)
template <class Map>
static const TextureInfo* check_map(Map& map, uint32_t width, uint32_t height, uint32_t pitch, bool neo)
{
// if (IsPowerOfTwo(width) && IsPowerOfTwo(height) && IsPowerOfTwo(pitch))
{
auto w = IntLog2(width);
auto h = IntLog2(height);
auto p = IntLog2(pitch);
auto n = neo ? 1 : 0;
return map[w][h][p][n];
}
// return nullptr;
auto w = IntLog2(width);
auto h = IntLog2(height);
auto p = IntLog2(pitch);
auto n = neo ? 1 : 0;
return map[w][h][p][n];
}
template <class Map>
static const TextureInfo2* check_map2(Map& map, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels)
{
auto w = IntLog2(width);
auto h = IntLog2(height);
auto p = IntLog2(pitch);
return map[w][h][p][levels];
}
static void init_maps()
@ -821,6 +925,8 @@ static void init_maps()
init_map(g_info_map_8_1_0, infos_8_1_0_pow2, std::size(infos_8_1_0_pow2));
init_map(g_info_map_8_10_0, infos_8_10_0_pow2, std::size(infos_8_10_0_pow2));
init_map(g_info_map_8_10_9, infos_8_10_9_pow2, std::size(infos_8_10_9_pow2));
init_map2(g_info_map_0_56, infos_0_56_pow2, std::size(infos_0_56_pow2));
}
#define KYTY_TEXTURE_CHECK(n) \
@ -841,6 +947,24 @@ static void init_maps()
*num = std::size(infos_##n); \
}
#define KYTY_TEXTURE_CHECK2(n) \
if (pow2) \
{ \
if (const auto* i = check_map2(g_info_map_##n, width, height, pitch, levels); i != nullptr) \
{ \
*info = i; \
*num = 1; \
} else \
{ \
*info = nullptr; \
*num = 0; \
} \
} else \
{ \
*info = infos_##n; \
*num = std::size(infos_##n); \
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
static void FindTextureInfo(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t tile, bool neo,
const TextureInfo** info, int* num, bool pow2)
@ -905,6 +1029,23 @@ static void FindTextureInfo(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32
}
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
static void FindTextureInfo2(uint32_t fmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t tile, uint32_t levels,
const TextureInfo2** info, int* num, bool pow2)
{
EXIT_IF(info == nullptr);
EXIT_IF(num == nullptr);
if (tile == 0 && fmt == 56)
{
KYTY_TEXTURE_CHECK2(0_56);
} else
{
*info = nullptr;
*num = 0;
}
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, uint32_t tile,
bool neo, TileSizeAlign* total_size, TileSizeOffset* level_sizes, TilePaddedSize* padded_size)
@ -1004,6 +1145,72 @@ void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t h
}
}
void TileGetTextureSize2(uint32_t format, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, uint32_t tile,
TileSizeAlign* total_size, TileSizeOffset* level_sizes, TilePaddedSize* padded_size)
{
KYTY_PROFILER_FUNCTION();
const TextureInfo2* infos = nullptr;
int num = 0;
bool pow2 = (IsPowerOfTwo(width) && IsPowerOfTwo(height) && IsPowerOfTwo(pitch));
EXIT_IF(levels == 0 || levels > 16);
FindTextureInfo2(format, width, height, pitch, tile, levels, &infos, &num, pow2);
for (int index = 0; index < num; index++)
{
const auto& i = infos[index];
if (i.fmt == format && i.width == width && i.pitch == pitch && i.height == height && i.levels == levels && i.tile == tile)
{
if (total_size != nullptr)
{
total_size->size = i.total_size;
total_size->align = i.total_align;
}
if (level_sizes != nullptr)
{
if (levels == 1)
{
level_sizes[0].size = i.total_size;
level_sizes[0].offset = 0;
} else
{
for (uint32_t l = 0; l < levels; l++)
{
level_sizes[l].size = i.size[l].mipmap_size;
level_sizes[l].offset = i.size[l].mipmap_offset;
}
}
}
if (padded_size != nullptr)
{
for (uint32_t l = 0; l < levels; l++)
{
padded_size[l].width = i.padded[l].width;
padded_size[l].height = i.padded[l].height;
}
}
return;
}
}
if (total_size != nullptr && total_size->size == 0)
{
Core::StringList list;
list.Add(String::FromPrintf("format = %u", format));
list.Add(String::FromPrintf("width = %u", width));
list.Add(String::FromPrintf("height = %u", height));
list.Add(String::FromPrintf("pitch = %u", pitch));
list.Add(String::FromPrintf("levels = %u", levels));
list.Add(String::FromPrintf("tile = %u", tile));
EXIT("unknown format:\n%s\n", list.Concat(U'\n').C_Str());
}
}
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED

View File

@ -236,7 +236,7 @@ static void calc_buffer_size(const VideoOutBufferAttribute* attribute, const Vid
if (attribute2 != nullptr)
{
EXIT_NOT_IMPLEMENTED(attribute2->option != 0);
EXIT_NOT_IMPLEMENTED(attribute2->option != 0 && attribute2->option != 8);
EXIT_NOT_IMPLEMENTED(attribute2->aspect_ratio != 0);
EXIT_NOT_IMPLEMENTED(attribute2->pixel_format != 0x8000000000000000ULL && attribute2->pixel_format != 0x8000000022000000ULL);
} else
@ -1015,7 +1015,7 @@ KYTY_SYSV_ABI int VideoOutRegisterBuffers2(int handle, int set_index, int buffer
EXIT_NOT_IMPLEMENTED(attribute->tiling_mode != 0);
EXIT_NOT_IMPLEMENTED(attribute->aspect_ratio != 0);
EXIT_NOT_IMPLEMENTED(attribute->pitch_in_pixel != 0);
EXIT_NOT_IMPLEMENTED(attribute->option != 0);
EXIT_NOT_IMPLEMENTED(attribute->option != 0 && attribute->option != 8);
EXIT_NOT_IMPLEMENTED(attribute->dcc_cb_register_clear_color != 0);
EXIT_NOT_IMPLEMENTED(attribute->dcc_control != 0);

View File

@ -52,6 +52,9 @@ public:
bool Find(uint64_t vaddr, uint64_t* base_addr, size_t* len, int* prot, VirtualMemory::Mode* mode, Graphics::GpuMemoryMode* gpu_mode);
bool Find(uint64_t phys_addr, bool next, PhysicalMemory::AllocatedBlock* out);
[[nodiscard]] Core::Mutex& GetMutex() { return m_mutex; }
[[nodiscard]] const Vector<AllocatedBlock>& GetBlocks() const { return m_allocated; }
private:
Vector<AllocatedBlock> m_allocated;
Core::Mutex m_mutex;
@ -81,6 +84,9 @@ public:
bool Unmap(uint64_t vaddr, uint64_t size, Graphics::GpuMemoryMode* gpu_mode);
bool Find(uint64_t vaddr, uint64_t* base_addr, size_t* len, int* prot, VirtualMemory::Mode* mode, Graphics::GpuMemoryMode* gpu_mode);
[[nodiscard]] Core::Mutex& GetMutex() { return m_mutex; }
[[nodiscard]] const Vector<AllocatedBlock>& GetBlocks() const { return m_allocated; }
private:
Vector<AllocatedBlock> m_allocated;
uint64_t m_allocated_total = 0;
@ -89,6 +95,8 @@ private:
static PhysicalMemory* g_physical_memory = nullptr;
static FlexibleMemory* g_flexible_memory = nullptr;
static callback_func_t g_alloc_callback = nullptr;
static callback_func_t g_free_callback = nullptr;
KYTY_SUBSYSTEM_INIT(Memory)
{
@ -107,6 +115,29 @@ static uint64_t get_aligned_pos(uint64_t pos, size_t align)
return (align != 0 ? (pos + (align - 1)) & ~(align - 1) : pos);
}
void RegisterCallbacks(callback_func_t alloc_func, callback_func_t free_func)
{
EXIT_IF(g_alloc_callback != nullptr || g_free_callback != nullptr);
EXIT_IF(alloc_func == nullptr || free_func == nullptr);
g_alloc_callback = alloc_func;
g_free_callback = free_func;
g_physical_memory->GetMutex().Lock();
for (const auto& b: g_physical_memory->GetBlocks())
{
g_alloc_callback(b.map_vaddr, b.map_size);
}
g_physical_memory->GetMutex().Unlock();
g_flexible_memory->GetMutex().Lock();
for (const auto& b: g_flexible_memory->GetBlocks())
{
g_alloc_callback(b.map_vaddr, b.map_size);
}
g_flexible_memory->GetMutex().Unlock();
}
bool PhysicalMemory::Alloc(uint64_t search_start, uint64_t search_end, size_t len, size_t alignment, uint64_t* phys_addr_out,
int memory_type)
{
@ -445,6 +476,11 @@ int32_t KYTY_SYSV_ABI KernelMapNamedFlexibleMemory(void** addr_in_out, size_t le
Graphics::GpuMemorySetAllocatedRange(out_addr, len);
}
if (g_alloc_callback != nullptr)
{
g_alloc_callback(out_addr, len);
}
return OK;
}
@ -490,6 +526,11 @@ int KYTY_SYSV_ABI KernelMunmap(uint64_t vaddr, size_t len)
Graphics::GpuMemoryFree(Graphics::WindowGetGraphicContext(), vaddr, len, true);
}
if (g_free_callback != nullptr)
{
g_free_callback(vaddr, len);
}
return OK;
}
@ -639,6 +680,11 @@ int KYTY_SYSV_ABI KernelReleaseDirectMemory(int64_t start, size_t len)
Graphics::GpuMemoryFree(Graphics::WindowGetGraphicContext(), vaddr, size, true);
}
if (g_free_callback != nullptr)
{
g_free_callback(vaddr, len);
}
return OK;
}
@ -722,6 +768,11 @@ int KYTY_SYSV_ABI KernelMapDirectMemory(void** addr, size_t len, int prot, int f
Graphics::GpuMemorySetAllocatedRange(out_addr, len);
}
if (g_alloc_callback != nullptr)
{
g_alloc_callback(out_addr, len);
}
printf(FG_GREEN "\t [Ok]\n" FG_DEFAULT);
return OK;

View File

@ -46,6 +46,15 @@ static void load_symbols(const String& id, Loader::RuntimeLinker* rt)
}
}
static void load_symbols_all(Loader::RuntimeLinker* rt)
{
KYTY_PROFILER_FUNCTION();
EXIT_IF(rt == nullptr);
Libs::InitAll(rt->Symbols());
}
static void print_system_info()
{
Loader::SystemInfo info = Loader::GetSystemInfo();
@ -212,6 +221,22 @@ KYTY_SCRIPT_FUNC(kyty_load_symbols_func)
return 0;
}
KYTY_SCRIPT_FUNC(kyty_load_symbols_all_func)
{
auto count = Scripts::ArgGetVarCount();
if (count != 0)
{
EXIT("invalid args\n");
}
auto* rt = Core::Singleton<Loader::RuntimeLinker>::Instance();
load_symbols_all(rt);
return 0;
}
KYTY_SCRIPT_FUNC(kyty_load_param_sfo_func)
{
auto count = Scripts::ArgGetVarCount();
@ -405,6 +430,7 @@ void kyty_reg()
Scripts::RegisterFunc("kyty_load_elf", LuaFunc::kyty_load_elf_func, LuaFunc::kyty_help);
Scripts::RegisterFunc("kyty_save_main_elf", LuaFunc::kyty_save_main_elf_func, LuaFunc::kyty_help);
Scripts::RegisterFunc("kyty_load_symbols", LuaFunc::kyty_load_symbols_func, LuaFunc::kyty_help);
Scripts::RegisterFunc("kyty_load_symbols_all", LuaFunc::kyty_load_symbols_all_func, LuaFunc::kyty_help);
Scripts::RegisterFunc("kyty_load_param_sfo", LuaFunc::kyty_load_param_sfo_func, LuaFunc::kyty_help);
Scripts::RegisterFunc("kyty_dbg_dump", LuaFunc::kyty_dbg_dump_func, LuaFunc::kyty_help);
Scripts::RegisterFunc("kyty_execute", LuaFunc::kyty_execute_func, LuaFunc::kyty_help);

View File

@ -0,0 +1,251 @@
#include "Kyty/Core/Common.h"
#include "Kyty/Core/DbgAssert.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Threads.h"
#include "Kyty/Core/Vector.h"
#include "Kyty/Sys/SysDbg.h"
#include "Emulator/Common.h"
#include "Emulator/Kernel/Memory.h"
#include "Emulator/Libs/Libs.h"
#include "Emulator/Loader/SymbolDatabase.h"
#include "Emulator/Loader/VirtualMemory.h"
#include <algorithm>
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs {
LIB_VERSION("DbgAddressSanitizer", 1, "DbgAddressSanitizer", 1, 1);
namespace DbgAddressSanitizer {
struct SourceLocation
{
const char* filename;
int line_no;
int column_no;
};
struct Global
{
uintptr_t beg;
uintptr_t size;
uintptr_t size_with_redzone;
const char* name;
const char* module_name;
uintptr_t has_dynamic_init;
SourceLocation* location;
uintptr_t odr_indicator;
};
struct Shadow
{
uintptr_t start = 0;
int count = 0;
};
struct AsanContext
{
Core::Mutex mutex;
Vector<Shadow> shadows;
};
static uint32_t g_fake_stack = 0;
static AsanContext* g_ctx = nullptr;
static void AllocShadow(uintptr_t min_addr, uintptr_t max_addr)
{
EXIT_IF(g_ctx == nullptr);
Core::LockGuard lock(g_ctx->mutex);
static const uintptr_t page_size = 0x10000ull;
auto min_shadow = ((min_addr >> 3u) + 0x10000000000ull) & ~(page_size - 1);
auto max_shadow = ((max_addr >> 3u) + 0x10000000000ull) & ~(page_size - 1);
auto size = max_shadow - min_shadow + page_size;
printf("\t shadow = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(min_shadow));
printf("\t size = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(size));
for (uintptr_t page = min_shadow; page <= max_shadow; page += page_size)
{
if (auto index = g_ctx->shadows.Find(page, [](auto& s, auto p) { return s.start == p; }); g_ctx->shadows.IndexValid(index))
{
g_ctx->shadows[index].count++;
} else
{
if (!Loader::VirtualMemory::AllocFixed(page, page_size, Loader::VirtualMemory::Mode::ReadWrite))
{
EXIT("can't allocate shadow memory\n");
}
Shadow s;
s.start = page;
s.count = 1;
g_ctx->shadows.Add(s);
}
}
}
static void FreeShadow(uintptr_t min_addr, uintptr_t max_addr)
{
EXIT_IF(g_ctx == nullptr);
Core::LockGuard lock(g_ctx->mutex);
static const uintptr_t page_size = 0x10000ull;
auto min_shadow = ((min_addr >> 3u) + 0x10000000000ull) & ~(page_size - 1);
auto max_shadow = ((max_addr >> 3u) + 0x10000000000ull) & ~(page_size - 1);
auto size = max_shadow - min_shadow + page_size;
printf("\t shadow = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(min_shadow));
printf("\t size = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(size));
for (uintptr_t page = min_shadow; page <= max_shadow; page += page_size)
{
if (auto index = g_ctx->shadows.Find(page, [](auto& s, auto p) { return s.start == p; }); g_ctx->shadows.IndexValid(index))
{
g_ctx->shadows[index].count--;
if (g_ctx->shadows[index].count <= 0)
{
if (!Loader::VirtualMemory::Free(page))
{
EXIT("can't free shadow memory\n");
}
g_ctx->shadows.RemoveAt(index);
}
}
}
}
static void KernelAlloc(uintptr_t addr, size_t size)
{
AllocShadow(addr, addr + size - 1);
}
static void KernelFree(uintptr_t addr, size_t size)
{
FreeShadow(addr, addr + size - 1);
}
static void KYTY_SYSV_ABI asan_init()
{
PRINT_NAME();
EXIT_NOT_IMPLEMENTED(g_ctx != nullptr);
g_ctx = new AsanContext;
sys_dbg_stack_info_t s {};
sys_stack_usage(s);
AllocShadow(s.reserved_addr, reinterpret_cast<uintptr_t>(&s));
LibKernel::Memory::RegisterCallbacks(KernelAlloc, KernelFree);
}
static void KYTY_SYSV_ABI asan_version_mismatch_check_v8()
{
PRINT_NAME();
}
static void KYTY_SYSV_ABI asan_register_elf_globals(uintptr_t* flag, Global* start, Global* stop)
{
PRINT_NAME();
printf("\t flag = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(flag));
printf("\t start = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(start));
printf("\t stop = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(stop));
if (flag == nullptr || start == nullptr || stop == nullptr)
{
return;
}
if (*flag != 0)
{
return;
}
auto num = stop - start;
if (num != 0)
{
uintptr_t min_addr = UINTPTR_MAX;
uintptr_t max_addr = 0;
for (ptrdiff_t i = 0; i < num; i++)
{
auto* g = start + i;
printf("asan global:\n");
printf("\t beg = %016" PRIx64 "\n", static_cast<uint64_t>(g->beg));
printf("\t size = %016" PRIx64 "\n", static_cast<uint64_t>(g->size));
printf("\t size_with_redzone = %016" PRIx64 "\n", static_cast<uint64_t>(g->size_with_redzone));
printf("\t name = %s\n", g->name);
printf("\t module_name = %s\n", g->module_name);
printf("\t has_dynamic_init = %" PRIu64 "\n", static_cast<uint64_t>(g->has_dynamic_init));
printf("\t odr_indicator = %016" PRIx64 "\n", static_cast<uint64_t>(g->odr_indicator));
if (g->location != nullptr)
{
printf("\t location = %s:%d\n", g->location->filename, g->location->line_no);
}
min_addr = std::min(g->beg, min_addr);
max_addr = std::max(g->beg + g->size_with_redzone - 1, max_addr);
}
AllocShadow(min_addr, max_addr);
}
*flag = 0;
}
static void KYTY_SYSV_ABI asan_before_dynamic_init(const char* module_name)
{
PRINT_NAME();
printf("\t name = %s\n", module_name);
}
static void KYTY_SYSV_ABI asan_after_dynamic_init()
{
PRINT_NAME();
}
static void* KYTY_SYSV_ABI asan_memcpy(void* dst, const void* src, size_t size)
{
return std::memcpy(dst, src, size);
}
static void* KYTY_SYSV_ABI asan_memset(void* dst, int ch, size_t size)
{
return std::memset(dst, ch, size);
}
} // namespace DbgAddressSanitizer
LIB_DEFINE(InitDbgAddressSanitizer_1)
{
LIB_OBJECT("OmecxEgrhCs", &DbgAddressSanitizer::g_fake_stack);
LIB_FUNC("xLoVJKHvRMU", DbgAddressSanitizer::asan_init);
LIB_FUNC("GY2I-Okc7q0", DbgAddressSanitizer::asan_version_mismatch_check_v8);
LIB_FUNC("W+2HQAGdPuU", DbgAddressSanitizer::asan_register_elf_globals);
LIB_FUNC("G9xSYlaNv+Y", DbgAddressSanitizer::asan_before_dynamic_init);
LIB_FUNC("z5Gy5T3tptE", DbgAddressSanitizer::asan_after_dynamic_init);
LIB_FUNC("g+Neom2EHO8", DbgAddressSanitizer::asan_memcpy);
LIB_FUNC("q-hZf47nHhQ", DbgAddressSanitizer::asan_memset);
}
} // namespace Kyty::Libs
#endif // KYTY_EMU_ENABLED

View File

@ -85,6 +85,7 @@ LIB_DEFINE(InitGraphicsDriver_1)
LIB_FUNC("wr23dPKyWc0", Gen5::GraphicsCbReleaseMem);
LIB_FUNC("TRO721eVt4g", Gen5::GraphicsDcbResetQueue);
LIB_FUNC("MWiElSNE8j8", Gen5::GraphicsDcbWaitUntilSafeForRendering);
LIB_FUNC("pFLArOT53+w", Gen5::GraphicsDcbSetShRegisterDirect);
LIB_FUNC("ZvwO9euwYzc", Gen5::GraphicsDcbSetCxRegistersIndirect);
LIB_FUNC("-HOOCn0JY48", Gen5::GraphicsDcbSetShRegistersIndirect);
LIB_FUNC("hvUfkUIQcOE", Gen5::GraphicsDcbSetUcRegistersIndirect);

View File

@ -243,11 +243,16 @@ static void KYTY_SYSV_ABI KernelRtldSetApplicationHeapAPI(void* api[])
[[maybe_unused]] auto* heap_posix_memalign = api[6];
}
static int KYTY_SYSV_ABI write(int d, const char* str, int64_t size)
static int64_t KYTY_SYSV_ABI write(int d, const char* str, int64_t size)
{
// PRINT_NAME();
EXIT_NOT_IMPLEMENTED(d < 0 || d > 2);
EXIT_NOT_IMPLEMENTED(d < 0);
if (d > 2)
{
return POSIX_N_CALL(FileSystem::KernelWrite(d, str, size));
}
int size_int = static_cast<int>(size);
@ -256,6 +261,18 @@ static int KYTY_SYSV_ABI write(int d, const char* str, int64_t size)
return size_int;
}
static int KYTY_SYSV_ABI open(const char* path, int flags, int mode)
{
return POSIX_N_CALL(FileSystem::KernelOpen(path, flags, mode));
}
static int KYTY_SYSV_ABI close(int d)
{
EXIT_NOT_IMPLEMENTED(d <= 2);
return POSIX_CALL(FileSystem::KernelClose(d));
}
static int64_t KYTY_SYSV_ABI read(int d, void* buf, uint64_t nbytes)
{
// PRINT_NAME();
@ -623,6 +640,7 @@ LIB_DEFINE(InitLibKernel_1)
LIB_OBJECT("djxxOmW6-aw", &LibKernel::g_progname);
LIB_FUNC("1jfXLRVzisc", LibKernel::KernelUsleep);
LIB_FUNC("6c3rCVE-fTU", LibKernel::open);
LIB_FUNC("6xVpy0Fdq+I", LibKernel::sigprocmask);
LIB_FUNC("6Z83sYWFlA8", LibKernel::exit);
LIB_FUNC("8OnWXlgQlvo", LibKernel::KernelRtldThreadAtexitDecrement);
@ -636,6 +654,7 @@ LIB_DEFINE(InitLibKernel_1)
LIB_FUNC("FxVZqBAA7ks", LibKernel::write);
LIB_FUNC("kbw4UHHSYy0", LibKernel::pthread_cxa_finalize);
LIB_FUNC("lLMT9vJAck0", LibKernel::clock_gettime);
LIB_FUNC("NNtFaKJbPt0", LibKernel::close);
LIB_FUNC("OMDRKKAZ8I4", LibKernel::KernelDebugRaiseException);
LIB_FUNC("Ou3iL1abvng", LibKernel::stack_chk_fail);
LIB_FUNC("p5EcQeEeJAE", LibKernel::KernelRtldSetApplicationHeapAPI);

View File

@ -10,6 +10,7 @@ LIB_DEFINE(InitLibcInternal_1);
LIB_DEFINE(InitAppContent_1);
LIB_DEFINE(InitAudio_1);
LIB_DEFINE(InitDbgAddressSanitizer_1);
LIB_DEFINE(InitDebug_1);
LIB_DEFINE(InitDialog_1);
LIB_DEFINE(InitDiscMap_1);
@ -26,9 +27,10 @@ LIB_DEFINE(InitVideoOut_1);
bool Init(const String& id, Loader::SymbolDatabase* s)
{
LIB_CHECK(U"libAudio_1", InitAudio_1);
LIB_CHECK(U"libAppContent_1", InitAppContent_1);
LIB_CHECK(U"libAudio_1", InitAudio_1);
LIB_CHECK(U"libc_internal_1", LibcInternal::InitLibcInternal_1);
LIB_CHECK(U"libDbgAddressSanitizer_1", InitDbgAddressSanitizer_1);
LIB_CHECK(U"libDebug_1", InitDebug_1);
LIB_CHECK(U"libDialog_1", InitDialog_1);
LIB_CHECK(U"libDiscMap_1", InitDiscMap_1);
@ -46,6 +48,27 @@ bool Init(const String& id, Loader::SymbolDatabase* s)
return false;
}
void InitAll(Loader::SymbolDatabase* s)
{
LIB_LOAD(InitAudio_1);
LIB_LOAD(InitAppContent_1);
LIB_LOAD(LibcInternal::InitLibcInternal_1);
LIB_LOAD(InitDbgAddressSanitizer_1);
LIB_LOAD(InitDebug_1);
LIB_LOAD(InitDialog_1);
LIB_LOAD(InitDiscMap_1);
LIB_LOAD(InitGraphicsDriver_1);
LIB_LOAD(InitLibKernel_1);
LIB_LOAD(InitNet_1);
LIB_LOAD(InitPad_1);
LIB_LOAD(InitPlayGo_1);
LIB_LOAD(InitSaveData_1);
LIB_LOAD(InitSysmodule_1);
LIB_LOAD(InitSystemService_1);
LIB_LOAD(InitUserService_1);
LIB_LOAD(InitVideoOut_1);
}
} // namespace Kyty::Libs
#endif // KYTY_EMU_ENABLED

View File

@ -9,6 +9,7 @@
#include "Kyty/Core/Threads.h"
#include "Kyty/Sys/SysDbg.h"
#include "Emulator/Config.h"
#include "Emulator/Graphics/Objects/GpuMemory.h"
#include "Emulator/Kernel/Pthread.h"
#include "Emulator/Loader/Elf.h"
@ -211,13 +212,16 @@ static void kyty_exception_handler(const VirtualMemory::ExceptionHandler::Except
return;
}
Core::Singleton<Loader::RuntimeLinker>::Instance()->StackTrace(info->rbp);
if (info->rbp != 0)
{
Core::Singleton<Loader::RuntimeLinker>::Instance()->StackTrace(info->rbp);
}
EXIT("Access violation: %s [%016" PRIx64 "] %s\n", Core::EnumName(info->access_violation_type).C_Str(),
info->access_violation_vaddr, (info->access_violation_vaddr == g_invalid_memory ? "(Unpatched object)" : ""));
}
EXIT("Unknown exception!!!");
EXIT("Unknown exception!!! (%08" PRIx32 ")", info->exception_win_code);
}
static void encode_id_64(uint16_t in_id, String* out_id)
@ -1105,6 +1109,7 @@ static uint64_t calc_base_size(const Elf64_Ehdr* ehdr, const Elf64_Phdr* phdr)
return base_size;
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void RuntimeLinker::LoadProgramToMemory(Program* program)
{
KYTY_PROFILER_FUNCTION();
@ -1122,6 +1127,11 @@ void RuntimeLinker::LoadProgramToMemory(Program* program)
EXIT_IF(phdr == nullptr || ehdr == nullptr);
if (is_next_gen && !is_shared)
{
Config::SetNextGen(true);
}
program->base_size = calc_base_size(ehdr, phdr);
program->base_size_aligned = (program->base_size & ~(static_cast<uint64_t>(0x1000) - 1)) + 0x1000;
@ -1163,7 +1173,7 @@ void RuntimeLinker::LoadProgramToMemory(Program* program)
SYSTEM_RESERVED,
kyty_exception_handler);
if (Libs::Graphics::GpuMemoryWatcherEnabled())
// if (Libs::Graphics::GpuMemoryWatcherEnabled())
{
VirtualMemory::ExceptionHandler::InstallVectored(kyty_exception_handler);
}

View File

@ -115,7 +115,8 @@ public:
info.access_violation_vaddr = exception_record->ExceptionInformation[1];
}
info.rbp = dispatcher_context->ContextRecord->Rbp;
info.rbp = dispatcher_context->ContextRecord->Rbp;
info.exception_win_code = exception_record->ExceptionCode;
auto* p = *static_cast<ExceptionHandlerPrivate**>(dispatcher_context->HandlerData);
p->func(&info);
@ -205,6 +206,19 @@ static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception)
info.exception_address = reinterpret_cast<uint64_t>(exception_record->ExceptionAddress);
// printf("exception_record->ExceptionCode = %u\n", static_cast<uint32_t>(exception_record->ExceptionCode));
if (exception_record->ExceptionCode == DBG_PRINTEXCEPTION_C || exception_record->ExceptionCode == DBG_PRINTEXCEPTION_WIDE_C)
{
return EXCEPTION_CONTINUE_EXECUTION;
}
if (exception_record->ExceptionCode == 0x406D1388)
{
// Set a thread name
return EXCEPTION_CONTINUE_EXECUTION;
}
if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
info.type = ExceptionHandler::ExceptionType::AccessViolation;
@ -218,6 +232,9 @@ static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception)
info.access_violation_vaddr = exception_record->ExceptionInformation[1];
}
info.rbp = exception->ContextRecord->Rbp;
info.exception_win_code = exception_record->ExceptionCode;
ExceptionHandlerPrivate::g_vec_func(&info);
return EXCEPTION_CONTINUE_EXECUTION;

View File

@ -3,6 +3,7 @@
#include "Kyty/Core/Common.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/String8.h"
#include "magic_enum.hpp" // IWYU pragma: export
@ -15,6 +16,13 @@ inline String EnumName(E v)
return String::FromUtf8(str.data(), static_cast<uint32_t>(str.length()));
}
template <typename E>
inline String8 EnumName8(E v)
{
auto str = magic_enum::enum_name(v);
return String8(str.data(), static_cast<uint32_t>(str.length()));
}
template <typename E>
inline E EnumValue(const String& str, E default_value)
{
@ -26,6 +34,17 @@ inline E EnumValue(const String& str, E default_value)
return default_value;
}
template <typename E>
inline E EnumValue(const String8& str, E default_value)
{
auto v = magic_enum::enum_cast<E>(str.c_str());
if (v.has_value())
{
return v.value();
}
return default_value;
}
#define KYTY_ENUM_RANGE(e, mx, mn) \
namespace magic_enum::customize { \
template <> \

View File

@ -0,0 +1,182 @@
#ifndef CORE_KYTYSTRING8_H_
#define CORE_KYTYSTRING8_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/DbgAssert.h"
#include "Kyty/Core/SimpleArray.h" // IWYU pragma: export
#include "Kyty/Core/Vector.h"
#include <cstdarg> // IWYU pragma: export
namespace Kyty::Core {
constexpr uint32_t STRING8_INVALID_INDEX = static_cast<uint32_t>(-1);
class StringList8;
class String8
{
public:
using DataType = SimpleArray<char>;
enum class SplitType
{
WithEmptyParts,
SplitNoEmptyParts
};
String8();
String8(const String8& src);
String8(String8&& src) noexcept;
String8(char ch, uint32_t repeat = 1); // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
String8(const char* str); // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
explicit String8(const char* array, uint32_t size);
virtual ~String8();
[[nodiscard]] uint32_t Size() const;
[[nodiscard]] bool IsEmpty() const;
[[nodiscard]] bool IsInvalid() const;
void Clear();
char& operator[](uint32_t index);
const char& operator[](uint32_t index) const;
[[nodiscard]] const char& At(uint32_t index) const;
char* GetData();
[[nodiscard]] const char* GetData() const;
[[nodiscard]] const char* GetDataConst() const;
String8& operator=(const String8& src);
String8& operator=(String8&& src) noexcept;
String8& operator=(char ch);
String8& operator=(const char* utf8_str);
String8& operator+=(const String8& src);
String8& operator+=(char ch);
String8& operator+=(const char* utf8_str);
friend String8 operator+(const String8& str1, const String8& str2);
friend String8 operator+(const char* utf8_str1, const String8& str2);
friend String8 operator+(const String8& str1, const char* utf8_str2);
friend String8 operator+(char ch, const String8& str2);
friend String8 operator+(const String8& str1, char ch);
[[nodiscard]] bool Equal(const String8& src) const;
[[nodiscard]] bool Equal(char ch) const;
bool Equal(const char* utf8_str) const;
friend bool operator==(const String8& str1, const String8& str2) { return str2.Equal(str1); }
friend bool operator==(const char* utf8_str1, const String8& str2) { return str2.Equal(utf8_str1); }
friend bool operator==(const String8& str1, const char* utf8_str2) { return str1.Equal(utf8_str2); }
friend bool operator==(char ch, const String8& str2) { return str2.Equal(ch); }
friend bool operator==(const String8& str1, char ch) { return str1.Equal(ch); }
friend bool operator!=(const String8& str1, const String8& str2) { return !str2.Equal(str1); }
friend bool operator!=(const char* utf8_str1, const String8& str2) { return !str2.Equal(utf8_str1); }
friend bool operator!=(const String8& str1, const char* utf8_str2) { return !str1.Equal(utf8_str2); }
friend bool operator!=(char ch, const String8& str2) { return !str2.Equal(ch); }
friend bool operator!=(const String8& str1, char ch) { return !str1.Equal(ch); }
[[nodiscard]] String8 Mid(uint32_t first, uint32_t count) const;
[[nodiscard]] String8 Mid(uint32_t first) const;
[[nodiscard]] String8 Left(uint32_t count) const;
[[nodiscard]] String8 Right(uint32_t count) const;
[[nodiscard]] String8 TrimRight() const;
[[nodiscard]] String8 TrimLeft() const;
[[nodiscard]] String8 Trim() const;
[[nodiscard]] String8 Simplify() const;
[[nodiscard]] String8 ReplaceChar(char old_char, char new_char) const;
[[nodiscard]] String8 ReplaceStr(const String8& old_str, const String8& new_str) const;
[[nodiscard]] String8 RemoveAt(uint32_t index, uint32_t count = 1) const;
[[nodiscard]] String8 RemoveChar(char ch) const;
[[nodiscard]] String8 RemoveStr(const String8& str) const;
[[nodiscard]] String8 RemoveLast(uint32_t num) const;
[[nodiscard]] String8 RemoveFirst(uint32_t num) const;
[[nodiscard]] String8 InsertAt(uint32_t index, const String8& str) const;
[[nodiscard]] String8 SafeLua() const;
[[nodiscard]] String8 SafeCsv() const;
[[nodiscard]] uint32_t FindIndex(const String8& str, uint32_t from = 0) const;
[[nodiscard]] uint32_t FindLastIndex(const String8& str, uint32_t from = STRING8_INVALID_INDEX) const;
[[nodiscard]] uint32_t FindIndex(char chr, uint32_t from = 0) const;
[[nodiscard]] bool IndexValid(uint32_t index) const;
[[nodiscard]] uint32_t FindLastIndex(char chr, uint32_t from = STRING8_INVALID_INDEX) const;
[[nodiscard]] bool ContainsStr(const String8& str) const;
[[nodiscard]] bool ContainsAnyStr(const StringList8& list) const;
[[nodiscard]] bool ContainsAllStr(const StringList8& list) const;
[[nodiscard]] bool ContainsChar(char chr) const;
[[nodiscard]] bool ContainsAnyChar(const String8& list) const;
[[nodiscard]] bool ContainsAllChar(const String8& list) const;
[[nodiscard]] bool EndsWith(const String8& str) const;
[[nodiscard]] bool StartsWith(const String8& str) const;
[[nodiscard]] bool EndsWith(char chr) const;
[[nodiscard]] bool StartsWith(char chr) const;
[[nodiscard]] String8 DirectoryWithoutFilename() const;
[[nodiscard]] String8 FilenameWithoutDirectory() const;
[[nodiscard]] String8 FilenameWithoutExtension() const;
[[nodiscard]] String8 ExtensionWithoutFilename() const;
[[nodiscard]] String8 FixFilenameSlash() const;
[[nodiscard]] String8 FixDirectorySlash() const;
bool Printf(const char* format, va_list args);
bool Printf(const char* format, ...) KYTY_FORMAT_PRINTF(2, 3);
static String8 FromPrintf(const char* format, ...) KYTY_FORMAT_PRINTF(1, 2);
[[nodiscard]] StringList8 Split(const String8& sep, SplitType type = SplitType::SplitNoEmptyParts) const;
[[nodiscard]] StringList8 Split(char sep, SplitType type = SplitType::SplitNoEmptyParts) const;
[[nodiscard]] uint32_t ToUint32(int base = 10) const;
[[nodiscard]] uint64_t ToUint64(int base = 10) const;
[[nodiscard]] int32_t ToInt32(int base = 10) const;
[[nodiscard]] int64_t ToInt64(int base = 10) const;
[[nodiscard]] double ToDouble() const;
[[nodiscard]] float ToFloat() const;
[[nodiscard]] uint32_t Hash() const;
[[nodiscard]] const char* c_str() const // NOLINT(readability-identifier-naming)
{
EXIT_IF(m_data == nullptr);
return m_data->GetDataConst();
}
[[nodiscard]] String8 SortChars() const;
using iterator = char*;
using const_iterator = const char*;
iterator begin() { return GetData(); } // NOLINT(readability-identifier-naming)
iterator end() { return GetData() + Size(); } // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator begin() const { return GetDataConst(); } // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator end() const { return GetDataConst() + Size(); } // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator cbegin() const { return GetDataConst(); } // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator cend() const { return GetDataConst() + Size(); } // NOLINT(readability-identifier-naming)
private:
DataType* m_data;
};
class StringList8: public Vector<String8>
{
public:
using Vector<String8>::Vector;
[[nodiscard]] bool Contains(const String8& str) const;
[[nodiscard]] String8 Concat(const String8& str) const;
[[nodiscard]] String8 Concat(char chr) const;
[[nodiscard]] bool Equal(const StringList8& str) const;
bool operator==(const StringList8& str) const { return this->Equal(str); }
bool operator!=(const StringList8& str) const { return !(*this == str); }
};
} // namespace Kyty::Core
namespace Kyty {
using String8 = Core::String8;
} // namespace Kyty
#endif /* CORE_KYTYSTRING8_H_ */

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>837</width>
<height>822</height>
<height>818</height>
</rect>
</property>
<property name="windowTitle">
@ -492,41 +492,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_3">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QListWidget" name="listWidget_libs">
<property name="toolTip">
<string>Select libraries to load</string>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Load library:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>

View File

@ -17,12 +17,12 @@
#define KYTY_CFG_GET(n) n = s->value(#n).value<decltype(n)>();
#define KYTY_CFG_GETL(n) n = s->value(#n).toStringList();
#define KYTY_LIBS \
{ \
"libc_internal_1", "libkernel_1", "libVideoOut_1", "libSysmodule_1", "libDiscMap_1", "libDebug_1", "libGraphicsDriver_1", \
"libUserService_1", "libSystemService_1", "libPad_1", "libNet_1", "libDialog_1", "libAudio_1", "libPlayGo_1", "libSaveData_1", \
"libAppContent_1" \
}
//#define KYTY_LIBS \
// { \
// "libc_internal_1", "libkernel_1", "libVideoOut_1", "libSysmodule_1", "libDiscMap_1", "libDebug_1", "libGraphicsDriver_1", \
// "libUserService_1", "libSystemService_1", "libPad_1", "libNet_1", "libDialog_1", "libAudio_1", "libPlayGo_1", "libSaveData_1", \
// "libAppContent_1" \
// }
template <class T>
inline QStringList EnumToList()
@ -122,8 +122,8 @@ public:
QStringList elfs;
QStringList elfs_selected;
QStringList libs = KYTY_LIBS;
QStringList libs_selected = KYTY_LIBS;
// QStringList libs = KYTY_LIBS;
// QStringList libs_selected = KYTY_LIBS;
void WriteSettings(QSettings* s) const
{
@ -145,8 +145,8 @@ public:
KYTY_CFG_SET(profiler_output_file);
KYTY_CFG_SETL(elfs);
KYTY_CFG_SETL(elfs_selected);
KYTY_CFG_SETL(libs);
KYTY_CFG_SETL(libs_selected);
// KYTY_CFG_SETL(libs);
// KYTY_CFG_SETL(libs_selected);
}
void ReadSettings(QSettings* s)
@ -169,8 +169,8 @@ public:
KYTY_CFG_GET(profiler_output_file);
KYTY_CFG_GETL(elfs);
KYTY_CFG_GETL(elfs_selected);
KYTY_CFG_GETL(libs);
KYTY_CFG_GETL(libs_selected);
// KYTY_CFG_GETL(libs);
// KYTY_CFG_GETL(libs_selected);
}
};

View File

@ -55,7 +55,7 @@ protected:
void browse_base_path();
void browse_param_file();
void scan_elfs();
void scan_libs();
// void scan_libs();
void load_param_sfo();
void clear();
void test();

View File

@ -80,7 +80,7 @@ ConfigurationEditDialog::ConfigurationEditDialog(Kyty::Configuration* info, Conf
connect(m_ui->base_directory_lineedit, &QLineEdit::textChanged, this, &ConfigurationEditDialog::scan_elfs);
connect(m_ui->param_file_lineedit, &QLineEdit::textChanged, this, &ConfigurationEditDialog::load_param_sfo);
connect(m_ui->listWidget_elfs, &QListWidget::itemChanged, this, &ChangeColor);
connect(m_ui->listWidget_libs, &QListWidget::itemChanged, this, &ChangeColor);
// connect(m_ui->listWidget_libs, &QListWidget::itemChanged, this, &ChangeColor);
connect(&m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
[=](int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) { m_ui->test_button->setEnabled(true); });
@ -96,7 +96,7 @@ ConfigurationEditDialog::ConfigurationEditDialog(Kyty::Configuration* info, Conf
Init();
scan_libs();
// scan_libs();
scan_elfs();
load_param_sfo();
}
@ -231,7 +231,7 @@ static void UpdateInfo(Kyty::Configuration* info, Ui::ConfigurationEditDialog* u
}
UpdateList(&info->elfs, &info->elfs_selected, ui->listWidget_elfs);
UpdateList(&info->libs, &info->libs_selected, ui->listWidget_libs);
// UpdateList(&info->libs, &info->libs_selected, ui->listWidget_libs);
}
void ConfigurationEditDialog::update_info()
@ -344,46 +344,46 @@ void ConfigurationEditDialog::scan_elfs()
m_ui->test_button->setEnabled(m_process.state() == QProcess::NotRunning && dir_exists);
}
void ConfigurationEditDialog::scan_libs()
{
QStringList libs = KYTY_LIBS;
m_ui->listWidget_libs->clear();
// int selected_num = 0;
for (const auto& lib: m_info->libs)
{
bool not_enabled = !libs.contains(lib);
bool selected = m_info->libs_selected.contains(lib);
auto* item = new QListWidgetItem(lib, m_ui->listWidget_libs);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
if (not_enabled)
{
item->setCheckState(Qt::Unchecked);
item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
} else
{
item->setCheckState(selected ? Qt::Checked : Qt::Unchecked);
}
// selected_num += (selected ? 1 : 0);
}
for (const auto& lib: libs)
{
if (!m_info->libs.contains(lib))
{
auto* item = new QListWidgetItem(lib, m_ui->listWidget_libs);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(Qt::Unchecked);
}
}
m_ui->listWidget_libs->sortItems();
}
// void ConfigurationEditDialog::scan_libs()
//{
// QStringList libs = KYTY_LIBS;
//
// m_ui->listWidget_libs->clear();
//
// // int selected_num = 0;
//
// for (const auto& lib: m_info->libs)
// {
// bool not_enabled = !libs.contains(lib);
// bool selected = m_info->libs_selected.contains(lib);
//
// auto* item = new QListWidgetItem(lib, m_ui->listWidget_libs);
// item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
//
// if (not_enabled)
// {
// item->setCheckState(Qt::Unchecked);
// item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
// } else
// {
// item->setCheckState(selected ? Qt::Checked : Qt::Unchecked);
// }
//
// // selected_num += (selected ? 1 : 0);
// }
//
// for (const auto& lib: libs)
// {
// if (!m_info->libs.contains(lib))
// {
// auto* item = new QListWidgetItem(lib, m_ui->listWidget_libs);
// item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
// item->setCheckState(Qt::Unchecked);
// }
// }
//
// m_ui->listWidget_libs->sortItems();
// }
void ConfigurationEditDialog::load_param_sfo()
{
@ -452,7 +452,7 @@ void ConfigurationEditDialog::clear()
m_info = old_info;
scan_elfs();
scan_libs();
// scan_libs();
load_param_sfo();
}

View File

@ -35,13 +35,14 @@
class QWidget;
constexpr char SCRIPT_EXE[] = "fc_script.exe";
constexpr char CMD_EXE[] = "cmd.exe";
constexpr char CONEMU_EXE[] = "C:/Program Files/ConEmu/ConEmu64.exe";
constexpr char KYTY_MOUNT[] = "kyty_mount";
constexpr char KYTY_EXECUTE[] = "kyty_execute";
constexpr char KYTY_LOAD_ELF[] = "kyty_load_elf";
constexpr char KYTY_LOAD_SYMBOLS[] = "kyty_load_symbols";
constexpr char SCRIPT_EXE[] = "fc_script.exe";
constexpr char CMD_EXE[] = "cmd.exe";
constexpr char CONEMU_EXE[] = "C:/Program Files/ConEmu/ConEmu64.exe";
constexpr char KYTY_MOUNT[] = "kyty_mount";
constexpr char KYTY_EXECUTE[] = "kyty_execute";
constexpr char KYTY_LOAD_ELF[] = "kyty_load_elf";
// constexpr char KYTY_LOAD_SYMBOLS[] = "kyty_load_symbols";
constexpr char KYTY_LOAD_SYMBOLS_ALL[] = "kyty_load_symbols_all";
constexpr char KYTY_LOAD_PARAM_SFO[] = "kyty_load_param_sfo";
constexpr char KYTY_INIT[] = "kyty_init";
constexpr char KYTY_LUA_FILE[] = "kyty_run.lua";
@ -183,7 +184,7 @@ void MainDialogPrivate::FindInterpreter()
found = found && lines.contains(QString("Lua function: ") + KYTY_MOUNT);
found = found && lines.contains(QString("Lua function: ") + KYTY_EXECUTE);
found = found && lines.contains(QString("Lua function: ") + KYTY_LOAD_ELF);
found = found && lines.contains(QString("Lua function: ") + KYTY_LOAD_SYMBOLS);
found = found && lines.contains(QString("Lua function: ") + KYTY_LOAD_SYMBOLS_ALL);
found = found && lines.contains(QString("Lua function: ") + KYTY_LOAD_PARAM_SFO);
found = found && lines.contains(QString("Lua function: ") + KYTY_INIT);
}
@ -249,10 +250,12 @@ static bool CreateLuaScript(Kyty::Configuration* info, const QString& file_name)
s << KYTY_LOAD_ELF << "('/app0/" << elf << "');\n";
}
for (const auto& lib: info->libs_selected)
{
s << KYTY_LOAD_SYMBOLS << "('" << lib << "');\n";
}
// for (const auto& lib: info->libs_selected)
// {
// s << KYTY_LOAD_SYMBOLS << "('" << lib << "');\n";
// }
s << KYTY_LOAD_SYMBOLS_ALL << "();\n";
s << KYTY_EXECUTE << "();\n";

View File

@ -185,32 +185,22 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../forms/configuration_edit_dialog.ui" line="513"/>
<source>Select libraries to load</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../forms/configuration_edit_dialog.ui" line="523"/>
<source>Load library:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../forms/configuration_edit_dialog.ui" line="550"/>
<location filename="../forms/configuration_edit_dialog.ui" line="515"/>
<source>Save</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../forms/configuration_edit_dialog.ui" line="566"/>
<location filename="../forms/configuration_edit_dialog.ui" line="531"/>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../forms/configuration_edit_dialog.ui" line="586"/>
<location filename="../forms/configuration_edit_dialog.ui" line="551"/>
<source>Clear</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../forms/configuration_edit_dialog.ui" line="602"/>
<location filename="../forms/configuration_edit_dialog.ui" line="567"/>
<source>Test</source>
<translation type="unfinished"></translation>
</message>
@ -338,12 +328,12 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/MainDialog.cpp" line="276"/>
<location filename="../src/MainDialog.cpp" line="279"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/MainDialog.cpp" line="276"/>
<location filename="../src/MainDialog.cpp" line="279"/>
<source>Can&apos;t create file:
</source>
<translation type="unfinished"></translation>
@ -352,27 +342,27 @@
<context>
<name>MainDialogPrivate</name>
<message>
<location filename="../src/MainDialog.cpp" line="139"/>
<location filename="../src/MainDialog.cpp" line="140"/>
<source>Settings file: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/MainDialog.cpp" line="165"/>
<location filename="../src/MainDialog.cpp" line="166"/>
<source>Emulator: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/MainDialog.cpp" line="177"/>
<location filename="../src/MainDialog.cpp" line="178"/>
<source>Version: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/MainDialog.cpp" line="193"/>
<location filename="../src/MainDialog.cpp" line="194"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/MainDialog.cpp" line="193"/>
<location filename="../src/MainDialog.cpp" line="194"/>
<source>Can&apos;t find emulator</source>
<translation type="unfinished"></translation>
</message>

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,9 @@
namespace Kyty::UnitTest {
UT_LINK(CoreCharString);
UT_LINK(CoreCharString8);
UT_LINK(CoreMSpace);
UT_LINK(CoreDateTime);
KYTY_SUBSYSTEM_INIT(UnitTest)
{

View File

@ -0,0 +1,739 @@
#include "Kyty/Core/String8.h"
#include "Kyty/Core/Vector.h"
#include "Kyty/UnitTest.h"
UT_BEGIN(CoreCharString8);
using Core::StringList8;
void test()
{
String8 e;
String8 s = String8("abcdABCDАБВГДабвгд");
EXPECT_EQ(s.Size(), 28U);
EXPECT_TRUE(!s.IsEmpty());
EXPECT_EQ(e.Size(), 0U);
EXPECT_TRUE(e.IsEmpty());
e = s;
s.Clear();
EXPECT_EQ(s.Size(), 0U);
EXPECT_TRUE(s.IsEmpty());
EXPECT_EQ(e.Size(), 28U);
EXPECT_TRUE(!e.IsEmpty());
EXPECT_EQ(e[1], 'b');
EXPECT_EQ(e[9], '\x90');
s = String8("acdABCАВГДабвгд");
s = String8("abcdABCDАБВГДабвгд");
EXPECT_EQ(s[3], 'd');
EXPECT_EQ(s[11], '\x91');
s = '0';
EXPECT_EQ(s.Size(), 1U);
String8 ss = String8("abcd");
ss += String8("efgh");
EXPECT_EQ(strcmp(ss.c_str(), "abcdefgh"), 0);
String8 sum1 = String8("ab1") + String8("cd2");
String8 sum2 = sum1 + "cd2" + "апр";
EXPECT_TRUE(sum2 == "ab1cd2cd2апр");
EXPECT_TRUE(sum2 != "ab1cd2cd2апР");
String8 mt = String8("0123456789");
EXPECT_TRUE(String8("").IsEmpty());
EXPECT_EQ(mt.Mid(0, 4), "0123");
EXPECT_EQ(mt.Mid(6, 4), "6789");
EXPECT_EQ(mt.Mid(6, 5), "6789");
EXPECT_EQ(mt.Mid(10, 1), "");
EXPECT_EQ(mt.Mid(0, 0), "");
EXPECT_EQ(mt.Left(2), "01");
EXPECT_EQ(mt.Left(0), "");
EXPECT_EQ(mt.Left(12), "0123456789");
EXPECT_EQ(mt.Right(2), "89");
EXPECT_EQ(mt.Right(0), "");
EXPECT_EQ(mt.Right(12), "0123456789");
}
void test_3()
{
String8 tt = String8(" 123 abc\r\n");
String8 tt2 = String8(" \t \r\n ");
String8 tt3 = String8("no_space");
EXPECT_EQ(tt.TrimLeft(), "123 abc\r\n");
EXPECT_EQ(tt.TrimRight(), " 123 abc");
EXPECT_EQ(tt.Trim(), "123 abc");
EXPECT_EQ(tt.Simplify(), "123 abc");
EXPECT_EQ(tt2.TrimLeft(), "");
EXPECT_EQ(tt2.TrimRight(), "");
EXPECT_EQ(tt2.Trim(), "");
EXPECT_EQ(tt2.Simplify(), "");
EXPECT_EQ(tt3.TrimLeft(), tt3);
EXPECT_EQ(tt3.TrimRight(), tt3);
EXPECT_EQ(tt3.Trim(), tt3);
EXPECT_EQ(tt3.Simplify(), tt3);
EXPECT_EQ(String8("й ц у к е н").ReplaceChar(' ', '_'), "й_ц_у_к_е");
EXPECT_EQ(String8("й ц у к е н").RemoveChar(' '), "йцукен");
// EXPECT_EQ(String8("й ц у к е н").RemoveAt(1).RemoveAt(2).RemoveAt(3), "йцук е н");
EXPECT_EQ(String8("йцукен").RemoveAt(0, 0), "йцукен");
// EXPECT_EQ(String8("йцукен").RemoveAt(10, 1), "йцукен");
// EXPECT_EQ(String8("йцукен").RemoveAt(0, 10), "");
// EXPECT_EQ(String8("йцукен").RemoveAt(1, 10), "й");
// EXPECT_EQ(String8("йцукен").RemoveAt(1, 2), "йкен");
EXPECT_EQ(String8("\nй\nц\n\nу к е н\n").ReplaceStr("\n", "\r\n"), "\r\nй\r\nц\r\n\r\nу к е н\r\n");
EXPECT_EQ(String8("\nй\nц\n\nу к е н\n").RemoveStr("\n"), "йцу к е н");
EXPECT_EQ(String8("abcabcabc").RemoveStr("bc"), "aaa");
String8 it = String8("abcЙЦУ123");
EXPECT_EQ(it.InsertAt(0, 'q'), "qabcЙЦУ123");
EXPECT_EQ(it.InsertAt(3, "_d_"), "abc_d_ЙЦУ123");
// EXPECT_EQ(it.InsertAt(10, "000"), "abcЙЦУ123000");
String8 ft = String8("ab ab ab");
EXPECT_EQ(ft.FindIndex("ab", 0), 0U);
EXPECT_EQ(ft.FindIndex("ab", 1), 3U);
EXPECT_EQ(ft.FindIndex("AB", 0), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex("ab", 7), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex("ab", 15), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex("abc", 0), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex("", 5), 5U);
EXPECT_EQ(ft.FindLastIndex("ab"), 6U);
EXPECT_EQ(ft.FindLastIndex("ab", 6), 6U);
EXPECT_EQ(ft.FindLastIndex("ab", 5), 3U);
EXPECT_EQ(ft.FindLastIndex("AB"), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindLastIndex(""), 7U);
EXPECT_EQ(ft.FindIndex('a', 0), 0U);
EXPECT_EQ(ft.FindIndex('a', 1), 3U);
EXPECT_EQ(ft.FindIndex('A', 0), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex('a', 7), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex('a', 15), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex('c', 0), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindLastIndex('a'), 6U);
EXPECT_EQ(ft.FindLastIndex('a', 6), 6U);
EXPECT_EQ(ft.FindLastIndex('a', 5), 3U);
EXPECT_EQ(ft.FindLastIndex('A'), Core::STRING8_INVALID_INDEX);
String8 ft2 = String8("ab AB ab");
}
void test_2()
{
String8 pf;
EXPECT_TRUE(pf.Printf("s%s_d%d\n", "abcdАБВГ", 4));
EXPECT_EQ(pf, "sabcdАБВГ_d4\n");
EXPECT_TRUE(String8("abcdabcd").StartsWith("abc"));
EXPECT_TRUE(String8("abcdabcd").StartsWith(""));
EXPECT_TRUE(String8("").StartsWith(""));
EXPECT_TRUE(!String8("").StartsWith("abc"));
EXPECT_TRUE(!String8("abcdabcd").StartsWith("aBc"));
EXPECT_TRUE(String8("abcdabcd").StartsWith('a'));
EXPECT_TRUE(!String8("").StartsWith('a'));
EXPECT_TRUE(!String8("abcdabcd").StartsWith('A'));
EXPECT_TRUE(String8("abcdabcd").EndsWith("cd"));
EXPECT_TRUE(!String8("abcdabcd").EndsWith("bc"));
EXPECT_TRUE(!String8("").EndsWith("cd"));
EXPECT_TRUE(String8("abcdabcd").EndsWith(""));
EXPECT_TRUE(String8("").EndsWith(""));
EXPECT_TRUE(String8("abcdabcd").EndsWith('d'));
EXPECT_TRUE(!String8("abcdabcd").EndsWith('D'));
EXPECT_TRUE(!String8("").EndsWith('d'));
EXPECT_TRUE(String8("abcdabcd").ContainsStr("cda"));
EXPECT_TRUE(String8("abcdabcd").ContainsStr(""));
EXPECT_TRUE(!String8("").ContainsStr("cda"));
EXPECT_TRUE(String8("").ContainsStr(""));
EXPECT_TRUE(!String8("abcdabcd").ContainsStr("cDa"));
EXPECT_TRUE(String8("abcd").ContainsChar('b'));
EXPECT_TRUE(!String8("").ContainsChar('c'));
EXPECT_TRUE(!String8("abcdabcd").ContainsChar('D'));
EXPECT_EQ(String8("123456789012345678900").ToInt32(), INT32_MAX);
EXPECT_EQ(String8("-123456789012345678900").ToInt32(), INT32_MIN);
EXPECT_EQ(String8("123456789012345678900").ToUint32(), UINT32_MAX);
#if FC_PLATFORM == FC_PLATFORM_ANDROID || FC_COMPILER == FC_COMPILER_MSVC
// EXPECT_EQ(String8("-123456789012345678900").ToUint32(), UINT32_MAX);
#else
// EXPECT_EQ(String8("-123456789012345678900").ToUint32(), (~UINT32_MAX) + 1);
#endif
EXPECT_EQ(String8("123456789012345678900").ToInt64(), INT64_MAX);
EXPECT_EQ(String8("-123456789012345678900").ToInt64(), INT64_MIN);
EXPECT_EQ(String8("123456789012345678900").ToUint64(), UINT64_MAX);
#if FC_PLATFORM == FC_PLATFORM_ANDROID || FC_COMPILER == FC_COMPILER_MSVC
// EXPECT_EQ(String8("-123456789012345678900").ToUint64(), UINT64_MAX);
#else
// EXPECT_EQ(String8("-123456789012345678900").ToUint64(), (~UINT64_MAX) + 1);
#endif
EXPECT_EQ(String8("0xabcd").ToUint32(16), 0xabcdU);
EXPECT_EQ(String8("-0.345").ToDouble(), -0.345);
EXPECT_EQ(String8("abcd/dede/dcdc").DirectoryWithoutFilename(), String8("abcd/dede/"));
EXPECT_EQ(String8("abcd/dede/").DirectoryWithoutFilename(), String8("abcd/dede/"));
EXPECT_EQ(String8("/abcd/dede/dcdc").DirectoryWithoutFilename(), String8("/abcd/dede/"));
EXPECT_EQ(String8("abcddededcdc").DirectoryWithoutFilename(), String8(""));
EXPECT_EQ(String8("abcd/dede/dcdc").FilenameWithoutDirectory(), String8("dcdc"));
EXPECT_EQ(String8("abcd/dede/").FilenameWithoutDirectory(), String8(""));
EXPECT_EQ(String8("/abcd/dede/dcdc").FilenameWithoutDirectory(), String8("dcdc"));
EXPECT_EQ(String8("abcddededcdc").FilenameWithoutDirectory(), String8("abcddededcdc"));
EXPECT_EQ(String8("abcdef").RemoveLast(0), String8("abcdef"));
EXPECT_EQ(String8("abcdef").RemoveLast(1), String8("abcde"));
EXPECT_EQ(String8("abcdef").RemoveLast(6), String8(""));
EXPECT_EQ(String8("abcdef").RemoveLast(7), String8(""));
EXPECT_EQ(String8("abcdef").RemoveFirst(0), String8("abcdef"));
EXPECT_EQ(String8("abcdef").RemoveFirst(1), String8("bcdef"));
EXPECT_EQ(String8("abcdef").RemoveFirst(6), String8(""));
EXPECT_EQ(String8("abcdef").RemoveFirst(7), String8(""));
EXPECT_EQ(String8("abcd.ext").FilenameWithoutExtension(), String8("abcd"));
EXPECT_EQ(String8("abcd").FilenameWithoutExtension(), String8("abcd"));
EXPECT_EQ(String8("abcd.").FilenameWithoutExtension(), String8("abcd"));
EXPECT_EQ(String8(".ext").FilenameWithoutExtension(), String8(""));
EXPECT_EQ(String8("abcd.ext").ExtensionWithoutFilename(), String8(".ext"));
EXPECT_EQ(String8("abcd").ExtensionWithoutFilename(), String8(""));
EXPECT_EQ(String8("abcd.").ExtensionWithoutFilename(), String8("."));
EXPECT_EQ(String8(".ext").ExtensionWithoutFilename(), String8(".ext"));
String8 s = String8("test");
String8 s2(s.GetDataConst() + 2);
EXPECT_EQ(s2, "st");
String8 word = "ebadc";
EXPECT_EQ(word.SortChars(), "abcde");
}
void test_U()
{
String8 e;
String8 s = "abcdABCDАБВГДабвгд";
EXPECT_EQ(s.Size(), 28U);
EXPECT_TRUE(!s.IsEmpty());
EXPECT_EQ(e.Size(), 0U);
EXPECT_TRUE(e.IsEmpty());
e = s;
s.Clear();
EXPECT_EQ(s.Size(), 0U);
EXPECT_TRUE(s.IsEmpty());
EXPECT_EQ(e.Size(), 28U);
EXPECT_TRUE(!e.IsEmpty());
EXPECT_EQ(e[1], 'b');
EXPECT_EQ(e[9], '\x90');
s = "acdABCАВГДабвгд";
s = "abcdABCDАБВГДабвгд";
EXPECT_EQ(s[3], 'd');
EXPECT_EQ(s[11], '\x91');
s = '0';
EXPECT_EQ(s.Size(), 1U);
String8 ss = "abcd";
ss += "efgh";
EXPECT_EQ(strcmp(ss.c_str(), "abcdefgh"), 0);
String8 sum1 = "ab1" + String8("cd2");
String8 sum2 = sum1 + "cd2" + "апр";
EXPECT_TRUE(sum2 == "ab1cd2cd2апр");
EXPECT_TRUE(sum2 != "ab1cd2cd2апР");
sum1 = "_ab1" + String8("cd2");
sum2 = sum1 + "cd2" + "апр";
EXPECT_TRUE(sum2 == "_ab1cd2cd2апр");
EXPECT_TRUE(sum2 != "_ab1cd2cd2апР");
String8 mt = "0123456789";
EXPECT_TRUE(String8("").IsEmpty());
EXPECT_EQ(mt.Mid(0, 4), "0123");
EXPECT_EQ(mt.Mid(6, 4), "6789");
EXPECT_EQ(mt.Mid(6, 5), "6789");
EXPECT_EQ(mt.Mid(10, 1), "");
EXPECT_EQ(mt.Mid(0, 0), "");
EXPECT_EQ(mt.Left(2), "01");
EXPECT_EQ(mt.Left(0), "");
EXPECT_EQ(mt.Left(12), "0123456789");
EXPECT_EQ(mt.Right(2), "89");
EXPECT_EQ(mt.Right(0), "");
EXPECT_EQ(mt.Right(12), "0123456789");
}
void test_U_3()
{
String8 tt = " 123 abc\r\n";
String8 tt2 = " \t \r\n ";
String8 tt3 = "no_space";
EXPECT_EQ(tt.TrimLeft(), "123 abc\r\n");
EXPECT_EQ(tt.TrimRight(), " 123 abc");
EXPECT_EQ(tt.Trim(), "123 abc");
EXPECT_EQ(tt.Simplify(), "123 abc");
EXPECT_EQ(tt2.TrimLeft(), "");
EXPECT_EQ(tt2.TrimRight(), "");
EXPECT_EQ(tt2.Trim(), "");
EXPECT_EQ(tt2.Simplify(), "");
EXPECT_EQ(tt3.TrimLeft(), tt3);
EXPECT_EQ(tt3.TrimRight(), tt3);
EXPECT_EQ(tt3.Trim(), tt3);
EXPECT_EQ(tt3.Simplify(), tt3);
EXPECT_EQ(String8("й ц у к е н").ReplaceChar(' ', '_'), "й_ц_у_к_е");
EXPECT_EQ(String8("й ц у к е н").RemoveChar(' '), "йцукен");
// EXPECT_EQ(String8("й ц у к е н").RemoveAt(1).RemoveAt(2).RemoveAt(3), "йцук е н");
EXPECT_EQ(String8("йцукен").RemoveAt(0, 0), "йцукен");
// EXPECT_EQ(String8("йцукен").RemoveAt(10, 1), "йцукен");
// EXPECT_EQ(String8("йцукен").RemoveAt(0, 10), "");
// EXPECT_EQ(String8("йцукен").RemoveAt(1, 10), "й");
// EXPECT_EQ(String8("йцукен").RemoveAt(1, 2), "йкен");
EXPECT_EQ(String8("\nй\nц\n\nу к е н\n").ReplaceStr("\n", "\r\n"), "\r\nй\r\nц\r\n\r\nу к е н\r\n");
EXPECT_EQ(String8("\nй\nц\n\nу к е н\n").RemoveStr("\n"), "йцу к е н");
EXPECT_EQ(String8("abcabcabc").RemoveStr("bc"), "aaa");
String8 it = "abcЙЦУ123";
EXPECT_EQ(it.InsertAt(0, 'q'), "qabcЙЦУ123");
EXPECT_EQ(it.InsertAt(3, "_d_"), "abc_d_ЙЦУ123");
// EXPECT_EQ(it.InsertAt(10, "000"), "abcЙЦУ123000");
String8 ft = "ab ab ab";
EXPECT_EQ(ft.FindIndex("ab", 0), 0U);
EXPECT_EQ(ft.FindIndex("ab", 1), 3U);
EXPECT_EQ(ft.FindIndex("AB", 0), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex("ab", 7), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex("ab", 15), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex("abc", 0), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex("", 5), 5U);
EXPECT_EQ(ft.FindLastIndex("ab"), 6U);
EXPECT_EQ(ft.FindLastIndex("ab", 6), 6U);
EXPECT_EQ(ft.FindLastIndex("ab", 5), 3U);
EXPECT_EQ(ft.FindLastIndex("AB"), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindLastIndex(""), 7U);
EXPECT_EQ(ft.FindIndex('a', 0), 0U);
EXPECT_EQ(ft.FindIndex('a', 1), 3U);
EXPECT_EQ(ft.FindIndex('A', 0), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex('a', 7), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex('a', 15), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindIndex('c', 0), Core::STRING8_INVALID_INDEX);
EXPECT_EQ(ft.FindLastIndex('a'), 6U);
EXPECT_EQ(ft.FindLastIndex('a', 6), 6U);
EXPECT_EQ(ft.FindLastIndex('a', 5), 3U);
EXPECT_EQ(ft.FindLastIndex('A'), Core::STRING8_INVALID_INDEX);
String8 ft2 = "ab AB ab";
}
void test_U_2()
{
String8 pf;
EXPECT_TRUE(pf.Printf("s%s_d%d\n", "abcdАБВГ", 4));
EXPECT_EQ(pf, "sabcdАБВГ_d4\n");
EXPECT_TRUE(String8("abcdabcd").StartsWith("abc"));
EXPECT_TRUE(String8("abcdabcd").StartsWith(""));
EXPECT_TRUE(String8("").StartsWith(""));
EXPECT_TRUE(!String8("").StartsWith("abc"));
EXPECT_TRUE(!String8("abcdabcd").StartsWith("aBc"));
EXPECT_TRUE(String8("abcdabcd").StartsWith('a'));
EXPECT_TRUE(!String8("").StartsWith('a'));
EXPECT_TRUE(!String8("abcdabcd").StartsWith('A'));
EXPECT_TRUE(String8("abcdabcd").EndsWith("cd"));
EXPECT_TRUE(!String8("abcdabcd").EndsWith("bc"));
EXPECT_TRUE(!String8("").EndsWith("cd"));
EXPECT_TRUE(String8("abcdabcd").EndsWith(""));
EXPECT_TRUE(String8("").EndsWith(""));
EXPECT_TRUE(String8("abcdabcd").EndsWith('d'));
EXPECT_TRUE(!String8("abcdabcd").EndsWith('D'));
EXPECT_TRUE(!String8("").EndsWith('d'));
EXPECT_TRUE(String8("abcdabcd").ContainsStr("cda"));
EXPECT_TRUE(String8("abcdabcd").ContainsStr(""));
EXPECT_TRUE(!String8("").ContainsStr("cda"));
EXPECT_TRUE(String8("").ContainsStr(""));
EXPECT_TRUE(!String8("abcdabcd").ContainsStr("cDa"));
EXPECT_TRUE(String8("abcd").ContainsChar('b'));
EXPECT_TRUE(!String8("").ContainsChar('c'));
EXPECT_TRUE(!String8("abcdabcd").ContainsChar('D'));
EXPECT_EQ(String8("123456789012345678900").ToInt32(), INT32_MAX);
EXPECT_EQ(String8("-123456789012345678900").ToInt32(), INT32_MIN);
EXPECT_EQ(String8("123456789012345678900").ToUint32(), UINT32_MAX);
#if FC_PLATFORM == FC_PLATFORM_ANDROID || FC_COMPILER == FC_COMPILER_MSVC
// EXPECT_EQ(String8("-123456789012345678900").ToUint32(), UINT32_MAX);
#else
// EXPECT_EQ(String8("-123456789012345678900").ToUint32(), (~UINT32_MAX) + 1);
#endif
EXPECT_EQ(String8("123456789012345678900").ToInt64(), INT64_MAX);
EXPECT_EQ(String8("-123456789012345678900").ToInt64(), INT64_MIN);
EXPECT_EQ(String8("123456789012345678900").ToUint64(), UINT64_MAX);
#if FC_PLATFORM == FC_PLATFORM_ANDROID || FC_COMPILER == FC_COMPILER_MSVC
// EXPECT_EQ(String8("-123456789012345678900").ToUint64(), UINT64_MAX);
#else
// EXPECT_EQ(String8("-123456789012345678900").ToUint64(), (~UINT64_MAX) + 1);
#endif
EXPECT_EQ(String8("0xabcd").ToUint32(16), 0xabcdU);
EXPECT_EQ(String8("-0.345").ToDouble(), -0.345);
EXPECT_EQ(String8("abcd/dede/dcdc").DirectoryWithoutFilename(), String8("abcd/dede/"));
EXPECT_EQ(String8("abcd/dede/").DirectoryWithoutFilename(), String8("abcd/dede/"));
EXPECT_EQ(String8("/abcd/dede/dcdc").DirectoryWithoutFilename(), String8("/abcd/dede/"));
EXPECT_EQ(String8("abcddededcdc").DirectoryWithoutFilename(), String8(""));
EXPECT_EQ(String8("abcd/dede/dcdc").FilenameWithoutDirectory(), String8("dcdc"));
EXPECT_EQ(String8("abcd/dede/").FilenameWithoutDirectory(), String8(""));
EXPECT_EQ(String8("/abcd/dede/dcdc").FilenameWithoutDirectory(), String8("dcdc"));
EXPECT_EQ(String8("abcddededcdc").FilenameWithoutDirectory(), String8("abcddededcdc"));
EXPECT_EQ(String8("abcdef").RemoveLast(0), String8("abcdef"));
EXPECT_EQ(String8("abcdef").RemoveLast(1), String8("abcde"));
EXPECT_EQ(String8("abcdef").RemoveLast(6), String8(""));
EXPECT_EQ(String8("abcdef").RemoveLast(7), String8(""));
EXPECT_EQ(String8("abcdef").RemoveFirst(0), String8("abcdef"));
EXPECT_EQ(String8("abcdef").RemoveFirst(1), String8("bcdef"));
EXPECT_EQ(String8("abcdef").RemoveFirst(6), String8(""));
EXPECT_EQ(String8("abcdef").RemoveFirst(7), String8(""));
EXPECT_EQ(String8("abcd.ext").FilenameWithoutExtension(), String8("abcd"));
EXPECT_EQ(String8("abcd").FilenameWithoutExtension(), String8("abcd"));
EXPECT_EQ(String8("abcd.").FilenameWithoutExtension(), String8("abcd"));
EXPECT_EQ(String8(".ext").FilenameWithoutExtension(), String8(""));
EXPECT_EQ(String8("abcd.ext").ExtensionWithoutFilename(), String8(".ext"));
EXPECT_EQ(String8("abcd").ExtensionWithoutFilename(), String8(""));
EXPECT_EQ(String8("abcd.").ExtensionWithoutFilename(), String8("."));
EXPECT_EQ(String8(".ext").ExtensionWithoutFilename(), String8(".ext"));
String8 s = "test";
String8 s2(s.GetDataConst() + 2);
EXPECT_EQ(s2, "st");
}
void test_list()
{
StringList8 list = String8(" a b У р e ").Split(" ");
EXPECT_EQ(list[0], "a");
EXPECT_EQ(list[1], "b");
EXPECT_EQ(list[2], "У");
EXPECT_EQ(list[3], "р");
EXPECT_EQ(list[4], "e");
list = String8(",a,b,,У,р,e,").Split(",", String8::SplitType::WithEmptyParts);
EXPECT_EQ(list[0], "");
EXPECT_EQ(list[1], "a");
EXPECT_EQ(list[2], "b");
EXPECT_EQ(list[3], "");
EXPECT_EQ(list[4], "У");
EXPECT_EQ(list[5], "р");
EXPECT_EQ(list[6], "e");
EXPECT_EQ(list[7], "");
list = String8("qaQbqqУQрqeQ").Split("q", String8::SplitType::SplitNoEmptyParts);
EXPECT_EQ(list[0], "aQb");
EXPECT_EQ(list[1], "УQр");
EXPECT_EQ(list[2], "eQ");
StringList8 list2 = list;
list[0] = String8("a");
list[1] = "b";
list[2] = "c";
EXPECT_EQ(list2[0], "aQb");
EXPECT_EQ(list2[1], "УQр");
EXPECT_EQ(list2[2], "eQ");
EXPECT_TRUE(list.Contains("b"));
EXPECT_TRUE(!list.Contains("B"));
EXPECT_TRUE(String8("fdabn").ContainsAnyStr(list));
EXPECT_TRUE(!String8("Cfdabn").ContainsAllStr(list));
EXPECT_TRUE(String8("cfdabn").ContainsAllStr(list));
EXPECT_EQ(list.Concat(", "), "a, b, c");
auto chars = list.Concat("");
EXPECT_TRUE(String8("fdabn").ContainsAnyChar(chars));
EXPECT_TRUE(!String8("Cfdabn").ContainsAllChar(chars));
EXPECT_TRUE(String8("cfdabn").ContainsAllChar(chars));
StringList8 l1 = String8("a b c d e f").Split(" ");
StringList8 l2 = String8("a b c d e f").Split(" ");
EXPECT_TRUE(l1.Equal(l2));
EXPECT_TRUE(l1 == l2);
l1.Add("Q");
EXPECT_TRUE(!l1.Equal(l2));
EXPECT_TRUE(l1 != l2);
l2.Add("q");
EXPECT_TRUE(!l1.Equal(l2));
EXPECT_TRUE(l1 != l2);
}
void test_list_2()
{
StringList8 list = String8(" a b У р e ").Split(' ');
EXPECT_EQ(list[0], "a");
EXPECT_EQ(list[1], "b");
EXPECT_EQ(list[2], "У");
EXPECT_EQ(list[3], "р");
EXPECT_EQ(list[4], "e");
list = String8(",a,b,,У,р,e,").Split(',', String8::SplitType::WithEmptyParts);
EXPECT_EQ(list[0], "");
EXPECT_EQ(list[1], "a");
EXPECT_EQ(list[2], "b");
EXPECT_EQ(list[3], "");
EXPECT_EQ(list[4], "У");
EXPECT_EQ(list[5], "р");
EXPECT_EQ(list[6], "e");
EXPECT_EQ(list[7], "");
list = String8("qaQbqqУQрqeQ").Split('q', String8::SplitType::SplitNoEmptyParts);
EXPECT_EQ(list[0], "aQb");
EXPECT_EQ(list[1], "УQр");
EXPECT_EQ(list[2], "eQ");
StringList8 list2 = list;
list[0] = String8("a");
list[1] = "b";
list[2] = "c";
EXPECT_EQ(list2[0], "aQb");
EXPECT_EQ(list2[1], "УQр");
EXPECT_EQ(list2[2], "eQ");
EXPECT_TRUE(list.Contains("b"));
EXPECT_TRUE(!list.Contains("B"));
EXPECT_TRUE(String8("fdabn").ContainsAnyStr(list));
EXPECT_TRUE(!String8("Cfdabn").ContainsAllStr(list));
EXPECT_TRUE(String8("cfdabn").ContainsAllStr(list));
EXPECT_EQ(list.Concat(','), "a,b,c");
auto chars = list.Concat("");
EXPECT_TRUE(String8("fdabn").ContainsAnyChar(chars));
EXPECT_TRUE(!String8("Cfdabn").ContainsAllChar(chars));
EXPECT_TRUE(String8("cfdabn").ContainsAllChar(chars));
StringList8 l1 = String8("a b c d e f").Split(' ');
StringList8 l2 = String8("a b c d e f").Split(' ');
EXPECT_TRUE(l1.Equal(l2));
EXPECT_TRUE(l1 == l2);
l1.Add("Q");
EXPECT_TRUE(!l1.Equal(l2));
EXPECT_TRUE(l1 != l2);
l2.Add("q");
EXPECT_TRUE(!l1.Equal(l2));
EXPECT_TRUE(l1 != l2);
}
static void test_printf()
{
int8_t i8_1 = -1;
uint8_t u8_1 = i8_1;
int16_t i16_1 = -1;
uint16_t u16_1 = i16_1;
int32_t i32_1 = -1;
uint32_t u32_1 = i32_1;
int64_t i64_1 = -1;
uint64_t u64_1 = i64_1;
int8_t i8_0 = 0;
uint8_t u8_0 = 0;
int16_t i16_0 = 0;
uint16_t u16_0 = 0;
int32_t i32_0 = 0;
uint32_t u32_0 = 0;
int64_t i64_0 = 0;
uint64_t u64_0 = 0;
String8 s;
s.Printf("%" PRIi8 " %" PRIi8 " %" PRIi8 " %" PRIi8, i8_1, i8_0, i8_1, i8_0);
EXPECT_EQ(s, "-1 0 -1 0");
s.Printf("%" PRId8 " %" PRId8 " %" PRId8 " %" PRId8, i8_1, i8_0, i8_1, i8_0);
EXPECT_EQ(s, "-1 0 -1 0");
s.Printf("%" PRIu8 " %" PRIu8 " %" PRIu8 " %" PRIu8, u8_1, u8_0, u8_1, u8_0);
EXPECT_EQ(s, "255 0 255 0");
s.Printf("%02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8, u8_1, u8_0, u8_1, u8_0);
EXPECT_EQ(s, "ff 00 ff 00");
s.Printf("%02" PRIX8 " %02" PRIX8 " %02" PRIX8 " %02" PRIX8, u8_1, u8_0, u8_1, u8_0);
EXPECT_EQ(s, "FF 00 FF 00");
s.Printf("%" PRIi16 " %" PRIi16 " %" PRIi16 " %" PRIi16, i16_1, i16_0, i16_1, i16_0);
EXPECT_EQ(s, "-1 0 -1 0");
s.Printf("%" PRId16 " %" PRId16 " %" PRId16 " %" PRId16, i16_1, i16_0, i16_1, i16_0);
EXPECT_EQ(s, "-1 0 -1 0");
s.Printf("%" PRIu16 " %" PRIu16 " %" PRIu16 " %" PRIu16, u16_1, u16_0, u16_1, u16_0);
EXPECT_EQ(s, "65535 0 65535 0");
s.Printf("%04" PRIx16 " %04" PRIx16 " %04" PRIx16 " %04" PRIx16, u16_1, u16_0, u16_1, u16_0);
EXPECT_EQ(s, "ffff 0000 ffff 0000");
s.Printf("%04" PRIX16 " %04" PRIX16 " %04" PRIX16 " %04" PRIX16, u16_1, u16_0, u16_1, u16_0);
EXPECT_EQ(s, "FFFF 0000 FFFF 0000");
s.Printf("%" PRIi32 " %" PRIi32 " %" PRIi32 " %" PRIi32, i32_1, i32_0, i32_1, i32_0);
EXPECT_EQ(s, "-1 0 -1 0");
s.Printf("%" PRId32 " %" PRId32 " %" PRId32 " %" PRId32, i32_1, i32_0, i32_1, i32_0);
EXPECT_EQ(s, "-1 0 -1 0");
s.Printf("%" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32, u32_1, u32_0, u32_1, u32_0);
EXPECT_EQ(s, "4294967295 0 4294967295 0");
s.Printf("%08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32, u32_1, u32_0, u32_1, u32_0);
EXPECT_EQ(s, "ffffffff 00000000 ffffffff 00000000");
s.Printf("%08" PRIX32 " %08" PRIX32 " %08" PRIX32 " %08" PRIX32, u32_1, u32_0, u32_1, u32_0);
EXPECT_EQ(s, "FFFFFFFF 00000000 FFFFFFFF 00000000");
s.Printf("%" PRIi64 " %" PRIi64 " %" PRIi64 " %" PRIi64, i64_1, i64_0, i64_1, i64_0);
EXPECT_EQ(s, "-1 0 -1 0");
s.Printf("%" PRId64 " %" PRId64 " %" PRId64 " %" PRId64, i64_1, i64_0, i64_1, i64_0);
EXPECT_EQ(s, "-1 0 -1 0");
s.Printf("%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, u64_1, u64_0, u64_1, u64_0);
EXPECT_EQ(s, "18446744073709551615 0 18446744073709551615 0");
s.Printf("%016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64, u64_1, u64_0, u64_1, u64_0);
EXPECT_EQ(s, "ffffffffffffffff 0000000000000000 ffffffffffffffff 0000000000000000");
s.Printf("%016" PRIX64 " %016" PRIX64 " %016" PRIX64 " %016" PRIX64, u64_1, u64_0, u64_1, u64_0);
EXPECT_EQ(s, "FFFFFFFFFFFFFFFF 0000000000000000 FFFFFFFFFFFFFFFF 0000000000000000");
}
void test_cpp14()
{
StringList8 s = {"a", "b", "cd"};
EXPECT_EQ(s.Size(), 3U);
EXPECT_EQ(s.At(0), "a");
EXPECT_EQ(s.At(1), "b");
EXPECT_EQ(s.At(2), "cd");
String8 ss;
for (const auto& str: s)
{
ss += str;
}
EXPECT_EQ(ss, "abcd");
uint8_t int_c[] = {0xc3, 0xae, 0xed, 0x82, 0xb0, 0xf0, 0xa0, 0xbf, 0xbf};
String8 s1 = String8("î킰𠿿");
String8 s2 = "î킰𠿿";
int i = 0;
i = 0;
for (auto ch: s1)
{
EXPECT_EQ(ch, static_cast<char>(int_c[i++]));
}
i = 0;
for (auto& ch: s1)
{
EXPECT_EQ(ch, static_cast<char>(int_c[i++]));
}
i = 0;
for (const auto& ch: s1)
{
EXPECT_EQ(ch, static_cast<char>(int_c[i++]));
}
i = 0;
for (auto ch: s2)
{
EXPECT_EQ(ch, static_cast<char>(int_c[i++]));
}
i = 0;
for (auto& ch: s2)
{
EXPECT_EQ(ch, static_cast<char>(int_c[i++]));
}
i = 0;
for (const auto& ch: s2)
{
EXPECT_EQ(ch, static_cast<char>(int_c[i++]));
}
i = 0;
EXPECT_EQ(s1, s2);
EXPECT_EQ(s1.Hash(), s2.Hash());
for (auto& ch: s1)
{
ch++;
}
EXPECT_NE(s1, s2);
EXPECT_NE(s1.Hash(), s2.Hash());
i = 0;
for (const auto& ch: s1)
{
EXPECT_EQ(ch, static_cast<char>(int_c[i++] + 1));
}
}
void test_move()
{
String8 str = "123";
StringList8 list;
EXPECT_TRUE(!str.IsInvalid());
list.Add(std::move(str));
EXPECT_TRUE(str.IsInvalid()); // NOLINT(hicpp-invalid-access-moved,bugprone-use-after-move)
str = "234";
EXPECT_TRUE(!str.IsInvalid());
EXPECT_EQ(str, "234");
EXPECT_EQ(list, StringList8({"123"}));
}
TEST(Core, CharString8)
{
UT_MEM_CHECK_INIT();
test();
test_2();
test_3();
test_U();
test_U_2();
test_U_3();
test_list();
test_list_2();
test_printf();
test_cpp14();
test_move();
UT_MEM_CHECK();
}
UT_END();