Make Memory::Memcpy() execute memchecks directly.

This makes it easier to handle breakpoints in HLE.
This commit is contained in:
Unknown W. Brackets 2015-04-05 18:03:50 -07:00
parent d43368f4ca
commit 2450724be2
32 changed files with 132 additions and 86 deletions

View File

@ -1339,6 +1339,7 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/MemMap.cpp
Core/MemMap.h
Core/MemMapFunctions.cpp
Core/MemMapHelpers.h
Core/PSPLoaders.cpp
Core/PSPLoaders.h
Core/Reporting.cpp

View File

@ -539,6 +539,7 @@
<ClInclude Include="HW\StereoResampler.h" />
<ClInclude Include="Loaders.h" />
<ClInclude Include="MemMap.h" />
<ClInclude Include="MemMapHelpers.h" />
<ClInclude Include="MIPS\ARM\ArmAsm.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -631,4 +632,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -1061,6 +1061,9 @@
<ClInclude Include="HLE\sceSfmt19937.h">
<Filter>HLE\Libraries</Filter>
</ClInclude>
<ClInclude Include="MemMapHelpers.h">
<Filter>Core</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />

View File

@ -413,7 +413,7 @@ void CWCheatEngine::Run() {
int len = arg;
InvalidateICache(destAddr, len);
if (Memory::IsValidAddress(addr) && Memory::IsValidAddress(destAddr)) {
Memory::Memcpy(destAddr, Memory::GetPointer(addr), len);
Memory::MemcpyUnchecked(destAddr, addr, len);
}
}
break;
@ -442,7 +442,9 @@ void CWCheatEngine::Run() {
{
int srcAddr = Memory::Read_U32(addr) + offset;
int dstAddr = Memory::Read_U16(addr + baseOffset) + (arg3 & 0x0FFFFFFF);
Memory::Memcpy(dstAddr, Memory::GetPointer(srcAddr), arg);
if (Memory::IsValidAddress(dstAddr) && Memory::IsValidAddress(srcAddr)) {
Memory::MemcpyUnchecked(dstAddr, srcAddr, arg);
}
type = -1; //Done
break; }
case 0x2:

View File

@ -16,7 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/ChunkFile.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/System.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/Dialog/PSPGamedataInstallDialog.h"

View File

@ -15,12 +15,12 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "PSPMsgDialog.h"
#include "../Util/PPGeDraw.h"
#include "../HLE/sceCtrl.h"
#include "../Core/MemMap.h"
#include "Core/Dialog/PSPMsgDialog.h"
#include "Core/Util/PPGeDraw.h"
#include "Core/HLE/sceCtrl.h"
#include "Core/MemMapHelpers.h"
#include "Core/Reporting.h"
#include "ChunkFile.h"
#include "Common/ChunkFile.h"
#include "i18n/i18n.h"
#include "util/text/utf8.h"

View File

@ -18,7 +18,7 @@
#include "PSPNetconfDialog.h"
#include "ChunkFile.h"
#include "Core/Config.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/HLE/sceNetAdhoc.h"
#include "Core/Util/PPGeDraw.h"
#include "Core/HLE/sceCtrl.h"

View File

@ -24,7 +24,7 @@
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/Util/PPGeDraw.h"
#include "Core/HLE/sceCtrl.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/Config.h"
#include "Core/Reporting.h"
#include "Core/HW/MemoryStick.h"

View File

@ -24,7 +24,7 @@
#include "Core/Config.h"
#include "Core/CoreTiming.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/Reporting.h"
#include "Core/Core.h"

View File

@ -16,7 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/ChunkFile.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/HLEHelperThread.h"
#include "Core/HLE/sceKernelThread.h"

View File

@ -30,7 +30,7 @@
#include "Core/Config.h"
#include "Core/CoreTiming.h"
#include "Core/Host.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/Reporting.h"
#include "Core/HLE/__sceAudio.h"
#include "Core/HLE/sceAudio.h"

View File

@ -21,7 +21,7 @@
#include "Core/HLE/FunctionWrappers.h"
#include "Core/MIPS/MIPS.h"
#include "Core/CoreTiming.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/Reporting.h"
#include "Core/Config.h"
#include "Core/Debugger/Breakpoints.h"
@ -803,7 +803,6 @@ u32 _AtracAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd) {
return 0;
int addbytes = std::min(bytesToAdd, atrac->first.filesize - atrac->first.fileoffset);
Memory::Memcpy(atrac->data_buf + atrac->first.fileoffset, bufPtr, addbytes);
CBreakPoints::ExecMemCheck(bufPtr, false, addbytes, currentMIPS->pc);
atrac->first.size += bytesToAdd;
if (atrac->first.size > atrac->first.filesize)
atrac->first.size = atrac->first.filesize;
@ -839,7 +838,6 @@ static u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd) {
if (bytesToAdd > 0) {
int addbytes = std::min(bytesToAdd, atrac->first.filesize - atrac->first.fileoffset);
Memory::Memcpy(atrac->data_buf + atrac->first.fileoffset, atrac->first.addr + atrac->first.offset, addbytes);
CBreakPoints::ExecMemCheck(atrac->first.addr + atrac->first.offset, false, addbytes, currentMIPS->pc);
}
atrac->first.size += bytesToAdd;
if (atrac->first.size > atrac->first.filesize)
@ -1533,7 +1531,6 @@ static int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize) {
atrac->data_buf = new u8[atrac->first.filesize];
u32 copybytes = std::min(bufferSize, atrac->first.filesize);
Memory::Memcpy(atrac->data_buf, buffer, copybytes);
CBreakPoints::ExecMemCheck(buffer, false, copybytes, currentMIPS->pc);
return __AtracSetContext(atrac);
#endif // USE_FFMPEG
@ -1546,7 +1543,6 @@ static int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize) {
atrac->data_buf = new u8[atrac->first.filesize];
u32 copybytes = std::min(bufferSize, atrac->first.filesize);
Memory::Memcpy(atrac->data_buf, buffer, copybytes);
CBreakPoints::ExecMemCheck(buffer, false, copybytes, currentMIPS->pc);
return __AtracSetContext(atrac);
}
@ -2184,7 +2180,6 @@ static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesCo
u32 sourcebytes = atrac->first.writableBytes;
if (sourcebytes > 0) {
Memory::Memcpy(atrac->data_buf + atrac->first.size, sourceAddr, sourcebytes);
CBreakPoints::ExecMemCheck(sourceAddr, false, sourcebytes, currentMIPS->pc);
if (atrac->bufferPos >= atrac->first.size) {
atrac->bufferPos = atrac->first.size;
}

View File

@ -17,7 +17,7 @@
#include "Common/ChunkFile.h"
#include "Core/CoreTiming.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/Reporting.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/sceDmac.h"
@ -44,11 +44,6 @@ void __DmacDoState(PointerWrap &p) {
}
static int __DmacMemcpy(u32 dst, u32 src, u32 size) {
#ifndef MOBILE_DEVICE
CBreakPoints::ExecMemCheck(src, false, size, currentMIPS->pc);
CBreakPoints::ExecMemCheck(dst, true, size, currentMIPS->pc);
#endif
bool skip = false;
if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) {
skip = gpu->PerformMemoryCopy(dst, src, size);

View File

@ -19,6 +19,7 @@
#include <list>
#include <map>
#include "Core/MemMapHelpers.h"
#include "Core/Reporting.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/FunctionWrappers.h"

View File

@ -27,7 +27,7 @@
#include "Core/HLE/FunctionWrappers.h"
#include "Core/System.h"
#include "Core/MIPS/MIPS.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/CoreTiming.h"
#include "Core/Reporting.h"

View File

@ -41,7 +41,7 @@
#include "Core/CoreTiming.h"
#include "Core/PSPLoaders.h"
#include "Core/System.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/Debugger/SymbolMap.h"
#include "Core/MIPS/MIPS.h"

View File

@ -19,7 +19,7 @@
#include "Core/Reporting.h"
#include "Core/CoreTiming.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/sceKernel.h"
#include "Core/HLE/sceKernelMsgPipe.h"
@ -101,17 +101,17 @@ struct MsgPipeWaitingThread
Complete(waitID, result);
}
void ReadBuffer(u8 *dest, u32 len)
void ReadBuffer(u32 destPtr, u32 len)
{
Memory::Memcpy(dest, bufAddr + bufSize - freeSize, len);
Memory::Memcpy(destPtr, bufAddr + bufSize - freeSize, len);
freeSize -= len;
if (transferredBytes.IsValid())
*transferredBytes += len;
}
void WriteBuffer(const u8 *src, u32 len)
void WriteBuffer(u32 srcPtr, u32 len)
{
Memory::Memcpy(bufAddr + (bufSize - freeSize), src, len);
Memory::Memcpy(bufAddr + (bufSize - freeSize), srcPtr, len);
freeSize -= len;
if (transferredBytes.IsValid())
*transferredBytes += len;
@ -180,7 +180,7 @@ struct MsgPipe : public KernelObject
MsgPipeWaitingThread *thread = &sendWaitingThreads.front();
u32 bytesToSend = std::min(thread->freeSize, (u32) nmp.freeSize);
thread->ReadBuffer(Memory::GetPointer(buffer + GetUsedSize()), bytesToSend);
thread->ReadBuffer(buffer + GetUsedSize(), bytesToSend);
nmp.freeSize -= bytesToSend;
filledSpace = true;
@ -216,7 +216,7 @@ struct MsgPipe : public KernelObject
u32 bytesToSend = std::min(thread->freeSize, GetUsedSize());
u8* ptr = Memory::GetPointer(buffer);
thread->WriteBuffer(ptr, bytesToSend);
thread->WriteBuffer(buffer, bytesToSend);
// Put the unused data at the start of the buffer.
nmp.freeSize += bytesToSend;
memmove(ptr, ptr + bytesToSend, GetUsedSize());
@ -343,7 +343,7 @@ static int __KernelSendMsgPipe(MsgPipe *m, u32 sendBufAddr, u32 sendSize, int wa
u32 bytesToSend = std::min(thread->freeSize, sendSize);
if (bytesToSend > 0)
{
thread->WriteBuffer(Memory::GetPointer(curSendAddr), bytesToSend);
thread->WriteBuffer(curSendAddr, bytesToSend);
sendSize -= bytesToSend;
curSendAddr += bytesToSend;
@ -396,7 +396,7 @@ static int __KernelSendMsgPipe(MsgPipe *m, u32 sendBufAddr, u32 sendSize, int wa
if (bytesToSend != 0)
{
Memory::Memcpy(m->buffer + (m->nmp.bufSize - m->nmp.freeSize), Memory::GetPointer(sendBufAddr), bytesToSend);
Memory::Memcpy(m->buffer + (m->nmp.bufSize - m->nmp.freeSize), sendBufAddr, bytesToSend);
m->nmp.freeSize -= bytesToSend;
curSendAddr += bytesToSend;
sendSize -= bytesToSend;
@ -443,7 +443,7 @@ static int __KernelReceiveMsgPipe(MsgPipe *m, u32 receiveBufAddr, u32 receiveSiz
u32 bytesToReceive = std::min(thread->freeSize, receiveSize);
if (bytesToReceive > 0)
{
thread->ReadBuffer(Memory::GetPointer(curReceiveAddr), bytesToReceive);
thread->ReadBuffer(curReceiveAddr, bytesToReceive);
receiveSize -= bytesToReceive;
curReceiveAddr += bytesToReceive;
@ -489,7 +489,7 @@ static int __KernelReceiveMsgPipe(MsgPipe *m, u32 receiveBufAddr, u32 receiveSiz
u32 bytesToReceive = std::min(receiveSize, m->GetUsedSize());
if (bytesToReceive != 0)
{
Memory::Memcpy(curReceiveAddr, Memory::GetPointer(m->buffer), bytesToReceive);
Memory::Memcpy(curReceiveAddr, m->buffer, bytesToReceive);
m->nmp.freeSize += bytesToReceive;
memmove(Memory::GetPointer(m->buffer), Memory::GetPointer(m->buffer) + bytesToReceive, m->GetUsedSize());
curReceiveAddr += bytesToReceive;

View File

@ -28,7 +28,7 @@
#include "Core/MIPS/MIPSCodeUtils.h"
#include "Core/MIPS/MIPS.h"
#include "Core/CoreTiming.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/Reporting.h"
#include "Common/ChunkFile.h"
@ -2198,7 +2198,7 @@ int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bo
// Now copy argument to stack.
if (!forceArgs && Memory::IsValidAddress(argBlockPtr))
Memory::Memcpy(sp, Memory::GetPointer(argBlockPtr), argSize);
Memory::Memcpy(sp, argBlockPtr, argSize);
// On the PSP, there's an extra 64 bytes of stack eaten after the args.
// This could be stack overflow safety, or just stack eaten by the kernel entry func.

View File

@ -17,7 +17,7 @@
#include <algorithm>
#include "Core/CoreTiming.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/Reporting.h"
#include "Core/HLE/sceKernel.h"
#include "Core/HLE/sceKernelInterrupt.h"

View File

@ -27,6 +27,7 @@
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HW/MediaEngine.h"
#include "Core/Config.h"
#include "Core/MemMapHelpers.h"
#include "Core/Reporting.h"
#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"

View File

@ -21,7 +21,7 @@
// This is a direct port of Coldbird's code from http://code.google.com/p/aemu/
// All credit goes to him!
#include "Core/Core.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Common/ChunkFile.h"
#include "Core/MIPS/MIPSCodeUtils.h"

View File

@ -15,14 +15,14 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/ChunkFile.h"
#include "Core/MemMapHelpers.h"
#include "Core/Reporting.h"
#include "Core/System.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/HLEHelperThread.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Common/ChunkFile.h"
#include "Core/Reporting.h"
#include "Core/System.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/HLE/scePsmf.h"
#include "Core/HLE/sceMpeg.h"
#include "Core/HW/MediaEngine.h"

View File

@ -17,7 +17,7 @@
#include "base/basictypes.h"
#include "Globals.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/HLE/sceAtrac.h"
#include "Core/Config.h"
#include "Core/Reporting.h"

View File

@ -5,7 +5,7 @@
#include <cstdarg>
#include <cstring>
#include "util/text/utf8.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/MIPS/JitCommon/NativeJit.h"
#include "Core/Debugger/SymbolMap.h"

View File

@ -501,10 +501,4 @@ void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength)
#endif
}
const char *GetAddressName(u32 address)
{
// TODO, follow GetPointer
return "[mem]";
}
} // namespace

View File

@ -257,31 +257,21 @@ inline const char* GetCharPointer(const u32 address) {
return (const char *)GetPointer(address);
}
void Memset(const u32 _Address, const u8 _Data, const u32 _iLength);
inline void Memcpy(const u32 to_address, const void *from_data, const u32 len)
{
u8 *to = GetPointer(to_address);
if (to) {
memcpy(to, from_data, len);
}
// if not, GetPointer will log.
}
inline void Memcpy(void *to_data, const u32 from_address, const u32 len)
{
const u8 *from = GetPointer(from_address);
if (from) {
memcpy(to_data, from, len);
}
// if not, GetPointer will log.
}
inline void MemcpyUnchecked(void *to_data, const u32 from_address, const u32 len)
{
memcpy(to_data, GetPointerUnchecked(from_address), len);
}
inline void MemcpyUnchecked(const u32 to_address, const void *from_data, const u32 len)
{
memcpy(GetPointerUnchecked(to_address), from_data, len);
}
inline void MemcpyUnchecked(const u32 to_address, const u32 from_address, const u32 len)
{
MemcpyUnchecked(GetPointer(to_address), from_address, len);
}
inline bool IsValidAddress(const u32 address) {
if ((address & 0x3E000000) == 0x08000000) {
return true;
@ -314,8 +304,6 @@ void WriteStruct(u32 address, T *ptr)
memcpy(GetPointer(address), ptr, sz);
}
const char *GetAddressName(u32 address);
};
template <typename T>

65
Core/MemMapHelpers.h Normal file
View File

@ -0,0 +1,65 @@
// Copyright (C) 2003 Dolphin Project / 2012 PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#include "Common/CommonTypes.h"
#include "Core/Debugger/Breakpoints.h"
#include "Core/MemMap.h"
#include "Core/MIPS/MIPS.h"
// To avoid pulling in the entire HLE.h.
extern MIPSState *currentMIPS;
namespace Memory
{
inline void Memcpy(const u32 to_address, const void *from_data, const u32 len)
{
u8 *to = GetPointer(to_address);
if (to) {
memcpy(to, from_data, len);
#ifndef MOBILE_DEVICE
CBreakPoints::ExecMemCheck(to_address, true, len, currentMIPS->pc);
#endif
}
// if not, GetPointer will log.
}
inline void Memcpy(void *to_data, const u32 from_address, const u32 len)
{
const u8 *from = GetPointer(from_address);
if (from) {
memcpy(to_data, from, len);
#ifndef MOBILE_DEVICE
CBreakPoints::ExecMemCheck(from_address, false, len, currentMIPS->pc);
#endif
}
// if not, GetPointer will log.
}
inline void Memcpy(const u32 to_address, const u32 from_address, const u32 len)
{
#ifndef MOBILE_DEVICE
CBreakPoints::ExecMemCheck(to_address, true, len, currentMIPS->pc);
#endif
Memcpy(GetPointer(to_address), from_address, len);
}
void Memset(const u32 _Address, const u8 _Data, const u32 _iLength);
}

View File

@ -31,7 +31,7 @@
#include "Core/HLE/sceKernel.h"
#include "Core/HLE/sceKernelMemory.h"
#include "Core/HLE/sceGe.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/System.h"
static u32 atlasPtr;

View File

@ -20,7 +20,7 @@
#include "Common/ChunkFile.h"
#include "base/logging.h"
#include "Core/Debugger/Breakpoints.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/MIPS/MIPS.h"
#include "Core/Host.h"
#include "Core/Config.h"
@ -1912,7 +1912,7 @@ void DIRECTX9_GPU::PerformMemoryCopyInternal(u32 dest, u32 src, int size) {
// We use a little hack for Download/Upload using a VRAM mirror.
// Since they're identical we don't need to copy.
if (!Memory::IsVRAMAddress(dest) || (dest ^ 0x00400000) != src) {
Memory::Memcpy(dest, Memory::GetPointer(src), size);
Memory::Memcpy(dest, src, size);
}
}
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);

View File

@ -1535,7 +1535,7 @@ void *TextureCacheDX9::DecodeTextureLevel(GETextureFormat format, GEPaletteForma
int len = std::max(bufw, w) * h;
tmpTexBuf16.resize(len);
tmpTexBufRearrange.resize(len);
Memory::Memcpy(tmpTexBuf16.data(), texaddr, len * sizeof(u16));
Memory::MemcpyUnchecked(tmpTexBuf16.data(), texaddr, len * sizeof(u16));
finalBuf = tmpTexBuf16.data();
}
else {
@ -1554,7 +1554,7 @@ void *TextureCacheDX9::DecodeTextureLevel(GETextureFormat format, GEPaletteForma
int len = bufw * h;
tmpTexBuf32.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
Memory::Memcpy(tmpTexBuf32.data(), texaddr, len * sizeof(u32));
Memory::MemcpyUnchecked(tmpTexBuf32.data(), texaddr, len * sizeof(u32));
finalBuf = tmpTexBuf32.data();
}
} else {

View File

@ -1597,7 +1597,7 @@ void FramebufferManager::PackFramebufferAsync_(VirtualFramebuffer *vfb) {
ConvertFromRGBA8888(dst, packed, pbo.stride, pbo.stride, pbo.stride, pbo.height, pbo.format);
} else {
// We don't need to convert, GPU already did (or should have)
Memory::Memcpy(pbo.fb_address, packed, pbo.size);
Memory::MemcpyUnchecked(pbo.fb_address, packed, pbo.size);
}
pbo.reading = false;

View File

@ -21,7 +21,7 @@
#include "Common/ChunkFile.h"
#include "Core/Debugger/Breakpoints.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/Host.h"
#include "Core/Config.h"
#include "Core/Reporting.h"
@ -2053,7 +2053,7 @@ void GLES_GPU::PerformMemoryCopyInternal(u32 dest, u32 src, int size) {
// We use a little hack for Download/Upload using a VRAM mirror.
// Since they're identical we don't need to copy.
if (!Memory::IsVRAMAddress(dest) || (dest ^ 0x00400000) != src) {
Memory::Memcpy(dest, Memory::GetPointer(src), size);
Memory::Memcpy(dest, src, size);
}
}
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);