1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

Improved OpenGL renderer.

- Improved Vertex Shader Decompiler.
- Fixed CMD analyzer.

- Improved sys_fs module.
- Minor fixes.
This commit is contained in:
DH 2013-10-06 17:15:04 +03:00
parent dd48f827c3
commit 8259006bc3
10 changed files with 193 additions and 157 deletions

View File

@ -35,7 +35,7 @@ public:
switch(sizeof(T))
{
case 1:
res = m_data;
(u8&)res = (u8&)m_data;
break;
case 2:
@ -68,7 +68,7 @@ public:
switch(sizeof(T))
{
case 1:
m_data = value;
(u8&)m_data = (u8&)value;
return;
case 2:

View File

@ -170,7 +170,7 @@ void VFS::SaveLoadDevices(Array<VFSManagerEntry>& res, bool is_load)
res[idx].path = "$(EmulatorDir)\\dev_hdd0\\";
res[idx].mount = "/dev_hdd0/";
res[idx].device = vfsDevice_LocalFile;
/*
idx = res.Move(new VFSManagerEntry());
res[idx].path = "$(GameDir)";
res[idx].mount = "";
@ -180,6 +180,7 @@ void VFS::SaveLoadDevices(Array<VFSManagerEntry>& res, bool is_load)
res[idx].path = "$(GameDir)";
res[idx].mount = "/";
res[idx].device = vfsDevice_LocalFile;
*/
idx = res.Move(new VFSManagerEntry());
res[idx].path = "$(GameDir)";

View File

@ -569,7 +569,7 @@ void GLGSRender::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u
}
m_frame->Flip();
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
m_gcm_current_buffer = args[0];
@ -773,69 +773,52 @@ void GLGSRender::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u
m_surface_offset_b = args[4];
m_surface_pitch_b = args[5];
/*
ConLog.Write("surface color format: 0x%x", m_surface_color_format);
ConLog.Write("surface depth format: 0x%x", m_surface_depth_format);
ConLog.Write("surface type: 0x%x", m_surface_type);
ConLog.Write("surface antialias: 0x%x", m_surface_antialias);
ConLog.Write("surface width: 0x%x", m_surface_width);
ConLog.Write("surface height: 0x%x", m_surface_height);
ConLog.Write("surface pitch a: 0x%x", m_surface_pitch_a);
ConLog.Write("surface offset a: 0x%x", m_surface_offset_a);
ConLog.Write("surface offset z: 0x%x", m_surface_offset_z);
ConLog.Write("surface offset b: 0x%x", m_surface_offset_b);
ConLog.Write("surface pitch b: 0x%x", m_surface_pitch_b);
if(m_surface_offset_a && m_set_context_dma_color_a)
{
u32 surface_addr = GetAddress(m_surface_offset_a, (m_context_dma_color_a - 0xfeed0000));
auto& surface = (const CellGcmSurface&)Memory[surface_addr];
ConLog.Write("context_dma_color_a=0x%x", m_context_dma_color_a);
ConLog.Write("context a: color format: 0x%x", surface.color_format);
ConLog.Write("context a: depth format: 0x%x", surface.depth_format);
ConLog.Write("context a: type: 0x%x", surface.type);
ConLog.Write("context a: antialias: 0x%x", surface.antialias);
ConLog.Write("context a: width: 0x%x", surface.width);
ConLog.Write("context a: height: 0x%x", surface.height);
}
else if(m_surface_offset_z && m_set_context_dma_z)
{
u32 surface_addr = GetAddress(m_surface_offset_z, m_context_dma_z);
auto& surface = (const CellGcmSurface&)Memory[surface_addr];
ConLog.Write("m_surface_offset_z=0x%x", m_surface_offset_z);
ConLog.Write("context x: color format: 0x%x", surface.color_format);
ConLog.Write("context z: depth format: 0x%x", surface.depth_format);
ConLog.Write("context z: type: 0x%x", surface.type);
ConLog.Write("context z: antialias: 0x%x", surface.antialias);
ConLog.Write("context z: width: 0x%x", surface.width);
ConLog.Write("context z: height: 0x%x", surface.height);
m_width = surface.width;
m_height = surface.height;
}
*/
m_depth_offset = m_surface_offset_z;
gcmBuffer* buffers = (gcmBuffer*)Memory.GetMemFromAddr(m_gcm_buffers_addr);
m_width = re(buffers[m_gcm_current_buffer].width);
m_height = re(buffers[m_gcm_current_buffer].height);
if(1)
{
break;
m_rbo.Create(2);
checkForGlError("m_rbo.Create");
m_rbo.Bind(0);
m_rbo.Storage(GL_RGBA, m_width, m_height);
checkForGlError("m_rbo.Storage(GL_RGBA)");
m_rbo.Bind(1);
switch(m_surface_depth_format)
{
case 1:
m_rbo.Storage(GL_DEPTH_COMPONENT16, m_width, m_height);
break;
case 2:
m_rbo.Storage(GL_DEPTH24_STENCIL8, m_width, m_height);
break;
default:
ConLog.Error("Bad depth format! (%d)", m_surface_depth_format);
assert(0);
break;
}
checkForGlError("m_rbo.Storage(GL_DEPTH24_STENCIL8)");
m_fbo.Create();
checkForGlError("m_fbo.Create");
m_fbo.Bind();
m_fbo.Renderbuffer(GL_COLOR_ATTACHMENT0, m_rbo.GetId(0));
checkForGlError("m_fbo.Renderbuffer(GL_COLOR_ATTACHMENT0)");
if(m_surface_depth_format == 2)
{
m_fbo.Renderbuffer(GL_DEPTH_STENCIL_ATTACHMENT, m_rbo.GetId(1));
checkForGlError("m_fbo.Renderbuffer(GL_DEPTH_STENCIL_ATTACHMENT)");
}
else
{
m_fbo.Renderbuffer(GL_DEPTH_ATTACHMENT, m_rbo.GetId(1));
checkForGlError("m_fbo.Renderbuffer(GL_DEPTH_STENCIL_ATTACHMENT)");
}
//CMD_LOG("color_format=%d, depth_format=%d, type=%d, antialias=%d, width=%d, height=%d, pitch_a=%d, offset_a=0x%x, offset_z=0x%x, offset_b=0x%x, pitch_b=%d",
// color_format, depth_format, type, antialias, width, height, pitch_a, offset_a, offset_z, offset_b, pitch_b);
}
@ -941,19 +924,10 @@ void GLGSRender::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u
case NV4097_SET_FRONT_POLYGON_MODE:
m_set_front_polygon_mode = true;
m_front_polygon_mode = args[0];
//glPolygonMode(GL_FRONT, args[0]);
break;
case NV4097_CLEAR_SURFACE:
{
u32 a0 = args[0];
GLbitfield f = 0;
if (a0 & 0x1) f |= GL_DEPTH_BUFFER_BIT;
if (a0 & 0x2) f |= GL_STENCIL_BUFFER_BIT;
if (a0 & 0xF0) f |= GL_COLOR_BUFFER_BIT;
glClear(f);
checkForGlError("glClear");
/*
if(m_set_clear_surface)
{
m_clear_surface_mask |= args[0];
@ -963,7 +937,6 @@ void GLGSRender::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u
m_clear_surface_mask = args[0];
m_set_clear_surface = true;
}
*/
}
break;
@ -1021,8 +994,9 @@ void GLGSRender::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u
{
for(u32 c=0; c<count; ++c)
{
const u32 first = args[c] & 0xffffff;
const u32 _count = (args[c] >> 24) + 1;
u32 ac = args[c];
const u32 first = ac & 0xffffff;
const u32 _count = (ac >> 24) + 1;
LoadVertexData(first, _count);
@ -1508,7 +1482,7 @@ void GLGSRender::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u
case NV4097_SET_SURFACE_PITCH_Z:
{
//TODO
m_depth_pitch = args[0];
}
break;
@ -1580,10 +1554,9 @@ void GLGSRender::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u
case NV4097_SET_ZSTENCIL_CLEAR_VALUE:
{
u32 clear_valuei = args[0];
//double clear_valuef = (double)clear_valuei / 0xffffffff;
//glClearDepth(clear_valuef);
double clear_valuef = (double)clear_valuei / 0xffffffff;
glClearDepth(clear_valuef);
glClearStencil(clear_valuei);
glClear(GL_STENCIL_BUFFER_BIT);
}
break;
@ -1897,6 +1870,59 @@ bool GLGSRender::LoadProgram()
return true;
}
void GLGSRender::WriteDepthBuffer()
{
if(!m_set_context_dma_z)
{
return;
}
u32 address = GetAddress(m_depth_offset, m_context_dma_z - 0xfeed0000);
if(!Memory.IsGoodAddr(address))
{
ConLog.Warning("Bad depth address: address=0x%x, offset=0x%x, dma=0x%x", address, m_depth_offset, m_context_dma_z);
return;
}
u8* dst = &Memory[address];
//m_fbo.Bind(GL_READ_FRAMEBUFFER);
//glPixelStorei(GL_PACK_ROW_LENGTH, m_depth_pitch);
m_fbo.Bind(GL_READ_FRAMEBUFFER);
GLuint depth_tex;
glGenTextures(1, &depth_tex);
glBindTexture(GL_TEXTURE_2D, depth_tex);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, m_width, m_height, 0);
checkForGlError("glCopyTexImage2D");
glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, dst);
checkForGlError("glGetTexImage");
glDeleteTextures(1, &depth_tex);
wxFile f("depth.raw", wxFile::write);
f.Write(dst, m_width * m_height * 4);
m_fbo.Bind();
/*
GLBufferObject pbo;
pbo.Create(GL_PIXEL_PACK_BUFFER);
pbo.Bind();
glReadPixels(0, 0, m_width, m_height, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
GLuint *src = (GLuint*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
if(src)
{
wxFile f("depth.raw", wxFile::write);
f.Write(src, m_width * m_height * 4);
memcpy(dst, src, m_width * m_height * 4);
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
else
{
ConLog.Error("glMapBuffer failed.");
}
pbo.UnBind();
pbo.Delete();
*/
Emu.Pause();
}
void GLGSRender::ExecCMD()
{
if(LoadProgram())
@ -1938,7 +1964,7 @@ void GLGSRender::ExecCMD()
GLbitfield f = 0;
if (m_clear_surface_mask & 0x1) f |= GL_DEPTH_BUFFER_BIT;
if (m_clear_surface_mask & 0x2) f |= GL_STENCIL_BUFFER_BIT;
if (m_clear_surface_mask & 0xF0) f |= GL_COLOR_BUFFER_BIT;
if ((m_clear_surface_mask & 0xF0) == 0xF0) f |= GL_COLOR_BUFFER_BIT;
glClear(f);
}
@ -1972,6 +1998,24 @@ void GLGSRender::ExecCMD()
checkForGlError("m_set_clip_plane");
}
if(m_set_stencil_fail && m_set_stencil_zfail && m_set_stencil_zpass)
{
glStencilOp(m_stencil_fail, m_stencil_zfail, m_stencil_zpass);
checkForGlError("glStencilOp");
}
if(m_set_stencil_mask)
{
glStencilMask(m_stencil_mask);
checkForGlError("glStencilMask");
}
if(m_set_stencil_func && m_set_stencil_func_ref && m_set_stencil_func_mask)
{
glStencilFunc(m_stencil_func, m_stencil_func_ref, m_stencil_func_mask);
checkForGlError("glStencilFunc");
}
if(m_set_two_sided_stencil_test_enable)
{
if(m_set_back_stencil_fail && m_set_back_stencil_zfail && m_set_back_stencil_zpass)
@ -1993,24 +2037,6 @@ void GLGSRender::ExecCMD()
}
}
if(m_set_stencil_fail && m_set_stencil_zfail && m_set_stencil_zpass)
{
glStencilOpSeparate(GL_FRONT, m_stencil_fail, m_stencil_zfail, m_stencil_zpass);
checkForGlError("glStencilOpSeparate(GL_FRONT)");
}
if(m_set_stencil_mask)
{
glStencilMaskSeparate(GL_FRONT, m_stencil_mask);
checkForGlError("glStencilMaskSeparate(GL_FRONT)");
}
if(m_set_stencil_func && m_set_stencil_func_ref && m_set_stencil_func_mask)
{
glStencilFuncSeparate(GL_FRONT, m_stencil_func, m_stencil_func_ref, m_stencil_func_mask);
checkForGlError("glStencilFuncSeparate(GL_FRONT)");
}
if(m_set_shade_mode)
{
glShadeModel(m_shade_mode);
@ -2149,6 +2175,8 @@ void GLGSRender::ExecCMD()
}
m_fragment_constants.Clear();
//WriteDepthBuffer();
}
else
{

View File

@ -556,6 +556,7 @@ private:
virtual void Draw();
virtual void Close();
bool LoadProgram();
void WriteDepthBuffer();
public:
void DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u32 count);

View File

@ -295,10 +295,10 @@ void VertexDecompilerThread::Task()
case 0x02: AddVecCode("(" + GetSRC(0) + " * " + GetSRC(1) + ")"); break; //MUL
case 0x03: AddVecCode("(" + GetSRC(0) + " + " + GetSRC(2) + ")"); break; //ADD
case 0x04: AddVecCode("(" + GetSRC(0) + " * " + GetSRC(1) + " + " + GetSRC(2) + ")"); break; //MAD
case 0x05: AddVecCode("vec4(dot(" + GetSRC(0) + ".xyz, " + GetSRC(1) + ".xyz)).xxxx"); break; //DP3
case 0x06: AddVecCode("vec4(dot(vec4(" + GetSRC(0) + ".xyz, 1), " + GetSRC(1) + ")).xxxx"); break; //DPH
case 0x07: AddVecCode("vec4(dot(" + GetSRC(0) + ", " + GetSRC(1) + ")).xxxx"); break; //DP4
case 0x08: AddVecCode("vec4(distance(" + GetSRC(0) + ", " + GetSRC(1) + ")).xxxx"); break; //DST
case 0x05: AddVecCode("vec4(dot(" + GetSRC(0) + ".xyz, " + GetSRC(1) + ".xyz), 0, 0, 0).xxxx"); break; //DP3
case 0x06: AddVecCode("vec4(dot(vec4(" + GetSRC(0) + ".xyz, 1), " + GetSRC(1) + "), 0, 0, 0).xxxx"); break; //DPH
case 0x07: AddVecCode("vec4(dot(" + GetSRC(0) + ", " + GetSRC(1) + "), 0, 0, 0).xxxx"); break; //DP4
case 0x08: AddVecCode("vec4(distance(" + GetSRC(0) + ", " + GetSRC(1) + "), 0, 0, 0).xxxx"); break; //DST
case 0x09: AddVecCode("min(" + GetSRC(0) + ", " + GetSRC(1) + ")"); break; //MIN
case 0x0a: AddVecCode("max(" + GetSRC(0) + ", " + GetSRC(1) + ")"); break; //MAX
case 0x0b: AddVecCode("vec4(lessThan(" + GetSRC(0) + ", " + GetSRC(1) + "))"); break; //SLT

View File

@ -47,6 +47,10 @@ public:
bool m_set_clear_surface;
u32 m_clear_surface_mask;
u8 m_clear_surface_color_r;
u8 m_clear_surface_color_g;
u8 m_clear_surface_color_b;
u8 m_clear_surface_color_a;
bool m_set_blend_sfactor;
u16 m_blend_sfactor_rgb;
@ -205,23 +209,33 @@ public:
bool m_set_alpha_ref;
u32 m_alpha_ref;
u32 m_depth_offset;
u32 m_depth_pitch;
u8 m_begin_end;
public:
ExecRSXCMDdata()
{
m_set_alpha_test = false;
m_set_blend = false;
m_set_depth_bounds_test = false;
m_depth_test_enable = false;
m_set_logic_op = false;
m_set_cull_face_enable = false;
m_set_dither = false;
m_set_stencil_test = false;
m_set_line_smooth = false;
m_set_poly_smooth = false;
Reset();
}
virtual void Reset()
{
m_set_color_mask = false;
m_set_alpha_test = false;
m_set_blend = false;
m_set_depth_bounds_test = false;
m_set_clip = false;
m_set_depth_func = false;
m_depth_test_enable = false;
m_set_viewport_horizontal = false;
m_set_viewport_vertical = false;
m_set_scissor_horizontal = false;
@ -230,10 +244,6 @@ public:
m_set_clear_surface = false;
m_set_blend_sfactor = false;
m_set_blend_dfactor = false;
m_set_logic_op = false;
m_set_cull_face_enable = false;
m_set_dither = false;
m_set_stencil_test = false;
m_set_stencil_mask = false;
m_set_stencil_func = false;
m_set_stencil_func_ref = false;
@ -251,8 +261,6 @@ public:
m_set_back_stencil_zpass = false;
m_set_blend_equation = false;
m_set_depth_mask = false;
m_set_line_smooth = false;
m_set_poly_smooth = false;
m_set_line_width = false;
m_set_shade_mode = false;
m_set_blend_color = false;

View File

@ -107,6 +107,12 @@ int cellFsRead(u32 fd, u32 buf_addr, u64 nbytes, mem64_t nread)
if(!sys_fs.CheckId(fd, id)) return CELL_ESRCH;
vfsStream& file = *(vfsStream*)id.m_data;
if(Memory.IsGoodAddr(buf_addr) && !Memory.IsGoodAddr(buf_addr, nbytes))
{
MemoryBlock& block = Memory.GetMemByAddr(buf_addr);
nbytes = block.GetSize() - (buf_addr - block.GetStartAddr());
}
const u64 res = nbytes ? file.Read(Memory.GetMemFromAddr(buf_addr), nbytes) : 0;
if(nread.IsGood())
@ -173,38 +179,40 @@ int cellFsStat(const u32 path_addr, mem_struct_ptr_t<CellFsStat> sb)
const wxString& path = Memory.ReadString(path_addr);
sys_fs.Log("cellFsFstat(path: %s, sb_addr: 0x%x)", path, sb.GetAddr());
// Check if path is a mount point. (TODO: Add information in sb_addr)
for(u32 i=0; i<Emu.GetVFS().m_devices.GetCount(); ++i)
{
if (path == Emu.GetVFS().m_devices[i].GetPs3Path().RemoveLast(1))
{
sys_fs.Log("cellFsFstat: '%s' is a mount point.", path);
return CELL_OK;
}
}
auto f = Emu.OpenFile(path);
if(!f->IsOpened())
{
sys_fs.Warning("cellFsFstat: '%s' not found.", path);
return CELL_ENOENT;
}
sb->st_mode =
CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR |
CELL_FS_S_IRGRP | CELL_FS_S_IWGRP | CELL_FS_S_IXGRP |
CELL_FS_S_IROTH | CELL_FS_S_IWOTH | CELL_FS_S_IXOTH;
sb->st_mode |= CELL_FS_S_IFREG; //TODO: dir CELL_FS_S_IFDIR
sb->st_uid = 0;
sb->st_gid = 0;
sb->st_atime = 0; //TODO
sb->st_mtime = 0; //TODO
sb->st_ctime = 0; //TODO
sb->st_size = f->GetSize();
sb->st_blksize = 4096;
// Check if path is a mount point. (TODO: Add information in sb_addr)
for(u32 i=0; i<Emu.GetVFS().m_devices.GetCount(); ++i)
{
if(path.CmpNoCase(Emu.GetVFS().m_devices[i].GetPs3Path().RemoveLast(1)) == 0)
{
sys_fs.Log("cellFsFstat: '%s' is a mount point.", path);
sb->st_mode |= CELL_FS_S_IFDIR;
return CELL_OK;
}
}
vfsFile f(path);
if(!f.IsOpened())
{
sys_fs.Warning("cellFsFstat: '%s' not found.", path);
return CELL_ENOENT;
}
sb->st_mode |= CELL_FS_S_IFREG; //TODO: dir CELL_FS_S_IFDIR
sb->st_size = f.GetSize();
return CELL_OK;
}
@ -307,19 +315,13 @@ int cellFsFtruncate(u32 fd, u64 size)
vfsStream& file = *(vfsStream*)id.m_data;
u64 initialSize = file.GetSize();
if (initialSize < size) // Is there any better way to fill the remaining bytes with 0, without allocating huge buffers in memory, or writing such a spaghetti code?
if (initialSize < size)
{
u64 last_pos = file.Tell();
file.Seek(0, vfsSeekEnd);
char* nullblock = (char*)calloc(4096, sizeof(char));
for(u64 i = (size-initialSize)/4096; i > 0; i--){
file.Write(nullblock, 4096);
}
free(nullblock);
char nullbyte = 0;
for(u64 i = (size-initialSize)%4096; i > 0; i--){
file.Write(&nullbyte, 1);
}
static const char nullbyte = 0;
file.Seek(size-initialSize-1, vfsSeekCur);
file.Write(&nullbyte, sizeof(char));
file.Seek(last_pos, vfsSeekSet);
}
@ -336,29 +338,22 @@ int cellFsTruncate(u32 path_addr, u64 size)
const wxString& path = Memory.ReadString(path_addr);
sys_fs.Log("cellFsTruncate(path: %s, size: %lld)", path, size);
vfsStream* f = Emu.GetVFS().Open(path, vfsRead);
if(!f || !f->IsOpened())
vfsFile f(path, vfsReadWrite);
if(!f.IsOpened())
{
sys_fs.Warning("cellFsTruncate: '%s' not found.", path);
Emu.GetVFS().Close(f);
return CELL_ENOENT;
}
u64 initialSize = f->GetSize();
u64 initialSize = f.GetSize();
if (initialSize < size) // Is there any better way to fill the remaining bytes with 0, without allocating huge buffers in memory, or writing such a spaghetti code?
if (initialSize < size)
{
u64 last_pos = f->Tell();
f->Seek(0, vfsSeekEnd);
char* nullblock = (char*)calloc(4096, sizeof(char));
for(u64 i = (size-initialSize)/4096; i > 0; i--){
f->Write(nullblock, 4096);
}
free(nullblock);
char nullbyte = 0;
for(u64 i = (size-initialSize)%4096; i > 0; i--){
f->Write(&nullbyte, 1);
}
f->Seek(last_pos, vfsSeekSet);
u64 last_pos = f.Tell();
f.Seek(0, vfsSeekEnd);
static const char nullbyte = 0;
f.Seek(size-initialSize-1, vfsSeekCur);
f.Write(&nullbyte, sizeof(char));
f.Seek(last_pos, vfsSeekSet);
}
if (initialSize > size)
@ -366,7 +361,6 @@ int cellFsTruncate(u32 path_addr, u64 size)
// (TODO)
}
Emu.GetVFS().Close(f);
return CELL_OK;
}

View File

@ -56,6 +56,8 @@ enum FsDirentType
CELL_FS_TYPE_SYMLINK = 3,
};
#pragma pack(4)
struct CellFsStat
{
be_t<u32> st_mode;
@ -80,3 +82,5 @@ struct CellFsDirent
u8 d_namlen;
char d_name[CELL_MAX_FS_FILE_NAME_LENGTH + 1];
};
#pragma pack()

View File

@ -449,7 +449,7 @@ void InterpreterDisAsmFrame::DoStep(wxCommandEvent& WXUNUSED(event))
void InterpreterDisAsmFrame::InstrKey(wxListEvent& event)
{
long i = m_list->GetFirstSelected();
if(i < 0) return;
if(i < 0 || !CPU) return;
const u64 start_pc = PC - m_item_count*4;
const u64 pc = start_pc + i*4;

View File

@ -133,7 +133,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>