mirror of https://github.com/PCSX2/pcsx2.git
Merge pull request #1474 from turtleli/windows-64-bit-fixes
Windows 64-bit compile fixes
This commit is contained in:
commit
a9f9c1406c
|
@ -74,7 +74,9 @@
|
||||||
<ClCompile Include="..\..\src\Utilities\pxWindowTextWriter.cpp" />
|
<ClCompile Include="..\..\src\Utilities\pxWindowTextWriter.cpp" />
|
||||||
<ClCompile Include="..\..\src\Utilities\ThreadingDialogs.cpp" />
|
<ClCompile Include="..\..\src\Utilities\ThreadingDialogs.cpp" />
|
||||||
<ClCompile Include="..\..\src\Utilities\VirtualMemory.cpp" />
|
<ClCompile Include="..\..\src\Utilities\VirtualMemory.cpp" />
|
||||||
<ClCompile Include="..\..\src\Utilities\x86\MemcpyFast.cpp" />
|
<ClCompile Include="..\..\src\Utilities\x86\MemcpyFast.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\Utilities\PathUtils.cpp" />
|
<ClCompile Include="..\..\src\Utilities\PathUtils.cpp" />
|
||||||
<ClCompile Include="..\..\src\Utilities\Perf.cpp" />
|
<ClCompile Include="..\..\src\Utilities\Perf.cpp" />
|
||||||
<ClCompile Include="..\..\src\Utilities\PrecompiledHeader.cpp">
|
<ClCompile Include="..\..\src\Utilities\PrecompiledHeader.cpp">
|
||||||
|
|
|
@ -22,132 +22,12 @@
|
||||||
// These functions are meant for memset operations of constant length only.
|
// These functions are meant for memset operations of constant length only.
|
||||||
// For dynamic length clears, use the C-compiler provided memset instead.
|
// For dynamic length clears, use the C-compiler provided memset instead.
|
||||||
|
|
||||||
// MemZero Code Strategies:
|
|
||||||
// I use a trick to help the MSVC compiler optimize it's asm code better. The compiler
|
|
||||||
// won't optimize local variables very well because it insists in storing them on the
|
|
||||||
// stack and then loading them out of the stack when I use them from inline ASM, and
|
|
||||||
// it won't allow me to use template parameters in inline asm code either. But I can
|
|
||||||
// assign the template parameters to enums, and then use the enums from asm code.
|
|
||||||
// Yeah, silly, but it works. :D (air)
|
|
||||||
|
|
||||||
// All methods defined in this header use template in combination with the aforementioned
|
|
||||||
// enumerations to generate very efficient and compact inlined code. These optimized
|
|
||||||
// memsets work on the theory that most uses of memset involve static arrays and
|
|
||||||
// structures, which are constant in size, thus allowing us to generate optimal compile-
|
|
||||||
// time code for each use of the function.
|
|
||||||
|
|
||||||
// Use of CLD (Clear Direction Flag):
|
|
||||||
// On Windows platforms the ABI declares that the direction flag should be cleared upon
|
|
||||||
// entry of *any* function. Therefore there is no need to have CLD prior to our use of
|
|
||||||
// rep strosd here.
|
|
||||||
|
|
||||||
// Notes on XMM0's "storage" area (_xmm_backup):
|
|
||||||
// Unfortunately there's no way to guarantee alignment for this variable. If I use the
|
|
||||||
// __declspec(aligned(16)) decorator, MSVC fails to inline the function since stack
|
|
||||||
// alignment requires prep work. And for the same reason it's not possible to check the
|
|
||||||
// alignment of the stack at compile time, so I'm forced to use movups to store and
|
|
||||||
// retrieve xmm0.
|
|
||||||
|
|
||||||
// MSVC Template Issue:
|
|
||||||
// MSVC treats int template parameters like macro insertions. That is, if you have a
|
|
||||||
// a template parameter in the form of "func<10-5>()", MSVC inserts 10-5 into the
|
|
||||||
// templated function, causing order-of-operation problems (sigh). The normal fix would
|
|
||||||
// be to assign the template parameter to a static const int inside each function, but that
|
|
||||||
// won't fly with the enums optimization. So in order to fix the problem I define a macro
|
|
||||||
// that encapsulates the template parameter inside parenthesis for us:
|
|
||||||
|
|
||||||
#define MZFbytes (_bytes)
|
|
||||||
|
|
||||||
// Code is only called in the init so no need to bother with ASM
|
|
||||||
template< u8 data, size_t bytes >
|
template< u8 data, size_t bytes >
|
||||||
static __fi void memset_8( void *dest )
|
static __fi void memset_8( void *dest )
|
||||||
{
|
{
|
||||||
memset(dest, data, bytes);
|
memset(dest, data, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is unused on Windows.
|
|
||||||
template< u32 data, size_t MZFbytes >
|
|
||||||
static __fi void memset_32( void *dest )
|
|
||||||
{
|
|
||||||
if( MZFbytes == 0 ) return;
|
|
||||||
|
|
||||||
// Assertion: data length must be a multiple of 32 bits
|
|
||||||
pxAssume( (MZFbytes & 0x3) == 0 );
|
|
||||||
|
|
||||||
//u64 _xmm_backup[2];
|
|
||||||
|
|
||||||
// This function only works on 32-bit alignments of data copied.
|
|
||||||
// If the data length is not a factor of 32 bits, the C++ optimizing compiler will
|
|
||||||
// probably just generate mysteriously broken code in Release builds. ;)
|
|
||||||
|
|
||||||
pxAssume( (MZFbytes & 0x3) == 0 );
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
remdat = MZFbytes>>2,
|
|
||||||
data32 = data
|
|
||||||
};
|
|
||||||
|
|
||||||
// macro to execute the x86/32 "stosd" copies.
|
|
||||||
switch( remdat )
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
*(u32*)dest = data32;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
((u32*)dest)[0] = data32;
|
|
||||||
((u32*)dest)[1] = data32;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
__asm
|
|
||||||
{
|
|
||||||
mov edi, dest;
|
|
||||||
mov eax, data32;
|
|
||||||
stosd;
|
|
||||||
stosd;
|
|
||||||
stosd;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
__asm
|
|
||||||
{
|
|
||||||
mov edi, dest;
|
|
||||||
mov eax, data32;
|
|
||||||
stosd;
|
|
||||||
stosd;
|
|
||||||
stosd;
|
|
||||||
stosd;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
__asm
|
|
||||||
{
|
|
||||||
mov edi, dest;
|
|
||||||
mov eax, data32;
|
|
||||||
stosd;
|
|
||||||
stosd;
|
|
||||||
stosd;
|
|
||||||
stosd;
|
|
||||||
stosd;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
default:
|
|
||||||
__asm
|
|
||||||
{
|
|
||||||
mov ecx, remdat;
|
|
||||||
mov edi, dest;
|
|
||||||
mov eax, data32;
|
|
||||||
rep stosd;
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method can clear any object-like entity -- which is anything that is not a pointer.
|
// This method can clear any object-like entity -- which is anything that is not a pointer.
|
||||||
// Structures, static arrays, etc. No need to include sizeof() crap, this does it automatically
|
// Structures, static arrays, etc. No need to include sizeof() crap, this does it automatically
|
||||||
// for you!
|
// for you!
|
||||||
|
@ -163,13 +43,3 @@ static __fi void memset8( T& object )
|
||||||
{
|
{
|
||||||
memset_8<data, sizeof(T)>( &object );
|
memset_8<data, sizeof(T)>( &object );
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method clears an object with the given 32 bit value.
|
|
||||||
// This is also unused.
|
|
||||||
template< u32 data, typename T >
|
|
||||||
static __fi void memset32( T& object )
|
|
||||||
{
|
|
||||||
memset_32<data, sizeof(T)>( &object );
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef MZFbytes
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ __fi void Threading::Sleep( int ms )
|
||||||
// improve performance and reduce cpu power consumption.
|
// improve performance and reduce cpu power consumption.
|
||||||
__fi void Threading::SpinWait()
|
__fi void Threading::SpinWait()
|
||||||
{
|
{
|
||||||
__asm pause;
|
_mm_pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
__fi void Threading::EnableHiresScheduler()
|
__fi void Threading::EnableHiresScheduler()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Cpudetection lib
|
/* Cpudetection lib
|
||||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
* Copyright (C) 2002-2016 PCSX2 Dev Team
|
||||||
*
|
*
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
@ -19,55 +19,53 @@
|
||||||
|
|
||||||
void x86capabilities::CountLogicalCores()
|
void x86capabilities::CountLogicalCores()
|
||||||
{
|
{
|
||||||
DWORD vProcessCPUs;
|
DWORD_PTR vProcessCPUs;
|
||||||
DWORD vSystemCPUs;
|
DWORD_PTR vSystemCPUs;
|
||||||
|
|
||||||
LogicalCores = 1;
|
LogicalCores = 1;
|
||||||
|
|
||||||
if( !GetProcessAffinityMask (GetCurrentProcess (),
|
if (!GetProcessAffinityMask(GetCurrentProcess(), &vProcessCPUs, &vSystemCPUs))
|
||||||
&vProcessCPUs, &vSystemCPUs) ) return;
|
return;
|
||||||
|
|
||||||
uint CPUs = 0;
|
uint CPUs = 0;
|
||||||
DWORD bit;
|
for (DWORD_PTR bit = 1; bit != 0; bit <<= 1)
|
||||||
|
|
||||||
for (bit = 1; bit != 0; bit <<= 1)
|
|
||||||
{
|
|
||||||
if (vSystemCPUs & bit)
|
if (vSystemCPUs & bit)
|
||||||
CPUs++;
|
CPUs++;
|
||||||
}
|
|
||||||
|
|
||||||
LogicalCores = CPUs;
|
LogicalCores = CPUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
SingleCoreAffinity::SingleCoreAffinity()
|
SingleCoreAffinity::SingleCoreAffinity()
|
||||||
{
|
{
|
||||||
s_threadId = NULL;
|
s_threadId = nullptr;
|
||||||
s_oldmask = ERROR_INVALID_PARAMETER;
|
s_oldmask = ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
DWORD_PTR availProcCpus, availSysCpus;
|
DWORD_PTR availProcCpus;
|
||||||
if( !GetProcessAffinityMask( GetCurrentProcess(), &availProcCpus, &availSysCpus ) ) return;
|
DWORD_PTR availSysCpus;
|
||||||
|
if (!GetProcessAffinityMask(GetCurrentProcess(), &availProcCpus, &availSysCpus))
|
||||||
|
return;
|
||||||
|
|
||||||
int i;
|
int cpu = 0;
|
||||||
for( i=0; i<32; ++i )
|
DWORD_PTR affinityMask;
|
||||||
{
|
for (affinityMask = 1; affinityMask != 0; affinityMask <<= 1, ++cpu)
|
||||||
if( availProcCpus & (1<<i) ) break;
|
if (availProcCpus & affinityMask)
|
||||||
}
|
break;
|
||||||
|
|
||||||
s_threadId = GetCurrentThread();
|
s_threadId = GetCurrentThread();
|
||||||
s_oldmask = SetThreadAffinityMask( s_threadId, (1UL<<i) );
|
s_oldmask = SetThreadAffinityMask(s_threadId, affinityMask);
|
||||||
|
|
||||||
if( s_oldmask == ERROR_INVALID_PARAMETER )
|
if (s_oldmask == ERROR_INVALID_PARAMETER) {
|
||||||
{
|
const int hexWidth = 2 * sizeof(DWORD_PTR);
|
||||||
Console.Warning(
|
Console.Warning(
|
||||||
"CpuDetect: SetThreadAffinityMask failed...\n"
|
"CpuDetect: SetThreadAffinityMask failed...\n"
|
||||||
"\tSystem Affinity : 0x%08x"
|
"\tSystem Affinity : 0x%0*x\n"
|
||||||
"\tProcess Affinity: 0x%08x"
|
"\tProcess Affinity: 0x%0*x\n"
|
||||||
"\tAttempted Thread Affinity CPU: i",
|
"\tAttempted Thread Affinity CPU: %i",
|
||||||
availProcCpus, availSysCpus, i
|
hexWidth, availProcCpus, hexWidth, availSysCpus, cpu
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sleep( 2 );
|
Sleep(2);
|
||||||
|
|
||||||
// Sleep Explained: I arbitrarily pick Core 0 to lock to for running the CPU test. This
|
// Sleep Explained: I arbitrarily pick Core 0 to lock to for running the CPU test. This
|
||||||
// means that the current thread will need to be switched to Core 0 if it's currently
|
// means that the current thread will need to be switched to Core 0 if it's currently
|
||||||
|
@ -80,15 +78,6 @@ SingleCoreAffinity::SingleCoreAffinity()
|
||||||
|
|
||||||
SingleCoreAffinity::~SingleCoreAffinity() throw()
|
SingleCoreAffinity::~SingleCoreAffinity() throw()
|
||||||
{
|
{
|
||||||
if( s_oldmask != ERROR_INVALID_PARAMETER )
|
if (s_oldmask != ERROR_INVALID_PARAMETER)
|
||||||
SetThreadAffinityMask( s_threadId, s_oldmask );
|
SetThreadAffinityMask(s_threadId, s_oldmask);
|
||||||
}
|
|
||||||
|
|
||||||
void SetSingleAffinity()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void RestoreAffinity()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ protected:
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE s_threadId;
|
HANDLE s_threadId;
|
||||||
DWORD s_oldmask;
|
DWORD_PTR s_oldmask;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -150,7 +150,6 @@ set(pcsx2Headers
|
||||||
R5900Exceptions.h
|
R5900Exceptions.h
|
||||||
R5900.h
|
R5900.h
|
||||||
R5900OpcodeTables.h
|
R5900OpcodeTables.h
|
||||||
SamplProf.h
|
|
||||||
SaveState.h
|
SaveState.h
|
||||||
Sifcmd.h
|
Sifcmd.h
|
||||||
Sif.h
|
Sif.h
|
||||||
|
@ -476,7 +475,6 @@ set(pcsx2WindowsSources
|
||||||
windows/DwmSetup.cpp
|
windows/DwmSetup.cpp
|
||||||
windows/ini.cpp
|
windows/ini.cpp
|
||||||
windows/PatchBrowser.cpp
|
windows/PatchBrowser.cpp
|
||||||
windows/SamplProf.cpp
|
|
||||||
windows/WinCompressNTFS.cpp
|
windows/WinCompressNTFS.cpp
|
||||||
windows/WinConsolePipe.cpp
|
windows/WinConsolePipe.cpp
|
||||||
windows/WinSysExec.cpp)
|
windows/WinSysExec.cpp)
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include "Gif_Unit.h"
|
#include "Gif_Unit.h"
|
||||||
#include "MTVU.h"
|
#include "MTVU.h"
|
||||||
#include "Elfheader.h"
|
#include "Elfheader.h"
|
||||||
#include "SamplProf.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Uncomment this to enable profiling of the GS RingBufferCopy function.
|
// Uncomment this to enable profiling of the GS RingBufferCopy function.
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
|
||||||
*
|
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
||||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SAMPLPROF_H_
|
|
||||||
#define _SAMPLPROF_H_
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
|
|
||||||
// The profiler does not have a Linux version yet.
|
|
||||||
// So for now we turn it into duds for non-Win32 platforms.
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
void ProfilerInit();
|
|
||||||
void ProfilerTerm();
|
|
||||||
void ProfilerSetEnabled(bool Enabled);
|
|
||||||
void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz);
|
|
||||||
void ProfilerRegisterSource(const char* Name, const void* function);
|
|
||||||
void ProfilerTerminateSource( const char* Name );
|
|
||||||
|
|
||||||
void ProfilerRegisterSource(const wxString& Name, const void* buff, u32 sz);
|
|
||||||
void ProfilerRegisterSource(const wxString& Name, const void* function);
|
|
||||||
void ProfilerTerminateSource( const wxString& Name );
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// Disables the profiler in Debug & Linux builds.
|
|
||||||
// Profiling info in debug builds isn't much use anyway and the console
|
|
||||||
// popups are annoying when you're trying to trace debug logs and stuff.
|
|
||||||
|
|
||||||
#define ProfilerInit() (void)0
|
|
||||||
#define ProfilerTerm() (void)0
|
|
||||||
#define ProfilerSetEnabled(...) (void)0
|
|
||||||
#define ProfilerRegisterSource(...) (void)0
|
|
||||||
#define ProfilerTerminateSource(...) (void)0
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -20,8 +20,6 @@
|
||||||
#include "newVif.h"
|
#include "newVif.h"
|
||||||
#include "MTVU.h"
|
#include "MTVU.h"
|
||||||
|
|
||||||
#include "SamplProf.h"
|
|
||||||
|
|
||||||
#include "Elfheader.h"
|
#include "Elfheader.h"
|
||||||
|
|
||||||
#include "System/RecTypes.h"
|
#include "System/RecTypes.h"
|
||||||
|
@ -43,8 +41,6 @@ RecompiledCodeReserve::RecompiledCodeReserve( const wxString& name, uint defComm
|
||||||
m_blocksize = (1024 * 128) / __pagesize;
|
m_blocksize = (1024 * 128) / __pagesize;
|
||||||
m_prot_mode = PageAccess_Any();
|
m_prot_mode = PageAccess_Any();
|
||||||
m_def_commit = defCommit / __pagesize;
|
m_def_commit = defCommit / __pagesize;
|
||||||
|
|
||||||
m_profiler_registered = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RecompiledCodeReserve::~RecompiledCodeReserve() throw()
|
RecompiledCodeReserve::~RecompiledCodeReserve() throw()
|
||||||
|
@ -55,17 +51,12 @@ RecompiledCodeReserve::~RecompiledCodeReserve() throw()
|
||||||
void RecompiledCodeReserve::_registerProfiler()
|
void RecompiledCodeReserve::_registerProfiler()
|
||||||
{
|
{
|
||||||
if (m_profiler_name.IsEmpty() || !IsOk()) return;
|
if (m_profiler_name.IsEmpty() || !IsOk()) return;
|
||||||
ProfilerRegisterSource( m_profiler_name, m_baseptr, GetReserveSizeInBytes() );
|
|
||||||
m_profiler_registered = true;
|
|
||||||
|
|
||||||
// Could potentially be integrated into ProfilerRegisterSource
|
|
||||||
Perf::any.map((uptr)m_baseptr, GetReserveSizeInBytes(), m_profiler_name.ToUTF8());
|
Perf::any.map((uptr)m_baseptr, GetReserveSizeInBytes(), m_profiler_name.ToUTF8());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecompiledCodeReserve::_termProfiler()
|
void RecompiledCodeReserve::_termProfiler()
|
||||||
{
|
{
|
||||||
if (m_profiler_registered)
|
|
||||||
ProfilerTerminateSource( m_profiler_name );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint RecompiledCodeReserve::_calcDefaultCommitInBlocks() const
|
uint RecompiledCodeReserve::_calcDefaultCommitInBlocks() const
|
||||||
|
|
|
@ -34,7 +34,6 @@ protected:
|
||||||
uint m_def_commit;
|
uint m_def_commit;
|
||||||
|
|
||||||
wxString m_profiler_name;
|
wxString m_profiler_name;
|
||||||
bool m_profiler_registered;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RecompiledCodeReserve( const wxString& name=wxEmptyString, uint defCommit = 0 );
|
RecompiledCodeReserve( const wxString& name=wxEmptyString, uint defCommit = 0 );
|
||||||
|
|
|
@ -1,356 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
|
||||||
*
|
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
||||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
|
||||||
#include "Utilities/RedtapeWindows.h"
|
|
||||||
|
|
||||||
#include "SamplProf.h"
|
|
||||||
#include <map>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
DWORD GetModuleFromPtr(IN void* ptr,OUT LPWSTR lpFilename,IN DWORD nSize)
|
|
||||||
{
|
|
||||||
MEMORY_BASIC_INFORMATION mbi;
|
|
||||||
VirtualQuery(ptr,&mbi,sizeof(mbi));
|
|
||||||
return GetModuleFileName((HMODULE)mbi.AllocationBase,lpFilename,nSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module
|
|
||||||
{
|
|
||||||
uptr base;
|
|
||||||
uptr end;
|
|
||||||
uptr len;
|
|
||||||
wxString name;
|
|
||||||
u32 ticks;
|
|
||||||
|
|
||||||
Module(const wxChar* name, const void* ptr)
|
|
||||||
{
|
|
||||||
if (name!=0)
|
|
||||||
this->name=name;
|
|
||||||
FromAddress(ptr,name==0);
|
|
||||||
ticks=0;
|
|
||||||
}
|
|
||||||
Module(const wxChar* name, const void* b, u32 s)
|
|
||||||
{
|
|
||||||
this->name=name;
|
|
||||||
FromValues(b,s);
|
|
||||||
ticks=0;
|
|
||||||
}
|
|
||||||
bool operator<(const Module &other) const
|
|
||||||
{
|
|
||||||
return ticks>other.ticks;
|
|
||||||
}
|
|
||||||
wxString ToString(u32 total_ticks)
|
|
||||||
{
|
|
||||||
return wxsFormat( L"| %s: %2.2f%% |", name.c_str(), (float)(((double)ticks*100.0) / (double)total_ticks) );
|
|
||||||
}
|
|
||||||
bool Inside(uptr val) { return val>=base && val<=end; }
|
|
||||||
void FromAddress(const void* ptr,bool getname)
|
|
||||||
{
|
|
||||||
wxChar filename[512];
|
|
||||||
wxChar filename2[512];
|
|
||||||
static const void* ptr_old=0;
|
|
||||||
|
|
||||||
if (ptr_old==ptr)
|
|
||||||
return;
|
|
||||||
ptr_old=ptr;
|
|
||||||
|
|
||||||
MEMORY_BASIC_INFORMATION mbi;
|
|
||||||
VirtualQuery(ptr,&mbi,sizeof(mbi));
|
|
||||||
base=(u32)mbi.AllocationBase;
|
|
||||||
GetModuleFileName((HMODULE)mbi.AllocationBase,filename,512);
|
|
||||||
len=(u8*)mbi.BaseAddress-(u8*)mbi.AllocationBase+mbi.RegionSize;
|
|
||||||
|
|
||||||
if (getname)
|
|
||||||
{
|
|
||||||
name=filename;
|
|
||||||
size_t last=name.find_last_of('\\');
|
|
||||||
last=last==name.npos?0:last+1;
|
|
||||||
name=name.substr(last);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
VirtualQuery(((u8*)base)+len,&mbi,sizeof(mbi));
|
|
||||||
if (!(mbi.Type&MEM_IMAGE))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!GetModuleFileName((HMODULE)mbi.AllocationBase,filename2,512))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (wxStrcmp(filename,filename2)!=0)
|
|
||||||
break;
|
|
||||||
len+=mbi.RegionSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
end=base+len-1;
|
|
||||||
}
|
|
||||||
void FromValues(const void* b,u32 s)
|
|
||||||
{
|
|
||||||
base= (uptr)b;
|
|
||||||
len=s;
|
|
||||||
end=base+len-1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::map<wxString,Module> MapType;
|
|
||||||
|
|
||||||
static std::vector<Module> ProfModules;
|
|
||||||
static MapType ProfUnknownHash;
|
|
||||||
|
|
||||||
static HANDLE hEmuThread = NULL;
|
|
||||||
static HANDLE hMtgsThread = NULL;
|
|
||||||
static HANDLE hProfThread = NULL;
|
|
||||||
|
|
||||||
static CRITICAL_SECTION ProfModulesLock;
|
|
||||||
|
|
||||||
static volatile bool ProfRunning=false;
|
|
||||||
|
|
||||||
static bool _registeredName( const wxString& name )
|
|
||||||
{
|
|
||||||
for( std::vector<Module>::const_iterator
|
|
||||||
iter = ProfModules.begin(),
|
|
||||||
end = ProfModules.end(); iter<end; ++iter )
|
|
||||||
{
|
|
||||||
if( iter->name.compare( name ) == 0 )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfilerRegisterSource(const wxString& Name, const void* buff, u32 sz)
|
|
||||||
{
|
|
||||||
if( ProfRunning )
|
|
||||||
EnterCriticalSection( &ProfModulesLock );
|
|
||||||
|
|
||||||
if( !_registeredName( Name ) )
|
|
||||||
ProfModules.push_back( Module( Name, buff, sz ) );
|
|
||||||
|
|
||||||
if( ProfRunning )
|
|
||||||
LeaveCriticalSection( &ProfModulesLock );
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfilerRegisterSource(const wxString& Name, const void* function)
|
|
||||||
{
|
|
||||||
if( ProfRunning )
|
|
||||||
EnterCriticalSection( &ProfModulesLock );
|
|
||||||
|
|
||||||
if( !_registeredName( Name ) )
|
|
||||||
ProfModules.push_back( Module(Name,function) );
|
|
||||||
|
|
||||||
if( ProfRunning )
|
|
||||||
LeaveCriticalSection( &ProfModulesLock );
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz)
|
|
||||||
{
|
|
||||||
ProfilerRegisterSource( fromUTF8(Name), buff, sz );
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfilerRegisterSource(const char* Name, const void* function)
|
|
||||||
{
|
|
||||||
ProfilerRegisterSource( fromUTF8(Name), function );
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfilerTerminateSource( const wxString& Name )
|
|
||||||
{
|
|
||||||
for( std::vector<Module>::const_iterator
|
|
||||||
iter = ProfModules.begin(),
|
|
||||||
end = ProfModules.end(); iter<end; ++iter )
|
|
||||||
{
|
|
||||||
if( iter->name.compare( Name ) == 0 )
|
|
||||||
{
|
|
||||||
ProfModules.erase( iter );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfilerTerminateSource( const char* Name )
|
|
||||||
{
|
|
||||||
ProfilerTerminateSource( fromUTF8(Name) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool DispatchKnownModules( uint Eip )
|
|
||||||
{
|
|
||||||
bool retval = false;
|
|
||||||
EnterCriticalSection( &ProfModulesLock );
|
|
||||||
|
|
||||||
size_t i;
|
|
||||||
for(i=0;i<ProfModules.size();i++)
|
|
||||||
if (ProfModules[i].Inside(Eip)) break;
|
|
||||||
|
|
||||||
if( i < ProfModules.size() )
|
|
||||||
{
|
|
||||||
ProfModules[i].ticks++;
|
|
||||||
retval = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
LeaveCriticalSection( &ProfModulesLock );
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MapUnknownSource( uint Eip )
|
|
||||||
{
|
|
||||||
wxChar modulename[512];
|
|
||||||
DWORD sz=GetModuleFromPtr((void*)Eip,modulename,512);
|
|
||||||
wxString modulenam( (sz==0) ? L"[Unknown]" : modulename );
|
|
||||||
|
|
||||||
std::map<wxString,Module>::iterator iter = ProfUnknownHash.find(modulenam);
|
|
||||||
if (iter!=ProfUnknownHash.end())
|
|
||||||
{
|
|
||||||
iter->second.ticks++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Module tmp((sz==0) ? modulenam.wc_str() : NULL, (void*)Eip);
|
|
||||||
tmp.ticks++;
|
|
||||||
|
|
||||||
ProfUnknownHash.insert(MapType::value_type(modulenam, tmp));
|
|
||||||
}
|
|
||||||
|
|
||||||
int __stdcall ProfilerThread(void* nada)
|
|
||||||
{
|
|
||||||
ProfUnknownHash.clear();
|
|
||||||
u32 tick_count=0;
|
|
||||||
|
|
||||||
while(ProfRunning)
|
|
||||||
{
|
|
||||||
Sleep(5);
|
|
||||||
|
|
||||||
if (tick_count>500)
|
|
||||||
{
|
|
||||||
wxString rT = L"";
|
|
||||||
wxString rv = L"";
|
|
||||||
u32 subtotal=0;
|
|
||||||
for (size_t i=0;i<ProfModules.size();i++)
|
|
||||||
{
|
|
||||||
wxString t = ProfModules[i].ToString(tick_count);
|
|
||||||
bool b0 = EmuConfig.Cpu.Recompiler.UseMicroVU0;
|
|
||||||
bool b1 = EmuConfig.Cpu.Recompiler.UseMicroVU1;
|
|
||||||
if ( b0 && b1) { if (t.Find(L"sVU") == -1) rT+=t;}
|
|
||||||
else if (!b0 && !b1) { if (t.Find(L"mVU") == -1) rT+=t;}
|
|
||||||
else if (!b0) { if (t.Find(L"mVU0") == -1) rT+=t;}
|
|
||||||
else if (!b1) { if (t.Find(L"mVU1") == -1) rT+=t;}
|
|
||||||
else rT+=t;
|
|
||||||
|
|
||||||
subtotal+=ProfModules[i].ticks;
|
|
||||||
ProfModules[i].ticks=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rT += wxsFormat( L"| Recs Total: %2.2f%% |", (float)(((double)subtotal*100.0) / (double)tick_count));
|
|
||||||
std::vector<MapType::mapped_type> lst;
|
|
||||||
for (MapType::iterator i=ProfUnknownHash.begin();i!=ProfUnknownHash.end();i++)
|
|
||||||
{
|
|
||||||
lst.push_back(i->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
sort(lst.begin(),lst.end());
|
|
||||||
for (size_t i=0;i<lst.size();i++)
|
|
||||||
{
|
|
||||||
rv += lst[i].ToString(tick_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLn( L"Sampling Profiler Results:\n%s\n%s\n", rT.c_str(), rv.c_str() );
|
|
||||||
Console.SetTitle(rT);
|
|
||||||
|
|
||||||
tick_count=0;
|
|
||||||
|
|
||||||
ProfUnknownHash.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
tick_count++;
|
|
||||||
|
|
||||||
CONTEXT ctx;
|
|
||||||
ctx.ContextFlags = CONTEXT_FULL;
|
|
||||||
GetThreadContext(hEmuThread,&ctx);
|
|
||||||
|
|
||||||
if( !DispatchKnownModules( ctx.Eip ) )
|
|
||||||
{
|
|
||||||
MapUnknownSource( ctx.Eip );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( hMtgsThread != NULL )
|
|
||||||
{
|
|
||||||
GetThreadContext(hMtgsThread,&ctx);
|
|
||||||
if( DispatchKnownModules( ctx.Eip ) )
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfilerInit()
|
|
||||||
{
|
|
||||||
if (ProfRunning)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Console.WriteLn( "Profiler Thread Initializing..." );
|
|
||||||
ProfRunning=true;
|
|
||||||
DuplicateHandle(GetCurrentProcess(),
|
|
||||||
GetCurrentThread(),
|
|
||||||
GetCurrentProcess(),
|
|
||||||
&(HANDLE)hEmuThread,
|
|
||||||
0,
|
|
||||||
FALSE,
|
|
||||||
DUPLICATE_SAME_ACCESS);
|
|
||||||
|
|
||||||
InitializeCriticalSection( &ProfModulesLock );
|
|
||||||
|
|
||||||
hProfThread=CreateThread(0,0,(LPTHREAD_START_ROUTINE)ProfilerThread,0,0,0);
|
|
||||||
SetThreadPriority(hProfThread,THREAD_PRIORITY_HIGHEST);
|
|
||||||
Console.WriteLn( "Profiler Thread Started!" );
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfilerTerm()
|
|
||||||
{
|
|
||||||
Console.WriteLn( "Profiler Terminating..." );
|
|
||||||
if (!ProfRunning)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ProfRunning=false;
|
|
||||||
|
|
||||||
if( hProfThread != NULL )
|
|
||||||
{
|
|
||||||
ResumeThread(hProfThread);
|
|
||||||
WaitForSingleObject(hProfThread,INFINITE);
|
|
||||||
CloseHandle(hProfThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( hEmuThread != NULL )
|
|
||||||
CloseHandle( hEmuThread );
|
|
||||||
|
|
||||||
if( hMtgsThread != NULL )
|
|
||||||
CloseHandle( hMtgsThread );
|
|
||||||
|
|
||||||
DeleteCriticalSection( &ProfModulesLock );
|
|
||||||
Console.WriteLn( "Profiler Termination Done!" );
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfilerSetEnabled(bool Enabled)
|
|
||||||
{
|
|
||||||
if (!ProfRunning)
|
|
||||||
{
|
|
||||||
if( !Enabled ) return;
|
|
||||||
ProfilerInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Enabled)
|
|
||||||
ResumeThread(hProfThread);
|
|
||||||
else
|
|
||||||
SuspendThread(hProfThread);
|
|
||||||
}
|
|
|
@ -57,6 +57,7 @@
|
||||||
<ItemDefinitionGroup>
|
<ItemDefinitionGroup>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalIncludeDirectories>$(ProjectRootDir)/gui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectRootDir)/gui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions Condition="'$(Platform)'=='x64'">DISABLE_SVU;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ExceptionHandling>Async</ExceptionHandling>
|
<ExceptionHandling>Async</ExceptionHandling>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
|
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
|
||||||
|
@ -202,7 +203,6 @@
|
||||||
<ClCompile Include="..\..\Pcsx2Config.cpp" />
|
<ClCompile Include="..\..\Pcsx2Config.cpp" />
|
||||||
<ClCompile Include="..\..\PluginManager.cpp" />
|
<ClCompile Include="..\..\PluginManager.cpp" />
|
||||||
<ClCompile Include="..\FlatFileReaderWindows.cpp" />
|
<ClCompile Include="..\FlatFileReaderWindows.cpp" />
|
||||||
<ClCompile Include="..\SamplProf.cpp" />
|
|
||||||
<ClCompile Include="..\..\SaveState.cpp" />
|
<ClCompile Include="..\..\SaveState.cpp" />
|
||||||
<ClCompile Include="..\..\SourceLog.cpp" />
|
<ClCompile Include="..\..\SourceLog.cpp" />
|
||||||
<ClCompile Include="..\..\System\SysCoreThread.cpp" />
|
<ClCompile Include="..\..\System\SysCoreThread.cpp" />
|
||||||
|
@ -226,10 +226,18 @@
|
||||||
<ClCompile Include="..\..\VUmicroMem.cpp" />
|
<ClCompile Include="..\..\VUmicroMem.cpp" />
|
||||||
<ClCompile Include="..\..\x86\iVU1micro.cpp" />
|
<ClCompile Include="..\..\x86\iVU1micro.cpp" />
|
||||||
<ClCompile Include="..\..\x86\microVU.cpp" />
|
<ClCompile Include="..\..\x86\microVU.cpp" />
|
||||||
<ClCompile Include="..\..\x86\sVU_Lower.cpp" />
|
<ClCompile Include="..\..\x86\sVU_Lower.cpp">
|
||||||
<ClCompile Include="..\..\x86\sVU_Micro.cpp" />
|
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
|
||||||
<ClCompile Include="..\..\x86\sVU_Upper.cpp" />
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\x86\sVU_zerorec.cpp" />
|
<ClCompile Include="..\..\x86\sVU_Micro.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\x86\sVU_Upper.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\x86\sVU_zerorec.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'=='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\VU0.cpp" />
|
<ClCompile Include="..\..\VU0.cpp" />
|
||||||
<ClCompile Include="..\..\VU0micro.cpp" />
|
<ClCompile Include="..\..\VU0micro.cpp" />
|
||||||
<ClCompile Include="..\..\VU0microInterp.cpp" />
|
<ClCompile Include="..\..\VU0microInterp.cpp" />
|
||||||
|
@ -447,7 +455,6 @@
|
||||||
<ClInclude Include="..\..\IopCommon.h" />
|
<ClInclude Include="..\..\IopCommon.h" />
|
||||||
<ClInclude Include="..\..\NakedAsm.h" />
|
<ClInclude Include="..\..\NakedAsm.h" />
|
||||||
<ClInclude Include="..\..\Plugins.h" />
|
<ClInclude Include="..\..\Plugins.h" />
|
||||||
<ClInclude Include="..\..\SamplProf.h" />
|
|
||||||
<ClInclude Include="..\..\SaveState.h" />
|
<ClInclude Include="..\..\SaveState.h" />
|
||||||
<ClInclude Include="..\..\System.h" />
|
<ClInclude Include="..\..\System.h" />
|
||||||
<ClInclude Include="..\..\System\SysThreads.h" />
|
<ClInclude Include="..\..\System\SysThreads.h" />
|
||||||
|
|
|
@ -230,9 +230,6 @@
|
||||||
<ClCompile Include="..\..\PluginManager.cpp">
|
<ClCompile Include="..\..\PluginManager.cpp">
|
||||||
<Filter>System</Filter>
|
<Filter>System</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\SamplProf.cpp">
|
|
||||||
<Filter>System</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\SaveState.cpp">
|
<ClCompile Include="..\..\SaveState.cpp">
|
||||||
<Filter>System</Filter>
|
<Filter>System</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -915,9 +912,6 @@
|
||||||
<ClInclude Include="..\..\Plugins.h">
|
<ClInclude Include="..\..\Plugins.h">
|
||||||
<Filter>System\Include</Filter>
|
<Filter>System\Include</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\SamplProf.h">
|
|
||||||
<Filter>System\Include</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\SaveState.h">
|
<ClInclude Include="..\..\SaveState.h">
|
||||||
<Filter>System\Include</Filter>
|
<Filter>System\Include</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -242,7 +242,7 @@ static void recLUT_SetPage(uptr reclut[0x10000], uptr hwlut[0x10000],
|
||||||
hwlut[page] = 0u - (pagebase << 16);
|
hwlut[page] = 0u - (pagebase << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#if defined(_M_X86_64)
|
||||||
static_assert( sizeof(BASEBLOCK) == 8, "BASEBLOCK is not 8 bytes" );
|
static_assert( sizeof(BASEBLOCK) == 8, "BASEBLOCK is not 8 bytes" );
|
||||||
#else
|
#else
|
||||||
static_assert( sizeof(BASEBLOCK) == 4, "BASEBLOCK is not 4 bytes" );
|
static_assert( sizeof(BASEBLOCK) == 4, "BASEBLOCK is not 4 bytes" );
|
||||||
|
|
|
@ -181,7 +181,7 @@ bool GSCaptureDlg::OnCommand(HWND hWnd, UINT id, UINT code)
|
||||||
m_width = GetTextAsInt(IDC_WIDTH);
|
m_width = GetTextAsInt(IDC_WIDTH);
|
||||||
m_height = GetTextAsInt(IDC_HEIGHT);
|
m_height = GetTextAsInt(IDC_HEIGHT);
|
||||||
m_filename = GetText(IDC_FILENAME);
|
m_filename = GetText(IDC_FILENAME);
|
||||||
ComboBoxGetSelData(IDC_COLORSPACE, (INT_PTR)m_colorspace);
|
ComboBoxGetSelData(IDC_COLORSPACE, m_colorspace);
|
||||||
|
|
||||||
Codec c;
|
Codec c;
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,6 @@ public:
|
||||||
int m_width;
|
int m_width;
|
||||||
int m_height;
|
int m_height;
|
||||||
string m_filename;
|
string m_filename;
|
||||||
int m_colorspace;
|
INT_PTR m_colorspace;
|
||||||
CComPtr<IBaseFilter> m_enc;
|
CComPtr<IBaseFilter> m_enc;
|
||||||
};
|
};
|
||||||
|
|
|
@ -390,7 +390,7 @@ EXPORT_C_(s32) SPU2init()
|
||||||
extern bool debugDialogOpen;
|
extern bool debugDialogOpen;
|
||||||
extern HWND hDebugDialog;
|
extern HWND hDebugDialog;
|
||||||
|
|
||||||
static BOOL CALLBACK DebugProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
static INT_PTR CALLBACK DebugProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
||||||
{
|
{
|
||||||
int wmId;
|
int wmId;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue