Merge remote-tracking branch 'remotes/origin/master' into dsi_camera

This commit is contained in:
Arisotura 2020-12-04 18:28:15 +01:00
commit 129018a662
51 changed files with 1772 additions and 760 deletions

39
.github/workflows/build-macos.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: CMake Build (macOS x86-64)
on:
push:
branches:
- master
pull_request:
branches:
- master
env:
BUILD_TYPE: Release
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: Install dependencies
working-directory: ${{runner.workspace}}
run: |
brew install cmake sdl2 qt5 libslirp
- name: Create build environment
run: mkdir ${{runner.workspace}}/build
- name: Configure
working-directory: ${{runner.workspace}}/build
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DQt5_DIR=$(brew --prefix qt5)/lib/cmake/Qt5
- name: Make
working-directory: ${{runner.workspace}}/build
run: |
make -j$(sysctl -n hw.ncpu)
mkdir dist
cp -r melonDS.app dist
- uses: actions/upload-artifact@v1
with:
name: melonDS.app
path: ${{runner.workspace}}/build/dist

View File

@ -29,6 +29,7 @@ jobs:
shell: bash
working-directory: ${{runner.workspace}}
run: |
sudo rm -f /etc/apt/sources.list.d/kubernetes.list
sudo dpkg --add-architecture arm64
sudo sh -c "sed \"s|^deb \([a-z\.:/]*\) \([a-z\-]*\) \(.*\)$|deb [arch=amd64] \1 \2 \3\ndeb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports \2 \3|\" /etc/apt/sources.list > /etc/apt/sources.list.new"
sudo rm /etc/apt/sources.list

View File

@ -1,20 +1,30 @@
cmake_minimum_required(VERSION 3.13)
include(CheckSymbolExists)
include(CheckLibraryExists)
cmake_policy(VERSION 3.13)
if (POLICY CMP0076)
cmake_policy(SET CMP0076 NEW)
endif()
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
project(melonDS CXX)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
project(melonDS)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
check_library_exists(m pow "" LIBM)
if(LIBM)
link_libraries(m)
endif()
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
include(CheckSymbolExists)
function(detect_architecture symbol arch)
if (NOT DEFINED ARCHITECTURE)
set(CMAKE_REQUIRED_QUIET 1)
@ -65,8 +75,22 @@ if (CMAKE_BUILD_TYPE STREQUAL Release)
add_link_options(-s)
endif()
add_compile_options(-fno-pic)
add_link_options(-no-pie)
if (ENABLE_LTO)
add_compile_options(-flto -fPIC)
add_link_options(-flto -fuse-linker-plugin -pie)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_AR "gcc-ar")
set(CMAKE_RANLIB "gcc-ranlib")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
find_program(LLD NAMES ld.lld ld64.lld lld-link)
if (NOT LLD STREQUAL "LLD-NOTFOUND")
add_link_options(-fuse-ld=lld)
endif()
set(CMAKE_AR "llvm-ar")
set(CMAKE_RANLIB "llvm-ranlib")
endif()
option(BUILD_QT_SDL "Build Qt/SDL frontend" ON)

View File

@ -38,7 +38,7 @@ As for the rest, the interface should be pretty straightforward. If you have a q
* Install dependencies:
```sh
sudo apt-get install cmake libgtk-3-dev libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qtbase5-dev qtdeclarative5-dev libslirp-dev
sudo apt-get install cmake libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qtbase5-dev qtdeclarative5-dev libslirp-dev
```
* Compile:
@ -84,6 +84,21 @@ If everything went well, melonDS and the libraries it needs should now be in the
```
If everything went well, melonDS should now be in the `dist` folder.
### macOS:
1. Install the [Homebrew Package Manager](https://brew.sh)
2. Install dependencies: `brew install git pkg-config cmake sdl2 qt5 libslirp`
3. Compile:
```zsh
git clone https://github.com/Arisotura/melonDS.git
cd melonDS
mkdir build && cd build
cmake .. -DQt5_DIR=$(brew --prefix qt5)/lib/cmake/Qt5
make -j$(sysctl -n hw.ncpu)
mkdir dist && cp -r melonDS.app dist
```
If everything went well, melonDS.app should now be in the `dist` folder.
## TODO LIST
* DSi emulation

BIN
melonDS.icns Normal file

Binary file not shown.

24
melonDS.plist Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>melonDS</string>
<key>CFBundleIconFile</key>
<string>melonDS.icns</string>
<key>CFBundleIdentifier</key>
<string>net.kuribo64.melonDS</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleVersion</key>
<string>0.9</string>
<key>CFBundleShortVersionString</key>
<string>0.9</string>
<key>NSHumanReadableCopyright</key>
<string>Licensed under GPLv3</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>

View File

@ -176,7 +176,7 @@ T SlowRead9(u32 addr, ARMv5* cpu)
}
template <typename T, int ConsoleType>
void SlowWrite9(u32 addr, ARMv5* cpu, T val)
void SlowWrite9(u32 addr, ARMv5* cpu, u32 val)
{
addr &= ~(sizeof(T) - 1);
@ -224,7 +224,7 @@ T SlowRead7(u32 addr)
}
template <typename T, int ConsoleType>
void SlowWrite7(u32 addr, T val)
void SlowWrite7(u32 addr, u32 val)
{
addr &= ~(sizeof(T) - 1);
@ -266,16 +266,16 @@ void SlowBlockTransfer7(u32 addr, u64* data, u32 num)
#define INSTANTIATE_SLOWMEM(consoleType) \
template void SlowWrite9<u32, consoleType>(u32, ARMv5*, u32); \
template void SlowWrite9<u16, consoleType>(u32, ARMv5*, u16); \
template void SlowWrite9<u8, consoleType>(u32, ARMv5*, u8); \
template void SlowWrite9<u16, consoleType>(u32, ARMv5*, u32); \
template void SlowWrite9<u8, consoleType>(u32, ARMv5*, u32); \
\
template u32 SlowRead9<u32, consoleType>(u32, ARMv5*); \
template u16 SlowRead9<u16, consoleType>(u32, ARMv5*); \
template u8 SlowRead9<u8, consoleType>(u32, ARMv5*); \
\
template void SlowWrite7<u32, consoleType>(u32, u32); \
template void SlowWrite7<u16, consoleType>(u32, u16); \
template void SlowWrite7<u8, consoleType>(u32, u8); \
template void SlowWrite7<u16, consoleType>(u32, u32); \
template void SlowWrite7<u8, consoleType>(u32, u32); \
\
template u32 SlowRead7<u32, consoleType>(u32); \
template u16 SlowRead7<u16, consoleType>(u32); \
@ -298,6 +298,7 @@ void Init()
void DeInit()
{
ResetBlockCache();
ARMJIT_Memory::DeInit();
delete JITCompiler;
@ -594,7 +595,8 @@ void CompileBlock(ARM* cpu)
u32 r15 = cpu->R[15];
u32 addressRanges[Config::JIT_MaxBlockSize];
u32 addressMasks[Config::JIT_MaxBlockSize] = {0};
u32 addressMasks[Config::JIT_MaxBlockSize];
memset(addressMasks, 0, Config::JIT_MaxBlockSize * sizeof(u32));
u32 numAddressRanges = 0;
u32 numLiterals = 0;
@ -1116,6 +1118,7 @@ void ResetBlockCache()
range->Blocks.Clear();
range->Code = 0;
}
delete block;
}
JitBlocks9.clear();
JitBlocks7.clear();

View File

@ -68,6 +68,11 @@ void Compiler::A_Comp_MRS()
MOV(rd, RCPSR);
}
void UpdateModeTrampoline(ARM* arm, u32 oldmode, u32 newmode)
{
arm->UpdateMode(oldmode, newmode);
}
void Compiler::A_Comp_MSR()
{
Comp_AddCycles_C();
@ -139,7 +144,7 @@ void Compiler::A_Comp_MSR()
PushRegs(true);
QuickCallFunction(X3, (void*)&ARM::UpdateMode);
QuickCallFunction(X3, (void*)&UpdateModeTrampoline);
PopRegs(true);
}

View File

@ -187,6 +187,7 @@ public:
void Comp_RegShiftReg(int op, bool S, Op2& op2, Arm64Gen::ARM64Reg rs);
bool Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr);
enum
{
memop_Writeback = 1 << 0,
@ -213,8 +214,8 @@ public:
return (u8*)entry - GetRXBase();
}
bool IsJITFault(u64 pc);
s64 RewriteMemAccess(u64 pc);
bool IsJITFault(u8* pc);
u8* RewriteMemAccess(u8* pc);
void SwapCodeRegion()
{

View File

@ -9,37 +9,34 @@ using namespace Arm64Gen;
namespace ARMJIT
{
bool Compiler::IsJITFault(u64 pc)
bool Compiler::IsJITFault(u8* pc)
{
return pc >= (u64)GetRXBase() && pc - (u64)GetRXBase() < (JitMemMainSize + JitMemSecondarySize);
return (u64)pc >= (u64)GetRXBase() && (u64)pc - (u64)GetRXBase() < (JitMemMainSize + JitMemSecondarySize);
}
s64 Compiler::RewriteMemAccess(u64 pc)
u8* Compiler::RewriteMemAccess(u8* pc)
{
ptrdiff_t pcOffset = pc - (u64)GetRXBase();
ptrdiff_t pcOffset = pc - GetRXBase();
auto it = LoadStorePatches.find(pcOffset);
if (it != LoadStorePatches.end())
{
LoadStorePatch patch = it->second;
LoadStorePatches.erase(it);
ptrdiff_t curCodeOffset = GetCodeOffset();
SetCodePtrUnsafe(pcOffset + patch.PatchOffset);
BL(patch.PatchFunc);
for (int i = 0; i < patch.PatchSize / 4 - 1; i++)
HINT(HINT_NOP);
FlushIcacheSection((u8*)pc + patch.PatchOffset, (u8*)GetRXPtr());
SetCodePtrUnsafe(curCodeOffset);
LoadStorePatches.erase(it);
return patch.PatchOffset;
return pc + (ptrdiff_t)patch.PatchOffset;
}
printf("this is a JIT bug! %08x\n", __builtin_bswap32(*(u32*)pc));
abort();
@ -192,7 +189,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
else
{
LDRGeneric(size, flags & memop_SignExtend, rdMapped, size > 8 ? X1 : X0, X7);
if (size == 32)
if (size == 32 && !addrIsStatic)
{
UBFIZ(W0, W0, 3, 2);
RORV(rdMapped, rdMapped, W0);

View File

@ -216,9 +216,9 @@ template <u32 Num>
void LinkBlock(ARM* cpu, u32 codeOffset);
template <typename T, int ConsoleType> T SlowRead9(u32 addr, ARMv5* cpu);
template <typename T, int ConsoleType> void SlowWrite9(u32 addr, ARMv5* cpu, T val);
template <typename T, int ConsoleType> void SlowWrite9(u32 addr, ARMv5* cpu, u32 val);
template <typename T, int ConsoleType> T SlowRead7(u32 addr);
template <typename T, int ConsoleType> void SlowWrite7(u32 addr, T val);
template <typename T, int ConsoleType> void SlowWrite7(u32 addr, u32 val);
template <bool Write, int ConsoleType> void SlowBlockTransfer9(u32 addr, u64* data, u32 num, ARMv5* cpu);
template <bool Write, int ConsoleType> void SlowBlockTransfer7(u32 addr, u64* data, u32 num);

View File

@ -10,6 +10,12 @@
#include <signal.h>
#endif
#if defined(__ANDROID__)
#include <dlfcn.h>
#include <linux/ashmem.h>
#include <sys/ioctl.h>
#endif
#include "ARMJIT_Memory.h"
#include "ARMJIT_Internal.h"
@ -22,7 +28,9 @@
#include "NDSCart.h"
#include "SPU.h"
#ifndef __APPLE__
#include <malloc.h>
#endif
/*
We're handling fastmem here.
@ -40,7 +48,8 @@
We handle this by only mapping those regions which are actually
used and by praying the games don't go wild.
Beware, this file is full of platform specific code.
Beware, this file is full of platform specific code and copied
from Dolphin, so enjoy the copied comments!
*/
@ -49,12 +58,16 @@ namespace ARMJIT_Memory
struct FaultDescription
{
u32 EmulatedFaultAddr;
u64 FaultPC;
u8* FaultPC;
};
bool FaultHandler(FaultDescription* faultDesc, s32& offset);
bool FaultHandler(FaultDescription& faultDesc);
}
#if defined(__ANDROID__)
#define ASHMEM_DEVICE "/dev/ashmem"
#endif
#if defined(__SWITCH__)
// with LTO the symbols seem to be not properly overriden
// if they're somewhere else
@ -75,7 +88,7 @@ void __libnx_exception_handler(ThreadExceptionDump* ctx)
ARMJIT_Memory::FaultDescription desc;
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
desc.EmulatedFaultAddr = (u8*)ctx->far.x - curArea;
desc.FaultPC = ctx->pc.x;
desc.FaultPC = (u8*)ctx->pc.x;
u64 integerRegisters[33];
memcpy(integerRegisters, &ctx->cpu_gprs[0].x, 8*29);
@ -84,10 +97,9 @@ void __libnx_exception_handler(ThreadExceptionDump* ctx)
integerRegisters[31] = ctx->sp.x;
integerRegisters[32] = ctx->pc.x;
s32 offset;
if (ARMJIT_Memory::FaultHandler(&desc, offset))
if (ARMJIT_Memory::FaultHandler(desc, offset))
{
integerRegisters[32] += offset;
integerRegisters[32] = (u64)desc.FaultPC;
ARM_RestoreContext(integerRegisters);
}
@ -117,12 +129,11 @@ static LONG ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
ARMJIT_Memory::FaultDescription desc;
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
desc.EmulatedFaultAddr = (u8*)exceptionInfo->ExceptionRecord->ExceptionInformation[1] - curArea;
desc.FaultPC = exceptionInfo->ContextRecord->Rip;
desc.FaultPC = (u8*)exceptionInfo->ContextRecord->Rip;
s32 offset = 0;
if (ARMJIT_Memory::FaultHandler(&desc, offset))
if (ARMJIT_Memory::FaultHandler(desc))
{
exceptionInfo->ContextRecord->Rip += offset;
exceptionInfo->ContextRecord->Rip = (u64)desc.FaultPC;
return EXCEPTION_CONTINUE_EXECUTION;
}
@ -131,50 +142,75 @@ static LONG ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
#else
struct sigaction NewSa;
struct sigaction OldSa;
static struct sigaction OldSaSegv;
static struct sigaction OldSaBus;
static void SigsegvHandler(int sig, siginfo_t* info, void* rawContext)
{
if (sig != SIGSEGV && sig != SIGBUS)
{
// We are not interested in other signals - handle it as usual.
return;
}
if (info->si_code != SEGV_MAPERR && info->si_code != SEGV_ACCERR)
{
// Huh? Return.
return;
}
ucontext_t* context = (ucontext_t*)rawContext;
ARMJIT_Memory::FaultDescription desc;
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
#ifdef __x86_64__
desc.EmulatedFaultAddr = (u8*)info->si_addr - curArea;
desc.FaultPC = context->uc_mcontext.gregs[REG_RIP];
#ifdef __APPLE__
desc.FaultPC = (u8*)context->uc_mcontext->__ss.__rip;
#else
desc.FaultPC = (u8*)context->uc_mcontext.gregs[REG_RIP];
#endif
#else
desc.EmulatedFaultAddr = (u8*)context->uc_mcontext.fault_address - curArea;
desc.FaultPC = context->uc_mcontext.pc;
desc.FaultPC = (u8*)context->uc_mcontext.pc;
#endif
s32 offset = 0;
if (ARMJIT_Memory::FaultHandler(&desc, offset))
if (ARMJIT_Memory::FaultHandler(desc))
{
#ifdef __x86_64__
context->uc_mcontext.gregs[REG_RIP] += offset;
#ifdef __APPLE__
context->uc_mcontext->__ss.__rip = (u64)desc.FaultPC;
#else
context->uc_mcontext.gregs[REG_RIP] = (u64)desc.FaultPC;
#endif
#else
context->uc_mcontext.pc += offset;
context->uc_mcontext.pc = (u64)desc.FaultPC;
#endif
return;
}
if (OldSa.sa_flags & SA_SIGINFO)
struct sigaction* oldSa;
if (sig == SIGSEGV)
oldSa = &OldSaSegv;
else
oldSa = &OldSaBus;
if (oldSa->sa_flags & SA_SIGINFO)
{
OldSa.sa_sigaction(sig, info, rawContext);
oldSa->sa_sigaction(sig, info, rawContext);
return;
}
if (OldSa.sa_handler == SIG_DFL)
if (oldSa->sa_handler == SIG_DFL)
{
signal(sig, SIG_DFL);
return;
}
if (OldSa.sa_handler == SIG_IGN)
if (oldSa->sa_handler == SIG_IGN)
{
// Ignore signal
return;
}
OldSa.sa_handler(sig);
oldSa->sa_handler(sig);
}
#endif
@ -231,7 +267,7 @@ enum
{
memstate_Unmapped,
memstate_MappedRW,
// on switch this is unmapped as well
// on Switch this is unmapped as well
memstate_MappedProtected,
};
@ -314,14 +350,16 @@ struct Mapping
void Unmap(int region)
{
u32 dtcmStart = NDS::ARM9->DTCMBase;
u32 dtcmSize = NDS::ARM9->DTCMSize;
bool skipDTCM = Num == 0 && region != memregion_DTCM;
u8* statuses = Num == 0 ? MappingStatus9 : MappingStatus7;
u32 offset = 0;
while (offset < Size)
{
if (skipDTCM && Addr + offset == NDS::ARM9->DTCMBase)
if (skipDTCM && Addr + offset == dtcmStart)
{
offset += NDS::ARM9->DTCMSize;
offset += dtcmSize;
}
else
{
@ -329,7 +367,7 @@ struct Mapping
u8 status = statuses[(Addr + offset) >> 12];
while (statuses[(Addr + offset) >> 12] == status
&& offset < Size
&& (!skipDTCM || Addr + offset != NDS::ARM9->DTCMBase))
&& (!skipDTCM || Addr + offset != dtcmStart))
{
assert(statuses[(Addr + offset) >> 12] != memstate_Unmapped);
statuses[(Addr + offset) >> 12] = memstate_Unmapped;
@ -347,9 +385,33 @@ struct Mapping
#endif
}
}
#ifndef __SWITCH__
bool succeded = UnmapFromRange(Addr, Num, OffsetsPerRegion[region] + LocalOffset, Size);
assert(succeded);
#ifndef _WIN32
u32 dtcmEnd = dtcmStart + dtcmSize;
if (Num == 0
&& dtcmEnd >= Addr
&& dtcmStart < Addr + Size)
{
bool success;
if (dtcmStart > Addr)
{
success = UnmapFromRange(Addr, 0, OffsetsPerRegion[region] + LocalOffset, dtcmStart - Addr);
assert(success);
}
if (dtcmEnd < Addr + Size)
{
u32 offset = dtcmStart - Addr + dtcmSize;
success = UnmapFromRange(dtcmEnd, 0, OffsetsPerRegion[region] + LocalOffset + offset, Size - offset);
assert(success);
}
}
else
#endif
{
bool succeded = UnmapFromRange(Addr, Num, OffsetsPerRegion[region] + LocalOffset, Size);
assert(succeded);
}
#endif
}
};
@ -418,10 +480,10 @@ void RemapDTCM(u32 newBase, u32 newSize)
printf("unmapping %d %x %x %x %x\n", region, mapping.Addr, mapping.Size, mapping.Num, mapping.LocalOffset);
bool oldOverlap = NDS::ARM9->DTCMSize > 0 && !(oldDTCMBase >= end || oldDTCBEnd <= start);
bool newOverlap = newSize > 0 && !(newBase >= end || newEnd <= start);
bool overlap = (NDS::ARM9->DTCMSize > 0 && oldDTCMBase < end && oldDTCBEnd > start)
|| (newSize > 0 && newBase < end && newEnd > start);
if (mapping.Num == 0 && (oldOverlap || newOverlap))
if (mapping.Num == 0 && overlap)
{
mapping.Unmap(region);
Mappings[region].Remove(i);
@ -445,8 +507,8 @@ void RemapNWRAM(int num)
for (int i = 0; i < Mappings[memregion_SharedWRAM].Length;)
{
Mapping& mapping = Mappings[memregion_SharedWRAM][i];
if (!(DSi::NWRAMStart[mapping.Num][num] >= mapping.Addr + mapping.Size
|| DSi::NWRAMEnd[mapping.Num][num] < mapping.Addr))
if (DSi::NWRAMStart[mapping.Num][num] < mapping.Addr + mapping.Size
&& DSi::NWRAMEnd[mapping.Num][num] > mapping.Addr)
{
mapping.Unmap(memregion_SharedWRAM);
Mappings[memregion_SharedWRAM].Remove(i);
@ -469,7 +531,7 @@ void RemapSWRAM()
for (int i = 0; i < Mappings[memregion_WRAM7].Length;)
{
Mapping& mapping = Mappings[memregion_WRAM7][i];
if (mapping.Addr + mapping.Size < 0x03800000)
if (mapping.Addr + mapping.Size <= 0x03800000)
{
mapping.Unmap(memregion_WRAM7);
Mappings[memregion_WRAM7].Remove(i);
@ -501,26 +563,53 @@ bool MapAtAddress(u32 addr)
return false;
u8* states = num == 0 ? MappingStatus9 : MappingStatus7;
printf("trying to create mapping %x, %x %x %d %d\n", mirrorStart, mirrorSize, memoryOffset, region, num);
printf("mapping mirror %x, %x %x %d %d\n", mirrorStart, mirrorSize, memoryOffset, region, num);
bool isExecutable = ARMJIT::CodeMemRegions[region];
u32 dtcmStart = NDS::ARM9->DTCMBase;
u32 dtcmSize = NDS::ARM9->DTCMSize;
u32 dtcmEnd = dtcmStart + dtcmSize;
#ifndef __SWITCH__
bool succeded = MapIntoRange(mirrorStart, num, OffsetsPerRegion[region] + memoryOffset, mirrorSize);
assert(succeded);
#ifndef _WIN32
if (num == 0
&& dtcmEnd >= mirrorStart
&& dtcmStart < mirrorStart + mirrorSize)
{
bool success;
if (dtcmStart > mirrorStart)
{
success = MapIntoRange(mirrorStart, 0, OffsetsPerRegion[region] + memoryOffset, dtcmStart - mirrorStart);
assert(success);
}
if (dtcmEnd < mirrorStart + mirrorSize)
{
u32 offset = dtcmStart - mirrorStart + dtcmSize;
success = MapIntoRange(dtcmEnd, 0, OffsetsPerRegion[region] + memoryOffset + offset, mirrorSize - offset);
assert(success);
}
}
else
#endif
{
bool succeded = MapIntoRange(mirrorStart, num, OffsetsPerRegion[region] + memoryOffset, mirrorSize);
assert(succeded);
}
#endif
ARMJIT::AddressRange* range = ARMJIT::CodeMemRegions[region] + memoryOffset / 512;
// this overcomplicated piece of code basically just finds whole pieces of code memory
// which can be mapped
// which can be mapped/protected
u32 offset = 0;
bool skipDTCM = num == 0 && region != memregion_DTCM;
while (offset < mirrorSize)
{
if (skipDTCM && mirrorStart + offset == NDS::ARM9->DTCMBase)
if (skipDTCM && mirrorStart + offset == dtcmStart)
{
SetCodeProtectionRange(NDS::ARM9->DTCMBase, NDS::ARM9->DTCMSize, 0, 0);
offset += NDS::ARM9->DTCMSize;
#ifdef _WIN32
SetCodeProtectionRange(dtcmStart, dtcmSize, 0, 0);
#endif
offset += dtcmSize;
}
else
{
@ -557,26 +646,25 @@ bool MapAtAddress(u32 addr)
Mapping mapping{mirrorStart, mirrorSize, memoryOffset, num};
Mappings[region].Add(mapping);
printf("mapped mirror at %08x-%08x\n", mirrorStart, mirrorStart + mirrorSize - 1);
//printf("mapped mirror at %08x-%08x\n", mirrorStart, mirrorStart + mirrorSize - 1);
return true;
}
bool FaultHandler(FaultDescription* faultDesc, s32& offset)
bool FaultHandler(FaultDescription& faultDesc)
{
if (ARMJIT::JITCompiler->IsJITFault(faultDesc->FaultPC))
if (ARMJIT::JITCompiler->IsJITFault(faultDesc.FaultPC))
{
bool rewriteToSlowPath = true;
u32 addr = faultDesc->EmulatedFaultAddr;
u8* memStatus = NDS::CurCPU == 0 ? MappingStatus9 : MappingStatus7;
if ((NDS::CurCPU == 0 ? MappingStatus9 : MappingStatus7)[addr >> 12] == memstate_Unmapped)
rewriteToSlowPath = !MapAtAddress(faultDesc->EmulatedFaultAddr);
if (memStatus[faultDesc.EmulatedFaultAddr >> 12] == memstate_Unmapped)
rewriteToSlowPath = !MapAtAddress(faultDesc.EmulatedFaultAddr);
if (rewriteToSlowPath)
{
offset = ARMJIT::JITCompiler->RewriteMemAccess(faultDesc->FaultPC);
}
faultDesc.FaultPC = ARMJIT::JITCompiler->RewriteMemAccess(faultDesc.FaultPC);
return true;
}
return false;
@ -624,22 +712,52 @@ void Init()
u8* basePtr = MemoryBase;
#else
FastMem9Start = mmap(NULL, AddrSpaceSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
FastMem7Start = mmap(NULL, AddrSpaceSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
// this used to be allocated with three different mmaps
// The idea was to give the OS more freedom where to position the buffers,
// but something was bad about this so instead we take this vmem eating monster
// which seems to work better.
MemoryBase = (u8*)mmap(NULL, AddrSpaceSize*4, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
munmap(MemoryBase, AddrSpaceSize*4);
FastMem9Start = MemoryBase;
FastMem7Start = MemoryBase + AddrSpaceSize;
MemoryBase = MemoryBase + AddrSpaceSize*2;
MemoryBase = (u8*)mmap(NULL, MemoryTotalSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
#if defined(__ANDROID__)
static void* libandroid = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
using type_ASharedMemory_create = int(*)(const char* name, size_t size);
static void* symbol = dlsym(libandroid, "ASharedMemory_create");
static auto shared_memory_create = reinterpret_cast<type_ASharedMemory_create>(symbol);
if (shared_memory_create)
{
MemoryFile = shared_memory_create("melondsfastmem", MemoryTotalSize);
}
else
{
int fd = open(ASHMEM_DEVICE, O_RDWR);
ioctl(fd, ASHMEM_SET_NAME, "melondsfastmem");
ioctl(fd, ASHMEM_SET_SIZE, MemoryTotalSize);
MemoryFile = fd;
}
#elif defined(__APPLE__)
char* fastmemPidName = new char[snprintf(NULL, 0, "melondsfastmem%d", getpid()) + 1];
sprintf(fastmemPidName, "melondsfastmem%d", getpid());
MemoryFile = shm_open(fastmemPidName, O_RDWR|O_CREAT, 0600);
delete[] fastmemPidName;
#else
MemoryFile = memfd_create("melondsfastmem", 0);
#endif
ftruncate(MemoryFile, MemoryTotalSize);
NewSa.sa_flags = SA_SIGINFO;
sigemptyset(&NewSa.sa_mask);
NewSa.sa_sigaction = SigsegvHandler;
sigaction(SIGSEGV, &NewSa, &OldSa);
munmap(MemoryBase, MemoryTotalSize);
munmap(FastMem9Start, AddrSpaceSize);
munmap(FastMem7Start, AddrSpaceSize);
struct sigaction sa;
sa.sa_handler = nullptr;
sa.sa_sigaction = &SigsegvHandler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sigaction(SIGSEGV, &sa, &OldSaSegv);
#ifdef __APPLE__
sigaction(SIGBUS, &sa, &OldSaBus);
#endif
mmap(MemoryBase, MemoryTotalSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, MemoryFile, 0);
@ -657,17 +775,30 @@ void Init()
void DeInit()
{
#if defined(__SWITCH__)
virtmemFree(FastMem9Start, 0x100000000);
virtmemFree(FastMem7Start, 0x100000000);
virtmemFree(FastMem9Start, AddrSpaceSize);
virtmemFree(FastMem7Start, AddrSpaceSize);
svcUnmapProcessCodeMemory(envGetOwnProcessHandle(), (u64)MemoryBaseCodeMem, (u64)MemoryBase, MemoryTotalSize);
virtmemFree(MemoryBaseCodeMem, MemoryTotalSize);
free(MemoryBase);
#elif defined(__APPLE__)
char* fastmemPidName = new char[snprintf(NULL, 0, "melondsfastmem%d", getpid()) + 1];
sprintf(fastmemPidName, "melondsfastmem%d", getpid());
shm_unlink(fastmemPidName);
delete[] fastmemPidName;
#elif defined(_WIN32)
assert(UnmapViewOfFile(MemoryBase));
CloseHandle(MemoryFile);
RemoveVectoredExceptionHandler(ExceptionHandlerHandle);
#else
sigaction(SIGSEGV, &OldSaSegv, nullptr);
#ifdef __APPLE__
sigaction(SIGBUS, &OldSaBus, nullptr);
#endif
munmap(MemoryBase, MemoryTotalSize);
close(MemoryFile);
#endif
}
@ -997,9 +1128,11 @@ int ClassifyAddress7(u32 addr)
case 0x06000000:
case 0x06800000:
return memregion_VWRAM;
default:
return memregion_Other;
}
}
return memregion_Other;
}
void WifiWrite32(u32 addr, u32 val)

View File

@ -130,6 +130,16 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
ADD(32, MDisp(RCPU, offsetof(ARM, Cycles)), Imm8(cycles));
}
void ARMv4JumpToTrampoline(ARMv4* arm, u32 addr, bool restorecpsr)
{
arm->JumpTo(addr, restorecpsr);
}
void ARMv5JumpToTrampoline(ARMv5* arm, u32 addr, bool restorecpsr)
{
arm->JumpTo(addr, restorecpsr);
}
void Compiler::Comp_JumpTo(Gen::X64Reg addr, bool restoreCPSR)
{
IrregularCycles = true;
@ -146,9 +156,9 @@ void Compiler::Comp_JumpTo(Gen::X64Reg addr, bool restoreCPSR)
else
MOV(32, R(ABI_PARAM3), Imm32(true)); // what a waste
if (Num == 0)
CALL((void*)&ARMv5::JumpTo);
CALL((void*)&ARMv5JumpToTrampoline);
else
CALL((void*)&ARMv4::JumpTo);
CALL((void*)&ARMv4JumpToTrampoline);
PopRegs(restoreCPSR);

View File

@ -101,6 +101,11 @@ void Compiler::A_Comp_MRS()
MOV(32, rd, R(RCPSR));
}
void UpdateModeTrampoline(ARM* arm, u32 oldmode, u32 newmode)
{
arm->UpdateMode(oldmode, newmode);
}
void Compiler::A_Comp_MSR()
{
Comp_AddCycles_C();
@ -185,7 +190,7 @@ void Compiler::A_Comp_MSR()
MOV(32, R(ABI_PARAM3), R(RCPSR));
MOV(32, R(ABI_PARAM2), R(RSCRATCH3));
MOV(64, R(ABI_PARAM1), R(RCPU));
CALL((void*)&ARM::UpdateMode);
CALL((void*)&UpdateModeTrampoline);
PopRegs(true);
}
@ -216,6 +221,8 @@ Compiler::Compiler()
#ifdef _WIN32
DWORD dummy;
VirtualProtect(pageAligned, alignedSize, PAGE_EXECUTE_READWRITE, &dummy);
#elif defined(__APPLE__)
pageAligned = (u8*)mmap(NULL, 1024*1024*32, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS ,-1, 0);
#else
mprotect(pageAligned, alignedSize, PROT_EXEC | PROT_READ | PROT_WRITE);
#endif
@ -340,7 +347,7 @@ Compiler::Compiler()
ABI_PushRegistersAndAdjustStack(CallerSavedPushRegs, 8);
if (consoleType == 0)
{
switch ((8 << size) | num)
switch ((8 << size) | num)
{
case 32: ABI_CallFunction(SlowWrite9<u32, 0>); break;
case 33: ABI_CallFunction(SlowWrite7<u32, 0>); break;
@ -352,7 +359,7 @@ Compiler::Compiler()
}
else
{
switch ((8 << size) | num)
switch ((8 << size) | num)
{
case 32: ABI_CallFunction(SlowWrite9<u32, 1>); break;
case 33: ABI_CallFunction(SlowWrite7<u32, 1>); break;
@ -375,7 +382,7 @@ Compiler::Compiler()
ABI_PushRegistersAndAdjustStack(CallerSavedPushRegs, 8);
if (consoleType == 0)
{
switch ((8 << size) | num)
switch ((8 << size) | num)
{
case 32: ABI_CallFunction(SlowRead9<u32, 0>); break;
case 33: ABI_CallFunction(SlowRead7<u32, 0>); break;
@ -387,7 +394,7 @@ Compiler::Compiler()
}
else
{
switch ((8 << size) | num)
switch ((8 << size) | num)
{
case 32: ABI_CallFunction(SlowRead9<u32, 1>); break;
case 33: ABI_CallFunction(SlowRead7<u32, 1>); break;
@ -612,9 +619,9 @@ void Compiler::Reset()
LoadStorePatches.clear();
}
bool Compiler::IsJITFault(u64 addr)
bool Compiler::IsJITFault(u8* addr)
{
return addr >= (u64)CodeMemory && addr < (u64)CodeMemory + sizeof(CodeMemory);
return (u64)addr >= (u64)ResetStart && (u64)addr < (u64)ResetStart + CodeMemSize;
}
void Compiler::Comp_SpecialBranchBehaviour(bool taken)
@ -896,5 +903,4 @@ void Compiler::Comp_AddCycles_CD()
else
ConstantCycles += cycles;
}
}

View File

@ -208,9 +208,9 @@ public:
SetCodePtr(FarCode);
}
bool IsJITFault(u64 addr);
bool IsJITFault(u8* addr);
s32 RewriteMemAccess(u64 pc);
u8* RewriteMemAccess(u8* pc);
u8* FarCode;
u8* NearCode;

View File

@ -29,8 +29,13 @@
.p2align 4,,15
#ifdef __APPLE__
.global _ARM_Dispatch
_ARM_Dispatch:
#else
.global ARM_Dispatch
ARM_Dispatch:
#endif
#ifdef WIN64
push rdi
push rsi
@ -54,8 +59,13 @@ ARM_Dispatch:
.p2align 4,,15
#ifdef __APPLE__
.global _ARM_Ret
_ARM_Ret:
#else
.global ARM_Ret
ARM_Ret:
#endif
mov [RCPU + ARM_CPSR_offset], RCPSR
#ifdef WIN64

View File

@ -15,28 +15,24 @@ int squeezePointer(T* ptr)
return truncated;
}
s32 Compiler::RewriteMemAccess(u64 pc)
u8* Compiler::RewriteMemAccess(u8* pc)
{
auto it = LoadStorePatches.find((u8*)pc);
auto it = LoadStorePatches.find(pc);
if (it != LoadStorePatches.end())
{
LoadStorePatch patch = it->second;
LoadStorePatches.erase(it);
u8* curCodePtr = GetWritableCodePtr();
u8* rewritePtr = (u8*)pc + (ptrdiff_t)patch.Offset;
SetCodePtr(rewritePtr);
//printf("rewriting memory access %p %d %d\n", (u8*)pc-ResetStart, patch.Offset, patch.Size);
CALL(patch.PatchFunc);
u32 remainingSize = patch.Size - (GetWritableCodePtr() - rewritePtr);
XEmitter emitter(pc + (ptrdiff_t)patch.Offset);
emitter.CALL(patch.PatchFunc);
ptrdiff_t remainingSize = (ptrdiff_t)patch.Size - 5;
assert(remainingSize >= 0);
if (remainingSize > 0)
NOP(remainingSize);
emitter.NOP(remainingSize);
//printf("rewriting memory access %p %d %d\n", patch.PatchFunc, patch.Offset, patch.Size);
SetCodePtr(curCodePtr);
return patch.Offset;
return pc + (ptrdiff_t)patch.Offset;
}
printf("this is a JIT bug %llx\n", pc);
@ -192,6 +188,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
u8* memopStart = GetWritableCodePtr();
LoadStorePatch patch;
assert(rdMapped.GetSimpleReg() >= 0 && rdMapped.GetSimpleReg() < 16);
patch.PatchFunc = flags & memop_Store
? PatchedStoreFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][rdMapped.GetSimpleReg()]
: PatchedLoadFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][!!(flags & memop_SignExtend)][rdMapped.GetSimpleReg()];

View File

@ -80,9 +80,8 @@ if (ENABLE_JIT)
ARMJIT_x64/ARMJIT_LoadStore.cpp
ARMJIT_x64/ARMJIT_Branch.cpp
ARMJIT_x64/ARMJIT_Linkage.s
ARMJIT_x64/ARMJIT_Linkage.S
)
set_source_files_properties(ARMJIT_x64/ARMJIT_Linkage.s PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
endif()
if (ARCHITECTURE STREQUAL ARM64)
target_sources(core PRIVATE
@ -94,16 +93,22 @@ if (ENABLE_JIT)
ARMJIT_A64/ARMJIT_LoadStore.cpp
ARMJIT_A64/ARMJIT_Branch.cpp
ARMJIT_A64/ARMJIT_Linkage.s
ARMJIT_A64/ARMJIT_Linkage.S
)
set_source_files_properties(ARMJIT_A64/ARMJIT_Linkage.s PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
endif()
endif()
if (APPLE)
target_include_directories(core PUBLIC /usr/local/include)
target_link_directories(core PUBLIC /usr/local/lib)
endif()
if (ENABLE_OGLRENDERER)
if (WIN32)
target_link_libraries(core ole32 comctl32 ws2_32 opengl32)
else()
elseif (APPLE)
target_link_libraries(core "-framework OpenGL")
else()
target_link_libraries(core GL EGL)
endif()
else()

View File

@ -73,7 +73,11 @@ ConfigEntry ConfigFile[] =
{"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, NULL, 0},
{"JIT_BranchOptimisations", 0, &JIT_BranchOptimisations, 1, NULL, 0},
{"JIT_LiteralOptimisations", 0, &JIT_LiteralOptimisations, 1, NULL, 0},
{"JIT_FastMemory", 0, &JIT_FastMemory, 1, NULL, 0},
#ifdef __APPLE__
{"JIT_FastMemory", 0, &JIT_FastMemory, 0, NULL, 0},
#else
{"JIT_FastMemory", 0, &JIT_FastMemory, 1, NULL, 0},
#endif
#endif
{"", -1, NULL, 0, NULL, 0}

View File

@ -77,21 +77,6 @@ void DMA::Reset()
Running = false;
InProgress = false;
if (NDS::ConsoleType == 1)
{
BusRead16 = (CPU==0) ? DSi::ARM9Read16 : DSi::ARM7Read16;
BusRead32 = (CPU==0) ? DSi::ARM9Read32 : DSi::ARM7Read32;
BusWrite16 = (CPU==0) ? DSi::ARM9Write16 : DSi::ARM7Write16;
BusWrite32 = (CPU==0) ? DSi::ARM9Write32 : DSi::ARM7Write32;
}
else
{
BusRead16 = (CPU==0) ? NDS::ARM9Read16 : NDS::ARM7Read16;
BusRead32 = (CPU==0) ? NDS::ARM9Read32 : NDS::ARM7Read32;
BusWrite16 = (CPU==0) ? NDS::ARM9Write16 : NDS::ARM7Write16;
BusWrite32 = (CPU==0) ? NDS::ARM9Write32 : NDS::ARM7Write32;
}
}
void DMA::DoSavestate(Savestate* file)
@ -198,13 +183,7 @@ void DMA::Start()
NDS::StopCPU(CPU, 1<<Num);
}
void DMA::Run()
{
if (!Running) return;
if (CPU == 0) return Run9();
else return Run7();
}
template <int ConsoleType>
void DMA::Run9()
{
if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
@ -242,7 +221,10 @@ void DMA::Run9()
{
NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift);
BusWrite16(CurDstAddr, BusRead16(CurSrcAddr));
if (ConsoleType == 1)
DSi::ARM9Write16(CurDstAddr, DSi::ARM9Read16(CurSrcAddr));
else
NDS::ARM9Write16(CurDstAddr, NDS::ARM9Read16(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<1;
CurDstAddr += DstAddrInc<<1;
@ -278,7 +260,10 @@ void DMA::Run9()
{
NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift);
BusWrite32(CurDstAddr, BusRead32(CurSrcAddr));
if (ConsoleType == 1)
DSi::ARM9Write32(CurDstAddr, DSi::ARM9Read32(CurSrcAddr));
else
NDS::ARM9Write32(CurDstAddr, NDS::ARM9Read32(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<2;
CurDstAddr += DstAddrInc<<2;
@ -317,6 +302,7 @@ void DMA::Run9()
NDS::ResumeCPU(0, 1<<Num);
}
template <int ConsoleType>
void DMA::Run7()
{
if (NDS::ARM7Timestamp >= NDS::ARM7Target) return;
@ -354,7 +340,10 @@ void DMA::Run7()
{
NDS::ARM7Timestamp += unitcycles;
BusWrite16(CurDstAddr, BusRead16(CurSrcAddr));
if (ConsoleType == 1)
DSi::ARM7Write16(CurDstAddr, DSi::ARM7Read16(CurSrcAddr));
else
NDS::ARM7Write16(CurDstAddr, NDS::ARM7Read16(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<1;
CurDstAddr += DstAddrInc<<1;
@ -390,7 +379,10 @@ void DMA::Run7()
{
NDS::ARM7Timestamp += unitcycles;
BusWrite32(CurDstAddr, BusRead32(CurSrcAddr));
if (ConsoleType == 1)
DSi::ARM7Write32(CurDstAddr, DSi::ARM7Read32(CurSrcAddr));
else
NDS::ARM7Write32(CurDstAddr, NDS::ARM7Read32(CurSrcAddr));
CurSrcAddr += SrcAddrInc<<2;
CurDstAddr += DstAddrInc<<2;
@ -425,3 +417,14 @@ void DMA::Run7()
InProgress = false;
NDS::ResumeCPU(1, 1<<Num);
}
template <int ConsoleType>
void DMA::Run()
{
if (!Running) return;
if (CPU == 0) return Run9<ConsoleType>();
else return Run7<ConsoleType>();
}
template void DMA::Run<0>();
template void DMA::Run<1>();

View File

@ -34,9 +34,12 @@ public:
void WriteCnt(u32 val);
void Start();
template <int ConsoleType>
void Run();
template <int ConsoleType>
void Run9();
template <int ConsoleType>
void Run7();
bool IsInMode(u32 mode)
@ -86,11 +89,6 @@ private:
bool Stall;
bool IsGXFIFODMA;
u16 (*BusRead16)(u32 addr);
u32 (*BusRead32)(u32 addr);
void (*BusWrite16)(u32 addr, u16 val);
void (*BusWrite32)(u32 addr, u32 val);
};
#endif

View File

@ -543,15 +543,15 @@ void MapNWRAM_A(u32 num, u8 val)
return;
}
#ifdef JIT_ENABLED
ARMJIT_Memory::RemapNWRAM(0);
#endif
int mbkn = 0, mbks = 8*num;
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
if (oldval == val) return;
#ifdef JIT_ENABLED
ARMJIT_Memory::RemapNWRAM(0);
#endif
MBK[0][mbkn] &= ~(0xFF << mbks);
MBK[0][mbkn] |= (val << mbks);
MBK[1][mbkn] = MBK[0][mbkn];
@ -578,15 +578,15 @@ void MapNWRAM_B(u32 num, u8 val)
return;
}
#ifdef JIT_ENABLED
ARMJIT_Memory::RemapNWRAM(1);
#endif
int mbkn = 1+(num>>2), mbks = 8*(num&3);
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
if (oldval == val) return;
#ifdef JIT_ENABLED
ARMJIT_Memory::RemapNWRAM(1);
#endif
MBK[0][mbkn] &= ~(0xFF << mbks);
MBK[0][mbkn] |= (val << mbks);
MBK[1][mbkn] = MBK[0][mbkn];
@ -617,15 +617,15 @@ void MapNWRAM_C(u32 num, u8 val)
return;
}
#ifdef JIT_ENABLED
ARMJIT_Memory::RemapNWRAM(2);
#endif
int mbkn = 3+(num>>2), mbks = 8*(num&3);
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
if (oldval == val) return;
#ifdef JIT_ENABLED
ARMJIT_Memory::RemapNWRAM(2);
#endif
MBK[0][mbkn] &= ~(0xFF << mbks);
MBK[0][mbkn] |= (val << mbks);
MBK[1][mbkn] = MBK[0][mbkn];

View File

@ -49,8 +49,8 @@ u8 VRAM_F[ 16*1024];
u8 VRAM_G[ 16*1024];
u8 VRAM_H[ 32*1024];
u8 VRAM_I[ 16*1024];
u8* VRAM[9] = {VRAM_A, VRAM_B, VRAM_C, VRAM_D, VRAM_E, VRAM_F, VRAM_G, VRAM_H, VRAM_I};
u32 VRAMMask[9] = {0x1FFFF, 0x1FFFF, 0x1FFFF, 0x1FFFF, 0xFFFF, 0x3FFF, 0x3FFF, 0x7FFF, 0x3FFF};
u8* const VRAM[9] = {VRAM_A, VRAM_B, VRAM_C, VRAM_D, VRAM_E, VRAM_F, VRAM_G, VRAM_H, VRAM_I};
u32 const VRAMMask[9] = {0x1FFFF, 0x1FFFF, 0x1FFFF, 0x1FFFF, 0xFFFF, 0x3FFF, 0x3FFF, 0x7FFF, 0x3FFF};
u8 VRAMCNT[9];
u8 VRAMSTAT;
@ -85,6 +85,62 @@ bool Accelerated;
GPU2D* GPU2D_A;
GPU2D* GPU2D_B;
/*
VRAM invalidation tracking
- we want to know when a VRAM region used for graphics changed
- for some regions unmapping is mandatory to modify them (Texture, TexPal and ExtPal) and
we don't want to completely invalidate them every time they're unmapped and remapped
For this reason we don't track the dirtyness per mapping region, but instead per VRAM bank
with VRAMDirty. Writes to LCDC go directly into VRAMDirty, while writes via other mapping regions
like BG or OBJ are first tracked in VRAMWritten_* and need to be flushed using SyncDirtyFlags.
This is more or less a description of VRAMTrackingSet::DeriveState
Each time before the memory is read two things could have happened
to each 16kb piece (16kb is the smallest unit in which mappings can
be made thus also the size VRAMMap_* use):
- this piece was remapped compared to last time we checked,
which means this location in memory is invalid.
- this piece wasn't remapped, which means we need to check whether
it was changed. This can be archived by checking VRAMDirty.
VRAMDirty need to be reset for the respective VRAM bank.
*/
VRAMTrackingSet<512*1024, 16*1024> VRAMDirty_ABG;
VRAMTrackingSet<256*1024, 16*1024> VRAMDirty_AOBJ;
VRAMTrackingSet<128*1024, 16*1024> VRAMDirty_BBG;
VRAMTrackingSet<128*1024, 16*1024> VRAMDirty_BOBJ;
VRAMTrackingSet<32*1024, 8*1024> VRAMDirty_ABGExtPal;
VRAMTrackingSet<32*1024, 8*1024> VRAMDirty_BBGExtPal;
VRAMTrackingSet<8*1024, 8*1024> VRAMDirty_AOBJExtPal;
VRAMTrackingSet<8*1024, 8*1024> VRAMDirty_BOBJExtPal;
VRAMTrackingSet<512*1024, 128*1024> VRAMDirty_Texture;
VRAMTrackingSet<128*1024, 16*1024> VRAMDirty_TexPal;
NonStupidBitField<512*1024/VRAMDirtyGranularity> VRAMWritten_ABG;
NonStupidBitField<256*1024/VRAMDirtyGranularity> VRAMWritten_AOBJ;
NonStupidBitField<128*1024/VRAMDirtyGranularity> VRAMWritten_BBG;
NonStupidBitField<128*1024/VRAMDirtyGranularity> VRAMWritten_BOBJ;
NonStupidBitField<256*1024/VRAMDirtyGranularity> VRAMWritten_ARM7;
NonStupidBitField<128*1024/VRAMDirtyGranularity> VRAMDirty[9];
u8 VRAMFlat_ABG[512*1024];
u8 VRAMFlat_BBG[128*1024];
u8 VRAMFlat_AOBJ[256*1024];
u8 VRAMFlat_BOBJ[128*1024];
u8 VRAMFlat_ABGExtPal[32*1024];
u8 VRAMFlat_BBGExtPal[32*1024];
u8 VRAMFlat_AOBJExtPal[8*1024];
u8 VRAMFlat_BOBJExtPal[8*1024];
u8 VRAMFlat_Texture[512*1024];
u8 VRAMFlat_TexPal[128*1024];
bool Init()
{
@ -113,6 +169,30 @@ void DeInit()
if (Framebuffer[1][1]) delete[] Framebuffer[1][1];
}
void ResetVRAMCache()
{
for (int i = 0; i < 9; i++)
VRAMDirty[i] = NonStupidBitField<128*1024/VRAMDirtyGranularity>();
VRAMDirty_ABG.Reset();
VRAMDirty_BBG.Reset();
VRAMDirty_AOBJ.Reset();
VRAMDirty_BOBJ.Reset();
VRAMDirty_ABGExtPal.Reset();
VRAMDirty_BBGExtPal.Reset();
VRAMDirty_AOBJExtPal.Reset();
VRAMDirty_BOBJExtPal.Reset();
memset(VRAMFlat_ABG, 0, sizeof(VRAMFlat_ABG));
memset(VRAMFlat_BBG, 0, sizeof(VRAMFlat_BBG));
memset(VRAMFlat_AOBJ, 0, sizeof(VRAMFlat_AOBJ));
memset(VRAMFlat_BOBJ, 0, sizeof(VRAMFlat_BOBJ));
memset(VRAMFlat_ABGExtPal, 0, sizeof(VRAMFlat_ABGExtPal));
memset(VRAMFlat_BBGExtPal, 0, sizeof(VRAMFlat_BBGExtPal));
memset(VRAMFlat_AOBJExtPal, 0, sizeof(VRAMFlat_AOBJExtPal));
memset(VRAMFlat_BOBJExtPal, 0, sizeof(VRAMFlat_BOBJExtPal));
}
void Reset()
{
VCount = 0;
@ -186,6 +266,8 @@ void Reset()
GPU2D_B->SetFramebuffer(Framebuffer[backbuf][0]);
ResetRenderer();
ResetVRAMCache();
}
void Stop()
@ -261,6 +343,8 @@ void DoSavestate(Savestate* file)
GPU2D_A->DoSavestate(file);
GPU2D_B->DoSavestate(file);
GPU3D::DoSavestate(file);
ResetVRAMCache();
}
void AssignFramebuffers()
@ -411,18 +495,8 @@ void SetRenderSettings(int renderer, RenderSettings& settings)
u8* GetUniqueBankPtr(u32 mask, u32 offset)
{
if (!mask) return NULL;
int num = 0;
if (!(mask & 0xFF)) { mask >>= 8; num += 8; }
else
{
if (!(mask & 0xF)) { mask >>= 4; num += 4; }
if (!(mask & 0x3)) { mask >>= 2; num += 2; }
if (!(mask & 0x1)) { mask >>= 1; num += 1; }
}
if (mask != 1) return NULL;
if (!mask || (mask & (mask - 1)) != 0) return NULL;
int num = __builtin_ctz(mask);
return &VRAM[num][offset & VRAMMask[num]];
}
@ -606,8 +680,6 @@ void MapVRAM_E(u32 bank, u8 cnt)
case 4: // ABG ext palette
UNMAP_RANGE(ABGExtPal, 0, 4);
GPU2D_A->BGExtPalDirty(0);
GPU2D_A->BGExtPalDirty(2);
break;
}
}
@ -634,8 +706,6 @@ void MapVRAM_E(u32 bank, u8 cnt)
case 4: // ABG ext palette
MAP_RANGE(ABGExtPal, 0, 4);
GPU2D_A->BGExtPalDirty(0);
GPU2D_A->BGExtPalDirty(2);
break;
}
}
@ -687,12 +757,10 @@ void MapVRAM_FG(u32 bank, u8 cnt)
case 4: // ABG ext palette
VRAMMap_ABGExtPal[((oldofs & 0x1) << 1)] &= ~bankmask;
VRAMMap_ABGExtPal[((oldofs & 0x1) << 1) + 1] &= ~bankmask;
GPU2D_A->BGExtPalDirty((oldofs & 0x1) << 1);
break;
case 5: // AOBJ ext palette
VRAMMap_AOBJExtPal &= ~bankmask;
GPU2D_A->OBJExtPalDirty();
break;
}
}
@ -732,12 +800,10 @@ void MapVRAM_FG(u32 bank, u8 cnt)
case 4: // ABG ext palette
VRAMMap_ABGExtPal[((ofs & 0x1) << 1)] |= bankmask;
VRAMMap_ABGExtPal[((ofs & 0x1) << 1) + 1] |= bankmask;
GPU2D_A->BGExtPalDirty((ofs & 0x1) << 1);
break;
case 5: // AOBJ ext palette
VRAMMap_AOBJExtPal |= bankmask;
GPU2D_A->OBJExtPalDirty();
break;
}
}
@ -773,8 +839,6 @@ void MapVRAM_H(u32 bank, u8 cnt)
case 2: // BBG ext palette
UNMAP_RANGE(BBGExtPal, 0, 4);
GPU2D_B->BGExtPalDirty(0);
GPU2D_B->BGExtPalDirty(2);
break;
}
}
@ -800,8 +864,6 @@ void MapVRAM_H(u32 bank, u8 cnt)
case 2: // BBG ext palette
MAP_RANGE(BBGExtPal, 0, 4);
GPU2D_B->BGExtPalDirty(0);
GPU2D_B->BGExtPalDirty(2);
break;
}
}
@ -841,7 +903,6 @@ void MapVRAM_I(u32 bank, u8 cnt)
case 3: // BOBJ ext palette
VRAMMap_BOBJExtPal &= ~bankmask;
GPU2D_B->OBJExtPalDirty();
break;
}
}
@ -871,7 +932,6 @@ void MapVRAM_I(u32 bank, u8 cnt)
case 3: // BOBJ ext palette
VRAMMap_BOBJExtPal |= bankmask;
GPU2D_B->OBJExtPalDirty();
break;
}
}
@ -937,6 +997,8 @@ void StartHBlank(u32 line)
DispStat[0] |= (1<<1);
DispStat[1] |= (1<<1);
SyncDirtyFlags();
if (VCount < 192)
{
// draw
@ -1096,4 +1158,224 @@ void SetVCount(u16 val)
NextVCount = val;
}
template <u32 Size, u32 MappingGranularity>
NonStupidBitField<Size/VRAMDirtyGranularity> VRAMTrackingSet<Size, MappingGranularity>::DeriveState(u32* currentMappings)
{
NonStupidBitField<Size/VRAMDirtyGranularity> result;
u16 banksToBeZeroed = 0;
for (u32 i = 0; i < Size / MappingGranularity; i++)
{
if (currentMappings[i] != Mapping[i])
{
result |= NonStupidBitField<Size/VRAMDirtyGranularity>(i*VRAMBitsPerMapping, VRAMBitsPerMapping);
banksToBeZeroed |= currentMappings[i];
Mapping[i] = currentMappings[i];
}
else
{
u32 mapping = Mapping[i];
banksToBeZeroed |= mapping;
while (mapping != 0)
{
u32 num = __builtin_ctz(mapping);
mapping &= ~(1 << num);
// hack for **speed**
// this could probably be done less ugly but then we would rely
// on the compiler for vectorisation
static_assert(VRAMDirtyGranularity == 512);
if (MappingGranularity == 16*1024)
{
u32 dirty = ((u32*)VRAMDirty[num].Data)[i & (VRAMMask[num] >> 14)];
((u32*)result.Data)[i] |= dirty;
}
else if (MappingGranularity == 8*1024)
{
u16 dirty = ((u16*)VRAMDirty[num].Data)[i & (VRAMMask[num] >> 13)];
((u16*)result.Data)[i] |= dirty;
}
else if (MappingGranularity == 128*1024)
{
((u64*)result.Data)[i * 4 + 0] |= ((u64*)VRAMDirty[num].Data)[0];
((u64*)result.Data)[i * 4 + 1] |= ((u64*)VRAMDirty[num].Data)[1];
((u64*)result.Data)[i * 4 + 2] |= ((u64*)VRAMDirty[num].Data)[2];
((u64*)result.Data)[i * 4 + 3] |= ((u64*)VRAMDirty[num].Data)[3];
}
else
{
// welp
abort();
}
}
}
}
while (banksToBeZeroed != 0)
{
u32 num = __builtin_ctz(banksToBeZeroed);
banksToBeZeroed &= ~(1 << num);
memset(VRAMDirty[num].Data, 0, sizeof(VRAMDirty[num].Data));
}
return result;
}
template NonStupidBitField<32*1024/VRAMDirtyGranularity> VRAMTrackingSet<32*1024, 8*1024>::DeriveState(u32*);
template NonStupidBitField<8*1024/VRAMDirtyGranularity> VRAMTrackingSet<8*1024, 8*1024>::DeriveState(u32*);
template NonStupidBitField<512*1024/VRAMDirtyGranularity> VRAMTrackingSet<512*1024, 128*1024>::DeriveState(u32*);
template NonStupidBitField<128*1024/VRAMDirtyGranularity> VRAMTrackingSet<128*1024, 16*1024>::DeriveState(u32*);
template NonStupidBitField<256*1024/VRAMDirtyGranularity> VRAMTrackingSet<256*1024, 16*1024>::DeriveState(u32*);
template NonStupidBitField<512*1024/VRAMDirtyGranularity> VRAMTrackingSet<512*1024, 16*1024>::DeriveState(u32*);
template <u32 Size>
void SyncDirtyFlags(u32* mappings, NonStupidBitField<Size>& writtenFlags)
{
const u32 VRAMWrittenBitsPer16KB = 16*1024/VRAMDirtyGranularity;
for (typename NonStupidBitField<Size>::Iterator it = writtenFlags.Begin(); it != writtenFlags.End(); it++)
{
u32 mapping = mappings[*it / VRAMWrittenBitsPer16KB];
while (mapping != 0)
{
u32 num = __builtin_ctz(mapping);
VRAMDirty[num][*it & (VRAMMask[num] / VRAMDirtyGranularity)] = true;
mapping &= ~(1 << num);
}
}
memset(writtenFlags.Data, 0, sizeof(writtenFlags.Data));
}
void SyncDirtyFlags()
{
SyncDirtyFlags(VRAMMap_ABG, VRAMWritten_ABG);
SyncDirtyFlags(VRAMMap_AOBJ, VRAMWritten_AOBJ);
SyncDirtyFlags(VRAMMap_BBG, VRAMWritten_BBG);
SyncDirtyFlags(VRAMMap_BOBJ, VRAMWritten_BOBJ);
SyncDirtyFlags(VRAMMap_ARM7, VRAMWritten_ARM7);
}
template <u32 MappingGranularity, u32 Size>
inline bool CopyLinearVRAM(u8* flat, u32* mappings, NonStupidBitField<Size>& dirty, u64 (*slowAccess)(u32 addr))
{
const u32 VRAMBitsPerMapping = MappingGranularity / VRAMDirtyGranularity;
bool change = false;
typename NonStupidBitField<Size>::Iterator it = dirty.Begin();
while (it != dirty.End())
{
u32 offset = *it * VRAMDirtyGranularity;
u8* dst = flat + offset;
u8* fastAccess = GetUniqueBankPtr(mappings[*it / VRAMBitsPerMapping], offset);
if (fastAccess)
{
memcpy(dst, fastAccess, VRAMDirtyGranularity);
}
else
{
for (u32 i = 0; i < VRAMDirtyGranularity; i += 8)
*(u64*)&dst[i] = slowAccess(offset + i);
}
change = true;
it++;
}
return change;
}
bool MakeVRAMFlat_TextureCoherent(NonStupidBitField<512*1024/VRAMDirtyGranularity>& dirty)
{
return CopyLinearVRAM<128*1024>(VRAMFlat_Texture, VRAMMap_Texture, dirty, ReadVRAM_Texture<u64>);
}
bool MakeVRAMFlat_TexPalCoherent(NonStupidBitField<128*1024/VRAMDirtyGranularity>& dirty)
{
return CopyLinearVRAM<16*1024>(VRAMFlat_TexPal, VRAMMap_TexPal, dirty, ReadVRAM_TexPal<u64>);
}
bool MakeVRAMFlat_ABGCoherent(NonStupidBitField<512*1024/VRAMDirtyGranularity>& dirty)
{
return CopyLinearVRAM<16*1024>(VRAMFlat_ABG, VRAMMap_ABG, dirty, ReadVRAM_ABG<u64>);
}
bool MakeVRAMFlat_BBGCoherent(NonStupidBitField<128*1024/VRAMDirtyGranularity>& dirty)
{
return CopyLinearVRAM<16*1024>(VRAMFlat_BBG, VRAMMap_BBG, dirty, ReadVRAM_BBG<u64>);
}
bool MakeVRAMFlat_AOBJCoherent(NonStupidBitField<256*1024/VRAMDirtyGranularity>& dirty)
{
return CopyLinearVRAM<16*1024>(VRAMFlat_AOBJ, VRAMMap_AOBJ, dirty, ReadVRAM_AOBJ<u64>);
}
bool MakeVRAMFlat_BOBJCoherent(NonStupidBitField<128*1024/VRAMDirtyGranularity>& dirty)
{
return CopyLinearVRAM<16*1024>(VRAMFlat_BOBJ, VRAMMap_BOBJ, dirty, ReadVRAM_BOBJ<u64>);
}
template<typename T>
T ReadVRAM_ABGExtPal(u32 addr)
{
u32 mask = VRAMMap_ABGExtPal[(addr >> 13) & 0x3];
T ret = 0;
if (mask & (1<<4)) ret |= *(T*)&VRAM_E[addr & 0x7FFF];
if (mask & (1<<5)) ret |= *(T*)&VRAM_F[addr & 0x3FFF];
if (mask & (1<<6)) ret |= *(T*)&VRAM_G[addr & 0x3FFF];
return ret;
}
template<typename T>
T ReadVRAM_BBGExtPal(u32 addr)
{
u32 mask = VRAMMap_BBGExtPal[(addr >> 13) & 0x3];
T ret = 0;
if (mask & (1<<7)) ret |= *(T*)&VRAM_H[addr & 0x7FFF];
return ret;
}
template<typename T>
T ReadVRAM_AOBJExtPal(u32 addr)
{
u32 mask = VRAMMap_AOBJExtPal;
T ret = 0;
if (mask & (1<<4)) ret |= *(T*)&VRAM_F[addr & 0x1FFF];
if (mask & (1<<5)) ret |= *(T*)&VRAM_G[addr & 0x1FFF];
return ret;
}
template<typename T>
T ReadVRAM_BOBJExtPal(u32 addr)
{
u32 mask = VRAMMap_BOBJExtPal;
T ret = 0;
if (mask & (1<<8)) ret |= *(T*)&VRAM_I[addr & 0x1FFF];
return ret;
}
bool MakeVRAMFlat_ABGExtPalCoherent(NonStupidBitField<32*1024/VRAMDirtyGranularity>& dirty)
{
return CopyLinearVRAM<8*1024>(VRAMFlat_ABGExtPal, VRAMMap_ABGExtPal, dirty, ReadVRAM_ABGExtPal<u64>);
}
bool MakeVRAMFlat_BBGExtPalCoherent(NonStupidBitField<32*1024/VRAMDirtyGranularity>& dirty)
{
return CopyLinearVRAM<8*1024>(VRAMFlat_BBGExtPal, VRAMMap_BBGExtPal, dirty, ReadVRAM_BBGExtPal<u64>);
}
bool MakeVRAMFlat_AOBJExtPalCoherent(NonStupidBitField<8*1024/VRAMDirtyGranularity>& dirty)
{
return CopyLinearVRAM<8*1024>(VRAMFlat_AOBJExtPal, &VRAMMap_AOBJExtPal, dirty, ReadVRAM_AOBJExtPal<u64>);
}
bool MakeVRAMFlat_BOBJExtPalCoherent(NonStupidBitField<8*1024/VRAMDirtyGranularity>& dirty)
{
return CopyLinearVRAM<8*1024>(VRAMFlat_BOBJExtPal, &VRAMMap_BOBJExtPal, dirty, ReadVRAM_BOBJExtPal<u64>);
}
}

View File

@ -20,6 +20,7 @@
#define GPU_H
#include "GPU2D.h"
#include "NonStupidBitfield.h"
namespace GPU
{
@ -45,7 +46,7 @@ extern u8 VRAM_G[ 16*1024];
extern u8 VRAM_H[ 32*1024];
extern u8 VRAM_I[ 16*1024];
extern u8* VRAM[9];
extern u8* const VRAM[9];
extern u32 VRAMMap_LCDC;
extern u32 VRAMMap_ABG[0x20];
@ -73,6 +74,73 @@ extern GPU2D* GPU2D_B;
extern int Renderer;
const u32 VRAMDirtyGranularity = 512;
extern NonStupidBitField<512*1024/VRAMDirtyGranularity> VRAMWritten_ABG;
extern NonStupidBitField<256*1024/VRAMDirtyGranularity> VRAMWritten_AOBJ;
extern NonStupidBitField<128*1024/VRAMDirtyGranularity> VRAMWritten_BBG;
extern NonStupidBitField<128*1024/VRAMDirtyGranularity> VRAMWritten_BOBJ;
extern NonStupidBitField<256*1024/VRAMDirtyGranularity> VRAMWritten_ARM7;
extern NonStupidBitField<128*1024/VRAMDirtyGranularity> VRAMDirty[9];
template <u32 Size, u32 MappingGranularity>
struct VRAMTrackingSet
{
u16 Mapping[Size / MappingGranularity];
const u32 VRAMBitsPerMapping = MappingGranularity / VRAMDirtyGranularity;
void Reset()
{
memset(Mapping, 0, sizeof(Mapping));
}
NonStupidBitField<Size/VRAMDirtyGranularity> DeriveState(u32* currentMappings);
};
extern VRAMTrackingSet<512*1024, 16*1024> VRAMDirty_ABG;
extern VRAMTrackingSet<256*1024, 16*1024> VRAMDirty_AOBJ;
extern VRAMTrackingSet<128*1024, 16*1024> VRAMDirty_BBG;
extern VRAMTrackingSet<128*1024, 16*1024> VRAMDirty_BOBJ;
extern VRAMTrackingSet<32*1024, 8*1024> VRAMDirty_ABGExtPal;
extern VRAMTrackingSet<32*1024, 8*1024> VRAMDirty_BBGExtPal;
extern VRAMTrackingSet<8*1024, 8*1024> VRAMDirty_AOBJExtPal;
extern VRAMTrackingSet<8*1024, 8*1024> VRAMDirty_BOBJExtPal;
extern VRAMTrackingSet<512*1024, 128*1024> VRAMDirty_Texture;
extern VRAMTrackingSet<128*1024, 16*1024> VRAMDirty_TexPal;
extern u8 VRAMFlat_ABG[512*1024];
extern u8 VRAMFlat_BBG[128*1024];
extern u8 VRAMFlat_AOBJ[256*1024];
extern u8 VRAMFlat_BOBJ[128*1024];
extern u8 VRAMFlat_ABGExtPal[32*1024];
extern u8 VRAMFlat_BBGExtPal[32*1024];
extern u8 VRAMFlat_AOBJExtPal[8*1024];
extern u8 VRAMFlat_BOBJExtPal[8*1024];
extern u8 VRAMFlat_Texture[512*1024];
extern u8 VRAMFlat_TexPal[128*1024];
bool MakeVRAMFlat_ABGCoherent(NonStupidBitField<512*1024/VRAMDirtyGranularity>& dirty);
bool MakeVRAMFlat_BBGCoherent(NonStupidBitField<128*1024/VRAMDirtyGranularity>& dirty);
bool MakeVRAMFlat_AOBJCoherent(NonStupidBitField<256*1024/VRAMDirtyGranularity>& dirty);
bool MakeVRAMFlat_BOBJCoherent(NonStupidBitField<128*1024/VRAMDirtyGranularity>& dirty);
bool MakeVRAMFlat_ABGExtPalCoherent(NonStupidBitField<32*1024/VRAMDirtyGranularity>& dirty);
bool MakeVRAMFlat_BBGExtPalCoherent(NonStupidBitField<32*1024/VRAMDirtyGranularity>& dirty);
bool MakeVRAMFlat_AOBJExtPalCoherent(NonStupidBitField<8*1024/VRAMDirtyGranularity>& dirty);
bool MakeVRAMFlat_BOBJExtPalCoherent(NonStupidBitField<8*1024/VRAMDirtyGranularity>& dirty);
bool MakeVRAMFlat_TextureCoherent(NonStupidBitField<512*1024/VRAMDirtyGranularity>& dirty);
bool MakeVRAMFlat_TexPalCoherent(NonStupidBitField<128*1024/VRAMDirtyGranularity>& dirty);
void SyncDirtyFlags();
typedef struct
{
@ -233,7 +301,11 @@ void WriteVRAM_LCDC(u32 addr, T val)
default: return;
}
if (VRAMMap_LCDC & (1<<bank)) *(T*)&VRAM[bank][addr] = val;
if (VRAMMap_LCDC & (1<<bank))
{
*(T*)&VRAM[bank][addr] = val;
VRAMDirty[bank][addr / VRAMDirtyGranularity] = true;
}
}
@ -262,6 +334,8 @@ void WriteVRAM_ABG(u32 addr, T val)
{
u32 mask = VRAMMap_ABG[(addr >> 14) & 0x1F];
VRAMWritten_ABG[(addr & 0x7FFFF) / VRAMDirtyGranularity] = true;
if (mask & (1<<0)) *(T*)&VRAM_A[addr & 0x1FFFF] = val;
if (mask & (1<<1)) *(T*)&VRAM_B[addr & 0x1FFFF] = val;
if (mask & (1<<2)) *(T*)&VRAM_C[addr & 0x1FFFF] = val;
@ -295,6 +369,8 @@ void WriteVRAM_AOBJ(u32 addr, T val)
{
u32 mask = VRAMMap_AOBJ[(addr >> 14) & 0xF];
VRAMWritten_AOBJ[(addr & 0x3FFFF) / VRAMDirtyGranularity] = true;
if (mask & (1<<0)) *(T*)&VRAM_A[addr & 0x1FFFF] = val;
if (mask & (1<<1)) *(T*)&VRAM_B[addr & 0x1FFFF] = val;
if (mask & (1<<4)) *(T*)&VRAM_E[addr & 0xFFFF] = val;
@ -324,6 +400,8 @@ void WriteVRAM_BBG(u32 addr, T val)
{
u32 mask = VRAMMap_BBG[(addr >> 14) & 0x7];
VRAMWritten_BBG[(addr & 0x1FFFF) / VRAMDirtyGranularity] = true;
if (mask & (1<<2)) *(T*)&VRAM_C[addr & 0x1FFFF] = val;
if (mask & (1<<7)) *(T*)&VRAM_H[addr & 0x7FFF] = val;
if (mask & (1<<8)) *(T*)&VRAM_I[addr & 0x3FFF] = val;
@ -350,11 +428,12 @@ void WriteVRAM_BOBJ(u32 addr, T val)
{
u32 mask = VRAMMap_BOBJ[(addr >> 14) & 0x7];
VRAMWritten_BOBJ[(addr & 0x1FFFF) / VRAMDirtyGranularity] = true;
if (mask & (1<<3)) *(T*)&VRAM_D[addr & 0x1FFFF] = val;
if (mask & (1<<8)) *(T*)&VRAM_I[addr & 0x3FFF] = val;
}
template<typename T>
T ReadVRAM_ARM7(u32 addr)
{
@ -372,6 +451,8 @@ void WriteVRAM_ARM7(u32 addr, T val)
{
u32 mask = VRAMMap_ARM7[(addr >> 17) & 0x1];
VRAMWritten_ARM7[(addr & 0x1FFFF) / VRAMDirtyGranularity] = true;
if (mask & (1<<2)) *(T*)&VRAM_C[addr & 0x1FFFF] = val;
if (mask & (1<<3)) *(T*)&VRAM_D[addr & 0x1FFFF] = val;
}

View File

@ -148,12 +148,6 @@ void GPU2D::Reset()
CaptureCnt = 0;
MasterBrightness = 0;
BGExtPalStatus[0] = 0;
BGExtPalStatus[1] = 0;
BGExtPalStatus[2] = 0;
BGExtPalStatus[3] = 0;
OBJExtPalStatus = 0;
}
void GPU2D::DoSavestate(Savestate* file)
@ -208,13 +202,6 @@ void GPU2D::DoSavestate(Savestate* file)
if (!file->Saving)
{
// refresh those
BGExtPalStatus[0] = 0;
BGExtPalStatus[1] = 0;
BGExtPalStatus[2] = 0;
BGExtPalStatus[3] = 0;
OBJExtPalStatus = 0;
CurBGXMosaicTable = MosaicTable[BGMosaicSize[0]];
CurOBJXMosaicTable = MosaicTable[OBJMosaicSize[0]];
}
@ -228,9 +215,6 @@ void GPU2D::SetFramebuffer(u32* buf)
void GPU2D::SetRenderSettings(bool accel)
{
Accelerated = accel;
if (Accelerated) DrawPixel = DrawPixel_Accel;
else DrawPixel = DrawPixel_Normal;
}
@ -761,6 +745,25 @@ void GPU2D::DrawScanline(u32 line)
int n3dline = line;
line = GPU::VCount;
if (Num == 0)
{
auto bgDirty = GPU::VRAMDirty_ABG.DeriveState(GPU::VRAMMap_ABG);
GPU::MakeVRAMFlat_ABGCoherent(bgDirty);
auto bgExtPalDirty = GPU::VRAMDirty_ABGExtPal.DeriveState(GPU::VRAMMap_ABGExtPal);
GPU::MakeVRAMFlat_ABGExtPalCoherent(bgExtPalDirty);
auto objExtPalDirty = GPU::VRAMDirty_AOBJExtPal.DeriveState(&GPU::VRAMMap_AOBJExtPal);
GPU::MakeVRAMFlat_AOBJExtPalCoherent(objExtPalDirty);
}
else
{
auto bgDirty = GPU::VRAMDirty_BBG.DeriveState(GPU::VRAMMap_BBG);
GPU::MakeVRAMFlat_BBGCoherent(bgDirty);
auto bgExtPalDirty = GPU::VRAMDirty_BBGExtPal.DeriveState(GPU::VRAMMap_BBGExtPal);
GPU::MakeVRAMFlat_BBGExtPalCoherent(bgExtPalDirty);
auto objExtPalDirty = GPU::VRAMDirty_BOBJExtPal.DeriveState(&GPU::VRAMMap_BOBJExtPal);
GPU::MakeVRAMFlat_BOBJExtPalCoherent(objExtPalDirty);
}
bool forceblank = false;
// scanlines that end up outside of the GPU drawing range
@ -973,6 +976,9 @@ void GPU2D::DoCapture(u32 line, u32 width)
u16* dst = (u16*)GPU::VRAM[dstvram];
u32 dstaddr = (((CaptureCnt >> 18) & 0x3) << 14) + (line * width);
static_assert(GPU::VRAMDirtyGranularity == 512);
GPU::VRAMDirty[dstvram][(dstaddr & 0x1FFFF) / GPU::VRAMDirtyGranularity] = true;
// TODO: handle 3D in accelerated mode!!
u32* srcA;
@ -1191,85 +1197,20 @@ void GPU2D::SampleFIFO(u32 offset, u32 num)
}
}
void GPU2D::BGExtPalDirty(u32 base)
{
BGExtPalStatus[base] = 0;
BGExtPalStatus[base+1] = 0;
}
void GPU2D::OBJExtPalDirty()
{
OBJExtPalStatus = 0;
}
u16* GPU2D::GetBGExtPal(u32 slot, u32 pal)
{
u16* dst = &BGExtPalCache[slot][pal << 8];
if (!(BGExtPalStatus[slot] & (1<<pal)))
{
if (Num)
{
if (GPU::VRAMMap_BBGExtPal[slot] & (1<<7))
memcpy(dst, &GPU::VRAM_H[(slot << 13) + (pal << 9)], 256*2);
else
memset(dst, 0, 256*2);
}
else
{
memset(dst, 0, 256*2);
if (GPU::VRAMMap_ABGExtPal[slot] & (1<<4))
for (int i = 0; i < 256; i+=2)
*(u32*)&dst[i] |= *(u32*)&GPU::VRAM_E[(slot << 13) + (pal << 9) + (i << 1)];
if (GPU::VRAMMap_ABGExtPal[slot] & (1<<5))
for (int i = 0; i < 256; i+=2)
*(u32*)&dst[i] |= *(u32*)&GPU::VRAM_F[((slot&1) << 13) + (pal << 9) + (i << 1)];
if (GPU::VRAMMap_ABGExtPal[slot] & (1<<6))
for (int i = 0; i < 256; i+=2)
*(u32*)&dst[i] |= *(u32*)&GPU::VRAM_G[((slot&1) << 13) + (pal << 9) + (i << 1)];
}
BGExtPalStatus[slot] |= (1<<pal);
}
return dst;
const u32 PaletteSize = 256 * 2;
const u32 SlotSize = PaletteSize * 16;
return (u16*)&(Num == 0
? GPU::VRAMFlat_ABGExtPal
: GPU::VRAMFlat_BBGExtPal)[slot * SlotSize + pal * PaletteSize];
}
u16* GPU2D::GetOBJExtPal()
{
u16* dst = OBJExtPalCache;
if (!OBJExtPalStatus)
{
if (Num)
{
if (GPU::VRAMMap_BOBJExtPal & (1<<8))
memcpy(dst, &GPU::VRAM_I[0], 16*256*2);
else
memset(dst, 0, 16*256*2);
}
else
{
memset(dst, 0, 16*256*2);
if (GPU::VRAMMap_AOBJExtPal & (1<<5))
for (int i = 0; i < 16*256; i+=2)
*(u32*)&dst[i] |= *(u32*)&GPU::VRAM_F[i << 1];
if (GPU::VRAMMap_AOBJExtPal & (1<<6))
for (int i = 0; i < 16*256; i+=2)
*(u32*)&dst[i] |= *(u32*)&GPU::VRAM_G[i << 1];
}
OBJExtPalStatus = 1;
}
return dst;
return Num == 0
? (u16*)GPU::VRAMFlat_AOBJExtPal
: (u16*)GPU::VRAMFlat_BOBJExtPal;
}
@ -1330,10 +1271,36 @@ void GPU2D::CalculateWindowMask(u32 line)
#define DoDrawBG(type, line, num) \
{ if ((BGCnt[num] & 0x0040) && (BGMosaicSize[0] > 0)) DrawBG_##type<true>(line, num); else DrawBG_##type<false>(line, num); }
{ \
if ((BGCnt[num] & 0x0040) && (BGMosaicSize[0] > 0)) \
{ \
if (Accelerated) DrawBG_##type<true, DrawPixel_Accel>(line, num); \
else DrawBG_##type<true, DrawPixel_Normal>(line, num); \
} \
else \
{ \
if (Accelerated) DrawBG_##type<false, DrawPixel_Accel>(line, num); \
else DrawBG_##type<false, DrawPixel_Normal>(line, num); \
} \
}
#define DoDrawBG_Large(line) \
{ if ((BGCnt[2] & 0x0040) && (BGMosaicSize[0] > 0)) DrawBG_Large<true>(line); else DrawBG_Large<false>(line); }
do \
{ \
if ((BGCnt[2] & 0x0040) && (BGMosaicSize[0] > 0)) \
{ \
if (Accelerated) DrawBG_Large<true, DrawPixel_Accel>(line); \
else DrawBG_Large<true, DrawPixel_Normal>(line); \
} \
else \
{ \
if (Accelerated) DrawBG_Large<false, DrawPixel_Accel>(line); \
else DrawBG_Large<false, DrawPixel_Normal>(line); \
} \
} while (false)
#define DoInterleaveSprites(prio) \
if (Accelerated) InterleaveSprites<DrawPixel_Accel>(prio); else InterleaveSprites<DrawPixel_Normal>(prio);
template<u32 bgmode>
void GPU2D::DrawScanlineBGMode(u32 line)
@ -1382,7 +1349,7 @@ void GPU2D::DrawScanlineBGMode(u32 line)
}
}
if ((DispCnt & 0x1000) && NumSprites)
InterleaveSprites(0x40000 | (i<<16));
DoInterleaveSprites(0x40000 | (i<<16));
}
}
@ -1394,7 +1361,7 @@ void GPU2D::DrawScanlineBGMode6(u32 line)
{
if (DispCnt & 0x0400)
{
DoDrawBG_Large(line)
DoDrawBG_Large(line);
}
}
if ((BGCnt[0] & 0x3) == i)
@ -1406,7 +1373,7 @@ void GPU2D::DrawScanlineBGMode6(u32 line)
}
}
if ((DispCnt & 0x1000) && NumSprites)
InterleaveSprites(0x40000 | (i<<16));
DoInterleaveSprites(0x40000 | (i<<16))
}
}
@ -1434,7 +1401,7 @@ void GPU2D::DrawScanlineBGMode7(u32 line)
}
}
if ((DispCnt & 0x1000) && NumSprites)
InterleaveSprites(0x40000 | (i<<16));
DoInterleaveSprites(0x40000 | (i<<16))
}
}
@ -1674,7 +1641,21 @@ void GPU2D::DrawBG_3D()
}
}
template<bool mosaic>
void GetBGVRAM(u32 num, u8*& data, u32& mask)
{
if (num == 0)
{
data = GPU::VRAMFlat_ABG;
mask = 0x7FFFF;
}
else
{
data = GPU::VRAMFlat_BBG;
mask = 0x1FFFF;
}
}
template<bool mosaic, GPU2D::DrawPixel drawPixel>
void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
{
u16 bgcnt = BGCnt[bgnum];
@ -1697,17 +1678,20 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
extpal = (DispCnt & 0x40000000);
if (extpal) extpalslot = ((bgnum<2) && (bgcnt&0x2000)) ? (2+bgnum) : bgnum;
u8* bgvram;
u32 bgvrammask;
GetBGVRAM(Num, bgvram, bgvrammask);
if (Num)
{
tilesetaddr = 0x06200000 + ((bgcnt & 0x003C) << 12);
tilemapaddr = 0x06200000 + ((bgcnt & 0x1F00) << 3);
tilesetaddr = ((bgcnt & 0x003C) << 12);
tilemapaddr = ((bgcnt & 0x1F00) << 3);
pal = (u16*)&GPU::Palette[0x400];
}
else
{
tilesetaddr = 0x06000000 + ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
tilemapaddr = 0x06000000 + ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
tilesetaddr = ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
tilemapaddr = ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
pal = (u16*)&GPU::Palette[0];
}
@ -1735,7 +1719,7 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
// preload shit as needed
if ((xoff & 0x7) || mosaic)
{
curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + ((xoff & 0xF8) >> 2) + ((xoff & widexmask) << 3));
curtile = *(u16*)&bgvram[(tilemapaddr + ((xoff & 0xF8) >> 2) + ((xoff & widexmask) << 3)) & bgvrammask];
if (extpal) curpal = GetBGExtPal(extpalslot, curtile>>12);
else curpal = pal;
@ -1756,7 +1740,7 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
(mosaic && ((xpos >> 3) != (lastxpos >> 3))))
{
// load a new tile
curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + ((xpos & 0xF8) >> 2) + ((xpos & widexmask) << 3));
curtile = *(u16*)&bgvram[(tilemapaddr + ((xpos & 0xF8) >> 2) + ((xpos & widexmask) << 3)) & bgvrammask];
if (extpal) curpal = GetBGExtPal(extpalslot, curtile>>12);
else curpal = pal;
@ -1771,10 +1755,10 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
if (WindowMask[i] & (1<<bgnum))
{
u32 tilexoff = (curtile & 0x0400) ? (7-(xpos&0x7)) : (xpos&0x7);
color = GPU::ReadVRAM_BG<u8>(pixelsaddr + tilexoff);
color = bgvram[(pixelsaddr + tilexoff) & bgvrammask];
if (color)
DrawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
drawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
}
xoff++;
@ -1787,7 +1771,7 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
// preload shit as needed
if ((xoff & 0x7) || mosaic)
{
curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + ((xoff & 0xF8) >> 2) + ((xoff & widexmask) << 3));
curtile = *(u16*)&bgvram[((tilemapaddr + ((xoff & 0xF8) >> 2) + ((xoff & widexmask) << 3))) & bgvrammask];
curpal = pal + ((curtile & 0xF000) >> 8);
pixelsaddr = tilesetaddr + ((curtile & 0x03FF) << 5)
+ (((curtile & 0x0800) ? (7-(yoff&0x7)) : (yoff&0x7)) << 2);
@ -1805,7 +1789,7 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
(mosaic && ((xpos >> 3) != (lastxpos >> 3))))
{
// load a new tile
curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + ((xpos & 0xF8) >> 2) + ((xpos & widexmask) << 3));
curtile = *(u16*)&bgvram[(tilemapaddr + ((xpos & 0xF8) >> 2) + ((xpos & widexmask) << 3)) & bgvrammask];
curpal = pal + ((curtile & 0xF000) >> 8);
pixelsaddr = tilesetaddr + ((curtile & 0x03FF) << 5)
+ (((curtile & 0x0800) ? (7-(yoff&0x7)) : (yoff&0x7)) << 2);
@ -1819,15 +1803,15 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
u32 tilexoff = (curtile & 0x0400) ? (7-(xpos&0x7)) : (xpos&0x7);
if (tilexoff & 0x1)
{
color = GPU::ReadVRAM_BG<u8>(pixelsaddr + (tilexoff >> 1)) >> 4;
color = bgvram[(pixelsaddr + (tilexoff >> 1)) & bgvrammask] >> 4;
}
else
{
color = GPU::ReadVRAM_BG<u8>(pixelsaddr + (tilexoff >> 1)) & 0x0F;
color = bgvram[(pixelsaddr + (tilexoff >> 1)) & bgvrammask] & 0x0F;
}
if (color)
DrawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
drawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
}
xoff++;
@ -1835,7 +1819,7 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
}
}
template<bool mosaic>
template<bool mosaic, GPU2D::DrawPixel drawPixel>
void GPU2D::DrawBG_Affine(u32 line, u32 bgnum)
{
u16 bgcnt = BGCnt[bgnum];
@ -1872,17 +1856,20 @@ void GPU2D::DrawBG_Affine(u32 line, u32 bgnum)
rotY -= (BGMosaicY * rotD);
}
u8* bgvram;
u32 bgvrammask;
if (Num)
{
tilesetaddr = 0x06200000 + ((bgcnt & 0x003C) << 12);
tilemapaddr = 0x06200000 + ((bgcnt & 0x1F00) << 3);
tilesetaddr = ((bgcnt & 0x003C) << 12);
tilemapaddr = ((bgcnt & 0x1F00) << 3);
pal = (u16*)&GPU::Palette[0x400];
}
else
{
tilesetaddr = 0x06000000 + ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
tilemapaddr = 0x06000000 + ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
tilesetaddr = ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
tilemapaddr = ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
pal = (u16*)&GPU::Palette[0];
}
@ -1911,16 +1898,16 @@ void GPU2D::DrawBG_Affine(u32 line, u32 bgnum)
if ((!((finalX|finalY) & overflowmask)))
{
curtile = GPU::ReadVRAM_BG<u8>(tilemapaddr + ((((finalY & coordmask) >> 11) << yshift) + ((finalX & coordmask) >> 11)));
curtile = bgvram[(tilemapaddr + ((((finalY & coordmask) >> 11) << yshift) + ((finalX & coordmask) >> 11))) & bgvrammask];
// draw pixel
u32 tilexoff = (finalX >> 8) & 0x7;
u32 tileyoff = (finalY >> 8) & 0x7;
color = GPU::ReadVRAM_BG<u8>(tilesetaddr + (curtile << 6) + (tileyoff << 3) + tilexoff);
color = bgvram[(tilesetaddr + (curtile << 6) + (tileyoff << 3) + tilexoff) & bgvrammask];
if (color)
DrawPixel(&BGOBJLine[i], pal[color], 0x01000000<<bgnum);
drawPixel(&BGOBJLine[i], pal[color], 0x01000000<<bgnum);
}
}
@ -1932,7 +1919,7 @@ void GPU2D::DrawBG_Affine(u32 line, u32 bgnum)
BGYRefInternal[bgnum-2] += rotD;
}
template<bool mosaic>
template<bool mosaic, GPU2D::DrawPixel drawPixel>
void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
{
u16 bgcnt = BGCnt[bgnum];
@ -1941,6 +1928,10 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
u16* pal;
u32 extpal;
u8* bgvram;
u32 bgvrammask;
GetBGVRAM(Num, bgvram, bgvrammask);
extpal = (DispCnt & 0x40000000);
s16 rotA = BGRotA[bgnum-2];
@ -1984,8 +1975,8 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
ofymask = ~ymask;
}
if (Num) tilemapaddr = 0x06200000 + ((bgcnt & 0x1F00) << 6);
else tilemapaddr = 0x06000000 + ((bgcnt & 0x1F00) << 6);
if (Num) tilemapaddr = ((bgcnt & 0x1F00) << 6);
else tilemapaddr = ((bgcnt & 0x1F00) << 6);
if (bgcnt & 0x0004)
{
@ -2012,10 +2003,10 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
if (!(finalX & ofxmask) && !(finalY & ofymask))
{
color = GPU::ReadVRAM_BG<u16>(tilemapaddr + (((((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8)) << 1));
color = *(u16*)&bgvram[(tilemapaddr + (((((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8)) << 1)) & bgvrammask];
if (color & 0x8000)
DrawPixel(&BGOBJLine[i], color, 0x01000000<<bgnum);
drawPixel(&BGOBJLine[i], color, 0x01000000<<bgnum);
}
}
@ -2051,10 +2042,10 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
if (!(finalX & ofxmask) && !(finalY & ofymask))
{
color = GPU::ReadVRAM_BG<u8>(tilemapaddr + (((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8));
color = bgvram[(tilemapaddr + (((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8)) & bgvrammask];
if (color)
DrawPixel(&BGOBJLine[i], pal[color], 0x01000000<<bgnum);
drawPixel(&BGOBJLine[i], pal[color], 0x01000000<<bgnum);
}
}
@ -2083,15 +2074,15 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
if (Num)
{
tilesetaddr = 0x06200000 + ((bgcnt & 0x003C) << 12);
tilemapaddr = 0x06200000 + ((bgcnt & 0x1F00) << 3);
tilesetaddr = ((bgcnt & 0x003C) << 12);
tilemapaddr = ((bgcnt & 0x1F00) << 3);
pal = (u16*)&GPU::Palette[0x400];
}
else
{
tilesetaddr = 0x06000000 + ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
tilemapaddr = 0x06000000 + ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
tilesetaddr = ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
tilemapaddr = ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
pal = (u16*)&GPU::Palette[0];
}
@ -2121,7 +2112,7 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
if ((!((finalX|finalY) & overflowmask)))
{
curtile = GPU::ReadVRAM_BG<u16>(tilemapaddr + (((((finalY & coordmask) >> 11) << yshift) + ((finalX & coordmask) >> 11)) << 1));
curtile = *(u16*)&bgvram[(tilemapaddr + (((((finalY & coordmask) >> 11) << yshift) + ((finalX & coordmask) >> 11)) << 1)) & bgvrammask];
if (extpal) curpal = GetBGExtPal(bgnum, curtile>>12);
else curpal = pal;
@ -2133,10 +2124,10 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
if (curtile & 0x0400) tilexoff = 7-tilexoff;
if (curtile & 0x0800) tileyoff = 7-tileyoff;
color = GPU::ReadVRAM_BG<u8>(tilesetaddr + ((curtile & 0x03FF) << 6) + (tileyoff << 3) + tilexoff);
color = bgvram[(tilesetaddr + ((curtile & 0x03FF) << 6) + (tileyoff << 3) + tilexoff) & bgvrammask];
if (color)
DrawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
drawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
}
}
@ -2149,7 +2140,7 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
BGYRefInternal[bgnum-2] += rotD;
}
template<bool mosaic>
template<bool mosaic, GPU2D::DrawPixel drawPixel>
void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
{
u16 bgcnt = BGCnt[2];
@ -2199,8 +2190,9 @@ void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
rotY -= (BGMosaicY * rotD);
}
if (Num) tilemapaddr = 0x06200000;
else tilemapaddr = 0x06000000;
u8* bgvram;
u32 bgvrammask;
GetBGVRAM(Num, bgvram, bgvrammask);
// 256-color bitmap
@ -2228,10 +2220,10 @@ void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
if (!(finalX & ofxmask) && !(finalY & ofymask))
{
color = GPU::ReadVRAM_BG<u8>(tilemapaddr + (((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8));
color = bgvram[(tilemapaddr + (((finalY & ymask) >> 8) << yshift) + ((finalX & xmask) >> 8)) & bgvrammask];
if (color)
DrawPixel(&BGOBJLine[i], pal[color], 0x01000000<<2);
drawPixel(&BGOBJLine[i], pal[color], 0x01000000<<2);
}
}
@ -2274,6 +2266,7 @@ void GPU2D::ApplySpriteMosaicX()
}
}
template <GPU2D::DrawPixel drawPixel>
void GPU2D::InterleaveSprites(u32 prio)
{
u16* pal = (u16*)&GPU::Palette[Num ? 0x600 : 0x200];
@ -2297,7 +2290,7 @@ void GPU2D::InterleaveSprites(u32 prio)
else
color = extpal[pixel & 0xFFF];
DrawPixel(&BGOBJLine[i], color, pixel & 0xFF000000);
drawPixel(&BGOBJLine[i], color, pixel & 0xFF000000);
}
}
else
@ -2317,11 +2310,25 @@ void GPU2D::InterleaveSprites(u32 prio)
else
color = pal[pixel & 0xFF];
DrawPixel(&BGOBJLine[i], color, pixel & 0xFF000000);
drawPixel(&BGOBJLine[i], color, pixel & 0xFF000000);
}
}
}
void GetOBJVRAM(u32 num, u8*& data, u32& mask)
{
if (num == 0)
{
data = GPU::VRAMFlat_AOBJ;
mask = 0x3FFFF;
}
else
{
data = GPU::VRAMFlat_BOBJ;
mask = 0x1FFFF;
}
}
#define DoDrawSprite(type, ...) \
if (iswin) \
{ \
@ -2346,6 +2353,17 @@ void GPU2D::DrawSprites(u32 line)
OBJMosaicYCount = 0;
}
if (Num == 0)
{
auto objDirty = GPU::VRAMDirty_AOBJ.DeriveState(GPU::VRAMMap_AOBJ);
GPU::MakeVRAMFlat_AOBJCoherent(objDirty);
}
else
{
auto objDirty = GPU::VRAMDirty_BOBJ.DeriveState(GPU::VRAMMap_BOBJ);
GPU::MakeVRAMFlat_BOBJCoherent(objDirty);
}
NumSprites = 0;
memset(OBJLine, 0, 256*4);
memset(OBJWindow, 0, 256);
@ -2458,6 +2476,10 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
u32 ytilefactor;
u8* objvram;
u32 objvrammask;
GetOBJVRAM(Num, objvram, objvrammask);
s32 centerX = boundwidth >> 1;
s32 centerY = boundheight >> 1;
@ -2501,6 +2523,7 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
pixelattr |= (0xC0000000 | (alpha << 24));
u32 pixelsaddr;
if (DispCnt & 0x40)
{
if (DispCnt & 0x20)
@ -2512,7 +2535,7 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
}
else
{
tilenum <<= (7 + ((DispCnt >> 22) & 0x1));
pixelsaddr = tilenum << (7 + ((DispCnt >> 22) & 0x1));
ytilefactor = ((width >> 8) * 2);
}
}
@ -2520,23 +2543,21 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
{
if (DispCnt & 0x20)
{
tilenum = ((tilenum & 0x01F) << 4) + ((tilenum & 0x3E0) << 7);
pixelsaddr = ((tilenum & 0x01F) << 4) + ((tilenum & 0x3E0) << 7);
ytilefactor = (256 * 2);
}
else
{
tilenum = ((tilenum & 0x00F) << 4) + ((tilenum & 0x3F0) << 7);
pixelsaddr = ((tilenum & 0x00F) << 4) + ((tilenum & 0x3F0) << 7);
ytilefactor = (128 * 2);
}
}
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
for (; xoff < boundwidth;)
{
if ((u32)rotX < width && (u32)rotY < height)
{
color = GPU::ReadVRAM_OBJ<u16>(pixelsaddr + ((rotY >> 8) * ytilefactor) + ((rotX >> 8) << 1));
color = *(u16*)&objvram[(pixelsaddr + ((rotY >> 8) * ytilefactor) + ((rotX >> 8) << 1)) & objvrammask];
if (color & 0x8000)
{
@ -2561,9 +2582,10 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
}
else
{
u32 pixelsaddr = tilenum;
if (DispCnt & 0x10)
{
tilenum <<= ((DispCnt >> 20) & 0x3);
pixelsaddr <<= ((DispCnt >> 20) & 0x3);
ytilefactor = (width >> 11) << ((attrib[0] & 0x2000) ? 1:0);
}
else
@ -2574,12 +2596,12 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
if (spritemode == 1) pixelattr |= 0x80000000;
else pixelattr |= 0x10000000;
ytilefactor <<= 5;
pixelsaddr <<= 5;
if (attrib[0] & 0x2000)
{
// 256-color
tilenum <<= 5;
ytilefactor <<= 5;
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
if (!window)
{
@ -2593,7 +2615,7 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
{
if ((u32)rotX < width && (u32)rotY < height)
{
color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr + ((rotY>>11)*ytilefactor) + ((rotY&0x700)>>5) + ((rotX>>11)*64) + ((rotX&0x700)>>8));
color = objvram[(pixelsaddr + ((rotY>>11)*ytilefactor) + ((rotY&0x700)>>5) + ((rotX>>11)*64) + ((rotX&0x700)>>8)) & objvrammask];
if (color)
{
@ -2619,10 +2641,6 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
else
{
// 16-color
tilenum <<= 5;
ytilefactor <<= 5;
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
if (!window)
{
pixelattr |= 0x1000;
@ -2633,7 +2651,7 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
{
if ((u32)rotX < width && (u32)rotY < height)
{
color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr + ((rotY>>11)*ytilefactor) + ((rotY&0x700)>>6) + ((rotX>>11)*32) + ((rotX&0x700)>>9));
color = objvram[(pixelsaddr + ((rotY>>11)*ytilefactor) + ((rotY&0x700)>>6) + ((rotX>>11)*32) + ((rotX&0x700)>>9)) & objvrammask];
if (rotX & 0x100)
color >>= 4;
else
@ -2681,6 +2699,10 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
pixelattr |= 0x100000;
}
u8* objvram;
u32 objvrammask;
GetOBJVRAM(Num, objvram, objvrammask);
// yflip
if (attrib[1] & 0x2000)
ypos = height-1 - ypos;
@ -2711,6 +2733,7 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
pixelattr |= (0xC0000000 | (alpha << 24));
u32 pixelsaddr = tilenum;
if (DispCnt & 0x40)
{
if (DispCnt & 0x20)
@ -2722,25 +2745,24 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
}
else
{
tilenum <<= (7 + ((DispCnt >> 22) & 0x1));
tilenum += (ypos * width * 2);
pixelsaddr <<= (7 + ((DispCnt >> 22) & 0x1));
pixelsaddr += (ypos * width * 2);
}
}
else
{
if (DispCnt & 0x20)
{
tilenum = ((tilenum & 0x01F) << 4) + ((tilenum & 0x3E0) << 7);
tilenum += (ypos * 256 * 2);
pixelsaddr = ((tilenum & 0x01F) << 4) + ((tilenum & 0x3E0) << 7);
pixelsaddr += (ypos * 256 * 2);
}
else
{
tilenum = ((tilenum & 0x00F) << 4) + ((tilenum & 0x3F0) << 7);
tilenum += (ypos * 128 * 2);
pixelsaddr = ((tilenum & 0x00F) << 4) + ((tilenum & 0x3F0) << 7);
pixelsaddr += (ypos * 128 * 2);
}
}
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
s32 pixelstride;
if (attrib[1] & 0x1000) // xflip
@ -2757,7 +2779,7 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
for (; xoff < xend;)
{
color = GPU::ReadVRAM_OBJ<u16>(pixelsaddr);
color = *(u16*)&objvram[pixelsaddr & objvrammask];
pixelsaddr += pixelstride;
@ -2781,14 +2803,15 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
}
else
{
u32 pixelsaddr = tilenum;
if (DispCnt & 0x10)
{
tilenum <<= ((DispCnt >> 20) & 0x3);
tilenum += ((ypos >> 3) * (width >> 3)) << ((attrib[0] & 0x2000) ? 1:0);
pixelsaddr <<= ((DispCnt >> 20) & 0x3);
pixelsaddr += ((ypos >> 3) * (width >> 3)) << ((attrib[0] & 0x2000) ? 1:0);
}
else
{
tilenum += ((ypos >> 3) * 0x20);
pixelsaddr += ((ypos >> 3) * 0x20);
}
if (spritemode == 1) pixelattr |= 0x80000000;
@ -2797,8 +2820,7 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
if (attrib[0] & 0x2000)
{
// 256-color
tilenum <<= 5;
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
pixelsaddr <<= 5;
pixelsaddr += ((ypos & 0x7) << 3);
s32 pixelstride;
@ -2827,7 +2849,7 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
for (; xoff < xend;)
{
color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr);
color = objvram[pixelsaddr];
pixelsaddr += pixelstride;
@ -2853,8 +2875,7 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
else
{
// 16-color
tilenum <<= 5;
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
pixelsaddr <<= 5;
pixelsaddr += ((ypos & 0x7) << 2);
s32 pixelstride;
@ -2886,13 +2907,13 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
{
if (attrib[1] & 0x1000)
{
if (xoff & 0x1) { color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) & 0x0F; pixelsaddr--; }
else color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) >> 4;
if (xoff & 0x1) { color = objvram[pixelsaddr & objvrammask] & 0x0F; pixelsaddr--; }
else color = objvram[pixelsaddr & objvrammask] >> 4;
}
else
{
if (xoff & 0x1) { color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) >> 4; pixelsaddr++; }
else color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) & 0x0F;
if (xoff & 0x1) { color = objvram[pixelsaddr & objvrammask] >> 4; pixelsaddr++; }
else color = objvram[pixelsaddr & objvrammask] & 0x0F;
}
if (color)

View File

@ -59,9 +59,6 @@ public:
void CheckWindows(u32 line);
void BGExtPalDirty(u32 base);
void OBJExtPalDirty();
u16* GetBGExtPal(u32 slot, u32 pal);
u16* GetOBJExtPal();
@ -128,9 +125,6 @@ private:
u16 MasterBrightness;
u16 BGExtPalCache[4][16*256];
u16 OBJExtPalCache[16*256];
u32 BGExtPalStatus[4];
u32 OBJExtPalStatus;
u32 ColorBlend4(u32 val1, u32 val2, u32 eva, u32 evb);
u32 ColorBlend5(u32 val1, u32 val2);
@ -147,15 +141,17 @@ private:
static void DrawPixel_Normal(u32* dst, u16 color, u32 flag);
static void DrawPixel_Accel(u32* dst, u16 color, u32 flag);
void (*DrawPixel)(u32* dst, u16 color, u32 flag);
typedef void (*DrawPixel)(u32* dst, u16 color, u32 flag);
void DrawBG_3D();
template<bool mosaic> void DrawBG_Text(u32 line, u32 bgnum);
template<bool mosaic> void DrawBG_Affine(u32 line, u32 bgnum);
template<bool mosaic> void DrawBG_Extended(u32 line, u32 bgnum);
template<bool mosaic> void DrawBG_Large(u32 line);
template<bool mosaic, DrawPixel drawPixel> void DrawBG_Text(u32 line, u32 bgnum);
template<bool mosaic, DrawPixel drawPixel> void DrawBG_Affine(u32 line, u32 bgnum);
template<bool mosaic, DrawPixel drawPixel> void DrawBG_Extended(u32 line, u32 bgnum);
template<bool mosaic, DrawPixel drawPixel> void DrawBG_Large(u32 line);
void ApplySpriteMosaicX();
template<DrawPixel drawPixel>
void InterleaveSprites(u32 prio);
template<bool window> void DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos);
template<bool window> void DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos);

View File

@ -179,6 +179,8 @@ u8 RenderFogDensityTable[34];
u32 RenderClearAttr1, RenderClearAttr2;
bool RenderFrameIdentical;
u32 ZeroDotWLimit;
u32 GXStat;
@ -2491,6 +2493,19 @@ void VBlank()
}
RenderNumPolygons = NumPolygons;
RenderFrameIdentical = false;
}
else
{
RenderFrameIdentical = RenderDispCnt == DispCnt
&& RenderAlphaRef == AlphaRef
&& RenderClearAttr1 == ClearAttr1
&& RenderClearAttr2 == ClearAttr2
&& RenderFogColor == FogColor
&& RenderFogOffset == FogOffset * 0x200
&& memcmp(RenderEdgeTable, EdgeTable, 8*2) == 0
&& memcmp(RenderFogDensityTable + 1, FogDensityTable, 32) == 0
&& memcmp(RenderToonTable, ToonTable, 32*2) == 0;
}
RenderDispCnt = DispCnt;

View File

@ -87,6 +87,8 @@ extern u8 RenderFogDensityTable[34];
extern u32 RenderClearAttr1, RenderClearAttr2;
extern bool RenderFrameIdentical;
extern std::array<Polygon*,2048> RenderPolygonRAM;
extern u32 RenderNumPolygons;

View File

@ -74,11 +74,11 @@ typedef struct
Polygon* PolyData;
u32 NumIndices;
u16* Indices;
u32 IndicesOffset;
GLuint PrimType;
u32 NumEdgeIndices;
u16* EdgeIndices;
u32 EdgeIndicesOffset;
u32 RenderKey;
@ -107,7 +107,11 @@ u32 VertexBuffer[10240 * 7];
u32 NumVertices;
GLuint VertexArrayID;
GLuint IndexBufferID;
u16 IndexBuffer[2048 * 40];
u32 NumIndices, NumEdgeIndices;
const u32 EdgeIndicesOffset = 2048 * 30;
GLuint TexMemID;
GLuint TexPalMemID;
@ -320,6 +324,9 @@ bool Init()
glEnableVertexAttribArray(3); // attrib
glVertexAttribIPointer(3, 3, GL_UNSIGNED_INT, 7*4, (void*)(4*4));
glGenBuffers(1, &IndexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(IndexBuffer), NULL, GL_DYNAMIC_DRAW);
glGenFramebuffers(4, &FramebufferID[0]);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[0]);
@ -563,15 +570,15 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
u32* vptr = &VertexBuffer[0];
u32 vidx = 0;
u16* iptr = &IndexBuffer[0];
u16* eiptr = &IndexBuffer[2048*30];
u32 iidx = 0;
u32 eidx = EdgeIndicesOffset;
for (int i = 0; i < npolys; i++)
{
RendererPolygon* rp = &polygons[i];
Polygon* poly = rp->PolyData;
rp->Indices = iptr;
rp->IndicesOffset = iidx;
rp->NumIndices = 0;
u32 vidx_first = vidx;
@ -606,7 +613,7 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
*iptr++ = vidx;
IndexBuffer[iidx++] = vidx;
rp->NumIndices++;
vidx++;
@ -627,9 +634,9 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
}
// build a triangle
*iptr++ = vidx_first;
*iptr++ = vidx - 2;
*iptr++ = vidx - 1;
IndexBuffer[iidx++] = vidx_first;
IndexBuffer[iidx++] = vidx - 2;
IndexBuffer[iidx++] = vidx - 1;
rp->NumIndices += 3;
}
else // quad, pentagon, etc
@ -649,9 +656,9 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
if (j >= 2)
{
// build a triangle
*iptr++ = vidx_first;
*iptr++ = vidx - 1;
*iptr++ = vidx;
IndexBuffer[iidx++] = vidx_first;
IndexBuffer[iidx++] = vidx - 1;
IndexBuffer[iidx++] = vidx;
rp->NumIndices += 3;
}
@ -743,46 +750,48 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
if (j >= 1)
{
// build a triangle
*iptr++ = vidx_first;
*iptr++ = vidx - 1;
*iptr++ = vidx;
IndexBuffer[iidx++] = vidx_first;
IndexBuffer[iidx++] = vidx - 1;
IndexBuffer[iidx++] = vidx;
rp->NumIndices += 3;
}
vidx++;
}
*iptr++ = vidx_first;
*iptr++ = vidx - 1;
*iptr++ = vidx_first + 1;
IndexBuffer[iidx++] = vidx_first;
IndexBuffer[iidx++] = vidx - 1;
IndexBuffer[iidx++] = vidx_first + 1;
rp->NumIndices += 3;
}
}
rp->EdgeIndices = eiptr;
rp->EdgeIndicesOffset = eidx;
rp->NumEdgeIndices = 0;
u32 vidx_cur = vidx_first;
for (int j = 1; j < poly->NumVertices; j++)
{
*eiptr++ = vidx_cur;
*eiptr++ = vidx_cur + 1;
IndexBuffer[eidx++] = vidx_cur;
IndexBuffer[eidx++] = vidx_cur + 1;
vidx_cur++;
rp->NumEdgeIndices += 2;
}
*eiptr++ = vidx_cur;
*eiptr++ = vidx_first;
IndexBuffer[eidx++] = vidx_cur;
IndexBuffer[eidx++] = vidx_first;
rp->NumEdgeIndices += 2;
}
NumVertices = vidx;
NumIndices = iidx;
NumEdgeIndices = eidx - EdgeIndicesOffset;
}
void RenderSinglePolygon(int i)
{
RendererPolygon* rp = &PolygonList[i];
glDrawElements(rp->PrimType, rp->NumIndices, GL_UNSIGNED_SHORT, rp->Indices);
glDrawElements(rp->PrimType, rp->NumIndices, GL_UNSIGNED_SHORT, (void*)(uintptr_t)(rp->IndicesOffset * 2));
}
int RenderPolygonBatch(int i)
@ -803,7 +812,7 @@ int RenderPolygonBatch(int i)
numindices += cur_rp->NumIndices;
}
glDrawElements(primtype, numindices, GL_UNSIGNED_SHORT, rp->Indices);
glDrawElements(primtype, numindices, GL_UNSIGNED_SHORT, (void*)(uintptr_t)(rp->IndicesOffset * 2));
return numpolys;
}
@ -823,7 +832,7 @@ int RenderPolygonEdgeBatch(int i)
numindices += cur_rp->NumEdgeIndices;
}
glDrawElements(GL_LINES, numindices, GL_UNSIGNED_SHORT, rp->EdgeIndices);
glDrawElements(GL_LINES, numindices, GL_UNSIGNED_SHORT, (void*)(uintptr_t)(rp->EdgeIndicesOffset * 2));
return numpolys;
}
@ -1320,6 +1329,11 @@ void RenderFrame()
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
glBufferSubData(GL_ARRAY_BUFFER, 0, NumVertices*7*4, VertexBuffer);
// bind to access the index buffer
glBindVertexArray(VertexArrayID);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, NumIndices * 2, IndexBuffer);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, EdgeIndicesOffset * 2, NumEdgeIndices * 2, IndexBuffer + EdgeIndicesOffset);
RenderSceneChunk(0, 192);
}

View File

@ -58,15 +58,17 @@ bool PrevIsShadowMask;
bool Enabled;
bool FrameIdentical;
// threading
bool Threaded;
void* RenderThread;
Platform::Thread* RenderThread;
bool RenderThreadRunning;
bool RenderThreadRendering;
void* Sema_RenderStart;
void* Sema_RenderDone;
void* Sema_ScanlineCount;
Platform::Semaphore* Sema_RenderStart;
Platform::Semaphore* Sema_RenderDone;
Platform::Semaphore* Sema_ScanlineCount;
void RenderThreadFunc();
@ -550,6 +552,16 @@ typedef struct
RendererPolygon PolygonList[2048];
template <typename T>
inline T ReadVRAM_Texture(u32 addr)
{
return *(T*)&GPU::VRAMFlat_Texture[addr & 0x7FFFF];
}
template <typename T>
inline T ReadVRAM_TexPal(u32 addr)
{
return *(T*)&GPU::VRAMFlat_TexPal[addr & 0x1FFFF];
}
void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha)
{
@ -606,10 +618,10 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
case 1: // A3I5
{
vramaddr += ((t * width) + s);
u8 pixel = GPU::ReadVRAM_Texture<u8>(vramaddr);
u8 pixel = ReadVRAM_Texture<u8>(vramaddr);
texpal <<= 4;
*color = GPU::ReadVRAM_TexPal<u16>(texpal + ((pixel&0x1F)<<1));
*color = ReadVRAM_TexPal<u16>(texpal + ((pixel&0x1F)<<1));
*alpha = ((pixel >> 3) & 0x1C) + (pixel >> 6);
}
break;
@ -617,12 +629,12 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
case 2: // 4-color
{
vramaddr += (((t * width) + s) >> 2);
u8 pixel = GPU::ReadVRAM_Texture<u8>(vramaddr);
u8 pixel = ReadVRAM_Texture<u8>(vramaddr);
pixel >>= ((s & 0x3) << 1);
pixel &= 0x3;
texpal <<= 3;
*color = GPU::ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
*color = ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
*alpha = (pixel==0) ? alpha0 : 31;
}
break;
@ -630,12 +642,12 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
case 3: // 16-color
{
vramaddr += (((t * width) + s) >> 1);
u8 pixel = GPU::ReadVRAM_Texture<u8>(vramaddr);
u8 pixel = ReadVRAM_Texture<u8>(vramaddr);
if (s & 0x1) pixel >>= 4;
else pixel &= 0xF;
texpal <<= 4;
*color = GPU::ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
*color = ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
*alpha = (pixel==0) ? alpha0 : 31;
}
break;
@ -643,10 +655,10 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
case 4: // 256-color
{
vramaddr += ((t * width) + s);
u8 pixel = GPU::ReadVRAM_Texture<u8>(vramaddr);
u8 pixel = ReadVRAM_Texture<u8>(vramaddr);
texpal <<= 4;
*color = GPU::ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
*color = ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
*alpha = (pixel==0) ? alpha0 : 31;
}
break;
@ -660,30 +672,30 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
if (vramaddr >= 0x40000)
slot1addr += 0x10000;
u8 val = GPU::ReadVRAM_Texture<u8>(vramaddr);
u8 val = ReadVRAM_Texture<u8>(vramaddr);
val >>= (2 * (s & 0x3));
u16 palinfo = GPU::ReadVRAM_Texture<u16>(slot1addr);
u16 palinfo = ReadVRAM_Texture<u16>(slot1addr);
u32 paloffset = (palinfo & 0x3FFF) << 2;
texpal <<= 4;
switch (val & 0x3)
{
case 0:
*color = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset);
*color = ReadVRAM_TexPal<u16>(texpal + paloffset);
*alpha = 31;
break;
case 1:
*color = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
*color = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
*alpha = 31;
break;
case 2:
if ((palinfo >> 14) == 1)
{
u16 color0 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset);
u16 color1 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
u16 color0 = ReadVRAM_TexPal<u16>(texpal + paloffset);
u16 color1 = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
u32 r0 = color0 & 0x001F;
u32 g0 = color0 & 0x03E0;
@ -700,8 +712,8 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
}
else if ((palinfo >> 14) == 3)
{
u16 color0 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset);
u16 color1 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
u16 color0 = ReadVRAM_TexPal<u16>(texpal + paloffset);
u16 color1 = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
u32 r0 = color0 & 0x001F;
u32 g0 = color0 & 0x03E0;
@ -717,20 +729,20 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
*color = r | g | b;
}
else
*color = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 4);
*color = ReadVRAM_TexPal<u16>(texpal + paloffset + 4);
*alpha = 31;
break;
case 3:
if ((palinfo >> 14) == 2)
{
*color = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 6);
*color = ReadVRAM_TexPal<u16>(texpal + paloffset + 6);
*alpha = 31;
}
else if ((palinfo >> 14) == 3)
{
u16 color0 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset);
u16 color1 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
u16 color0 = ReadVRAM_TexPal<u16>(texpal + paloffset);
u16 color1 = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
u32 r0 = color0 & 0x001F;
u32 g0 = color0 & 0x03E0;
@ -759,10 +771,10 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
case 6: // A5I3
{
vramaddr += ((t * width) + s);
u8 pixel = GPU::ReadVRAM_Texture<u8>(vramaddr);
u8 pixel = ReadVRAM_Texture<u8>(vramaddr);
texpal <<= 4;
*color = GPU::ReadVRAM_TexPal<u16>(texpal + ((pixel&0x7)<<1));
*color = ReadVRAM_TexPal<u16>(texpal + ((pixel&0x7)<<1));
*alpha = (pixel >> 3);
}
break;
@ -770,7 +782,7 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
case 7: // direct color
{
vramaddr += (((t * width) + s) << 1);
*color = GPU::ReadVRAM_Texture<u16>(vramaddr);
*color = ReadVRAM_Texture<u16>(vramaddr);
*alpha = (*color & 0x8000) ? 31 : 0;
}
break;
@ -2007,8 +2019,8 @@ void ClearBuffers()
{
for (int x = 0; x < 256; x++)
{
u16 val2 = GPU::ReadVRAM_Texture<u16>(0x40000 + (yoff << 9) + (xoff << 1));
u16 val3 = GPU::ReadVRAM_Texture<u16>(0x60000 + (yoff << 9) + (xoff << 1));
u16 val2 = ReadVRAM_Texture<u16>(0x40000 + (yoff << 9) + (xoff << 1));
u16 val3 = ReadVRAM_Texture<u16>(0x60000 + (yoff << 9) + (xoff << 1));
// TODO: confirm color conversion
u32 r = (val2 << 1) & 0x3E; if (r) r++;
@ -2088,11 +2100,19 @@ void VCount144()
void RenderFrame()
{
auto textureDirty = GPU::VRAMDirty_Texture.DeriveState(GPU::VRAMMap_Texture);
auto texPalDirty = GPU::VRAMDirty_TexPal.DeriveState(GPU::VRAMMap_TexPal);
bool textureChanged = GPU::MakeVRAMFlat_TextureCoherent(textureDirty);
bool texPalChanged = GPU::MakeVRAMFlat_TexPalCoherent(texPalDirty);
FrameIdentical = !(textureChanged || texPalChanged) && RenderFrameIdentical;
if (RenderThreadRunning)
{
Platform::Semaphore_Post(Sema_RenderStart);
}
else
else if (!FrameIdentical)
{
ClearBuffers();
RenderPolygons(false, &RenderPolygonRAM[0], RenderNumPolygons);
@ -2107,8 +2127,15 @@ void RenderThreadFunc()
if (!RenderThreadRunning) return;
RenderThreadRendering = true;
ClearBuffers();
RenderPolygons(true, &RenderPolygonRAM[0], RenderNumPolygons);
if (FrameIdentical)
{
Platform::Semaphore_Post(Sema_ScanlineCount, 192);
}
else
{
ClearBuffers();
RenderPolygons(true, &RenderPolygonRAM[0], RenderNumPolygons);
}
Platform::Semaphore_Post(Sema_RenderDone);
RenderThreadRendering = false;

View File

@ -210,13 +210,13 @@ bool Init()
void DeInit()
{
delete ARM9;
delete ARM7;
#ifdef JIT_ENABLED
ARMJIT::DeInit();
#endif
delete ARM9;
delete ARM7;
for (int i = 0; i < 8; i++)
delete DMAs[i];
@ -908,7 +908,7 @@ void RunSystem(u64 timestamp)
}
}
template <bool EnableJIT>
template <bool EnableJIT, int ConsoleType>
u32 RunFrame()
{
FrameStartTimestamp = SysTimestamp;
@ -934,10 +934,10 @@ u32 RunFrame()
}
else if (CPUStop & 0x0FFF)
{
DMAs[0]->Run();
if (!(CPUStop & 0x80000000)) DMAs[1]->Run();
if (!(CPUStop & 0x80000000)) DMAs[2]->Run();
if (!(CPUStop & 0x80000000)) DMAs[3]->Run();
DMAs[0]->Run<ConsoleType>();
if (!(CPUStop & 0x80000000)) DMAs[1]->Run<ConsoleType>();
if (!(CPUStop & 0x80000000)) DMAs[2]->Run<ConsoleType>();
if (!(CPUStop & 0x80000000)) DMAs[3]->Run<ConsoleType>();
if (ConsoleType == 1) DSi::RunNDMAs(0);
}
else
@ -962,10 +962,10 @@ u32 RunFrame()
if (CPUStop & 0x0FFF0000)
{
DMAs[4]->Run();
DMAs[5]->Run();
DMAs[6]->Run();
DMAs[7]->Run();
DMAs[4]->Run<ConsoleType>();
DMAs[5]->Run<ConsoleType>();
DMAs[6]->Run<ConsoleType>();
DMAs[7]->Run<ConsoleType>();
if (ConsoleType == 1) DSi::RunNDMAs(1);
}
else
@ -999,6 +999,9 @@ u32 RunFrame()
ARM7Timestamp-SysTimestamp,
GPU3D::Timestamp-SysTimestamp);
#endif
SPU::TransferOutput();
NDSCart::FlushSRAMFile();
NumFrames++;
@ -1009,10 +1012,14 @@ u32 RunFrame()
{
#ifdef JIT_ENABLED
if (Config::JIT_Enable)
return RunFrame<true>();
return NDS::ConsoleType == 1
? RunFrame<true, 1>()
: RunFrame<true, 0>();
else
#endif
return RunFrame<false>();
return NDS::ConsoleType == 1
? RunFrame<false, 1>()
: RunFrame<false, 0>();
}
void Reschedule(u64 target)
@ -3130,6 +3137,10 @@ void ARM9IOWrite8(u32 addr, u8 val)
NDSCart::WriteSPIData(val);
return;
case 0x04000188:
ARM9IOWrite32(addr, val | (val << 8) | (val << 16) | (val << 24));
return;
case 0x040001A8: NDSCart::ROMCommand[0] = val; return;
case 0x040001A9: NDSCart::ROMCommand[1] = val; return;
case 0x040001AA: NDSCart::ROMCommand[2] = val; return;
@ -3246,6 +3257,10 @@ void ARM9IOWrite16(u32 addr, u16 val)
IPCFIFOCnt9 = val & 0x8404;
return;
case 0x04000188:
ARM9IOWrite32(addr, val | (val << 16));
return;
case 0x040001A0:
if (!(ExMemCnt[0] & (1<<11))) NDSCart::WriteSPICnt(val);
return;
@ -3733,6 +3748,10 @@ void ARM7IOWrite8(u32 addr, u8 val)
case 0x04000138: RTC::Write(val, true); return;
case 0x04000188:
ARM7IOWrite32(addr, val | (val << 8) | (val << 16) | (val << 24));
return;
case 0x040001A0:
if (ExMemCnt[0] & (1<<11))
{
@ -3841,6 +3860,10 @@ void ARM7IOWrite16(u32 addr, u16 val)
IPCFIFOCnt7 = val & 0x8404;
return;
case 0x04000188:
ARM7IOWrite32(addr, val | (val << 16));
return;
case 0x040001A0:
if (ExMemCnt[0] & (1<<11))
NDSCart::WriteSPICnt(val);

View File

@ -37,6 +37,7 @@ u8* SRAM;
u32 SRAMLength;
char SRAMPath[1024];
bool SRAMFileDirty;
void (*WriteFunc)(u8 val, bool islast);
@ -445,14 +446,21 @@ void Write(u8 val, u32 hold)
break;
}
if (islast && (CurCmd == 0x02 || CurCmd == 0x0A) && (SRAMLength > 0))
SRAMFileDirty |= islast && (CurCmd == 0x02 || CurCmd == 0x0A) && (SRAMLength > 0);
}
void FlushSRAMFile()
{
if (!SRAMFileDirty)
return;
SRAMFileDirty = false;
FILE* f = Platform::OpenFile(SRAMPath, "wb");
if (f)
{
FILE* f = Platform::OpenFile(SRAMPath, "wb");
if (f)
{
fwrite(SRAM, SRAMLength, 1, f);
fclose(f);
}
fwrite(SRAM, SRAMLength, 1, f);
fclose(f);
}
}
@ -1034,6 +1042,11 @@ void RelocateSave(const char* path, bool write)
NDSCart_SRAM::RelocateSave(path, write);
}
void FlushSRAMFile()
{
NDSCart_SRAM::FlushSRAMFile();
}
int ImportSRAM(const u8* data, u32 length)
{
memcpy(NDSCart_SRAM::SRAM, data, std::min(length, NDSCart_SRAM::SRAMLength));

View File

@ -46,6 +46,9 @@ void DoSavestate(Savestate* file);
void DecryptSecureArea(u8* out);
bool LoadROM(const char* path, const char* sram, bool direct);
void FlushSRAMFile();
void RelocateSave(const char* path, bool write);
int ImportSRAM(const u8* data, u32 length);

149
src/NonStupidBitfield.h Normal file
View File

@ -0,0 +1,149 @@
#ifndef NONSTUPIDBITFIELD_H
#define NONSTUPIDBITFIELD_H
#include "types.h"
#include <memory.h>
#include <initializer_list>
#include <algorithm>
// like std::bitset but less stupid and optimised for
// our use case (keeping track of memory invalidations)
template <u32 Size>
struct NonStupidBitField
{
static_assert((Size % 8) == 0, "bitfield size must be a multiple of 8");
static const u32 DataLength = Size / 8;
u8 Data[DataLength];
struct Ref
{
NonStupidBitField<Size>& BitField;
u32 Idx;
operator bool()
{
return BitField.Data[Idx >> 3] & (1 << (Idx & 0x7));
}
Ref& operator=(bool set)
{
BitField.Data[Idx >> 3] &= ~(1 << (Idx & 0x7));
BitField.Data[Idx >> 3] |= ((u8)set << (Idx & 0x7));
return *this;
}
};
struct Iterator
{
NonStupidBitField<Size>& BitField;
u32 DataIdx;
u32 BitIdx;
u64 RemainingBits;
u32 operator*() { return DataIdx * 8 + BitIdx; }
bool operator==(const Iterator& other) { return other.DataIdx == DataIdx; }
bool operator!=(const Iterator& other) { return other.DataIdx != DataIdx; }
template <typename T>
void Next()
{
while (RemainingBits == 0 && DataIdx < DataLength)
{
DataIdx += sizeof(T);
RemainingBits = *(T*)&BitField.Data[DataIdx];
}
BitIdx = __builtin_ctzll(RemainingBits);
RemainingBits &= ~(1ULL << BitIdx);
}
Iterator operator++(int)
{
Iterator prev(*this);
++*this;
return prev;
}
Iterator& operator++()
{
if ((DataLength % 8) == 0)
Next<u64>();
else if ((DataLength % 4) == 0)
Next<u32>();
else if ((DataLength % 2) == 0)
Next<u16>();
else
Next<u8>();
return *this;
}
};
NonStupidBitField(u32 start, u32 size)
{
memset(Data, 0, sizeof(Data));
if (size == 0)
return;
u32 roundedStartBit = (start + 7) & ~7;
u32 roundedEndBit = (start + size) & ~7;
if (roundedStartBit != roundedEndBit)
memset(Data + roundedStartBit / 8, 0xFF, (roundedEndBit - roundedStartBit) / 8);
if (start & 0x7)
Data[start >> 3] = 0xFF << (start & 0x7);
if ((start + size) & 0x7)
Data[(start + size) >> 3] = 0xFF >> ((start + size) & 0x7);
}
NonStupidBitField()
{
memset(Data, 0, sizeof(Data));
}
Iterator End()
{
return Iterator{*this, DataLength, 0, 0};
}
Iterator Begin()
{
if ((DataLength % 8) == 0)
return ++Iterator{*this, 0, 0, *(u64*)Data};
else if ((DataLength % 4) == 0)
return ++Iterator{*this, 0, 0, *(u32*)Data};
else if ((DataLength % 2) == 0)
return ++Iterator{*this, 0, 0, *(u16*)Data};
else
return ++Iterator{*this, 0, 0, *Data};
}
Ref operator[](u32 idx)
{
return Ref{*this, idx};
}
NonStupidBitField& operator|=(const NonStupidBitField<Size>& other)
{
for (u32 i = 0; i < DataLength; i++)
{
Data[i] |= other.Data[i];
}
return *this;
}
NonStupidBitField& operator&=(const NonStupidBitField<Size>& other)
{
for (u32 i = 0; i < DataLength; i++)
{
Data[i] &= other.Data[i];
}
return *this;
}
};
#endif

View File

@ -23,8 +23,13 @@
#include <string.h>
// TODO: different includes for each platform
#include <GL/gl.h>
#include <GL/glext.h>
#ifdef __APPLE__
#include <OpenGL/gl3.h>
#include <OpenGL/gl3ext.h>
#else
#include <GL/gl.h>
#include <GL/glext.h>
#endif
#include "Platform.h"
@ -61,6 +66,11 @@
#endif
#ifdef __APPLE__
#define DO_PROCLIST(func)
#else
#define DO_PROCLIST(func) \
DO_PROCLIST_1_3(func) \
@ -128,6 +138,7 @@
\
func(GLGETSTRINGI, glGetStringi); \
#endif
namespace OpenGL
{

View File

@ -67,15 +67,24 @@ inline bool LocalFileExists(const char* name)
return true;
}
void* Thread_Create(void (*func)());
void Thread_Free(void* thread);
void Thread_Wait(void* thread);
struct Thread;
Thread* Thread_Create(void (*func)());
void Thread_Free(Thread* thread);
void Thread_Wait(Thread* thread);
void* Semaphore_Create();
void Semaphore_Free(void* sema);
void Semaphore_Reset(void* sema);
void Semaphore_Wait(void* sema);
void Semaphore_Post(void* sema);
struct Semaphore;
Semaphore* Semaphore_Create();
void Semaphore_Free(Semaphore* sema);
void Semaphore_Reset(Semaphore* sema);
void Semaphore_Wait(Semaphore* sema);
void Semaphore_Post(Semaphore* sema, int count = 1);
struct Mutex;
Mutex* Mutex_Create();
void Mutex_Free(Mutex* mutex);
void Mutex_Lock(Mutex* mutex);
void Mutex_Unlock(Mutex* mutex);
bool Mutex_TryLock(Mutex* mutex);
void* GL_GetProcAddress(const char* proc);

View File

@ -18,6 +18,7 @@
#include <stdio.h>
#include <string.h>
#include "Platform.h"
#include "NDS.h"
#include "DSi.h"
#include "SPU.h"
@ -61,13 +62,15 @@ const s16 PSGTable[8][8] =
{-0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF}
};
const u32 kSamplesPerRun = 1;
const u32 OutputBufferSize = 2*2048;
s16 OutputBackbuffer[2 * OutputBufferSize];
u32 OutputBackbufferWritePosition;
const u32 OutputBufferSize = 2*1024;
s16 OutputBuffer[2 * OutputBufferSize];
volatile u32 OutputReadOffset;
volatile u32 OutputWriteOffset;
s16 OutputFrontBuffer[2 * OutputBufferSize];
u32 OutputFrontBufferWritePosition;
u32 OutputFrontBufferReadPosition;
Platform::Mutex* AudioLock;
u16 Cnt;
u8 MasterVolume;
@ -85,6 +88,8 @@ bool Init()
Capture[0] = new CaptureUnit(0);
Capture[1] = new CaptureUnit(1);
AudioLock = Platform::Mutex_Create();
return true;
}
@ -95,6 +100,8 @@ void DeInit()
delete Capture[0];
delete Capture[1];
Platform::Mutex_Free(AudioLock);
}
void Reset()
@ -111,15 +118,18 @@ void Reset()
Capture[0]->Reset();
Capture[1]->Reset();
NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*kSamplesPerRun, Mix, kSamplesPerRun);
NDS::ScheduleEvent(NDS::Event_SPU, true, 1024, Mix, 0);
}
void Stop()
{
memset(OutputBuffer, 0, 2*OutputBufferSize*2);
Platform::Mutex_Lock(AudioLock);
memset(OutputFrontBuffer, 0, 2*OutputBufferSize*2);
OutputReadOffset = 0;
OutputWriteOffset = 0;
OutputBackbufferWritePosition = 0;
OutputFrontBufferReadPosition = 0;
OutputFrontBufferWritePosition = 0;
Platform::Mutex_Unlock(AudioLock);
}
void DoSavestate(Savestate* file)
@ -416,11 +426,11 @@ void Channel::NextSample_Noise()
}
template<u32 type>
void Channel::Run(s32* buf, u32 samples)
s32 Channel::Run()
{
if (!(Cnt & (1<<31))) return;
if (!(Cnt & (1<<31))) return 0;
if ((type < 3) && ((Length+LoopPos) < 16)) return;
if ((type < 3) && ((Length+LoopPos) < 16)) return 0;
if (KeyOn)
{
@ -428,45 +438,32 @@ void Channel::Run(s32* buf, u32 samples)
KeyOn = false;
}
for (u32 s = 0; s < samples; s++)
Timer += 512; // 1 sample = 512 cycles at 16MHz
while (Timer >> 16)
{
Timer += 512; // 1 sample = 512 cycles at 16MHz
Timer = TimerReload + (Timer - 0x10000);
while (Timer >> 16)
switch (type)
{
Timer = TimerReload + (Timer - 0x10000);
switch (type)
{
case 0: NextSample_PCM8(); break;
case 1: NextSample_PCM16(); break;
case 2: NextSample_ADPCM(); break;
case 3: NextSample_PSG(); break;
case 4: NextSample_Noise(); break;
}
case 0: NextSample_PCM8(); break;
case 1: NextSample_PCM16(); break;
case 2: NextSample_ADPCM(); break;
case 3: NextSample_PSG(); break;
case 4: NextSample_Noise(); break;
}
s32 val = (s32)CurSample;
val <<= VolumeShift;
val *= Volume;
buf[s] = val;
if (!(Cnt & (1<<31))) break;
}
s32 val = (s32)CurSample;
val <<= VolumeShift;
val *= Volume;
return val;
}
void Channel::PanOutput(s32* inbuf, u32 samples, s32* leftbuf, s32* rightbuf)
void Channel::PanOutput(s32 in, s32& left, s32& right)
{
for (u32 s = 0; s < samples; s++)
{
s32 val = (s32)inbuf[s];
s32 l = ((s64)val * (128-Pan)) >> 10;
s32 r = ((s64)val * Pan) >> 10;
leftbuf[s] += l;
rightbuf[s] += r;
}
left += ((s64)in * (128-Pan)) >> 10;
right += ((s64)in * Pan) >> 10;
}
@ -602,39 +599,31 @@ void CaptureUnit::Run(s32 sample)
}
void Mix(u32 samples)
void Mix(u32 dummy)
{
s32 channelbuf[32];
s32 leftbuf[32], rightbuf[32];
s32 ch0buf[32], ch1buf[32], ch2buf[32], ch3buf[32];
s32 leftoutput[32], rightoutput[32];
for (u32 s = 0; s < samples; s++)
{
leftbuf[s] = 0; rightbuf[s] = 0;
leftoutput[s] = 0; rightoutput[s] = 0;
}
s32 left = 0, right = 0;
s32 leftoutput = 0, rightoutput = 0;
if (Cnt & (1<<15))
{
Channels[0]->DoRun(ch0buf, samples);
Channels[1]->DoRun(ch1buf, samples);
Channels[2]->DoRun(ch2buf, samples);
Channels[3]->DoRun(ch3buf, samples);
s32 ch0 = Channels[0]->DoRun();
s32 ch1 = Channels[1]->DoRun();
s32 ch2 = Channels[2]->DoRun();
s32 ch3 = Channels[3]->DoRun();
// TODO: addition from capture registers
Channels[0]->PanOutput(ch0buf, samples, leftbuf, rightbuf);
Channels[2]->PanOutput(ch2buf, samples, leftbuf, rightbuf);
Channels[0]->PanOutput(ch0, left, right);
Channels[2]->PanOutput(ch2, left, right);
if (!(Cnt & (1<<12))) Channels[1]->PanOutput(ch1buf, samples, leftbuf, rightbuf);
if (!(Cnt & (1<<13))) Channels[3]->PanOutput(ch3buf, samples, leftbuf, rightbuf);
if (!(Cnt & (1<<12))) Channels[1]->PanOutput(ch1, left, right);
if (!(Cnt & (1<<13))) Channels[3]->PanOutput(ch3, left, right);
for (int i = 4; i < 16; i++)
{
Channel* chan = Channels[i];
chan->DoRun(channelbuf, samples);
chan->PanOutput(channelbuf, samples, leftbuf, rightbuf);
s32 channel = chan->DoRun();
chan->PanOutput(channel, left, right);
}
// sound capture
@ -642,32 +631,24 @@ void Mix(u32 samples)
if (Capture[0]->Cnt & (1<<7))
{
for (u32 s = 0; s < samples; s++)
{
s32 val = leftbuf[s];
s32 val = left;
val >>= 8;
if (val < -0x8000) val = -0x8000;
else if (val > 0x7FFF) val = 0x7FFF;
val >>= 8;
if (val < -0x8000) val = -0x8000;
else if (val > 0x7FFF) val = 0x7FFF;
Capture[0]->Run(val);
if (!(Capture[0]->Cnt & (1<<7))) break;
}
Capture[0]->Run(val);
}
if (Capture[1]->Cnt & (1<<7))
{
for (u32 s = 0; s < samples; s++)
{
s32 val = rightbuf[s];
s32 val = right;
val >>= 8;
if (val < -0x8000) val = -0x8000;
else if (val > 0x7FFF) val = 0x7FFF;
val >>= 8;
if (val < -0x8000) val = -0x8000;
else if (val > 0x7FFF) val = 0x7FFF;
Capture[1]->Run(val);
if (!(Capture[1]->Cnt & (1<<7))) break;
}
Capture[1]->Run(val);
}
// final output
@ -675,31 +656,25 @@ void Mix(u32 samples)
switch (Cnt & 0x0300)
{
case 0x0000: // left mixer
{
for (u32 s = 0; s < samples; s++)
leftoutput[s] = leftbuf[s];
}
leftoutput = left;
break;
case 0x0100: // channel 1
{
s32 pan = 128 - Channels[1]->Pan;
for (u32 s = 0; s < samples; s++)
leftoutput[s] = ((s64)ch1buf[s] * pan) >> 10;
leftoutput = ((s64)ch1 * pan) >> 10;
}
break;
case 0x0200: // channel 3
{
s32 pan = 128 - Channels[3]->Pan;
for (u32 s = 0; s < samples; s++)
leftoutput[s] = ((s64)ch3buf[s] * pan) >> 10;
leftoutput = ((s64)ch3 * pan) >> 10;
}
break;
case 0x0300: // channel 1+3
{
s32 pan1 = 128 - Channels[1]->Pan;
s32 pan3 = 128 - Channels[3]->Pan;
for (u32 s = 0; s < samples; s++)
leftoutput[s] = (((s64)ch1buf[s] * pan1) >> 10) + (((s64)ch3buf[s] * pan3) >> 10);
leftoutput = (((s64)ch1 * pan1) >> 10) + (((s64)ch3 * pan3) >> 10);
}
break;
}
@ -707,105 +682,122 @@ void Mix(u32 samples)
switch (Cnt & 0x0C00)
{
case 0x0000: // right mixer
{
for (u32 s = 0; s < samples; s++)
rightoutput[s] = rightbuf[s];
}
rightoutput = right;
break;
case 0x0400: // channel 1
{
s32 pan = Channels[1]->Pan;
for (u32 s = 0; s < samples; s++)
rightoutput[s] = ((s64)ch1buf[s] * pan) >> 10;
rightoutput = ((s64)ch1 * pan) >> 10;
}
break;
case 0x0800: // channel 3
{
s32 pan = Channels[3]->Pan;
for (u32 s = 0; s < samples; s++)
rightoutput[s] = ((s64)ch3buf[s] * pan) >> 10;
rightoutput = ((s64)ch3 * pan) >> 10;
}
break;
case 0x0C00: // channel 1+3
{
s32 pan1 = Channels[1]->Pan;
s32 pan3 = Channels[3]->Pan;
for (u32 s = 0; s < samples; s++)
rightoutput[s] = (((s64)ch1buf[s] * pan1) >> 10) + (((s64)ch3buf[s] * pan3) >> 10);
rightoutput = (((s64)ch1 * pan1) >> 10) + (((s64)ch3 * pan3) >> 10);
}
break;
}
}
for (u32 s = 0; s < samples; s++)
{
s32 l = leftoutput[s];
s32 r = rightoutput[s];
leftoutput = ((s64)leftoutput * MasterVolume) >> 7;
rightoutput = ((s64)rightoutput * MasterVolume) >> 7;
l = ((s64)l * MasterVolume) >> 7;
r = ((s64)r * MasterVolume) >> 7;
leftoutput >>= 8;
if (leftoutput < -0x8000) leftoutput = -0x8000;
else if (leftoutput > 0x7FFF) leftoutput = 0x7FFF;
rightoutput >>= 8;
if (rightoutput < -0x8000) rightoutput = -0x8000;
else if (rightoutput > 0x7FFF) rightoutput = 0x7FFF;
l >>= 8;
if (l < -0x8000) l = -0x8000;
else if (l > 0x7FFF) l = 0x7FFF;
r >>= 8;
if (r < -0x8000) r = -0x8000;
else if (r > 0x7FFF) r = 0x7FFF;
// OutputBufferFrame can never get full because it's
// transfered to OutputBuffer at the end of the frame
OutputBackbuffer[OutputBackbufferWritePosition ] = leftoutput >> 1;
OutputBackbuffer[OutputBackbufferWritePosition + 1] = rightoutput >> 1;
OutputBackbufferWritePosition += 2;
OutputBuffer[OutputWriteOffset ] = l >> 1;
OutputBuffer[OutputWriteOffset + 1] = r >> 1;
OutputWriteOffset += 2;
OutputWriteOffset &= ((2*OutputBufferSize)-1);
if (OutputWriteOffset == OutputReadOffset)
{
//printf("!! SOUND FIFO OVERFLOW %d\n", OutputWriteOffset>>1);
// advance the read position too, to avoid losing the entire FIFO
OutputReadOffset += 2;
OutputReadOffset &= ((2*OutputBufferSize)-1);
}
}
NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*kSamplesPerRun, Mix, kSamplesPerRun);
NDS::ScheduleEvent(NDS::Event_SPU, true, 1024, Mix, 0);
}
void TransferOutput()
{
Platform::Mutex_Lock(AudioLock);
for (u32 i = 0; i < OutputBackbufferWritePosition; i += 2)
{
OutputFrontBuffer[OutputFrontBufferWritePosition ] = OutputBackbuffer[i ];
OutputFrontBuffer[OutputFrontBufferWritePosition + 1] = OutputBackbuffer[i + 1];
OutputFrontBufferWritePosition += 2;
OutputFrontBufferWritePosition &= OutputBufferSize*2-1;
if (OutputFrontBufferWritePosition == OutputFrontBufferReadPosition)
{
// advance the read position too, to avoid losing the entire FIFO
OutputFrontBufferReadPosition += 2;
OutputFrontBufferReadPosition &= OutputBufferSize*2-1;
}
}
OutputBackbufferWritePosition = 0;
Platform::Mutex_Unlock(AudioLock);
}
void TrimOutput()
{
Platform::Mutex_Lock(AudioLock);
const int halflimit = (OutputBufferSize / 2);
int readpos = OutputWriteOffset - (halflimit*2);
int readpos = OutputFrontBufferWritePosition - (halflimit*2);
if (readpos < 0) readpos += (OutputBufferSize*2);
OutputReadOffset = readpos;
OutputFrontBufferReadPosition = readpos;
Platform::Mutex_Unlock(AudioLock);
}
void DrainOutput()
{
OutputReadOffset = 0;
OutputWriteOffset = 0;
Platform::Mutex_Lock(AudioLock);
OutputFrontBufferWritePosition = 0;
OutputFrontBufferReadPosition = 0;
Platform::Mutex_Unlock(AudioLock);
}
void InitOutput()
{
memset(OutputBuffer, 0, 2*OutputBufferSize*2);
OutputReadOffset = 0;
OutputWriteOffset = OutputBufferSize;
Platform::Mutex_Lock(AudioLock);
memset(OutputBackbuffer, 0, 2*OutputBufferSize*2);
memset(OutputFrontBuffer, 0, 2*OutputBufferSize*2);
OutputFrontBufferReadPosition = 0;
OutputFrontBufferWritePosition = 0;
Platform::Mutex_Unlock(AudioLock);
}
int GetOutputSize()
{
Platform::Mutex_Lock(AudioLock);
int ret;
if (OutputWriteOffset >= OutputReadOffset)
ret = OutputWriteOffset - OutputReadOffset;
if (OutputFrontBufferWritePosition >= OutputFrontBufferReadPosition)
ret = OutputFrontBufferWritePosition - OutputFrontBufferReadPosition;
else
ret = (OutputBufferSize*2) - OutputReadOffset + OutputWriteOffset;
ret = (OutputBufferSize*2) - OutputFrontBufferReadPosition + OutputFrontBufferWritePosition;
ret >>= 1;
Platform::Mutex_Unlock(AudioLock);
return ret;
}
void Sync(bool wait)
{
// this function is currently not used anywhere
// depending on the usage context the thread safety measures could be made
// a lot faster
// sync to audio output in case the core is running too fast
// * wait=true: wait until enough audio data has been played
// * wait=false: merely skip some audio data to avoid a FIFO overflow
@ -819,32 +811,42 @@ void Sync(bool wait)
}
else if (GetOutputSize() > halflimit)
{
int readpos = OutputWriteOffset - (halflimit*2);
Platform::Mutex_Lock(AudioLock);
int readpos = OutputFrontBufferWritePosition - (halflimit*2);
if (readpos < 0) readpos += (OutputBufferSize*2);
OutputReadOffset = readpos;
OutputFrontBufferReadPosition = readpos;
Platform::Mutex_Unlock(AudioLock);
}
}
int ReadOutput(s16* data, int samples)
{
if (OutputReadOffset == OutputWriteOffset)
Platform::Mutex_Lock(AudioLock);
if (OutputFrontBufferReadPosition == OutputFrontBufferWritePosition)
{
Platform::Mutex_Unlock(AudioLock);
return 0;
}
for (int i = 0; i < samples; i++)
{
*data++ = OutputBuffer[OutputReadOffset];
*data++ = OutputBuffer[OutputReadOffset + 1];
*data++ = OutputFrontBuffer[OutputFrontBufferReadPosition];
*data++ = OutputFrontBuffer[OutputFrontBufferReadPosition + 1];
//if (OutputReadOffset != OutputWriteOffset)
OutputFrontBufferReadPosition += 2;
OutputFrontBufferReadPosition &= ((2*OutputBufferSize)-1);
if (OutputFrontBufferWritePosition == OutputFrontBufferReadPosition)
{
OutputReadOffset += 2;
OutputReadOffset &= ((2*OutputBufferSize)-1);
}
if (OutputReadOffset == OutputWriteOffset)
Platform::Mutex_Unlock(AudioLock);
return i+1;
}
}
Platform::Mutex_Unlock(AudioLock);
return samples;
}

View File

@ -33,7 +33,7 @@ void DoSavestate(Savestate* file);
void SetBias(u16 bias);
void Mix(u32 samples);
void Mix(u32 dummy);
void TrimOutput();
void DrainOutput();
@ -41,6 +41,7 @@ void InitOutput();
int GetOutputSize();
void Sync(bool wait);
int ReadOutput(s16* data, int samples);
void TransferOutput();
u8 Read8(u32 addr);
u16 Read16(u32 addr);
@ -123,26 +124,24 @@ public:
void NextSample_PSG();
void NextSample_Noise();
template<u32 type> void Run(s32* buf, u32 samples);
template<u32 type> s32 Run();
void DoRun(s32* buf, u32 samples)
s32 DoRun()
{
for (u32 s = 0; s < samples; s++)
buf[s] = 0;
switch ((Cnt >> 29) & 0x3)
{
case 0: Run<0>(buf, samples); break;
case 1: Run<1>(buf, samples); break;
case 2: Run<2>(buf, samples); break;
case 0: return Run<0>(); break;
case 1: return Run<1>(); break;
case 2: return Run<2>(); break;
case 3:
if (Num >= 14) Run<4>(buf, samples);
else if (Num >= 8) Run<3>(buf, samples);
break;
if (Num >= 14) return Run<4>();
else if (Num >= 8) return Run<3>();
default:
return 0;
}
}
void PanOutput(s32* inbuf, u32 samples, s32* leftbuf, s32* rightbuf);
void PanOutput(s32 in, s32& left, s32& right);
private:
u32 (*BusRead32)(u32 addr);

View File

@ -0,0 +1,13 @@
#ifndef SHAREDCONFIG_H
#define SHAREDCONFIG_H
namespace Config
{
extern int ConsoleType;
extern int DirectBoot;
extern int SavestateRelocSRAM;
}
#endif

View File

@ -21,7 +21,7 @@
#include "FrontendUtil.h"
#include "Config.h"
#include "qt_sdl/PlatformConfig.h" // FIXME!!!
#include "SharedConfig.h"
#include "Platform.h"
#include "NDS.h"

View File

@ -95,6 +95,19 @@ if (PORTABLE)
add_definitions(-DPORTABLE)
endif()
if (APPLE)
set_target_properties(melonDS PROPERTIES
MACOSX_BUNDLE true
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/melonDS.plist
OUTPUT_NAME melonDS
)
# Copy icon into the bundle
target_sources(melonDS PRIVATE "${CMAKE_SOURCE_DIR}/melonDS.icns")
set_source_files_properties("${CMAKE_SOURCE_DIR}/melonDS.icns" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
endif()
install(FILES ../../../net.kuribo64.melonDS.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
install(FILES ../../../icon/melon_16x16.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/16x16/apps RENAME net.kuribo64.melonDS.png)
install(FILES ../../../icon/melon_32x32.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/32x32/apps RENAME net.kuribo64.melonDS.png)
@ -102,4 +115,4 @@ install(FILES ../../../icon/melon_48x48.png DESTINATION ${CMAKE_INSTALL_PREFIX}/
install(FILES ../../../icon/melon_64x64.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/64x64/apps RENAME net.kuribo64.melonDS.png)
install(FILES ../../../icon/melon_128x128.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/128x128/apps RENAME net.kuribo64.melonDS.png)
install(FILES ../../../icon/melon_256x256.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/256x256/apps RENAME net.kuribo64.melonDS.png)
install(TARGETS melonDS RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
install(TARGETS melonDS BUNDLE DESTINATION ${CMAKE_BINARY_DIR} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)

View File

@ -65,6 +65,9 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
ui->chkJITBranchOptimisations->setChecked(Config::JIT_BranchOptimisations != 0);
ui->chkJITLiteralOptimisations->setChecked(Config::JIT_LiteralOptimisations != 0);
ui->chkJITFastMemory->setChecked(Config::JIT_FastMemory != 0);
#ifdef __APPLE__
ui->chkJITFastMemory->setDisabled(true);
#endif
ui->spnJITMaximumBlockSize->setValue(Config::JIT_MaxBlockSize);
#else
ui->chkEnableJIT->setDisabled(true);
@ -329,6 +332,8 @@ void EmuSettingsDialog::on_chkEnableJIT_toggled()
bool disabled = !ui->chkEnableJIT->isChecked();
ui->chkJITBranchOptimisations->setDisabled(disabled);
ui->chkJITLiteralOptimisations->setDisabled(disabled);
ui->chkJITFastMemory->setDisabled(disabled);
#ifndef __APPLE__
ui->chkJITFastMemory->setDisabled(disabled);
#endif
ui->spnJITMaximumBlockSize->setDisabled(disabled);
}

View File

@ -216,6 +216,7 @@ KeyMapButton::KeyMapButton(int* mapping, bool hotkey) : QPushButton()
setCheckable(true);
setText(mappingText());
setFocusPolicy(Qt::StrongFocus); //Fixes binding keys in macOS
connect(this, &KeyMapButton::clicked, this, &KeyMapButton::onClick);
}

View File

@ -33,7 +33,11 @@
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <linux/if_packet.h>
#ifdef __linux__
#include <linux/if_packet.h>
#else
#include <net/if_dl.h>
#endif
#endif
@ -66,6 +70,9 @@ const char* PCapLibNames[] =
#ifdef __WIN32__
// TODO: name for npcap in non-WinPCap mode
"wpcap.dll",
#elif defined(__APPLE__)
"libpcap.A.dylib",
"libpcap.dylib",
#else
// Linux lib names
"libpcap.so.1",
@ -276,6 +283,7 @@ bool Init(bool open_adapter)
struct sockaddr_in* sa = (sockaddr_in*)curaddr->ifa_addr;
memcpy(adata->IP_v4, &sa->sin_addr, 4);
}
#ifdef __linux__
else if (af == AF_PACKET)
{
struct sockaddr_ll* sa = (sockaddr_ll*)curaddr->ifa_addr;
@ -284,7 +292,16 @@ bool Init(bool open_adapter)
else
memcpy(adata->MAC, sa->sll_addr, 6);
}
#else
else if (af == AF_LINK)
{
struct sockaddr_dl* sa = (sockaddr_dl*)curaddr->ifa_addr;
if (sa->sdl_alen != 6)
printf("weird MAC length %d for %s\n", sa->sdl_alen, curaddr->ifa_name);
else
memcpy(adata->MAC, LLADDR(sa), 6);
}
#endif
curaddr = curaddr->ifa_next;
}
}

View File

@ -23,6 +23,7 @@
#include <QDir>
#include <QThread>
#include <QSemaphore>
#include <QMutex>
#include <QOpenGLContext>
#include "Platform.h"
@ -187,53 +188,77 @@ FILE* OpenLocalFile(const char* path, const char* mode)
return OpenFile(fullpath.toUtf8(), mode, mode[0] != 'w');
}
void* Thread_Create(void (* func)())
Thread* Thread_Create(void (* func)())
{
QThread* t = QThread::create(func);
t->start();
return (void*) t;
return (Thread*) t;
}
void Thread_Free(void* thread)
void Thread_Free(Thread* thread)
{
QThread* t = (QThread*) thread;
t->terminate();
delete t;
}
void Thread_Wait(void* thread)
void Thread_Wait(Thread* thread)
{
((QThread*) thread)->wait();
}
void* Semaphore_Create()
Semaphore* Semaphore_Create()
{
return new QSemaphore();
return (Semaphore*)new QSemaphore();
}
void Semaphore_Free(void* sema)
void Semaphore_Free(Semaphore* sema)
{
delete (QSemaphore*) sema;
}
void Semaphore_Reset(void* sema)
void Semaphore_Reset(Semaphore* sema)
{
QSemaphore* s = (QSemaphore*) sema;
s->acquire(s->available());
}
void Semaphore_Wait(void* sema)
void Semaphore_Wait(Semaphore* sema)
{
((QSemaphore*) sema)->acquire();
}
void Semaphore_Post(void* sema)
void Semaphore_Post(Semaphore* sema, int count)
{
((QSemaphore*) sema)->release();
((QSemaphore*) sema)->release(count);
}
Mutex* Mutex_Create()
{
return (Mutex*)new QMutex();
}
void Mutex_Free(Mutex* mutex)
{
delete (QMutex*) mutex;
}
void Mutex_Lock(Mutex* mutex)
{
((QMutex*) mutex)->lock();
}
void Mutex_Unlock(Mutex* mutex)
{
((QMutex*) mutex)->unlock();
}
bool Mutex_TryLock(Mutex* mutex)
{
return ((QMutex*) mutex)->try_lock();
}
void* GL_GetProcAddress(const char* proc)
{

View File

@ -120,7 +120,7 @@ ConfigEntry PlatformConfigFile[] =
{"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1, NULL, 0},
{"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -1, NULL, 0},
{"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FastForwardToggle], -1, NULL, 0},
{"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FullscreenToggle], -1, NULL, 0},
{"HKJoy_FullscreenToggle", 0, &HKJoyMapping[HK_FullscreenToggle], -1, NULL, 0},
{"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1, NULL, 0},
{"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, NULL, 0},

View File

@ -54,7 +54,7 @@ WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(ne
LAN_Socket::Init();
haspcap = LAN_PCap::Init(false);
ui->cbDirectMode->setText("Direct mode (requires " PCAP_NAME " and ethernet connection)");
ui->rbDirectMode->setText("Direct mode (requires " PCAP_NAME " and ethernet connection)");
ui->cbBindAnyAddr->setChecked(Config::SocketBindAnyAddr != 0);
ui->cbRandomizeMAC->setChecked(Config::RandomizeMAC != 0);
@ -71,8 +71,9 @@ WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(ne
}
ui->cbxDirectAdapter->setCurrentIndex(sel);
ui->cbDirectMode->setChecked(Config::DirectLAN != 0);
if (!haspcap) ui->cbDirectMode->setEnabled(false);
ui->rbDirectMode->setChecked(Config::DirectLAN != 0);
ui->rbIndirectMode->setChecked(Config::DirectLAN == 0);
if (!haspcap) ui->rbDirectMode->setEnabled(false);
updateAdapterControls();
}
@ -101,7 +102,7 @@ void WifiSettingsDialog::done(int r)
Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked() ? 1:0;
Config::RandomizeMAC = randommac;
Config::DirectLAN = ui->cbDirectMode->isChecked() ? 1:0;
Config::DirectLAN = ui->rbDirectMode->isChecked() ? 1:0;
int sel = ui->cbxDirectAdapter->currentIndex();
if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0;
@ -125,11 +126,14 @@ void WifiSettingsDialog::done(int r)
closeDlg();
}
void WifiSettingsDialog::on_cbDirectMode_stateChanged(int state)
void WifiSettingsDialog::on_rbDirectMode_clicked()
{
updateAdapterControls();
}
void WifiSettingsDialog::on_rbIndirectMode_clicked()
{
updateAdapterControls();
}
void WifiSettingsDialog::on_cbxDirectAdapter_currentIndexChanged(int sel)
{
if (!haspcap) return;
@ -153,7 +157,7 @@ void WifiSettingsDialog::on_cbxDirectAdapter_currentIndexChanged(int sel)
void WifiSettingsDialog::updateAdapterControls()
{
bool enable = haspcap && ui->cbDirectMode->isChecked();
bool enable = haspcap && ui->rbDirectMode->isChecked();
ui->cbxDirectAdapter->setEnabled(enable);
ui->lblAdapterMAC->setEnabled(enable);

View File

@ -55,7 +55,8 @@ public:
private slots:
void done(int r);
void on_cbDirectMode_stateChanged(int state);
void on_rbDirectMode_clicked();
void on_rbIndirectMode_clicked();
void on_cbxDirectAdapter_currentIndexChanged(int sel);
private:

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>479</width>
<height>240</height>
<width>572</width>
<height>296</height>
</rect>
</property>
<property name="sizePolicy">
@ -58,15 +58,81 @@
<string>Online</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<item row="3" column="0" rowspan="3" colspan="2">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Direct Mode Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Network adapter:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cbxDirectAdapter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Selects the network adapter through which to route network traffic under direct mode.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>MAC address:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lblAdapterMAC">
<property name="text">
<string>[PLACEHOLDER]</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>IP address:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="lblAdapterIP">
<property name="text">
<string>[PLACEHOLDER]</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="rbIndirectMode">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Indirect mode uses libslirp. It requires no extra setup and is easy to use.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>MAC address:</string>
<string>Indirect Mode (uses libslirp, recommended)</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="cbDirectMode">
<item row="2" column="0">
<widget class="QRadioButton" name="rbDirectMode">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Direct mode directly routes network traffic to the host network. It is the most reliable, but requires an ethernet connection.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Non-direct mode uses a layer of emulation to get around this, but is more prone to problems.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
@ -75,53 +141,6 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cbxDirectAdapter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>350</width>
<height>0</height>
</size>
</property>
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Selects the network adapter through which to route network traffic under direct mode.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Network adapter:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>IP address:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="lblAdapterMAC">
<property name="text">
<string>[PLACEHOLDER]</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="lblAdapterIP">
<property name="text">
<string>[PLACEHOLDER]</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -355,10 +355,10 @@ void EmuThread::run()
Input::Init();
u32 nframes = 0;
u32 starttick = SDL_GetTicks();
u32 lasttick = starttick;
u32 lastmeasuretick = lasttick;
u32 fpslimitcount = 0;
double perfCountsSec = 1.0 / SDL_GetPerformanceFrequency();
double lastTime = SDL_GetPerformanceCounter() * perfCountsSec;
double frameLimitError = 0.0;
double lastMeasureTime = lastTime;
char melontitle[100];
@ -492,49 +492,43 @@ void EmuThread::run()
SDL_UnlockMutex(audioSyncLock);
}
float framerate = (1000.0f * nlines) / (60.0f * 263.0f);
double frametimeStep = nlines / (60.0 * 263.0);
{
u32 curtick = SDL_GetTicks();
u32 delay = curtick - lasttick;
bool limitfps = Config::LimitFPS && !fastforward;
if (limitfps)
{
float wantedtickF = starttick + (framerate * (fpslimitcount+1));
u32 wantedtick = (u32)ceil(wantedtickF);
if (curtick < wantedtick) SDL_Delay(wantedtick - curtick);
lasttick = SDL_GetTicks();
fpslimitcount++;
if ((abs(wantedtickF - (float)wantedtick) < 0.001312) || (fpslimitcount > 60))
{
fpslimitcount = 0;
starttick = lasttick;
}
}
else
double practicalFramelimit = limitfps ? frametimeStep : 1.0 / 1000.0;
double curtime = SDL_GetPerformanceCounter() * perfCountsSec;
frameLimitError += practicalFramelimit - (curtime - lastTime);
if (frameLimitError < -practicalFramelimit)
frameLimitError = -practicalFramelimit;
if (frameLimitError > practicalFramelimit)
frameLimitError = practicalFramelimit;
if (round(frameLimitError * 1000.0) > 0.0)
{
if (delay < 1) SDL_Delay(1);
lasttick = SDL_GetTicks();
SDL_Delay(round(frameLimitError * 1000.0));
double timeBeforeSleep = curtime;
curtime = SDL_GetPerformanceCounter() * perfCountsSec;
frameLimitError -= curtime - timeBeforeSleep;
}
lastTime = curtime;
}
nframes++;
if (nframes >= 30)
{
u32 tick = SDL_GetTicks();
u32 diff = tick - lastmeasuretick;
lastmeasuretick = tick;
double time = SDL_GetPerformanceCounter() * perfCountsSec;
double dt = time - lastMeasureTime;
lastMeasureTime = time;
u32 fps;
if (diff < 1) fps = 77777;
else fps = (nframes * 1000) / diff;
u32 fps = round(nframes / dt);
nframes = 0;
float fpstarget;
if (framerate < 1) fpstarget = 999;
else fpstarget = 1000.0f/framerate;
float fpstarget = 1.0/frametimeStep;
sprintf(melontitle, "[%d/%.0f] melonDS " MELONDS_VERSION, fps, fpstarget);
changeWindowTitle(melontitle);
@ -544,10 +538,8 @@ void EmuThread::run()
{
// paused
nframes = 0;
lasttick = SDL_GetTicks();
starttick = lasttick;
lastmeasuretick = lasttick;
fpslimitcount = 0;
lastTime = SDL_GetPerformanceCounter() * perfCountsSec;
lastMeasureTime = lastTime;
emit windowUpdate();
@ -1354,7 +1346,7 @@ void MainWindow::dragEnterEvent(QDragEnterEvent* event)
QString filename = urls.at(0).toLocalFile();
QString ext = filename.right(3);
if (ext == "nds" || ext == "srl" || ext == "dsi" || (ext == "gba" && RunningSomething))
if (ext == "nds" || ext == "srl" || ext == "dsi" || ext == "gba")
event->acceptProposedAction();
}