Merge remote-tracking branch 'remotes/origin/master' into dsi_camera
This commit is contained in:
commit
129018a662
|
@ -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
|
|
@ -29,6 +29,7 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ${{runner.workspace}}
|
working-directory: ${{runner.workspace}}
|
||||||
run: |
|
run: |
|
||||||
|
sudo rm -f /etc/apt/sources.list.d/kubernetes.list
|
||||||
sudo dpkg --add-architecture arm64
|
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 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
|
sudo rm /etc/apt/sources.list
|
||||||
|
|
|
@ -1,20 +1,30 @@
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
include(CheckLibraryExists)
|
||||||
|
|
||||||
cmake_policy(VERSION 3.13)
|
cmake_policy(VERSION 3.13)
|
||||||
if (POLICY CMP0076)
|
if (POLICY CMP0076)
|
||||||
cmake_policy(SET CMP0076 NEW)
|
cmake_policy(SET CMP0076 NEW)
|
||||||
endif()
|
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})
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
project(melonDS)
|
check_library_exists(m pow "" LIBM)
|
||||||
|
if(LIBM)
|
||||||
if (NOT CMAKE_BUILD_TYPE)
|
link_libraries(m)
|
||||||
set(CMAKE_BUILD_TYPE Release)
|
endif()
|
||||||
|
|
||||||
|
if (NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(CheckSymbolExists)
|
|
||||||
function(detect_architecture symbol arch)
|
function(detect_architecture symbol arch)
|
||||||
if (NOT DEFINED ARCHITECTURE)
|
if (NOT DEFINED ARCHITECTURE)
|
||||||
set(CMAKE_REQUIRED_QUIET 1)
|
set(CMAKE_REQUIRED_QUIET 1)
|
||||||
|
@ -65,8 +75,22 @@ if (CMAKE_BUILD_TYPE STREQUAL Release)
|
||||||
add_link_options(-s)
|
add_link_options(-s)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_compile_options(-fno-pic)
|
if (ENABLE_LTO)
|
||||||
add_link_options(-no-pie)
|
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)
|
option(BUILD_QT_SDL "Build Qt/SDL frontend" ON)
|
||||||
|
|
||||||
|
@ -78,4 +102,4 @@ add_subdirectory(src)
|
||||||
|
|
||||||
if (BUILD_QT_SDL)
|
if (BUILD_QT_SDL)
|
||||||
add_subdirectory(src/frontend/qt_sdl)
|
add_subdirectory(src/frontend/qt_sdl)
|
||||||
endif()
|
endif()
|
17
README.md
17
README.md
|
@ -38,7 +38,7 @@ As for the rest, the interface should be pretty straightforward. If you have a q
|
||||||
* Install dependencies:
|
* Install dependencies:
|
||||||
|
|
||||||
```sh
|
```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:
|
* 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.
|
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
|
## TODO LIST
|
||||||
|
|
||||||
* DSi emulation
|
* DSi emulation
|
||||||
|
|
Binary file not shown.
|
@ -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>
|
|
@ -176,7 +176,7 @@ T SlowRead9(u32 addr, ARMv5* cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, int ConsoleType>
|
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);
|
addr &= ~(sizeof(T) - 1);
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ T SlowRead7(u32 addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, int ConsoleType>
|
template <typename T, int ConsoleType>
|
||||||
void SlowWrite7(u32 addr, T val)
|
void SlowWrite7(u32 addr, u32 val)
|
||||||
{
|
{
|
||||||
addr &= ~(sizeof(T) - 1);
|
addr &= ~(sizeof(T) - 1);
|
||||||
|
|
||||||
|
@ -266,16 +266,16 @@ void SlowBlockTransfer7(u32 addr, u64* data, u32 num)
|
||||||
|
|
||||||
#define INSTANTIATE_SLOWMEM(consoleType) \
|
#define INSTANTIATE_SLOWMEM(consoleType) \
|
||||||
template void SlowWrite9<u32, consoleType>(u32, ARMv5*, u32); \
|
template void SlowWrite9<u32, consoleType>(u32, ARMv5*, u32); \
|
||||||
template void SlowWrite9<u16, consoleType>(u32, ARMv5*, u16); \
|
template void SlowWrite9<u16, consoleType>(u32, ARMv5*, u32); \
|
||||||
template void SlowWrite9<u8, consoleType>(u32, ARMv5*, u8); \
|
template void SlowWrite9<u8, consoleType>(u32, ARMv5*, u32); \
|
||||||
\
|
\
|
||||||
template u32 SlowRead9<u32, consoleType>(u32, ARMv5*); \
|
template u32 SlowRead9<u32, consoleType>(u32, ARMv5*); \
|
||||||
template u16 SlowRead9<u16, consoleType>(u32, ARMv5*); \
|
template u16 SlowRead9<u16, consoleType>(u32, ARMv5*); \
|
||||||
template u8 SlowRead9<u8, consoleType>(u32, ARMv5*); \
|
template u8 SlowRead9<u8, consoleType>(u32, ARMv5*); \
|
||||||
\
|
\
|
||||||
template void SlowWrite7<u32, consoleType>(u32, u32); \
|
template void SlowWrite7<u32, consoleType>(u32, u32); \
|
||||||
template void SlowWrite7<u16, consoleType>(u32, u16); \
|
template void SlowWrite7<u16, consoleType>(u32, u32); \
|
||||||
template void SlowWrite7<u8, consoleType>(u32, u8); \
|
template void SlowWrite7<u8, consoleType>(u32, u32); \
|
||||||
\
|
\
|
||||||
template u32 SlowRead7<u32, consoleType>(u32); \
|
template u32 SlowRead7<u32, consoleType>(u32); \
|
||||||
template u16 SlowRead7<u16, consoleType>(u32); \
|
template u16 SlowRead7<u16, consoleType>(u32); \
|
||||||
|
@ -298,6 +298,7 @@ void Init()
|
||||||
|
|
||||||
void DeInit()
|
void DeInit()
|
||||||
{
|
{
|
||||||
|
ResetBlockCache();
|
||||||
ARMJIT_Memory::DeInit();
|
ARMJIT_Memory::DeInit();
|
||||||
|
|
||||||
delete JITCompiler;
|
delete JITCompiler;
|
||||||
|
@ -594,7 +595,8 @@ void CompileBlock(ARM* cpu)
|
||||||
u32 r15 = cpu->R[15];
|
u32 r15 = cpu->R[15];
|
||||||
|
|
||||||
u32 addressRanges[Config::JIT_MaxBlockSize];
|
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 numAddressRanges = 0;
|
||||||
|
|
||||||
u32 numLiterals = 0;
|
u32 numLiterals = 0;
|
||||||
|
@ -1116,6 +1118,7 @@ void ResetBlockCache()
|
||||||
range->Blocks.Clear();
|
range->Blocks.Clear();
|
||||||
range->Code = 0;
|
range->Code = 0;
|
||||||
}
|
}
|
||||||
|
delete block;
|
||||||
}
|
}
|
||||||
JitBlocks9.clear();
|
JitBlocks9.clear();
|
||||||
JitBlocks7.clear();
|
JitBlocks7.clear();
|
||||||
|
|
|
@ -68,6 +68,11 @@ void Compiler::A_Comp_MRS()
|
||||||
MOV(rd, RCPSR);
|
MOV(rd, RCPSR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateModeTrampoline(ARM* arm, u32 oldmode, u32 newmode)
|
||||||
|
{
|
||||||
|
arm->UpdateMode(oldmode, newmode);
|
||||||
|
}
|
||||||
|
|
||||||
void Compiler::A_Comp_MSR()
|
void Compiler::A_Comp_MSR()
|
||||||
{
|
{
|
||||||
Comp_AddCycles_C();
|
Comp_AddCycles_C();
|
||||||
|
@ -139,7 +144,7 @@ void Compiler::A_Comp_MSR()
|
||||||
|
|
||||||
PushRegs(true);
|
PushRegs(true);
|
||||||
|
|
||||||
QuickCallFunction(X3, (void*)&ARM::UpdateMode);
|
QuickCallFunction(X3, (void*)&UpdateModeTrampoline);
|
||||||
|
|
||||||
PopRegs(true);
|
PopRegs(true);
|
||||||
}
|
}
|
||||||
|
@ -915,4 +920,4 @@ void Compiler::Comp_AddCycles_CD()
|
||||||
ConstantCycles += cycles;
|
ConstantCycles += cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,6 +187,7 @@ public:
|
||||||
void Comp_RegShiftReg(int op, bool S, Op2& op2, Arm64Gen::ARM64Reg rs);
|
void Comp_RegShiftReg(int op, bool S, Op2& op2, Arm64Gen::ARM64Reg rs);
|
||||||
|
|
||||||
bool Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr);
|
bool Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
memop_Writeback = 1 << 0,
|
memop_Writeback = 1 << 0,
|
||||||
|
@ -213,8 +214,8 @@ public:
|
||||||
return (u8*)entry - GetRXBase();
|
return (u8*)entry - GetRXBase();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsJITFault(u64 pc);
|
bool IsJITFault(u8* pc);
|
||||||
s64 RewriteMemAccess(u64 pc);
|
u8* RewriteMemAccess(u8* pc);
|
||||||
|
|
||||||
void SwapCodeRegion()
|
void SwapCodeRegion()
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,37 +9,34 @@ using namespace Arm64Gen;
|
||||||
namespace ARMJIT
|
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);
|
auto it = LoadStorePatches.find(pcOffset);
|
||||||
|
|
||||||
if (it != LoadStorePatches.end())
|
if (it != LoadStorePatches.end())
|
||||||
{
|
{
|
||||||
LoadStorePatch patch = it->second;
|
LoadStorePatch patch = it->second;
|
||||||
|
LoadStorePatches.erase(it);
|
||||||
|
|
||||||
ptrdiff_t curCodeOffset = GetCodeOffset();
|
ptrdiff_t curCodeOffset = GetCodeOffset();
|
||||||
|
|
||||||
SetCodePtrUnsafe(pcOffset + patch.PatchOffset);
|
SetCodePtrUnsafe(pcOffset + patch.PatchOffset);
|
||||||
|
|
||||||
BL(patch.PatchFunc);
|
BL(patch.PatchFunc);
|
||||||
|
|
||||||
for (int i = 0; i < patch.PatchSize / 4 - 1; i++)
|
for (int i = 0; i < patch.PatchSize / 4 - 1; i++)
|
||||||
HINT(HINT_NOP);
|
HINT(HINT_NOP);
|
||||||
|
|
||||||
FlushIcacheSection((u8*)pc + patch.PatchOffset, (u8*)GetRXPtr());
|
FlushIcacheSection((u8*)pc + patch.PatchOffset, (u8*)GetRXPtr());
|
||||||
|
|
||||||
SetCodePtrUnsafe(curCodeOffset);
|
SetCodePtrUnsafe(curCodeOffset);
|
||||||
|
|
||||||
LoadStorePatches.erase(it);
|
return pc + (ptrdiff_t)patch.PatchOffset;
|
||||||
|
|
||||||
return patch.PatchOffset;
|
|
||||||
}
|
}
|
||||||
printf("this is a JIT bug! %08x\n", __builtin_bswap32(*(u32*)pc));
|
printf("this is a JIT bug! %08x\n", __builtin_bswap32(*(u32*)pc));
|
||||||
abort();
|
abort();
|
||||||
|
@ -192,7 +189,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LDRGeneric(size, flags & memop_SignExtend, rdMapped, size > 8 ? X1 : X0, X7);
|
LDRGeneric(size, flags & memop_SignExtend, rdMapped, size > 8 ? X1 : X0, X7);
|
||||||
if (size == 32)
|
if (size == 32 && !addrIsStatic)
|
||||||
{
|
{
|
||||||
UBFIZ(W0, W0, 3, 2);
|
UBFIZ(W0, W0, 3, 2);
|
||||||
RORV(rdMapped, rdMapped, W0);
|
RORV(rdMapped, rdMapped, W0);
|
||||||
|
|
|
@ -216,9 +216,9 @@ template <u32 Num>
|
||||||
void LinkBlock(ARM* cpu, u32 codeOffset);
|
void LinkBlock(ARM* cpu, u32 codeOffset);
|
||||||
|
|
||||||
template <typename T, int ConsoleType> T SlowRead9(u32 addr, ARMv5* cpu);
|
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> 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 SlowBlockTransfer9(u32 addr, u64* data, u32 num, ARMv5* cpu);
|
||||||
template <bool Write, int ConsoleType> void SlowBlockTransfer7(u32 addr, u64* data, u32 num);
|
template <bool Write, int ConsoleType> void SlowBlockTransfer7(u32 addr, u64* data, u32 num);
|
||||||
|
|
|
@ -10,6 +10,12 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <linux/ashmem.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "ARMJIT_Memory.h"
|
#include "ARMJIT_Memory.h"
|
||||||
|
|
||||||
#include "ARMJIT_Internal.h"
|
#include "ARMJIT_Internal.h"
|
||||||
|
@ -22,7 +28,9 @@
|
||||||
#include "NDSCart.h"
|
#include "NDSCart.h"
|
||||||
#include "SPU.h"
|
#include "SPU.h"
|
||||||
|
|
||||||
|
#ifndef __APPLE__
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We're handling fastmem here.
|
We're handling fastmem here.
|
||||||
|
@ -40,7 +48,8 @@
|
||||||
We handle this by only mapping those regions which are actually
|
We handle this by only mapping those regions which are actually
|
||||||
used and by praying the games don't go wild.
|
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
|
struct FaultDescription
|
||||||
{
|
{
|
||||||
u32 EmulatedFaultAddr;
|
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__)
|
#if defined(__SWITCH__)
|
||||||
// with LTO the symbols seem to be not properly overriden
|
// with LTO the symbols seem to be not properly overriden
|
||||||
// if they're somewhere else
|
// if they're somewhere else
|
||||||
|
@ -75,7 +88,7 @@ void __libnx_exception_handler(ThreadExceptionDump* ctx)
|
||||||
ARMJIT_Memory::FaultDescription desc;
|
ARMJIT_Memory::FaultDescription desc;
|
||||||
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
|
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
|
||||||
desc.EmulatedFaultAddr = (u8*)ctx->far.x - curArea;
|
desc.EmulatedFaultAddr = (u8*)ctx->far.x - curArea;
|
||||||
desc.FaultPC = ctx->pc.x;
|
desc.FaultPC = (u8*)ctx->pc.x;
|
||||||
|
|
||||||
u64 integerRegisters[33];
|
u64 integerRegisters[33];
|
||||||
memcpy(integerRegisters, &ctx->cpu_gprs[0].x, 8*29);
|
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[31] = ctx->sp.x;
|
||||||
integerRegisters[32] = ctx->pc.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);
|
ARM_RestoreContext(integerRegisters);
|
||||||
}
|
}
|
||||||
|
@ -117,12 +129,11 @@ static LONG ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
|
||||||
ARMJIT_Memory::FaultDescription desc;
|
ARMJIT_Memory::FaultDescription desc;
|
||||||
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
|
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
|
||||||
desc.EmulatedFaultAddr = (u8*)exceptionInfo->ExceptionRecord->ExceptionInformation[1] - curArea;
|
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))
|
||||||
if (ARMJIT_Memory::FaultHandler(&desc, offset))
|
|
||||||
{
|
{
|
||||||
exceptionInfo->ContextRecord->Rip += offset;
|
exceptionInfo->ContextRecord->Rip = (u64)desc.FaultPC;
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,50 +142,75 @@ static LONG ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
struct sigaction NewSa;
|
static struct sigaction OldSaSegv;
|
||||||
struct sigaction OldSa;
|
static struct sigaction OldSaBus;
|
||||||
|
|
||||||
static void SigsegvHandler(int sig, siginfo_t* info, void* rawContext)
|
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;
|
ucontext_t* context = (ucontext_t*)rawContext;
|
||||||
|
|
||||||
ARMJIT_Memory::FaultDescription desc;
|
ARMJIT_Memory::FaultDescription desc;
|
||||||
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
|
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
desc.EmulatedFaultAddr = (u8*)info->si_addr - curArea;
|
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
|
#else
|
||||||
desc.EmulatedFaultAddr = (u8*)context->uc_mcontext.fault_address - curArea;
|
desc.EmulatedFaultAddr = (u8*)context->uc_mcontext.fault_address - curArea;
|
||||||
desc.FaultPC = context->uc_mcontext.pc;
|
desc.FaultPC = (u8*)context->uc_mcontext.pc;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
s32 offset = 0;
|
if (ARMJIT_Memory::FaultHandler(desc))
|
||||||
if (ARMJIT_Memory::FaultHandler(&desc, offset))
|
|
||||||
{
|
{
|
||||||
#ifdef __x86_64__
|
#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
|
#else
|
||||||
context->uc_mcontext.pc += offset;
|
context->uc_mcontext.pc = (u64)desc.FaultPC;
|
||||||
#endif
|
#endif
|
||||||
return;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (OldSa.sa_handler == SIG_DFL)
|
if (oldSa->sa_handler == SIG_DFL)
|
||||||
{
|
{
|
||||||
signal(sig, SIG_DFL);
|
signal(sig, SIG_DFL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (OldSa.sa_handler == SIG_IGN)
|
if (oldSa->sa_handler == SIG_IGN)
|
||||||
{
|
{
|
||||||
// Ignore signal
|
// Ignore signal
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OldSa.sa_handler(sig);
|
oldSa->sa_handler(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -231,7 +267,7 @@ enum
|
||||||
{
|
{
|
||||||
memstate_Unmapped,
|
memstate_Unmapped,
|
||||||
memstate_MappedRW,
|
memstate_MappedRW,
|
||||||
// on switch this is unmapped as well
|
// on Switch this is unmapped as well
|
||||||
memstate_MappedProtected,
|
memstate_MappedProtected,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -314,14 +350,16 @@ struct Mapping
|
||||||
|
|
||||||
void Unmap(int region)
|
void Unmap(int region)
|
||||||
{
|
{
|
||||||
|
u32 dtcmStart = NDS::ARM9->DTCMBase;
|
||||||
|
u32 dtcmSize = NDS::ARM9->DTCMSize;
|
||||||
bool skipDTCM = Num == 0 && region != memregion_DTCM;
|
bool skipDTCM = Num == 0 && region != memregion_DTCM;
|
||||||
u8* statuses = Num == 0 ? MappingStatus9 : MappingStatus7;
|
u8* statuses = Num == 0 ? MappingStatus9 : MappingStatus7;
|
||||||
u32 offset = 0;
|
u32 offset = 0;
|
||||||
while (offset < Size)
|
while (offset < Size)
|
||||||
{
|
{
|
||||||
if (skipDTCM && Addr + offset == NDS::ARM9->DTCMBase)
|
if (skipDTCM && Addr + offset == dtcmStart)
|
||||||
{
|
{
|
||||||
offset += NDS::ARM9->DTCMSize;
|
offset += dtcmSize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -329,7 +367,7 @@ struct Mapping
|
||||||
u8 status = statuses[(Addr + offset) >> 12];
|
u8 status = statuses[(Addr + offset) >> 12];
|
||||||
while (statuses[(Addr + offset) >> 12] == status
|
while (statuses[(Addr + offset) >> 12] == status
|
||||||
&& offset < Size
|
&& offset < Size
|
||||||
&& (!skipDTCM || Addr + offset != NDS::ARM9->DTCMBase))
|
&& (!skipDTCM || Addr + offset != dtcmStart))
|
||||||
{
|
{
|
||||||
assert(statuses[(Addr + offset) >> 12] != memstate_Unmapped);
|
assert(statuses[(Addr + offset) >> 12] != memstate_Unmapped);
|
||||||
statuses[(Addr + offset) >> 12] = memstate_Unmapped;
|
statuses[(Addr + offset) >> 12] = memstate_Unmapped;
|
||||||
|
@ -347,9 +385,33 @@ struct Mapping
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __SWITCH__
|
#ifndef __SWITCH__
|
||||||
bool succeded = UnmapFromRange(Addr, Num, OffsetsPerRegion[region] + LocalOffset, Size);
|
#ifndef _WIN32
|
||||||
assert(succeded);
|
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
|
#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);
|
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 overlap = (NDS::ARM9->DTCMSize > 0 && oldDTCMBase < end && oldDTCBEnd > start)
|
||||||
bool newOverlap = newSize > 0 && !(newBase >= end || newEnd <= start);
|
|| (newSize > 0 && newBase < end && newEnd > start);
|
||||||
|
|
||||||
if (mapping.Num == 0 && (oldOverlap || newOverlap))
|
if (mapping.Num == 0 && overlap)
|
||||||
{
|
{
|
||||||
mapping.Unmap(region);
|
mapping.Unmap(region);
|
||||||
Mappings[region].Remove(i);
|
Mappings[region].Remove(i);
|
||||||
|
@ -445,8 +507,8 @@ void RemapNWRAM(int num)
|
||||||
for (int i = 0; i < Mappings[memregion_SharedWRAM].Length;)
|
for (int i = 0; i < Mappings[memregion_SharedWRAM].Length;)
|
||||||
{
|
{
|
||||||
Mapping& mapping = Mappings[memregion_SharedWRAM][i];
|
Mapping& mapping = Mappings[memregion_SharedWRAM][i];
|
||||||
if (!(DSi::NWRAMStart[mapping.Num][num] >= mapping.Addr + mapping.Size
|
if (DSi::NWRAMStart[mapping.Num][num] < mapping.Addr + mapping.Size
|
||||||
|| DSi::NWRAMEnd[mapping.Num][num] < mapping.Addr))
|
&& DSi::NWRAMEnd[mapping.Num][num] > mapping.Addr)
|
||||||
{
|
{
|
||||||
mapping.Unmap(memregion_SharedWRAM);
|
mapping.Unmap(memregion_SharedWRAM);
|
||||||
Mappings[memregion_SharedWRAM].Remove(i);
|
Mappings[memregion_SharedWRAM].Remove(i);
|
||||||
|
@ -469,7 +531,7 @@ void RemapSWRAM()
|
||||||
for (int i = 0; i < Mappings[memregion_WRAM7].Length;)
|
for (int i = 0; i < Mappings[memregion_WRAM7].Length;)
|
||||||
{
|
{
|
||||||
Mapping& mapping = Mappings[memregion_WRAM7][i];
|
Mapping& mapping = Mappings[memregion_WRAM7][i];
|
||||||
if (mapping.Addr + mapping.Size < 0x03800000)
|
if (mapping.Addr + mapping.Size <= 0x03800000)
|
||||||
{
|
{
|
||||||
mapping.Unmap(memregion_WRAM7);
|
mapping.Unmap(memregion_WRAM7);
|
||||||
Mappings[memregion_WRAM7].Remove(i);
|
Mappings[memregion_WRAM7].Remove(i);
|
||||||
|
@ -501,26 +563,53 @@ bool MapAtAddress(u32 addr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
u8* states = num == 0 ? MappingStatus9 : MappingStatus7;
|
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];
|
bool isExecutable = ARMJIT::CodeMemRegions[region];
|
||||||
|
|
||||||
|
u32 dtcmStart = NDS::ARM9->DTCMBase;
|
||||||
|
u32 dtcmSize = NDS::ARM9->DTCMSize;
|
||||||
|
u32 dtcmEnd = dtcmStart + dtcmSize;
|
||||||
#ifndef __SWITCH__
|
#ifndef __SWITCH__
|
||||||
bool succeded = MapIntoRange(mirrorStart, num, OffsetsPerRegion[region] + memoryOffset, mirrorSize);
|
#ifndef _WIN32
|
||||||
assert(succeded);
|
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
|
#endif
|
||||||
|
|
||||||
ARMJIT::AddressRange* range = ARMJIT::CodeMemRegions[region] + memoryOffset / 512;
|
ARMJIT::AddressRange* range = ARMJIT::CodeMemRegions[region] + memoryOffset / 512;
|
||||||
|
|
||||||
// this overcomplicated piece of code basically just finds whole pieces of code memory
|
// 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;
|
u32 offset = 0;
|
||||||
bool skipDTCM = num == 0 && region != memregion_DTCM;
|
bool skipDTCM = num == 0 && region != memregion_DTCM;
|
||||||
while (offset < mirrorSize)
|
while (offset < mirrorSize)
|
||||||
{
|
{
|
||||||
if (skipDTCM && mirrorStart + offset == NDS::ARM9->DTCMBase)
|
if (skipDTCM && mirrorStart + offset == dtcmStart)
|
||||||
{
|
{
|
||||||
SetCodeProtectionRange(NDS::ARM9->DTCMBase, NDS::ARM9->DTCMSize, 0, 0);
|
#ifdef _WIN32
|
||||||
offset += NDS::ARM9->DTCMSize;
|
SetCodeProtectionRange(dtcmStart, dtcmSize, 0, 0);
|
||||||
|
#endif
|
||||||
|
offset += dtcmSize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -557,26 +646,25 @@ bool MapAtAddress(u32 addr)
|
||||||
Mapping mapping{mirrorStart, mirrorSize, memoryOffset, num};
|
Mapping mapping{mirrorStart, mirrorSize, memoryOffset, num};
|
||||||
Mappings[region].Add(mapping);
|
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;
|
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;
|
bool rewriteToSlowPath = true;
|
||||||
|
|
||||||
u32 addr = faultDesc->EmulatedFaultAddr;
|
u8* memStatus = NDS::CurCPU == 0 ? MappingStatus9 : MappingStatus7;
|
||||||
|
|
||||||
if ((NDS::CurCPU == 0 ? MappingStatus9 : MappingStatus7)[addr >> 12] == memstate_Unmapped)
|
if (memStatus[faultDesc.EmulatedFaultAddr >> 12] == memstate_Unmapped)
|
||||||
rewriteToSlowPath = !MapAtAddress(faultDesc->EmulatedFaultAddr);
|
rewriteToSlowPath = !MapAtAddress(faultDesc.EmulatedFaultAddr);
|
||||||
|
|
||||||
if (rewriteToSlowPath)
|
if (rewriteToSlowPath)
|
||||||
{
|
faultDesc.FaultPC = ARMJIT::JITCompiler->RewriteMemAccess(faultDesc.FaultPC);
|
||||||
offset = ARMJIT::JITCompiler->RewriteMemAccess(faultDesc->FaultPC);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -624,22 +712,52 @@ void Init()
|
||||||
|
|
||||||
u8* basePtr = MemoryBase;
|
u8* basePtr = MemoryBase;
|
||||||
#else
|
#else
|
||||||
FastMem9Start = mmap(NULL, AddrSpaceSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
// this used to be allocated with three different mmaps
|
||||||
FastMem7Start = mmap(NULL, AddrSpaceSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
// 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);
|
MemoryFile = memfd_create("melondsfastmem", 0);
|
||||||
|
#endif
|
||||||
ftruncate(MemoryFile, MemoryTotalSize);
|
ftruncate(MemoryFile, MemoryTotalSize);
|
||||||
|
|
||||||
NewSa.sa_flags = SA_SIGINFO;
|
struct sigaction sa;
|
||||||
sigemptyset(&NewSa.sa_mask);
|
sa.sa_handler = nullptr;
|
||||||
NewSa.sa_sigaction = SigsegvHandler;
|
sa.sa_sigaction = &SigsegvHandler;
|
||||||
sigaction(SIGSEGV, &NewSa, &OldSa);
|
sa.sa_flags = SA_SIGINFO;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
munmap(MemoryBase, MemoryTotalSize);
|
sigaction(SIGSEGV, &sa, &OldSaSegv);
|
||||||
munmap(FastMem9Start, AddrSpaceSize);
|
#ifdef __APPLE__
|
||||||
munmap(FastMem7Start, AddrSpaceSize);
|
sigaction(SIGBUS, &sa, &OldSaBus);
|
||||||
|
#endif
|
||||||
|
|
||||||
mmap(MemoryBase, MemoryTotalSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, MemoryFile, 0);
|
mmap(MemoryBase, MemoryTotalSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, MemoryFile, 0);
|
||||||
|
|
||||||
|
@ -657,17 +775,30 @@ void Init()
|
||||||
void DeInit()
|
void DeInit()
|
||||||
{
|
{
|
||||||
#if defined(__SWITCH__)
|
#if defined(__SWITCH__)
|
||||||
virtmemFree(FastMem9Start, 0x100000000);
|
virtmemFree(FastMem9Start, AddrSpaceSize);
|
||||||
virtmemFree(FastMem7Start, 0x100000000);
|
virtmemFree(FastMem7Start, AddrSpaceSize);
|
||||||
|
|
||||||
svcUnmapProcessCodeMemory(envGetOwnProcessHandle(), (u64)MemoryBaseCodeMem, (u64)MemoryBase, MemoryTotalSize);
|
svcUnmapProcessCodeMemory(envGetOwnProcessHandle(), (u64)MemoryBaseCodeMem, (u64)MemoryBase, MemoryTotalSize);
|
||||||
virtmemFree(MemoryBaseCodeMem, MemoryTotalSize);
|
virtmemFree(MemoryBaseCodeMem, MemoryTotalSize);
|
||||||
free(MemoryBase);
|
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)
|
#elif defined(_WIN32)
|
||||||
assert(UnmapViewOfFile(MemoryBase));
|
assert(UnmapViewOfFile(MemoryBase));
|
||||||
CloseHandle(MemoryFile);
|
CloseHandle(MemoryFile);
|
||||||
|
|
||||||
RemoveVectoredExceptionHandler(ExceptionHandlerHandle);
|
RemoveVectoredExceptionHandler(ExceptionHandlerHandle);
|
||||||
|
#else
|
||||||
|
sigaction(SIGSEGV, &OldSaSegv, nullptr);
|
||||||
|
#ifdef __APPLE__
|
||||||
|
sigaction(SIGBUS, &OldSaBus, nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
munmap(MemoryBase, MemoryTotalSize);
|
||||||
|
close(MemoryFile);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -997,9 +1128,11 @@ int ClassifyAddress7(u32 addr)
|
||||||
case 0x06000000:
|
case 0x06000000:
|
||||||
case 0x06800000:
|
case 0x06800000:
|
||||||
return memregion_VWRAM;
|
return memregion_VWRAM;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return memregion_Other;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return memregion_Other;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiWrite32(u32 addr, u32 val)
|
void WifiWrite32(u32 addr, u32 val)
|
||||||
|
@ -1176,4 +1309,4 @@ void* GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,16 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
|
||||||
ADD(32, MDisp(RCPU, offsetof(ARM, Cycles)), Imm8(cycles));
|
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)
|
void Compiler::Comp_JumpTo(Gen::X64Reg addr, bool restoreCPSR)
|
||||||
{
|
{
|
||||||
IrregularCycles = true;
|
IrregularCycles = true;
|
||||||
|
@ -146,9 +156,9 @@ void Compiler::Comp_JumpTo(Gen::X64Reg addr, bool restoreCPSR)
|
||||||
else
|
else
|
||||||
MOV(32, R(ABI_PARAM3), Imm32(true)); // what a waste
|
MOV(32, R(ABI_PARAM3), Imm32(true)); // what a waste
|
||||||
if (Num == 0)
|
if (Num == 0)
|
||||||
CALL((void*)&ARMv5::JumpTo);
|
CALL((void*)&ARMv5JumpToTrampoline);
|
||||||
else
|
else
|
||||||
CALL((void*)&ARMv4::JumpTo);
|
CALL((void*)&ARMv4JumpToTrampoline);
|
||||||
|
|
||||||
PopRegs(restoreCPSR);
|
PopRegs(restoreCPSR);
|
||||||
|
|
||||||
|
@ -269,4 +279,4 @@ void Compiler::T_Comp_BL_Merged()
|
||||||
Comp_JumpTo(target);
|
Comp_JumpTo(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,11 @@ void Compiler::A_Comp_MRS()
|
||||||
MOV(32, rd, R(RCPSR));
|
MOV(32, rd, R(RCPSR));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateModeTrampoline(ARM* arm, u32 oldmode, u32 newmode)
|
||||||
|
{
|
||||||
|
arm->UpdateMode(oldmode, newmode);
|
||||||
|
}
|
||||||
|
|
||||||
void Compiler::A_Comp_MSR()
|
void Compiler::A_Comp_MSR()
|
||||||
{
|
{
|
||||||
Comp_AddCycles_C();
|
Comp_AddCycles_C();
|
||||||
|
@ -185,7 +190,7 @@ void Compiler::A_Comp_MSR()
|
||||||
MOV(32, R(ABI_PARAM3), R(RCPSR));
|
MOV(32, R(ABI_PARAM3), R(RCPSR));
|
||||||
MOV(32, R(ABI_PARAM2), R(RSCRATCH3));
|
MOV(32, R(ABI_PARAM2), R(RSCRATCH3));
|
||||||
MOV(64, R(ABI_PARAM1), R(RCPU));
|
MOV(64, R(ABI_PARAM1), R(RCPU));
|
||||||
CALL((void*)&ARM::UpdateMode);
|
CALL((void*)&UpdateModeTrampoline);
|
||||||
|
|
||||||
PopRegs(true);
|
PopRegs(true);
|
||||||
}
|
}
|
||||||
|
@ -216,6 +221,8 @@ Compiler::Compiler()
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DWORD dummy;
|
DWORD dummy;
|
||||||
VirtualProtect(pageAligned, alignedSize, PAGE_EXECUTE_READWRITE, &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
|
#else
|
||||||
mprotect(pageAligned, alignedSize, PROT_EXEC | PROT_READ | PROT_WRITE);
|
mprotect(pageAligned, alignedSize, PROT_EXEC | PROT_READ | PROT_WRITE);
|
||||||
#endif
|
#endif
|
||||||
|
@ -340,7 +347,7 @@ Compiler::Compiler()
|
||||||
ABI_PushRegistersAndAdjustStack(CallerSavedPushRegs, 8);
|
ABI_PushRegistersAndAdjustStack(CallerSavedPushRegs, 8);
|
||||||
if (consoleType == 0)
|
if (consoleType == 0)
|
||||||
{
|
{
|
||||||
switch ((8 << size) | num)
|
switch ((8 << size) | num)
|
||||||
{
|
{
|
||||||
case 32: ABI_CallFunction(SlowWrite9<u32, 0>); break;
|
case 32: ABI_CallFunction(SlowWrite9<u32, 0>); break;
|
||||||
case 33: ABI_CallFunction(SlowWrite7<u32, 0>); break;
|
case 33: ABI_CallFunction(SlowWrite7<u32, 0>); break;
|
||||||
|
@ -352,7 +359,7 @@ Compiler::Compiler()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch ((8 << size) | num)
|
switch ((8 << size) | num)
|
||||||
{
|
{
|
||||||
case 32: ABI_CallFunction(SlowWrite9<u32, 1>); break;
|
case 32: ABI_CallFunction(SlowWrite9<u32, 1>); break;
|
||||||
case 33: ABI_CallFunction(SlowWrite7<u32, 1>); break;
|
case 33: ABI_CallFunction(SlowWrite7<u32, 1>); break;
|
||||||
|
@ -375,7 +382,7 @@ Compiler::Compiler()
|
||||||
ABI_PushRegistersAndAdjustStack(CallerSavedPushRegs, 8);
|
ABI_PushRegistersAndAdjustStack(CallerSavedPushRegs, 8);
|
||||||
if (consoleType == 0)
|
if (consoleType == 0)
|
||||||
{
|
{
|
||||||
switch ((8 << size) | num)
|
switch ((8 << size) | num)
|
||||||
{
|
{
|
||||||
case 32: ABI_CallFunction(SlowRead9<u32, 0>); break;
|
case 32: ABI_CallFunction(SlowRead9<u32, 0>); break;
|
||||||
case 33: ABI_CallFunction(SlowRead7<u32, 0>); break;
|
case 33: ABI_CallFunction(SlowRead7<u32, 0>); break;
|
||||||
|
@ -387,7 +394,7 @@ Compiler::Compiler()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch ((8 << size) | num)
|
switch ((8 << size) | num)
|
||||||
{
|
{
|
||||||
case 32: ABI_CallFunction(SlowRead9<u32, 1>); break;
|
case 32: ABI_CallFunction(SlowRead9<u32, 1>); break;
|
||||||
case 33: ABI_CallFunction(SlowRead7<u32, 1>); break;
|
case 33: ABI_CallFunction(SlowRead7<u32, 1>); break;
|
||||||
|
@ -612,9 +619,9 @@ void Compiler::Reset()
|
||||||
LoadStorePatches.clear();
|
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)
|
void Compiler::Comp_SpecialBranchBehaviour(bool taken)
|
||||||
|
@ -896,5 +903,4 @@ void Compiler::Comp_AddCycles_CD()
|
||||||
else
|
else
|
||||||
ConstantCycles += cycles;
|
ConstantCycles += cycles;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -208,9 +208,9 @@ public:
|
||||||
SetCodePtr(FarCode);
|
SetCodePtr(FarCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsJITFault(u64 addr);
|
bool IsJITFault(u8* addr);
|
||||||
|
|
||||||
s32 RewriteMemAccess(u64 pc);
|
u8* RewriteMemAccess(u8* pc);
|
||||||
|
|
||||||
u8* FarCode;
|
u8* FarCode;
|
||||||
u8* NearCode;
|
u8* NearCode;
|
||||||
|
|
|
@ -29,8 +29,13 @@
|
||||||
|
|
||||||
.p2align 4,,15
|
.p2align 4,,15
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
.global _ARM_Dispatch
|
||||||
|
_ARM_Dispatch:
|
||||||
|
#else
|
||||||
.global ARM_Dispatch
|
.global ARM_Dispatch
|
||||||
ARM_Dispatch:
|
ARM_Dispatch:
|
||||||
|
#endif
|
||||||
#ifdef WIN64
|
#ifdef WIN64
|
||||||
push rdi
|
push rdi
|
||||||
push rsi
|
push rsi
|
||||||
|
@ -54,8 +59,13 @@ ARM_Dispatch:
|
||||||
|
|
||||||
.p2align 4,,15
|
.p2align 4,,15
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
.global _ARM_Ret
|
||||||
|
_ARM_Ret:
|
||||||
|
#else
|
||||||
.global ARM_Ret
|
.global ARM_Ret
|
||||||
ARM_Ret:
|
ARM_Ret:
|
||||||
|
#endif
|
||||||
mov [RCPU + ARM_CPSR_offset], RCPSR
|
mov [RCPU + ARM_CPSR_offset], RCPSR
|
||||||
|
|
||||||
#ifdef WIN64
|
#ifdef WIN64
|
|
@ -15,28 +15,24 @@ int squeezePointer(T* ptr)
|
||||||
return truncated;
|
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())
|
if (it != LoadStorePatches.end())
|
||||||
{
|
{
|
||||||
LoadStorePatch patch = it->second;
|
LoadStorePatch patch = it->second;
|
||||||
LoadStorePatches.erase(it);
|
LoadStorePatches.erase(it);
|
||||||
|
|
||||||
u8* curCodePtr = GetWritableCodePtr();
|
//printf("rewriting memory access %p %d %d\n", (u8*)pc-ResetStart, patch.Offset, patch.Size);
|
||||||
u8* rewritePtr = (u8*)pc + (ptrdiff_t)patch.Offset;
|
|
||||||
SetCodePtr(rewritePtr);
|
|
||||||
|
|
||||||
CALL(patch.PatchFunc);
|
XEmitter emitter(pc + (ptrdiff_t)patch.Offset);
|
||||||
u32 remainingSize = patch.Size - (GetWritableCodePtr() - rewritePtr);
|
emitter.CALL(patch.PatchFunc);
|
||||||
|
ptrdiff_t remainingSize = (ptrdiff_t)patch.Size - 5;
|
||||||
|
assert(remainingSize >= 0);
|
||||||
if (remainingSize > 0)
|
if (remainingSize > 0)
|
||||||
NOP(remainingSize);
|
emitter.NOP(remainingSize);
|
||||||
|
|
||||||
//printf("rewriting memory access %p %d %d\n", patch.PatchFunc, patch.Offset, patch.Size);
|
return pc + (ptrdiff_t)patch.Offset;
|
||||||
|
|
||||||
SetCodePtr(curCodePtr);
|
|
||||||
|
|
||||||
return patch.Offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("this is a JIT bug %llx\n", pc);
|
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();
|
u8* memopStart = GetWritableCodePtr();
|
||||||
LoadStorePatch patch;
|
LoadStorePatch patch;
|
||||||
|
|
||||||
|
assert(rdMapped.GetSimpleReg() >= 0 && rdMapped.GetSimpleReg() < 16);
|
||||||
patch.PatchFunc = flags & memop_Store
|
patch.PatchFunc = flags & memop_Store
|
||||||
? PatchedStoreFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][rdMapped.GetSimpleReg()]
|
? PatchedStoreFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][rdMapped.GetSimpleReg()]
|
||||||
: PatchedLoadFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][!!(flags & memop_SignExtend)][rdMapped.GetSimpleReg()];
|
: PatchedLoadFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][!!(flags & memop_SignExtend)][rdMapped.GetSimpleReg()];
|
||||||
|
|
|
@ -80,9 +80,8 @@ if (ENABLE_JIT)
|
||||||
ARMJIT_x64/ARMJIT_LoadStore.cpp
|
ARMJIT_x64/ARMJIT_LoadStore.cpp
|
||||||
ARMJIT_x64/ARMJIT_Branch.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()
|
endif()
|
||||||
if (ARCHITECTURE STREQUAL ARM64)
|
if (ARCHITECTURE STREQUAL ARM64)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
|
@ -94,16 +93,22 @@ if (ENABLE_JIT)
|
||||||
ARMJIT_A64/ARMJIT_LoadStore.cpp
|
ARMJIT_A64/ARMJIT_LoadStore.cpp
|
||||||
ARMJIT_A64/ARMJIT_Branch.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()
|
||||||
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 (ENABLE_OGLRENDERER)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_libraries(core ole32 comctl32 ws2_32 opengl32)
|
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)
|
target_link_libraries(core GL EGL)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
|
|
|
@ -73,7 +73,11 @@ ConfigEntry ConfigFile[] =
|
||||||
{"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, NULL, 0},
|
{"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, NULL, 0},
|
||||||
{"JIT_BranchOptimisations", 0, &JIT_BranchOptimisations, 1, NULL, 0},
|
{"JIT_BranchOptimisations", 0, &JIT_BranchOptimisations, 1, NULL, 0},
|
||||||
{"JIT_LiteralOptimisations", 0, &JIT_LiteralOptimisations, 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
|
#endif
|
||||||
|
|
||||||
{"", -1, NULL, 0, NULL, 0}
|
{"", -1, NULL, 0, NULL, 0}
|
||||||
|
|
55
src/DMA.cpp
55
src/DMA.cpp
|
@ -77,21 +77,6 @@ void DMA::Reset()
|
||||||
|
|
||||||
Running = false;
|
Running = false;
|
||||||
InProgress = 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)
|
void DMA::DoSavestate(Savestate* file)
|
||||||
|
@ -198,13 +183,7 @@ void DMA::Start()
|
||||||
NDS::StopCPU(CPU, 1<<Num);
|
NDS::StopCPU(CPU, 1<<Num);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA::Run()
|
template <int ConsoleType>
|
||||||
{
|
|
||||||
if (!Running) return;
|
|
||||||
if (CPU == 0) return Run9();
|
|
||||||
else return Run7();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DMA::Run9()
|
void DMA::Run9()
|
||||||
{
|
{
|
||||||
if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
|
if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
|
||||||
|
@ -242,7 +221,10 @@ void DMA::Run9()
|
||||||
{
|
{
|
||||||
NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift);
|
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;
|
CurSrcAddr += SrcAddrInc<<1;
|
||||||
CurDstAddr += DstAddrInc<<1;
|
CurDstAddr += DstAddrInc<<1;
|
||||||
|
@ -278,7 +260,10 @@ void DMA::Run9()
|
||||||
{
|
{
|
||||||
NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift);
|
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;
|
CurSrcAddr += SrcAddrInc<<2;
|
||||||
CurDstAddr += DstAddrInc<<2;
|
CurDstAddr += DstAddrInc<<2;
|
||||||
|
@ -317,6 +302,7 @@ void DMA::Run9()
|
||||||
NDS::ResumeCPU(0, 1<<Num);
|
NDS::ResumeCPU(0, 1<<Num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <int ConsoleType>
|
||||||
void DMA::Run7()
|
void DMA::Run7()
|
||||||
{
|
{
|
||||||
if (NDS::ARM7Timestamp >= NDS::ARM7Target) return;
|
if (NDS::ARM7Timestamp >= NDS::ARM7Target) return;
|
||||||
|
@ -354,7 +340,10 @@ void DMA::Run7()
|
||||||
{
|
{
|
||||||
NDS::ARM7Timestamp += unitcycles;
|
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;
|
CurSrcAddr += SrcAddrInc<<1;
|
||||||
CurDstAddr += DstAddrInc<<1;
|
CurDstAddr += DstAddrInc<<1;
|
||||||
|
@ -390,7 +379,10 @@ void DMA::Run7()
|
||||||
{
|
{
|
||||||
NDS::ARM7Timestamp += unitcycles;
|
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;
|
CurSrcAddr += SrcAddrInc<<2;
|
||||||
CurDstAddr += DstAddrInc<<2;
|
CurDstAddr += DstAddrInc<<2;
|
||||||
|
@ -425,3 +417,14 @@ void DMA::Run7()
|
||||||
InProgress = false;
|
InProgress = false;
|
||||||
NDS::ResumeCPU(1, 1<<Num);
|
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>();
|
|
@ -34,9 +34,12 @@ public:
|
||||||
void WriteCnt(u32 val);
|
void WriteCnt(u32 val);
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
|
template <int ConsoleType>
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
|
template <int ConsoleType>
|
||||||
void Run9();
|
void Run9();
|
||||||
|
template <int ConsoleType>
|
||||||
void Run7();
|
void Run7();
|
||||||
|
|
||||||
bool IsInMode(u32 mode)
|
bool IsInMode(u32 mode)
|
||||||
|
@ -86,11 +89,6 @@ private:
|
||||||
bool Stall;
|
bool Stall;
|
||||||
|
|
||||||
bool IsGXFIFODMA;
|
bool IsGXFIFODMA;
|
||||||
|
|
||||||
u16 (*BusRead16)(u32 addr);
|
|
||||||
u32 (*BusRead32)(u32 addr);
|
|
||||||
void (*BusWrite16)(u32 addr, u16 val);
|
|
||||||
void (*BusWrite32)(u32 addr, u32 val);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
24
src/DSi.cpp
24
src/DSi.cpp
|
@ -543,15 +543,15 @@ void MapNWRAM_A(u32 num, u8 val)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
|
||||||
ARMJIT_Memory::RemapNWRAM(0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int mbkn = 0, mbks = 8*num;
|
int mbkn = 0, mbks = 8*num;
|
||||||
|
|
||||||
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
|
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
|
||||||
if (oldval == val) return;
|
if (oldval == val) return;
|
||||||
|
|
||||||
|
#ifdef JIT_ENABLED
|
||||||
|
ARMJIT_Memory::RemapNWRAM(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
MBK[0][mbkn] &= ~(0xFF << mbks);
|
MBK[0][mbkn] &= ~(0xFF << mbks);
|
||||||
MBK[0][mbkn] |= (val << mbks);
|
MBK[0][mbkn] |= (val << mbks);
|
||||||
MBK[1][mbkn] = MBK[0][mbkn];
|
MBK[1][mbkn] = MBK[0][mbkn];
|
||||||
|
@ -578,15 +578,15 @@ void MapNWRAM_B(u32 num, u8 val)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
|
||||||
ARMJIT_Memory::RemapNWRAM(1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int mbkn = 1+(num>>2), mbks = 8*(num&3);
|
int mbkn = 1+(num>>2), mbks = 8*(num&3);
|
||||||
|
|
||||||
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
|
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
|
||||||
if (oldval == val) return;
|
if (oldval == val) return;
|
||||||
|
|
||||||
|
#ifdef JIT_ENABLED
|
||||||
|
ARMJIT_Memory::RemapNWRAM(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
MBK[0][mbkn] &= ~(0xFF << mbks);
|
MBK[0][mbkn] &= ~(0xFF << mbks);
|
||||||
MBK[0][mbkn] |= (val << mbks);
|
MBK[0][mbkn] |= (val << mbks);
|
||||||
MBK[1][mbkn] = MBK[0][mbkn];
|
MBK[1][mbkn] = MBK[0][mbkn];
|
||||||
|
@ -617,15 +617,15 @@ void MapNWRAM_C(u32 num, u8 val)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
|
||||||
ARMJIT_Memory::RemapNWRAM(2);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int mbkn = 3+(num>>2), mbks = 8*(num&3);
|
int mbkn = 3+(num>>2), mbks = 8*(num&3);
|
||||||
|
|
||||||
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
|
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
|
||||||
if (oldval == val) return;
|
if (oldval == val) return;
|
||||||
|
|
||||||
|
#ifdef JIT_ENABLED
|
||||||
|
ARMJIT_Memory::RemapNWRAM(2);
|
||||||
|
#endif
|
||||||
|
|
||||||
MBK[0][mbkn] &= ~(0xFF << mbks);
|
MBK[0][mbkn] &= ~(0xFF << mbks);
|
||||||
MBK[0][mbkn] |= (val << mbks);
|
MBK[0][mbkn] |= (val << mbks);
|
||||||
MBK[1][mbkn] = MBK[0][mbkn];
|
MBK[1][mbkn] = MBK[0][mbkn];
|
||||||
|
|
338
src/GPU.cpp
338
src/GPU.cpp
|
@ -49,8 +49,8 @@ u8 VRAM_F[ 16*1024];
|
||||||
u8 VRAM_G[ 16*1024];
|
u8 VRAM_G[ 16*1024];
|
||||||
u8 VRAM_H[ 32*1024];
|
u8 VRAM_H[ 32*1024];
|
||||||
u8 VRAM_I[ 16*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};
|
u8* const 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};
|
u32 const VRAMMask[9] = {0x1FFFF, 0x1FFFF, 0x1FFFF, 0x1FFFF, 0xFFFF, 0x3FFF, 0x3FFF, 0x7FFF, 0x3FFF};
|
||||||
|
|
||||||
u8 VRAMCNT[9];
|
u8 VRAMCNT[9];
|
||||||
u8 VRAMSTAT;
|
u8 VRAMSTAT;
|
||||||
|
@ -85,6 +85,62 @@ bool Accelerated;
|
||||||
GPU2D* GPU2D_A;
|
GPU2D* GPU2D_A;
|
||||||
GPU2D* GPU2D_B;
|
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()
|
bool Init()
|
||||||
{
|
{
|
||||||
|
@ -113,6 +169,30 @@ void DeInit()
|
||||||
if (Framebuffer[1][1]) delete[] Framebuffer[1][1];
|
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()
|
void Reset()
|
||||||
{
|
{
|
||||||
VCount = 0;
|
VCount = 0;
|
||||||
|
@ -186,6 +266,8 @@ void Reset()
|
||||||
GPU2D_B->SetFramebuffer(Framebuffer[backbuf][0]);
|
GPU2D_B->SetFramebuffer(Framebuffer[backbuf][0]);
|
||||||
|
|
||||||
ResetRenderer();
|
ResetRenderer();
|
||||||
|
|
||||||
|
ResetVRAMCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stop()
|
void Stop()
|
||||||
|
@ -261,6 +343,8 @@ void DoSavestate(Savestate* file)
|
||||||
GPU2D_A->DoSavestate(file);
|
GPU2D_A->DoSavestate(file);
|
||||||
GPU2D_B->DoSavestate(file);
|
GPU2D_B->DoSavestate(file);
|
||||||
GPU3D::DoSavestate(file);
|
GPU3D::DoSavestate(file);
|
||||||
|
|
||||||
|
ResetVRAMCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignFramebuffers()
|
void AssignFramebuffers()
|
||||||
|
@ -411,18 +495,8 @@ void SetRenderSettings(int renderer, RenderSettings& settings)
|
||||||
|
|
||||||
u8* GetUniqueBankPtr(u32 mask, u32 offset)
|
u8* GetUniqueBankPtr(u32 mask, u32 offset)
|
||||||
{
|
{
|
||||||
if (!mask) return NULL;
|
if (!mask || (mask & (mask - 1)) != 0) return NULL;
|
||||||
|
int num = __builtin_ctz(mask);
|
||||||
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;
|
|
||||||
|
|
||||||
return &VRAM[num][offset & VRAMMask[num]];
|
return &VRAM[num][offset & VRAMMask[num]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,8 +680,6 @@ void MapVRAM_E(u32 bank, u8 cnt)
|
||||||
|
|
||||||
case 4: // ABG ext palette
|
case 4: // ABG ext palette
|
||||||
UNMAP_RANGE(ABGExtPal, 0, 4);
|
UNMAP_RANGE(ABGExtPal, 0, 4);
|
||||||
GPU2D_A->BGExtPalDirty(0);
|
|
||||||
GPU2D_A->BGExtPalDirty(2);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -634,8 +706,6 @@ void MapVRAM_E(u32 bank, u8 cnt)
|
||||||
|
|
||||||
case 4: // ABG ext palette
|
case 4: // ABG ext palette
|
||||||
MAP_RANGE(ABGExtPal, 0, 4);
|
MAP_RANGE(ABGExtPal, 0, 4);
|
||||||
GPU2D_A->BGExtPalDirty(0);
|
|
||||||
GPU2D_A->BGExtPalDirty(2);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -687,12 +757,10 @@ void MapVRAM_FG(u32 bank, u8 cnt)
|
||||||
case 4: // ABG ext palette
|
case 4: // ABG ext palette
|
||||||
VRAMMap_ABGExtPal[((oldofs & 0x1) << 1)] &= ~bankmask;
|
VRAMMap_ABGExtPal[((oldofs & 0x1) << 1)] &= ~bankmask;
|
||||||
VRAMMap_ABGExtPal[((oldofs & 0x1) << 1) + 1] &= ~bankmask;
|
VRAMMap_ABGExtPal[((oldofs & 0x1) << 1) + 1] &= ~bankmask;
|
||||||
GPU2D_A->BGExtPalDirty((oldofs & 0x1) << 1);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5: // AOBJ ext palette
|
case 5: // AOBJ ext palette
|
||||||
VRAMMap_AOBJExtPal &= ~bankmask;
|
VRAMMap_AOBJExtPal &= ~bankmask;
|
||||||
GPU2D_A->OBJExtPalDirty();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -732,12 +800,10 @@ void MapVRAM_FG(u32 bank, u8 cnt)
|
||||||
case 4: // ABG ext palette
|
case 4: // ABG ext palette
|
||||||
VRAMMap_ABGExtPal[((ofs & 0x1) << 1)] |= bankmask;
|
VRAMMap_ABGExtPal[((ofs & 0x1) << 1)] |= bankmask;
|
||||||
VRAMMap_ABGExtPal[((ofs & 0x1) << 1) + 1] |= bankmask;
|
VRAMMap_ABGExtPal[((ofs & 0x1) << 1) + 1] |= bankmask;
|
||||||
GPU2D_A->BGExtPalDirty((ofs & 0x1) << 1);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5: // AOBJ ext palette
|
case 5: // AOBJ ext palette
|
||||||
VRAMMap_AOBJExtPal |= bankmask;
|
VRAMMap_AOBJExtPal |= bankmask;
|
||||||
GPU2D_A->OBJExtPalDirty();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -773,8 +839,6 @@ void MapVRAM_H(u32 bank, u8 cnt)
|
||||||
|
|
||||||
case 2: // BBG ext palette
|
case 2: // BBG ext palette
|
||||||
UNMAP_RANGE(BBGExtPal, 0, 4);
|
UNMAP_RANGE(BBGExtPal, 0, 4);
|
||||||
GPU2D_B->BGExtPalDirty(0);
|
|
||||||
GPU2D_B->BGExtPalDirty(2);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -800,8 +864,6 @@ void MapVRAM_H(u32 bank, u8 cnt)
|
||||||
|
|
||||||
case 2: // BBG ext palette
|
case 2: // BBG ext palette
|
||||||
MAP_RANGE(BBGExtPal, 0, 4);
|
MAP_RANGE(BBGExtPal, 0, 4);
|
||||||
GPU2D_B->BGExtPalDirty(0);
|
|
||||||
GPU2D_B->BGExtPalDirty(2);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -841,7 +903,6 @@ void MapVRAM_I(u32 bank, u8 cnt)
|
||||||
|
|
||||||
case 3: // BOBJ ext palette
|
case 3: // BOBJ ext palette
|
||||||
VRAMMap_BOBJExtPal &= ~bankmask;
|
VRAMMap_BOBJExtPal &= ~bankmask;
|
||||||
GPU2D_B->OBJExtPalDirty();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -871,7 +932,6 @@ void MapVRAM_I(u32 bank, u8 cnt)
|
||||||
|
|
||||||
case 3: // BOBJ ext palette
|
case 3: // BOBJ ext palette
|
||||||
VRAMMap_BOBJExtPal |= bankmask;
|
VRAMMap_BOBJExtPal |= bankmask;
|
||||||
GPU2D_B->OBJExtPalDirty();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -937,6 +997,8 @@ void StartHBlank(u32 line)
|
||||||
DispStat[0] |= (1<<1);
|
DispStat[0] |= (1<<1);
|
||||||
DispStat[1] |= (1<<1);
|
DispStat[1] |= (1<<1);
|
||||||
|
|
||||||
|
SyncDirtyFlags();
|
||||||
|
|
||||||
if (VCount < 192)
|
if (VCount < 192)
|
||||||
{
|
{
|
||||||
// draw
|
// draw
|
||||||
|
@ -1096,4 +1158,224 @@ void SetVCount(u16 val)
|
||||||
NextVCount = 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>);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
87
src/GPU.h
87
src/GPU.h
|
@ -20,6 +20,7 @@
|
||||||
#define GPU_H
|
#define GPU_H
|
||||||
|
|
||||||
#include "GPU2D.h"
|
#include "GPU2D.h"
|
||||||
|
#include "NonStupidBitfield.h"
|
||||||
|
|
||||||
namespace GPU
|
namespace GPU
|
||||||
{
|
{
|
||||||
|
@ -45,7 +46,7 @@ extern u8 VRAM_G[ 16*1024];
|
||||||
extern u8 VRAM_H[ 32*1024];
|
extern u8 VRAM_H[ 32*1024];
|
||||||
extern u8 VRAM_I[ 16*1024];
|
extern u8 VRAM_I[ 16*1024];
|
||||||
|
|
||||||
extern u8* VRAM[9];
|
extern u8* const VRAM[9];
|
||||||
|
|
||||||
extern u32 VRAMMap_LCDC;
|
extern u32 VRAMMap_LCDC;
|
||||||
extern u32 VRAMMap_ABG[0x20];
|
extern u32 VRAMMap_ABG[0x20];
|
||||||
|
@ -73,6 +74,73 @@ extern GPU2D* GPU2D_B;
|
||||||
|
|
||||||
extern int Renderer;
|
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
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -233,7 +301,11 @@ void WriteVRAM_LCDC(u32 addr, T val)
|
||||||
default: return;
|
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];
|
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<<0)) *(T*)&VRAM_A[addr & 0x1FFFF] = val;
|
||||||
if (mask & (1<<1)) *(T*)&VRAM_B[addr & 0x1FFFF] = val;
|
if (mask & (1<<1)) *(T*)&VRAM_B[addr & 0x1FFFF] = val;
|
||||||
if (mask & (1<<2)) *(T*)&VRAM_C[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];
|
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<<0)) *(T*)&VRAM_A[addr & 0x1FFFF] = val;
|
||||||
if (mask & (1<<1)) *(T*)&VRAM_B[addr & 0x1FFFF] = val;
|
if (mask & (1<<1)) *(T*)&VRAM_B[addr & 0x1FFFF] = val;
|
||||||
if (mask & (1<<4)) *(T*)&VRAM_E[addr & 0xFFFF] = 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];
|
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<<2)) *(T*)&VRAM_C[addr & 0x1FFFF] = val;
|
||||||
if (mask & (1<<7)) *(T*)&VRAM_H[addr & 0x7FFF] = val;
|
if (mask & (1<<7)) *(T*)&VRAM_H[addr & 0x7FFF] = val;
|
||||||
if (mask & (1<<8)) *(T*)&VRAM_I[addr & 0x3FFF] = 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];
|
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<<3)) *(T*)&VRAM_D[addr & 0x1FFFF] = val;
|
||||||
if (mask & (1<<8)) *(T*)&VRAM_I[addr & 0x3FFF] = val;
|
if (mask & (1<<8)) *(T*)&VRAM_I[addr & 0x3FFF] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T ReadVRAM_ARM7(u32 addr)
|
T ReadVRAM_ARM7(u32 addr)
|
||||||
{
|
{
|
||||||
|
@ -372,6 +451,8 @@ void WriteVRAM_ARM7(u32 addr, T val)
|
||||||
{
|
{
|
||||||
u32 mask = VRAMMap_ARM7[(addr >> 17) & 0x1];
|
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<<2)) *(T*)&VRAM_C[addr & 0x1FFFF] = val;
|
||||||
if (mask & (1<<3)) *(T*)&VRAM_D[addr & 0x1FFFF] = val;
|
if (mask & (1<<3)) *(T*)&VRAM_D[addr & 0x1FFFF] = val;
|
||||||
}
|
}
|
||||||
|
|
369
src/GPU2D.cpp
369
src/GPU2D.cpp
|
@ -148,12 +148,6 @@ void GPU2D::Reset()
|
||||||
CaptureCnt = 0;
|
CaptureCnt = 0;
|
||||||
|
|
||||||
MasterBrightness = 0;
|
MasterBrightness = 0;
|
||||||
|
|
||||||
BGExtPalStatus[0] = 0;
|
|
||||||
BGExtPalStatus[1] = 0;
|
|
||||||
BGExtPalStatus[2] = 0;
|
|
||||||
BGExtPalStatus[3] = 0;
|
|
||||||
OBJExtPalStatus = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU2D::DoSavestate(Savestate* file)
|
void GPU2D::DoSavestate(Savestate* file)
|
||||||
|
@ -208,13 +202,6 @@ void GPU2D::DoSavestate(Savestate* file)
|
||||||
|
|
||||||
if (!file->Saving)
|
if (!file->Saving)
|
||||||
{
|
{
|
||||||
// refresh those
|
|
||||||
BGExtPalStatus[0] = 0;
|
|
||||||
BGExtPalStatus[1] = 0;
|
|
||||||
BGExtPalStatus[2] = 0;
|
|
||||||
BGExtPalStatus[3] = 0;
|
|
||||||
OBJExtPalStatus = 0;
|
|
||||||
|
|
||||||
CurBGXMosaicTable = MosaicTable[BGMosaicSize[0]];
|
CurBGXMosaicTable = MosaicTable[BGMosaicSize[0]];
|
||||||
CurOBJXMosaicTable = MosaicTable[OBJMosaicSize[0]];
|
CurOBJXMosaicTable = MosaicTable[OBJMosaicSize[0]];
|
||||||
}
|
}
|
||||||
|
@ -228,9 +215,6 @@ void GPU2D::SetFramebuffer(u32* buf)
|
||||||
void GPU2D::SetRenderSettings(bool accel)
|
void GPU2D::SetRenderSettings(bool accel)
|
||||||
{
|
{
|
||||||
Accelerated = accel;
|
Accelerated = accel;
|
||||||
|
|
||||||
if (Accelerated) DrawPixel = DrawPixel_Accel;
|
|
||||||
else DrawPixel = DrawPixel_Normal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -761,6 +745,25 @@ void GPU2D::DrawScanline(u32 line)
|
||||||
int n3dline = line;
|
int n3dline = line;
|
||||||
line = GPU::VCount;
|
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;
|
bool forceblank = false;
|
||||||
|
|
||||||
// scanlines that end up outside of the GPU drawing range
|
// 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];
|
u16* dst = (u16*)GPU::VRAM[dstvram];
|
||||||
u32 dstaddr = (((CaptureCnt >> 18) & 0x3) << 14) + (line * width);
|
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!!
|
// TODO: handle 3D in accelerated mode!!
|
||||||
|
|
||||||
u32* srcA;
|
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* GPU2D::GetBGExtPal(u32 slot, u32 pal)
|
||||||
{
|
{
|
||||||
u16* dst = &BGExtPalCache[slot][pal << 8];
|
const u32 PaletteSize = 256 * 2;
|
||||||
|
const u32 SlotSize = PaletteSize * 16;
|
||||||
if (!(BGExtPalStatus[slot] & (1<<pal)))
|
return (u16*)&(Num == 0
|
||||||
{
|
? GPU::VRAMFlat_ABGExtPal
|
||||||
if (Num)
|
: GPU::VRAMFlat_BBGExtPal)[slot * SlotSize + pal * PaletteSize];
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u16* GPU2D::GetOBJExtPal()
|
u16* GPU2D::GetOBJExtPal()
|
||||||
{
|
{
|
||||||
u16* dst = OBJExtPalCache;
|
return Num == 0
|
||||||
|
? (u16*)GPU::VRAMFlat_AOBJExtPal
|
||||||
if (!OBJExtPalStatus)
|
: (u16*)GPU::VRAMFlat_BOBJExtPal;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1330,10 +1271,36 @@ void GPU2D::CalculateWindowMask(u32 line)
|
||||||
|
|
||||||
|
|
||||||
#define DoDrawBG(type, line, num) \
|
#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) \
|
#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>
|
template<u32 bgmode>
|
||||||
void GPU2D::DrawScanlineBGMode(u32 line)
|
void GPU2D::DrawScanlineBGMode(u32 line)
|
||||||
|
@ -1382,7 +1349,7 @@ void GPU2D::DrawScanlineBGMode(u32 line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((DispCnt & 0x1000) && NumSprites)
|
if ((DispCnt & 0x1000) && NumSprites)
|
||||||
InterleaveSprites(0x40000 | (i<<16));
|
DoInterleaveSprites(0x40000 | (i<<16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1394,7 +1361,7 @@ void GPU2D::DrawScanlineBGMode6(u32 line)
|
||||||
{
|
{
|
||||||
if (DispCnt & 0x0400)
|
if (DispCnt & 0x0400)
|
||||||
{
|
{
|
||||||
DoDrawBG_Large(line)
|
DoDrawBG_Large(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((BGCnt[0] & 0x3) == i)
|
if ((BGCnt[0] & 0x3) == i)
|
||||||
|
@ -1406,7 +1373,7 @@ void GPU2D::DrawScanlineBGMode6(u32 line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((DispCnt & 0x1000) && NumSprites)
|
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)
|
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)
|
void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
|
||||||
{
|
{
|
||||||
u16 bgcnt = BGCnt[bgnum];
|
u16 bgcnt = BGCnt[bgnum];
|
||||||
|
@ -1697,17 +1678,20 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
|
||||||
extpal = (DispCnt & 0x40000000);
|
extpal = (DispCnt & 0x40000000);
|
||||||
if (extpal) extpalslot = ((bgnum<2) && (bgcnt&0x2000)) ? (2+bgnum) : bgnum;
|
if (extpal) extpalslot = ((bgnum<2) && (bgcnt&0x2000)) ? (2+bgnum) : bgnum;
|
||||||
|
|
||||||
|
u8* bgvram;
|
||||||
|
u32 bgvrammask;
|
||||||
|
GetBGVRAM(Num, bgvram, bgvrammask);
|
||||||
if (Num)
|
if (Num)
|
||||||
{
|
{
|
||||||
tilesetaddr = 0x06200000 + ((bgcnt & 0x003C) << 12);
|
tilesetaddr = ((bgcnt & 0x003C) << 12);
|
||||||
tilemapaddr = 0x06200000 + ((bgcnt & 0x1F00) << 3);
|
tilemapaddr = ((bgcnt & 0x1F00) << 3);
|
||||||
|
|
||||||
pal = (u16*)&GPU::Palette[0x400];
|
pal = (u16*)&GPU::Palette[0x400];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tilesetaddr = 0x06000000 + ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
|
tilesetaddr = ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
|
||||||
tilemapaddr = 0x06000000 + ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
|
tilemapaddr = ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
|
||||||
|
|
||||||
pal = (u16*)&GPU::Palette[0];
|
pal = (u16*)&GPU::Palette[0];
|
||||||
}
|
}
|
||||||
|
@ -1735,7 +1719,7 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
|
||||||
// preload shit as needed
|
// preload shit as needed
|
||||||
if ((xoff & 0x7) || mosaic)
|
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);
|
if (extpal) curpal = GetBGExtPal(extpalslot, curtile>>12);
|
||||||
else curpal = pal;
|
else curpal = pal;
|
||||||
|
@ -1756,7 +1740,7 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
|
||||||
(mosaic && ((xpos >> 3) != (lastxpos >> 3))))
|
(mosaic && ((xpos >> 3) != (lastxpos >> 3))))
|
||||||
{
|
{
|
||||||
// load a new tile
|
// 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);
|
if (extpal) curpal = GetBGExtPal(extpalslot, curtile>>12);
|
||||||
else curpal = pal;
|
else curpal = pal;
|
||||||
|
@ -1771,10 +1755,10 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
|
||||||
if (WindowMask[i] & (1<<bgnum))
|
if (WindowMask[i] & (1<<bgnum))
|
||||||
{
|
{
|
||||||
u32 tilexoff = (curtile & 0x0400) ? (7-(xpos&0x7)) : (xpos&0x7);
|
u32 tilexoff = (curtile & 0x0400) ? (7-(xpos&0x7)) : (xpos&0x7);
|
||||||
color = GPU::ReadVRAM_BG<u8>(pixelsaddr + tilexoff);
|
color = bgvram[(pixelsaddr + tilexoff) & bgvrammask];
|
||||||
|
|
||||||
if (color)
|
if (color)
|
||||||
DrawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
|
drawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
xoff++;
|
xoff++;
|
||||||
|
@ -1787,7 +1771,7 @@ void GPU2D::DrawBG_Text(u32 line, u32 bgnum)
|
||||||
// preload shit as needed
|
// preload shit as needed
|
||||||
if ((xoff & 0x7) || mosaic)
|
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);
|
curpal = pal + ((curtile & 0xF000) >> 8);
|
||||||
pixelsaddr = tilesetaddr + ((curtile & 0x03FF) << 5)
|
pixelsaddr = tilesetaddr + ((curtile & 0x03FF) << 5)
|
||||||
+ (((curtile & 0x0800) ? (7-(yoff&0x7)) : (yoff&0x7)) << 2);
|
+ (((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))))
|
(mosaic && ((xpos >> 3) != (lastxpos >> 3))))
|
||||||
{
|
{
|
||||||
// load a new tile
|
// 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);
|
curpal = pal + ((curtile & 0xF000) >> 8);
|
||||||
pixelsaddr = tilesetaddr + ((curtile & 0x03FF) << 5)
|
pixelsaddr = tilesetaddr + ((curtile & 0x03FF) << 5)
|
||||||
+ (((curtile & 0x0800) ? (7-(yoff&0x7)) : (yoff&0x7)) << 2);
|
+ (((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);
|
u32 tilexoff = (curtile & 0x0400) ? (7-(xpos&0x7)) : (xpos&0x7);
|
||||||
if (tilexoff & 0x1)
|
if (tilexoff & 0x1)
|
||||||
{
|
{
|
||||||
color = GPU::ReadVRAM_BG<u8>(pixelsaddr + (tilexoff >> 1)) >> 4;
|
color = bgvram[(pixelsaddr + (tilexoff >> 1)) & bgvrammask] >> 4;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
color = GPU::ReadVRAM_BG<u8>(pixelsaddr + (tilexoff >> 1)) & 0x0F;
|
color = bgvram[(pixelsaddr + (tilexoff >> 1)) & bgvrammask] & 0x0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (color)
|
if (color)
|
||||||
DrawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
|
drawPixel(&BGOBJLine[i], curpal[color], 0x01000000<<bgnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
xoff++;
|
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)
|
void GPU2D::DrawBG_Affine(u32 line, u32 bgnum)
|
||||||
{
|
{
|
||||||
u16 bgcnt = BGCnt[bgnum];
|
u16 bgcnt = BGCnt[bgnum];
|
||||||
|
@ -1872,17 +1856,20 @@ void GPU2D::DrawBG_Affine(u32 line, u32 bgnum)
|
||||||
rotY -= (BGMosaicY * rotD);
|
rotY -= (BGMosaicY * rotD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8* bgvram;
|
||||||
|
u32 bgvrammask;
|
||||||
|
|
||||||
if (Num)
|
if (Num)
|
||||||
{
|
{
|
||||||
tilesetaddr = 0x06200000 + ((bgcnt & 0x003C) << 12);
|
tilesetaddr = ((bgcnt & 0x003C) << 12);
|
||||||
tilemapaddr = 0x06200000 + ((bgcnt & 0x1F00) << 3);
|
tilemapaddr = ((bgcnt & 0x1F00) << 3);
|
||||||
|
|
||||||
pal = (u16*)&GPU::Palette[0x400];
|
pal = (u16*)&GPU::Palette[0x400];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tilesetaddr = 0x06000000 + ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
|
tilesetaddr = ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
|
||||||
tilemapaddr = 0x06000000 + ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
|
tilemapaddr = ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
|
||||||
|
|
||||||
pal = (u16*)&GPU::Palette[0];
|
pal = (u16*)&GPU::Palette[0];
|
||||||
}
|
}
|
||||||
|
@ -1911,16 +1898,16 @@ void GPU2D::DrawBG_Affine(u32 line, u32 bgnum)
|
||||||
|
|
||||||
if ((!((finalX|finalY) & overflowmask)))
|
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
|
// draw pixel
|
||||||
u32 tilexoff = (finalX >> 8) & 0x7;
|
u32 tilexoff = (finalX >> 8) & 0x7;
|
||||||
u32 tileyoff = (finalY >> 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)
|
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;
|
BGYRefInternal[bgnum-2] += rotD;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool mosaic>
|
template<bool mosaic, GPU2D::DrawPixel drawPixel>
|
||||||
void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
|
void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
|
||||||
{
|
{
|
||||||
u16 bgcnt = BGCnt[bgnum];
|
u16 bgcnt = BGCnt[bgnum];
|
||||||
|
@ -1941,6 +1928,10 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
|
||||||
u16* pal;
|
u16* pal;
|
||||||
u32 extpal;
|
u32 extpal;
|
||||||
|
|
||||||
|
u8* bgvram;
|
||||||
|
u32 bgvrammask;
|
||||||
|
GetBGVRAM(Num, bgvram, bgvrammask);
|
||||||
|
|
||||||
extpal = (DispCnt & 0x40000000);
|
extpal = (DispCnt & 0x40000000);
|
||||||
|
|
||||||
s16 rotA = BGRotA[bgnum-2];
|
s16 rotA = BGRotA[bgnum-2];
|
||||||
|
@ -1984,8 +1975,8 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
|
||||||
ofymask = ~ymask;
|
ofymask = ~ymask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Num) tilemapaddr = 0x06200000 + ((bgcnt & 0x1F00) << 6);
|
if (Num) tilemapaddr = ((bgcnt & 0x1F00) << 6);
|
||||||
else tilemapaddr = 0x06000000 + ((bgcnt & 0x1F00) << 6);
|
else tilemapaddr = ((bgcnt & 0x1F00) << 6);
|
||||||
|
|
||||||
if (bgcnt & 0x0004)
|
if (bgcnt & 0x0004)
|
||||||
{
|
{
|
||||||
|
@ -2012,10 +2003,10 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
|
||||||
|
|
||||||
if (!(finalX & ofxmask) && !(finalY & ofymask))
|
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)
|
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))
|
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)
|
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)
|
if (Num)
|
||||||
{
|
{
|
||||||
tilesetaddr = 0x06200000 + ((bgcnt & 0x003C) << 12);
|
tilesetaddr = ((bgcnt & 0x003C) << 12);
|
||||||
tilemapaddr = 0x06200000 + ((bgcnt & 0x1F00) << 3);
|
tilemapaddr = ((bgcnt & 0x1F00) << 3);
|
||||||
|
|
||||||
pal = (u16*)&GPU::Palette[0x400];
|
pal = (u16*)&GPU::Palette[0x400];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tilesetaddr = 0x06000000 + ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
|
tilesetaddr = ((DispCnt & 0x07000000) >> 8) + ((bgcnt & 0x003C) << 12);
|
||||||
tilemapaddr = 0x06000000 + ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
|
tilemapaddr = ((DispCnt & 0x38000000) >> 11) + ((bgcnt & 0x1F00) << 3);
|
||||||
|
|
||||||
pal = (u16*)&GPU::Palette[0];
|
pal = (u16*)&GPU::Palette[0];
|
||||||
}
|
}
|
||||||
|
@ -2121,7 +2112,7 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
|
||||||
|
|
||||||
if ((!((finalX|finalY) & overflowmask)))
|
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);
|
if (extpal) curpal = GetBGExtPal(bgnum, curtile>>12);
|
||||||
else curpal = pal;
|
else curpal = pal;
|
||||||
|
@ -2133,10 +2124,10 @@ void GPU2D::DrawBG_Extended(u32 line, u32 bgnum)
|
||||||
if (curtile & 0x0400) tilexoff = 7-tilexoff;
|
if (curtile & 0x0400) tilexoff = 7-tilexoff;
|
||||||
if (curtile & 0x0800) tileyoff = 7-tileyoff;
|
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)
|
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;
|
BGYRefInternal[bgnum-2] += rotD;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool mosaic>
|
template<bool mosaic, GPU2D::DrawPixel drawPixel>
|
||||||
void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
|
void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
|
||||||
{
|
{
|
||||||
u16 bgcnt = BGCnt[2];
|
u16 bgcnt = BGCnt[2];
|
||||||
|
@ -2199,8 +2190,9 @@ void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
|
||||||
rotY -= (BGMosaicY * rotD);
|
rotY -= (BGMosaicY * rotD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Num) tilemapaddr = 0x06200000;
|
u8* bgvram;
|
||||||
else tilemapaddr = 0x06000000;
|
u32 bgvrammask;
|
||||||
|
GetBGVRAM(Num, bgvram, bgvrammask);
|
||||||
|
|
||||||
// 256-color bitmap
|
// 256-color bitmap
|
||||||
|
|
||||||
|
@ -2228,10 +2220,10 @@ void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
|
||||||
|
|
||||||
if (!(finalX & ofxmask) && !(finalY & ofymask))
|
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)
|
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)
|
void GPU2D::InterleaveSprites(u32 prio)
|
||||||
{
|
{
|
||||||
u16* pal = (u16*)&GPU::Palette[Num ? 0x600 : 0x200];
|
u16* pal = (u16*)&GPU::Palette[Num ? 0x600 : 0x200];
|
||||||
|
@ -2297,7 +2290,7 @@ void GPU2D::InterleaveSprites(u32 prio)
|
||||||
else
|
else
|
||||||
color = extpal[pixel & 0xFFF];
|
color = extpal[pixel & 0xFFF];
|
||||||
|
|
||||||
DrawPixel(&BGOBJLine[i], color, pixel & 0xFF000000);
|
drawPixel(&BGOBJLine[i], color, pixel & 0xFF000000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2317,11 +2310,25 @@ void GPU2D::InterleaveSprites(u32 prio)
|
||||||
else
|
else
|
||||||
color = pal[pixel & 0xFF];
|
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, ...) \
|
#define DoDrawSprite(type, ...) \
|
||||||
if (iswin) \
|
if (iswin) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -2346,6 +2353,17 @@ void GPU2D::DrawSprites(u32 line)
|
||||||
OBJMosaicYCount = 0;
|
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;
|
NumSprites = 0;
|
||||||
memset(OBJLine, 0, 256*4);
|
memset(OBJLine, 0, 256*4);
|
||||||
memset(OBJWindow, 0, 256);
|
memset(OBJWindow, 0, 256);
|
||||||
|
@ -2458,6 +2476,10 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
|
||||||
|
|
||||||
u32 ytilefactor;
|
u32 ytilefactor;
|
||||||
|
|
||||||
|
u8* objvram;
|
||||||
|
u32 objvrammask;
|
||||||
|
GetOBJVRAM(Num, objvram, objvrammask);
|
||||||
|
|
||||||
s32 centerX = boundwidth >> 1;
|
s32 centerX = boundwidth >> 1;
|
||||||
s32 centerY = boundheight >> 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));
|
pixelattr |= (0xC0000000 | (alpha << 24));
|
||||||
|
|
||||||
|
u32 pixelsaddr;
|
||||||
if (DispCnt & 0x40)
|
if (DispCnt & 0x40)
|
||||||
{
|
{
|
||||||
if (DispCnt & 0x20)
|
if (DispCnt & 0x20)
|
||||||
|
@ -2512,7 +2535,7 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tilenum <<= (7 + ((DispCnt >> 22) & 0x1));
|
pixelsaddr = tilenum << (7 + ((DispCnt >> 22) & 0x1));
|
||||||
ytilefactor = ((width >> 8) * 2);
|
ytilefactor = ((width >> 8) * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2520,23 +2543,21 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
|
||||||
{
|
{
|
||||||
if (DispCnt & 0x20)
|
if (DispCnt & 0x20)
|
||||||
{
|
{
|
||||||
tilenum = ((tilenum & 0x01F) << 4) + ((tilenum & 0x3E0) << 7);
|
pixelsaddr = ((tilenum & 0x01F) << 4) + ((tilenum & 0x3E0) << 7);
|
||||||
ytilefactor = (256 * 2);
|
ytilefactor = (256 * 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tilenum = ((tilenum & 0x00F) << 4) + ((tilenum & 0x3F0) << 7);
|
pixelsaddr = ((tilenum & 0x00F) << 4) + ((tilenum & 0x3F0) << 7);
|
||||||
ytilefactor = (128 * 2);
|
ytilefactor = (128 * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
|
|
||||||
|
|
||||||
for (; xoff < boundwidth;)
|
for (; xoff < boundwidth;)
|
||||||
{
|
{
|
||||||
if ((u32)rotX < width && (u32)rotY < height)
|
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)
|
if (color & 0x8000)
|
||||||
{
|
{
|
||||||
|
@ -2561,9 +2582,10 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
u32 pixelsaddr = tilenum;
|
||||||
if (DispCnt & 0x10)
|
if (DispCnt & 0x10)
|
||||||
{
|
{
|
||||||
tilenum <<= ((DispCnt >> 20) & 0x3);
|
pixelsaddr <<= ((DispCnt >> 20) & 0x3);
|
||||||
ytilefactor = (width >> 11) << ((attrib[0] & 0x2000) ? 1:0);
|
ytilefactor = (width >> 11) << ((attrib[0] & 0x2000) ? 1:0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2574,12 +2596,12 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
|
||||||
if (spritemode == 1) pixelattr |= 0x80000000;
|
if (spritemode == 1) pixelattr |= 0x80000000;
|
||||||
else pixelattr |= 0x10000000;
|
else pixelattr |= 0x10000000;
|
||||||
|
|
||||||
|
ytilefactor <<= 5;
|
||||||
|
pixelsaddr <<= 5;
|
||||||
|
|
||||||
if (attrib[0] & 0x2000)
|
if (attrib[0] & 0x2000)
|
||||||
{
|
{
|
||||||
// 256-color
|
// 256-color
|
||||||
tilenum <<= 5;
|
|
||||||
ytilefactor <<= 5;
|
|
||||||
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
|
|
||||||
|
|
||||||
if (!window)
|
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)
|
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)
|
if (color)
|
||||||
{
|
{
|
||||||
|
@ -2619,10 +2641,6 @@ void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 wi
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 16-color
|
// 16-color
|
||||||
tilenum <<= 5;
|
|
||||||
ytilefactor <<= 5;
|
|
||||||
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
|
|
||||||
|
|
||||||
if (!window)
|
if (!window)
|
||||||
{
|
{
|
||||||
pixelattr |= 0x1000;
|
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)
|
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)
|
if (rotX & 0x100)
|
||||||
color >>= 4;
|
color >>= 4;
|
||||||
else
|
else
|
||||||
|
@ -2681,6 +2699,10 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
|
||||||
pixelattr |= 0x100000;
|
pixelattr |= 0x100000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8* objvram;
|
||||||
|
u32 objvrammask;
|
||||||
|
GetOBJVRAM(Num, objvram, objvrammask);
|
||||||
|
|
||||||
// yflip
|
// yflip
|
||||||
if (attrib[1] & 0x2000)
|
if (attrib[1] & 0x2000)
|
||||||
ypos = height-1 - ypos;
|
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));
|
pixelattr |= (0xC0000000 | (alpha << 24));
|
||||||
|
|
||||||
|
u32 pixelsaddr = tilenum;
|
||||||
if (DispCnt & 0x40)
|
if (DispCnt & 0x40)
|
||||||
{
|
{
|
||||||
if (DispCnt & 0x20)
|
if (DispCnt & 0x20)
|
||||||
|
@ -2722,25 +2745,24 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tilenum <<= (7 + ((DispCnt >> 22) & 0x1));
|
pixelsaddr <<= (7 + ((DispCnt >> 22) & 0x1));
|
||||||
tilenum += (ypos * width * 2);
|
pixelsaddr += (ypos * width * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (DispCnt & 0x20)
|
if (DispCnt & 0x20)
|
||||||
{
|
{
|
||||||
tilenum = ((tilenum & 0x01F) << 4) + ((tilenum & 0x3E0) << 7);
|
pixelsaddr = ((tilenum & 0x01F) << 4) + ((tilenum & 0x3E0) << 7);
|
||||||
tilenum += (ypos * 256 * 2);
|
pixelsaddr += (ypos * 256 * 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tilenum = ((tilenum & 0x00F) << 4) + ((tilenum & 0x3F0) << 7);
|
pixelsaddr = ((tilenum & 0x00F) << 4) + ((tilenum & 0x3F0) << 7);
|
||||||
tilenum += (ypos * 128 * 2);
|
pixelsaddr += (ypos * 128 * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
|
|
||||||
s32 pixelstride;
|
s32 pixelstride;
|
||||||
|
|
||||||
if (attrib[1] & 0x1000) // xflip
|
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;)
|
for (; xoff < xend;)
|
||||||
{
|
{
|
||||||
color = GPU::ReadVRAM_OBJ<u16>(pixelsaddr);
|
color = *(u16*)&objvram[pixelsaddr & objvrammask];
|
||||||
|
|
||||||
pixelsaddr += pixelstride;
|
pixelsaddr += pixelstride;
|
||||||
|
|
||||||
|
@ -2781,14 +2803,15 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
u32 pixelsaddr = tilenum;
|
||||||
if (DispCnt & 0x10)
|
if (DispCnt & 0x10)
|
||||||
{
|
{
|
||||||
tilenum <<= ((DispCnt >> 20) & 0x3);
|
pixelsaddr <<= ((DispCnt >> 20) & 0x3);
|
||||||
tilenum += ((ypos >> 3) * (width >> 3)) << ((attrib[0] & 0x2000) ? 1:0);
|
pixelsaddr += ((ypos >> 3) * (width >> 3)) << ((attrib[0] & 0x2000) ? 1:0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tilenum += ((ypos >> 3) * 0x20);
|
pixelsaddr += ((ypos >> 3) * 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spritemode == 1) pixelattr |= 0x80000000;
|
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)
|
if (attrib[0] & 0x2000)
|
||||||
{
|
{
|
||||||
// 256-color
|
// 256-color
|
||||||
tilenum <<= 5;
|
pixelsaddr <<= 5;
|
||||||
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
|
|
||||||
pixelsaddr += ((ypos & 0x7) << 3);
|
pixelsaddr += ((ypos & 0x7) << 3);
|
||||||
s32 pixelstride;
|
s32 pixelstride;
|
||||||
|
|
||||||
|
@ -2827,7 +2849,7 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
|
||||||
|
|
||||||
for (; xoff < xend;)
|
for (; xoff < xend;)
|
||||||
{
|
{
|
||||||
color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr);
|
color = objvram[pixelsaddr];
|
||||||
|
|
||||||
pixelsaddr += pixelstride;
|
pixelsaddr += pixelstride;
|
||||||
|
|
||||||
|
@ -2853,8 +2875,7 @@ void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 16-color
|
// 16-color
|
||||||
tilenum <<= 5;
|
pixelsaddr <<= 5;
|
||||||
u32 pixelsaddr = (Num ? 0x06600000 : 0x06400000) + tilenum;
|
|
||||||
pixelsaddr += ((ypos & 0x7) << 2);
|
pixelsaddr += ((ypos & 0x7) << 2);
|
||||||
s32 pixelstride;
|
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 (attrib[1] & 0x1000)
|
||||||
{
|
{
|
||||||
if (xoff & 0x1) { color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) & 0x0F; pixelsaddr--; }
|
if (xoff & 0x1) { color = objvram[pixelsaddr & objvrammask] & 0x0F; pixelsaddr--; }
|
||||||
else color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) >> 4;
|
else color = objvram[pixelsaddr & objvrammask] >> 4;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (xoff & 0x1) { color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) >> 4; pixelsaddr++; }
|
if (xoff & 0x1) { color = objvram[pixelsaddr & objvrammask] >> 4; pixelsaddr++; }
|
||||||
else color = GPU::ReadVRAM_OBJ<u8>(pixelsaddr) & 0x0F;
|
else color = objvram[pixelsaddr & objvrammask] & 0x0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (color)
|
if (color)
|
||||||
|
|
18
src/GPU2D.h
18
src/GPU2D.h
|
@ -59,9 +59,6 @@ public:
|
||||||
|
|
||||||
void CheckWindows(u32 line);
|
void CheckWindows(u32 line);
|
||||||
|
|
||||||
void BGExtPalDirty(u32 base);
|
|
||||||
void OBJExtPalDirty();
|
|
||||||
|
|
||||||
u16* GetBGExtPal(u32 slot, u32 pal);
|
u16* GetBGExtPal(u32 slot, u32 pal);
|
||||||
u16* GetOBJExtPal();
|
u16* GetOBJExtPal();
|
||||||
|
|
||||||
|
@ -128,9 +125,6 @@ private:
|
||||||
u16 MasterBrightness;
|
u16 MasterBrightness;
|
||||||
|
|
||||||
u16 BGExtPalCache[4][16*256];
|
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 ColorBlend4(u32 val1, u32 val2, u32 eva, u32 evb);
|
||||||
u32 ColorBlend5(u32 val1, u32 val2);
|
u32 ColorBlend5(u32 val1, u32 val2);
|
||||||
|
@ -147,15 +141,17 @@ private:
|
||||||
|
|
||||||
static void DrawPixel_Normal(u32* dst, u16 color, u32 flag);
|
static void DrawPixel_Normal(u32* dst, u16 color, u32 flag);
|
||||||
static void DrawPixel_Accel(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();
|
void DrawBG_3D();
|
||||||
template<bool mosaic> void DrawBG_Text(u32 line, u32 bgnum);
|
template<bool mosaic, DrawPixel drawPixel> void DrawBG_Text(u32 line, u32 bgnum);
|
||||||
template<bool mosaic> void DrawBG_Affine(u32 line, u32 bgnum);
|
template<bool mosaic, DrawPixel drawPixel> void DrawBG_Affine(u32 line, u32 bgnum);
|
||||||
template<bool mosaic> void DrawBG_Extended(u32 line, u32 bgnum);
|
template<bool mosaic, DrawPixel drawPixel> void DrawBG_Extended(u32 line, u32 bgnum);
|
||||||
template<bool mosaic> void DrawBG_Large(u32 line);
|
template<bool mosaic, DrawPixel drawPixel> void DrawBG_Large(u32 line);
|
||||||
|
|
||||||
void ApplySpriteMosaicX();
|
void ApplySpriteMosaicX();
|
||||||
|
template<DrawPixel drawPixel>
|
||||||
void InterleaveSprites(u32 prio);
|
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_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);
|
template<bool window> void DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos);
|
||||||
|
|
|
@ -179,6 +179,8 @@ u8 RenderFogDensityTable[34];
|
||||||
|
|
||||||
u32 RenderClearAttr1, RenderClearAttr2;
|
u32 RenderClearAttr1, RenderClearAttr2;
|
||||||
|
|
||||||
|
bool RenderFrameIdentical;
|
||||||
|
|
||||||
u32 ZeroDotWLimit;
|
u32 ZeroDotWLimit;
|
||||||
|
|
||||||
u32 GXStat;
|
u32 GXStat;
|
||||||
|
@ -2491,6 +2493,19 @@ void VBlank()
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderNumPolygons = NumPolygons;
|
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;
|
RenderDispCnt = DispCnt;
|
||||||
|
|
|
@ -87,6 +87,8 @@ extern u8 RenderFogDensityTable[34];
|
||||||
|
|
||||||
extern u32 RenderClearAttr1, RenderClearAttr2;
|
extern u32 RenderClearAttr1, RenderClearAttr2;
|
||||||
|
|
||||||
|
extern bool RenderFrameIdentical;
|
||||||
|
|
||||||
extern std::array<Polygon*,2048> RenderPolygonRAM;
|
extern std::array<Polygon*,2048> RenderPolygonRAM;
|
||||||
extern u32 RenderNumPolygons;
|
extern u32 RenderNumPolygons;
|
||||||
|
|
||||||
|
|
|
@ -74,11 +74,11 @@ typedef struct
|
||||||
Polygon* PolyData;
|
Polygon* PolyData;
|
||||||
|
|
||||||
u32 NumIndices;
|
u32 NumIndices;
|
||||||
u16* Indices;
|
u32 IndicesOffset;
|
||||||
GLuint PrimType;
|
GLuint PrimType;
|
||||||
|
|
||||||
u32 NumEdgeIndices;
|
u32 NumEdgeIndices;
|
||||||
u16* EdgeIndices;
|
u32 EdgeIndicesOffset;
|
||||||
|
|
||||||
u32 RenderKey;
|
u32 RenderKey;
|
||||||
|
|
||||||
|
@ -107,7 +107,11 @@ u32 VertexBuffer[10240 * 7];
|
||||||
u32 NumVertices;
|
u32 NumVertices;
|
||||||
|
|
||||||
GLuint VertexArrayID;
|
GLuint VertexArrayID;
|
||||||
|
GLuint IndexBufferID;
|
||||||
u16 IndexBuffer[2048 * 40];
|
u16 IndexBuffer[2048 * 40];
|
||||||
|
u32 NumIndices, NumEdgeIndices;
|
||||||
|
|
||||||
|
const u32 EdgeIndicesOffset = 2048 * 30;
|
||||||
|
|
||||||
GLuint TexMemID;
|
GLuint TexMemID;
|
||||||
GLuint TexPalMemID;
|
GLuint TexPalMemID;
|
||||||
|
@ -320,6 +324,9 @@ bool Init()
|
||||||
glEnableVertexAttribArray(3); // attrib
|
glEnableVertexAttribArray(3); // attrib
|
||||||
glVertexAttribIPointer(3, 3, GL_UNSIGNED_INT, 7*4, (void*)(4*4));
|
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]);
|
glGenFramebuffers(4, &FramebufferID[0]);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[0]);
|
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[0]);
|
||||||
|
@ -563,15 +570,15 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
|
||||||
u32* vptr = &VertexBuffer[0];
|
u32* vptr = &VertexBuffer[0];
|
||||||
u32 vidx = 0;
|
u32 vidx = 0;
|
||||||
|
|
||||||
u16* iptr = &IndexBuffer[0];
|
u32 iidx = 0;
|
||||||
u16* eiptr = &IndexBuffer[2048*30];
|
u32 eidx = EdgeIndicesOffset;
|
||||||
|
|
||||||
for (int i = 0; i < npolys; i++)
|
for (int i = 0; i < npolys; i++)
|
||||||
{
|
{
|
||||||
RendererPolygon* rp = &polygons[i];
|
RendererPolygon* rp = &polygons[i];
|
||||||
Polygon* poly = rp->PolyData;
|
Polygon* poly = rp->PolyData;
|
||||||
|
|
||||||
rp->Indices = iptr;
|
rp->IndicesOffset = iidx;
|
||||||
rp->NumIndices = 0;
|
rp->NumIndices = 0;
|
||||||
|
|
||||||
u32 vidx_first = vidx;
|
u32 vidx_first = vidx;
|
||||||
|
@ -606,7 +613,7 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
|
||||||
|
|
||||||
vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
|
vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
|
||||||
|
|
||||||
*iptr++ = vidx;
|
IndexBuffer[iidx++] = vidx;
|
||||||
rp->NumIndices++;
|
rp->NumIndices++;
|
||||||
|
|
||||||
vidx++;
|
vidx++;
|
||||||
|
@ -627,9 +634,9 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
|
||||||
}
|
}
|
||||||
|
|
||||||
// build a triangle
|
// build a triangle
|
||||||
*iptr++ = vidx_first;
|
IndexBuffer[iidx++] = vidx_first;
|
||||||
*iptr++ = vidx - 2;
|
IndexBuffer[iidx++] = vidx - 2;
|
||||||
*iptr++ = vidx - 1;
|
IndexBuffer[iidx++] = vidx - 1;
|
||||||
rp->NumIndices += 3;
|
rp->NumIndices += 3;
|
||||||
}
|
}
|
||||||
else // quad, pentagon, etc
|
else // quad, pentagon, etc
|
||||||
|
@ -649,9 +656,9 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
|
||||||
if (j >= 2)
|
if (j >= 2)
|
||||||
{
|
{
|
||||||
// build a triangle
|
// build a triangle
|
||||||
*iptr++ = vidx_first;
|
IndexBuffer[iidx++] = vidx_first;
|
||||||
*iptr++ = vidx - 1;
|
IndexBuffer[iidx++] = vidx - 1;
|
||||||
*iptr++ = vidx;
|
IndexBuffer[iidx++] = vidx;
|
||||||
rp->NumIndices += 3;
|
rp->NumIndices += 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,46 +750,48 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
|
||||||
if (j >= 1)
|
if (j >= 1)
|
||||||
{
|
{
|
||||||
// build a triangle
|
// build a triangle
|
||||||
*iptr++ = vidx_first;
|
IndexBuffer[iidx++] = vidx_first;
|
||||||
*iptr++ = vidx - 1;
|
IndexBuffer[iidx++] = vidx - 1;
|
||||||
*iptr++ = vidx;
|
IndexBuffer[iidx++] = vidx;
|
||||||
rp->NumIndices += 3;
|
rp->NumIndices += 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
vidx++;
|
vidx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*iptr++ = vidx_first;
|
IndexBuffer[iidx++] = vidx_first;
|
||||||
*iptr++ = vidx - 1;
|
IndexBuffer[iidx++] = vidx - 1;
|
||||||
*iptr++ = vidx_first + 1;
|
IndexBuffer[iidx++] = vidx_first + 1;
|
||||||
rp->NumIndices += 3;
|
rp->NumIndices += 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rp->EdgeIndices = eiptr;
|
rp->EdgeIndicesOffset = eidx;
|
||||||
rp->NumEdgeIndices = 0;
|
rp->NumEdgeIndices = 0;
|
||||||
|
|
||||||
u32 vidx_cur = vidx_first;
|
u32 vidx_cur = vidx_first;
|
||||||
for (int j = 1; j < poly->NumVertices; j++)
|
for (int j = 1; j < poly->NumVertices; j++)
|
||||||
{
|
{
|
||||||
*eiptr++ = vidx_cur;
|
IndexBuffer[eidx++] = vidx_cur;
|
||||||
*eiptr++ = vidx_cur + 1;
|
IndexBuffer[eidx++] = vidx_cur + 1;
|
||||||
vidx_cur++;
|
vidx_cur++;
|
||||||
rp->NumEdgeIndices += 2;
|
rp->NumEdgeIndices += 2;
|
||||||
}
|
}
|
||||||
*eiptr++ = vidx_cur;
|
IndexBuffer[eidx++] = vidx_cur;
|
||||||
*eiptr++ = vidx_first;
|
IndexBuffer[eidx++] = vidx_first;
|
||||||
rp->NumEdgeIndices += 2;
|
rp->NumEdgeIndices += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
NumVertices = vidx;
|
NumVertices = vidx;
|
||||||
|
NumIndices = iidx;
|
||||||
|
NumEdgeIndices = eidx - EdgeIndicesOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderSinglePolygon(int i)
|
void RenderSinglePolygon(int i)
|
||||||
{
|
{
|
||||||
RendererPolygon* rp = &PolygonList[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)
|
int RenderPolygonBatch(int i)
|
||||||
|
@ -803,7 +812,7 @@ int RenderPolygonBatch(int i)
|
||||||
numindices += cur_rp->NumIndices;
|
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;
|
return numpolys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,7 +832,7 @@ int RenderPolygonEdgeBatch(int i)
|
||||||
numindices += cur_rp->NumEdgeIndices;
|
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;
|
return numpolys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1320,6 +1329,11 @@ void RenderFrame()
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
|
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, NumVertices*7*4, VertexBuffer);
|
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);
|
RenderSceneChunk(0, 192);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,15 +58,17 @@ bool PrevIsShadowMask;
|
||||||
|
|
||||||
bool Enabled;
|
bool Enabled;
|
||||||
|
|
||||||
|
bool FrameIdentical;
|
||||||
|
|
||||||
// threading
|
// threading
|
||||||
|
|
||||||
bool Threaded;
|
bool Threaded;
|
||||||
void* RenderThread;
|
Platform::Thread* RenderThread;
|
||||||
bool RenderThreadRunning;
|
bool RenderThreadRunning;
|
||||||
bool RenderThreadRendering;
|
bool RenderThreadRendering;
|
||||||
void* Sema_RenderStart;
|
Platform::Semaphore* Sema_RenderStart;
|
||||||
void* Sema_RenderDone;
|
Platform::Semaphore* Sema_RenderDone;
|
||||||
void* Sema_ScanlineCount;
|
Platform::Semaphore* Sema_ScanlineCount;
|
||||||
|
|
||||||
void RenderThreadFunc();
|
void RenderThreadFunc();
|
||||||
|
|
||||||
|
@ -550,6 +552,16 @@ typedef struct
|
||||||
|
|
||||||
RendererPolygon PolygonList[2048];
|
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)
|
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
|
case 1: // A3I5
|
||||||
{
|
{
|
||||||
vramaddr += ((t * width) + s);
|
vramaddr += ((t * width) + s);
|
||||||
u8 pixel = GPU::ReadVRAM_Texture<u8>(vramaddr);
|
u8 pixel = ReadVRAM_Texture<u8>(vramaddr);
|
||||||
|
|
||||||
texpal <<= 4;
|
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);
|
*alpha = ((pixel >> 3) & 0x1C) + (pixel >> 6);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -617,12 +629,12 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
|
||||||
case 2: // 4-color
|
case 2: // 4-color
|
||||||
{
|
{
|
||||||
vramaddr += (((t * width) + s) >> 2);
|
vramaddr += (((t * width) + s) >> 2);
|
||||||
u8 pixel = GPU::ReadVRAM_Texture<u8>(vramaddr);
|
u8 pixel = ReadVRAM_Texture<u8>(vramaddr);
|
||||||
pixel >>= ((s & 0x3) << 1);
|
pixel >>= ((s & 0x3) << 1);
|
||||||
pixel &= 0x3;
|
pixel &= 0x3;
|
||||||
|
|
||||||
texpal <<= 3;
|
texpal <<= 3;
|
||||||
*color = GPU::ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
|
*color = ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
|
||||||
*alpha = (pixel==0) ? alpha0 : 31;
|
*alpha = (pixel==0) ? alpha0 : 31;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -630,12 +642,12 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
|
||||||
case 3: // 16-color
|
case 3: // 16-color
|
||||||
{
|
{
|
||||||
vramaddr += (((t * width) + s) >> 1);
|
vramaddr += (((t * width) + s) >> 1);
|
||||||
u8 pixel = GPU::ReadVRAM_Texture<u8>(vramaddr);
|
u8 pixel = ReadVRAM_Texture<u8>(vramaddr);
|
||||||
if (s & 0x1) pixel >>= 4;
|
if (s & 0x1) pixel >>= 4;
|
||||||
else pixel &= 0xF;
|
else pixel &= 0xF;
|
||||||
|
|
||||||
texpal <<= 4;
|
texpal <<= 4;
|
||||||
*color = GPU::ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
|
*color = ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
|
||||||
*alpha = (pixel==0) ? alpha0 : 31;
|
*alpha = (pixel==0) ? alpha0 : 31;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -643,10 +655,10 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
|
||||||
case 4: // 256-color
|
case 4: // 256-color
|
||||||
{
|
{
|
||||||
vramaddr += ((t * width) + s);
|
vramaddr += ((t * width) + s);
|
||||||
u8 pixel = GPU::ReadVRAM_Texture<u8>(vramaddr);
|
u8 pixel = ReadVRAM_Texture<u8>(vramaddr);
|
||||||
|
|
||||||
texpal <<= 4;
|
texpal <<= 4;
|
||||||
*color = GPU::ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
|
*color = ReadVRAM_TexPal<u16>(texpal + (pixel<<1));
|
||||||
*alpha = (pixel==0) ? alpha0 : 31;
|
*alpha = (pixel==0) ? alpha0 : 31;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -660,30 +672,30 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
|
||||||
if (vramaddr >= 0x40000)
|
if (vramaddr >= 0x40000)
|
||||||
slot1addr += 0x10000;
|
slot1addr += 0x10000;
|
||||||
|
|
||||||
u8 val = GPU::ReadVRAM_Texture<u8>(vramaddr);
|
u8 val = ReadVRAM_Texture<u8>(vramaddr);
|
||||||
val >>= (2 * (s & 0x3));
|
val >>= (2 * (s & 0x3));
|
||||||
|
|
||||||
u16 palinfo = GPU::ReadVRAM_Texture<u16>(slot1addr);
|
u16 palinfo = ReadVRAM_Texture<u16>(slot1addr);
|
||||||
u32 paloffset = (palinfo & 0x3FFF) << 2;
|
u32 paloffset = (palinfo & 0x3FFF) << 2;
|
||||||
texpal <<= 4;
|
texpal <<= 4;
|
||||||
|
|
||||||
switch (val & 0x3)
|
switch (val & 0x3)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
*color = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset);
|
*color = ReadVRAM_TexPal<u16>(texpal + paloffset);
|
||||||
*alpha = 31;
|
*alpha = 31;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
*color = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
|
*color = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
|
||||||
*alpha = 31;
|
*alpha = 31;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
if ((palinfo >> 14) == 1)
|
if ((palinfo >> 14) == 1)
|
||||||
{
|
{
|
||||||
u16 color0 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset);
|
u16 color0 = ReadVRAM_TexPal<u16>(texpal + paloffset);
|
||||||
u16 color1 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
|
u16 color1 = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
|
||||||
|
|
||||||
u32 r0 = color0 & 0x001F;
|
u32 r0 = color0 & 0x001F;
|
||||||
u32 g0 = color0 & 0x03E0;
|
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)
|
else if ((palinfo >> 14) == 3)
|
||||||
{
|
{
|
||||||
u16 color0 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset);
|
u16 color0 = ReadVRAM_TexPal<u16>(texpal + paloffset);
|
||||||
u16 color1 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
|
u16 color1 = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
|
||||||
|
|
||||||
u32 r0 = color0 & 0x001F;
|
u32 r0 = color0 & 0x001F;
|
||||||
u32 g0 = color0 & 0x03E0;
|
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;
|
*color = r | g | b;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*color = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 4);
|
*color = ReadVRAM_TexPal<u16>(texpal + paloffset + 4);
|
||||||
*alpha = 31;
|
*alpha = 31;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
if ((palinfo >> 14) == 2)
|
if ((palinfo >> 14) == 2)
|
||||||
{
|
{
|
||||||
*color = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 6);
|
*color = ReadVRAM_TexPal<u16>(texpal + paloffset + 6);
|
||||||
*alpha = 31;
|
*alpha = 31;
|
||||||
}
|
}
|
||||||
else if ((palinfo >> 14) == 3)
|
else if ((palinfo >> 14) == 3)
|
||||||
{
|
{
|
||||||
u16 color0 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset);
|
u16 color0 = ReadVRAM_TexPal<u16>(texpal + paloffset);
|
||||||
u16 color1 = GPU::ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
|
u16 color1 = ReadVRAM_TexPal<u16>(texpal + paloffset + 2);
|
||||||
|
|
||||||
u32 r0 = color0 & 0x001F;
|
u32 r0 = color0 & 0x001F;
|
||||||
u32 g0 = color0 & 0x03E0;
|
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
|
case 6: // A5I3
|
||||||
{
|
{
|
||||||
vramaddr += ((t * width) + s);
|
vramaddr += ((t * width) + s);
|
||||||
u8 pixel = GPU::ReadVRAM_Texture<u8>(vramaddr);
|
u8 pixel = ReadVRAM_Texture<u8>(vramaddr);
|
||||||
|
|
||||||
texpal <<= 4;
|
texpal <<= 4;
|
||||||
*color = GPU::ReadVRAM_TexPal<u16>(texpal + ((pixel&0x7)<<1));
|
*color = ReadVRAM_TexPal<u16>(texpal + ((pixel&0x7)<<1));
|
||||||
*alpha = (pixel >> 3);
|
*alpha = (pixel >> 3);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -770,7 +782,7 @@ void TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha
|
||||||
case 7: // direct color
|
case 7: // direct color
|
||||||
{
|
{
|
||||||
vramaddr += (((t * width) + s) << 1);
|
vramaddr += (((t * width) + s) << 1);
|
||||||
*color = GPU::ReadVRAM_Texture<u16>(vramaddr);
|
*color = ReadVRAM_Texture<u16>(vramaddr);
|
||||||
*alpha = (*color & 0x8000) ? 31 : 0;
|
*alpha = (*color & 0x8000) ? 31 : 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2007,8 +2019,8 @@ void ClearBuffers()
|
||||||
{
|
{
|
||||||
for (int x = 0; x < 256; x++)
|
for (int x = 0; x < 256; x++)
|
||||||
{
|
{
|
||||||
u16 val2 = GPU::ReadVRAM_Texture<u16>(0x40000 + (yoff << 9) + (xoff << 1));
|
u16 val2 = ReadVRAM_Texture<u16>(0x40000 + (yoff << 9) + (xoff << 1));
|
||||||
u16 val3 = GPU::ReadVRAM_Texture<u16>(0x60000 + (yoff << 9) + (xoff << 1));
|
u16 val3 = ReadVRAM_Texture<u16>(0x60000 + (yoff << 9) + (xoff << 1));
|
||||||
|
|
||||||
// TODO: confirm color conversion
|
// TODO: confirm color conversion
|
||||||
u32 r = (val2 << 1) & 0x3E; if (r) r++;
|
u32 r = (val2 << 1) & 0x3E; if (r) r++;
|
||||||
|
@ -2088,11 +2100,19 @@ void VCount144()
|
||||||
|
|
||||||
void RenderFrame()
|
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)
|
if (RenderThreadRunning)
|
||||||
{
|
{
|
||||||
Platform::Semaphore_Post(Sema_RenderStart);
|
Platform::Semaphore_Post(Sema_RenderStart);
|
||||||
}
|
}
|
||||||
else
|
else if (!FrameIdentical)
|
||||||
{
|
{
|
||||||
ClearBuffers();
|
ClearBuffers();
|
||||||
RenderPolygons(false, &RenderPolygonRAM[0], RenderNumPolygons);
|
RenderPolygons(false, &RenderPolygonRAM[0], RenderNumPolygons);
|
||||||
|
@ -2107,8 +2127,15 @@ void RenderThreadFunc()
|
||||||
if (!RenderThreadRunning) return;
|
if (!RenderThreadRunning) return;
|
||||||
|
|
||||||
RenderThreadRendering = true;
|
RenderThreadRendering = true;
|
||||||
ClearBuffers();
|
if (FrameIdentical)
|
||||||
RenderPolygons(true, &RenderPolygonRAM[0], RenderNumPolygons);
|
{
|
||||||
|
Platform::Semaphore_Post(Sema_ScanlineCount, 192);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClearBuffers();
|
||||||
|
RenderPolygons(true, &RenderPolygonRAM[0], RenderNumPolygons);
|
||||||
|
}
|
||||||
|
|
||||||
Platform::Semaphore_Post(Sema_RenderDone);
|
Platform::Semaphore_Post(Sema_RenderDone);
|
||||||
RenderThreadRendering = false;
|
RenderThreadRendering = false;
|
||||||
|
|
51
src/NDS.cpp
51
src/NDS.cpp
|
@ -210,13 +210,13 @@ bool Init()
|
||||||
|
|
||||||
void DeInit()
|
void DeInit()
|
||||||
{
|
{
|
||||||
delete ARM9;
|
|
||||||
delete ARM7;
|
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
ARMJIT::DeInit();
|
ARMJIT::DeInit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
delete ARM9;
|
||||||
|
delete ARM7;
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
delete DMAs[i];
|
delete DMAs[i];
|
||||||
|
|
||||||
|
@ -908,7 +908,7 @@ void RunSystem(u64 timestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool EnableJIT>
|
template <bool EnableJIT, int ConsoleType>
|
||||||
u32 RunFrame()
|
u32 RunFrame()
|
||||||
{
|
{
|
||||||
FrameStartTimestamp = SysTimestamp;
|
FrameStartTimestamp = SysTimestamp;
|
||||||
|
@ -934,10 +934,10 @@ u32 RunFrame()
|
||||||
}
|
}
|
||||||
else if (CPUStop & 0x0FFF)
|
else if (CPUStop & 0x0FFF)
|
||||||
{
|
{
|
||||||
DMAs[0]->Run();
|
DMAs[0]->Run<ConsoleType>();
|
||||||
if (!(CPUStop & 0x80000000)) DMAs[1]->Run();
|
if (!(CPUStop & 0x80000000)) DMAs[1]->Run<ConsoleType>();
|
||||||
if (!(CPUStop & 0x80000000)) DMAs[2]->Run();
|
if (!(CPUStop & 0x80000000)) DMAs[2]->Run<ConsoleType>();
|
||||||
if (!(CPUStop & 0x80000000)) DMAs[3]->Run();
|
if (!(CPUStop & 0x80000000)) DMAs[3]->Run<ConsoleType>();
|
||||||
if (ConsoleType == 1) DSi::RunNDMAs(0);
|
if (ConsoleType == 1) DSi::RunNDMAs(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -962,10 +962,10 @@ u32 RunFrame()
|
||||||
|
|
||||||
if (CPUStop & 0x0FFF0000)
|
if (CPUStop & 0x0FFF0000)
|
||||||
{
|
{
|
||||||
DMAs[4]->Run();
|
DMAs[4]->Run<ConsoleType>();
|
||||||
DMAs[5]->Run();
|
DMAs[5]->Run<ConsoleType>();
|
||||||
DMAs[6]->Run();
|
DMAs[6]->Run<ConsoleType>();
|
||||||
DMAs[7]->Run();
|
DMAs[7]->Run<ConsoleType>();
|
||||||
if (ConsoleType == 1) DSi::RunNDMAs(1);
|
if (ConsoleType == 1) DSi::RunNDMAs(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -999,6 +999,9 @@ u32 RunFrame()
|
||||||
ARM7Timestamp-SysTimestamp,
|
ARM7Timestamp-SysTimestamp,
|
||||||
GPU3D::Timestamp-SysTimestamp);
|
GPU3D::Timestamp-SysTimestamp);
|
||||||
#endif
|
#endif
|
||||||
|
SPU::TransferOutput();
|
||||||
|
|
||||||
|
NDSCart::FlushSRAMFile();
|
||||||
|
|
||||||
NumFrames++;
|
NumFrames++;
|
||||||
|
|
||||||
|
@ -1009,10 +1012,14 @@ u32 RunFrame()
|
||||||
{
|
{
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
if (Config::JIT_Enable)
|
if (Config::JIT_Enable)
|
||||||
return RunFrame<true>();
|
return NDS::ConsoleType == 1
|
||||||
|
? RunFrame<true, 1>()
|
||||||
|
: RunFrame<true, 0>();
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
return RunFrame<false>();
|
return NDS::ConsoleType == 1
|
||||||
|
? RunFrame<false, 1>()
|
||||||
|
: RunFrame<false, 0>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reschedule(u64 target)
|
void Reschedule(u64 target)
|
||||||
|
@ -3130,6 +3137,10 @@ void ARM9IOWrite8(u32 addr, u8 val)
|
||||||
NDSCart::WriteSPIData(val);
|
NDSCart::WriteSPIData(val);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case 0x04000188:
|
||||||
|
ARM9IOWrite32(addr, val | (val << 8) | (val << 16) | (val << 24));
|
||||||
|
return;
|
||||||
|
|
||||||
case 0x040001A8: NDSCart::ROMCommand[0] = val; return;
|
case 0x040001A8: NDSCart::ROMCommand[0] = val; return;
|
||||||
case 0x040001A9: NDSCart::ROMCommand[1] = val; return;
|
case 0x040001A9: NDSCart::ROMCommand[1] = val; return;
|
||||||
case 0x040001AA: NDSCart::ROMCommand[2] = val; return;
|
case 0x040001AA: NDSCart::ROMCommand[2] = val; return;
|
||||||
|
@ -3246,6 +3257,10 @@ void ARM9IOWrite16(u32 addr, u16 val)
|
||||||
IPCFIFOCnt9 = val & 0x8404;
|
IPCFIFOCnt9 = val & 0x8404;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case 0x04000188:
|
||||||
|
ARM9IOWrite32(addr, val | (val << 16));
|
||||||
|
return;
|
||||||
|
|
||||||
case 0x040001A0:
|
case 0x040001A0:
|
||||||
if (!(ExMemCnt[0] & (1<<11))) NDSCart::WriteSPICnt(val);
|
if (!(ExMemCnt[0] & (1<<11))) NDSCart::WriteSPICnt(val);
|
||||||
return;
|
return;
|
||||||
|
@ -3733,6 +3748,10 @@ void ARM7IOWrite8(u32 addr, u8 val)
|
||||||
|
|
||||||
case 0x04000138: RTC::Write(val, true); return;
|
case 0x04000138: RTC::Write(val, true); return;
|
||||||
|
|
||||||
|
case 0x04000188:
|
||||||
|
ARM7IOWrite32(addr, val | (val << 8) | (val << 16) | (val << 24));
|
||||||
|
return;
|
||||||
|
|
||||||
case 0x040001A0:
|
case 0x040001A0:
|
||||||
if (ExMemCnt[0] & (1<<11))
|
if (ExMemCnt[0] & (1<<11))
|
||||||
{
|
{
|
||||||
|
@ -3841,6 +3860,10 @@ void ARM7IOWrite16(u32 addr, u16 val)
|
||||||
IPCFIFOCnt7 = val & 0x8404;
|
IPCFIFOCnt7 = val & 0x8404;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case 0x04000188:
|
||||||
|
ARM7IOWrite32(addr, val | (val << 16));
|
||||||
|
return;
|
||||||
|
|
||||||
case 0x040001A0:
|
case 0x040001A0:
|
||||||
if (ExMemCnt[0] & (1<<11))
|
if (ExMemCnt[0] & (1<<11))
|
||||||
NDSCart::WriteSPICnt(val);
|
NDSCart::WriteSPICnt(val);
|
||||||
|
|
|
@ -37,6 +37,7 @@ u8* SRAM;
|
||||||
u32 SRAMLength;
|
u32 SRAMLength;
|
||||||
|
|
||||||
char SRAMPath[1024];
|
char SRAMPath[1024];
|
||||||
|
bool SRAMFileDirty;
|
||||||
|
|
||||||
void (*WriteFunc)(u8 val, bool islast);
|
void (*WriteFunc)(u8 val, bool islast);
|
||||||
|
|
||||||
|
@ -445,14 +446,21 @@ void Write(u8 val, u32 hold)
|
||||||
break;
|
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");
|
fwrite(SRAM, SRAMLength, 1, f);
|
||||||
if (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);
|
NDSCart_SRAM::RelocateSave(path, write);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FlushSRAMFile()
|
||||||
|
{
|
||||||
|
NDSCart_SRAM::FlushSRAMFile();
|
||||||
|
}
|
||||||
|
|
||||||
int ImportSRAM(const u8* data, u32 length)
|
int ImportSRAM(const u8* data, u32 length)
|
||||||
{
|
{
|
||||||
memcpy(NDSCart_SRAM::SRAM, data, std::min(length, NDSCart_SRAM::SRAMLength));
|
memcpy(NDSCart_SRAM::SRAM, data, std::min(length, NDSCart_SRAM::SRAMLength));
|
||||||
|
|
|
@ -46,6 +46,9 @@ void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
void DecryptSecureArea(u8* out);
|
void DecryptSecureArea(u8* out);
|
||||||
bool LoadROM(const char* path, const char* sram, bool direct);
|
bool LoadROM(const char* path, const char* sram, bool direct);
|
||||||
|
|
||||||
|
void FlushSRAMFile();
|
||||||
|
|
||||||
void RelocateSave(const char* path, bool write);
|
void RelocateSave(const char* path, bool write);
|
||||||
|
|
||||||
int ImportSRAM(const u8* data, u32 length);
|
int ImportSRAM(const u8* data, u32 length);
|
||||||
|
|
|
@ -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
|
|
@ -23,8 +23,13 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
// TODO: different includes for each platform
|
// TODO: different includes for each platform
|
||||||
#include <GL/gl.h>
|
#ifdef __APPLE__
|
||||||
#include <GL/glext.h>
|
#include <OpenGL/gl3.h>
|
||||||
|
#include <OpenGL/gl3ext.h>
|
||||||
|
#else
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glext.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
|
||||||
|
@ -61,6 +66,11 @@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
#define DO_PROCLIST(func)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
#define DO_PROCLIST(func) \
|
#define DO_PROCLIST(func) \
|
||||||
DO_PROCLIST_1_3(func) \
|
DO_PROCLIST_1_3(func) \
|
||||||
|
@ -128,6 +138,7 @@
|
||||||
\
|
\
|
||||||
func(GLGETSTRINGI, glGetStringi); \
|
func(GLGETSTRINGI, glGetStringi); \
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace OpenGL
|
namespace OpenGL
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,15 +67,24 @@ inline bool LocalFileExists(const char* name)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Thread_Create(void (*func)());
|
struct Thread;
|
||||||
void Thread_Free(void* thread);
|
Thread* Thread_Create(void (*func)());
|
||||||
void Thread_Wait(void* thread);
|
void Thread_Free(Thread* thread);
|
||||||
|
void Thread_Wait(Thread* thread);
|
||||||
|
|
||||||
void* Semaphore_Create();
|
struct Semaphore;
|
||||||
void Semaphore_Free(void* sema);
|
Semaphore* Semaphore_Create();
|
||||||
void Semaphore_Reset(void* sema);
|
void Semaphore_Free(Semaphore* sema);
|
||||||
void Semaphore_Wait(void* sema);
|
void Semaphore_Reset(Semaphore* sema);
|
||||||
void Semaphore_Post(void* 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);
|
void* GL_GetProcAddress(const char* proc);
|
||||||
|
|
||||||
|
|
298
src/SPU.cpp
298
src/SPU.cpp
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "Platform.h"
|
||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
#include "DSi.h"
|
#include "DSi.h"
|
||||||
#include "SPU.h"
|
#include "SPU.h"
|
||||||
|
@ -61,13 +62,15 @@ const s16 PSGTable[8][8] =
|
||||||
{-0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF}
|
{-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 OutputFrontBuffer[2 * OutputBufferSize];
|
||||||
s16 OutputBuffer[2 * OutputBufferSize];
|
u32 OutputFrontBufferWritePosition;
|
||||||
volatile u32 OutputReadOffset;
|
u32 OutputFrontBufferReadPosition;
|
||||||
volatile u32 OutputWriteOffset;
|
|
||||||
|
|
||||||
|
Platform::Mutex* AudioLock;
|
||||||
|
|
||||||
u16 Cnt;
|
u16 Cnt;
|
||||||
u8 MasterVolume;
|
u8 MasterVolume;
|
||||||
|
@ -85,6 +88,8 @@ bool Init()
|
||||||
Capture[0] = new CaptureUnit(0);
|
Capture[0] = new CaptureUnit(0);
|
||||||
Capture[1] = new CaptureUnit(1);
|
Capture[1] = new CaptureUnit(1);
|
||||||
|
|
||||||
|
AudioLock = Platform::Mutex_Create();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +100,8 @@ void DeInit()
|
||||||
|
|
||||||
delete Capture[0];
|
delete Capture[0];
|
||||||
delete Capture[1];
|
delete Capture[1];
|
||||||
|
|
||||||
|
Platform::Mutex_Free(AudioLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
|
@ -111,15 +118,18 @@ void Reset()
|
||||||
Capture[0]->Reset();
|
Capture[0]->Reset();
|
||||||
Capture[1]->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()
|
void Stop()
|
||||||
{
|
{
|
||||||
memset(OutputBuffer, 0, 2*OutputBufferSize*2);
|
Platform::Mutex_Lock(AudioLock);
|
||||||
|
memset(OutputFrontBuffer, 0, 2*OutputBufferSize*2);
|
||||||
|
|
||||||
OutputReadOffset = 0;
|
OutputBackbufferWritePosition = 0;
|
||||||
OutputWriteOffset = 0;
|
OutputFrontBufferReadPosition = 0;
|
||||||
|
OutputFrontBufferWritePosition = 0;
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoSavestate(Savestate* file)
|
void DoSavestate(Savestate* file)
|
||||||
|
@ -416,11 +426,11 @@ void Channel::NextSample_Noise()
|
||||||
}
|
}
|
||||||
|
|
||||||
template<u32 type>
|
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)
|
if (KeyOn)
|
||||||
{
|
{
|
||||||
|
@ -428,45 +438,32 @@ void Channel::Run(s32* buf, u32 samples)
|
||||||
KeyOn = false;
|
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);
|
case 0: NextSample_PCM8(); break;
|
||||||
|
case 1: NextSample_PCM16(); break;
|
||||||
switch (type)
|
case 2: NextSample_ADPCM(); break;
|
||||||
{
|
case 3: NextSample_PSG(); break;
|
||||||
case 0: NextSample_PCM8(); break;
|
case 4: NextSample_Noise(); 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++)
|
left += ((s64)in * (128-Pan)) >> 10;
|
||||||
{
|
right += ((s64)in * Pan) >> 10;
|
||||||
s32 val = (s32)inbuf[s];
|
|
||||||
|
|
||||||
s32 l = ((s64)val * (128-Pan)) >> 10;
|
|
||||||
s32 r = ((s64)val * Pan) >> 10;
|
|
||||||
|
|
||||||
leftbuf[s] += l;
|
|
||||||
rightbuf[s] += r;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -602,39 +599,31 @@ void CaptureUnit::Run(s32 sample)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Mix(u32 samples)
|
void Mix(u32 dummy)
|
||||||
{
|
{
|
||||||
s32 channelbuf[32];
|
s32 left = 0, right = 0;
|
||||||
s32 leftbuf[32], rightbuf[32];
|
s32 leftoutput = 0, rightoutput = 0;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Cnt & (1<<15))
|
if (Cnt & (1<<15))
|
||||||
{
|
{
|
||||||
Channels[0]->DoRun(ch0buf, samples);
|
s32 ch0 = Channels[0]->DoRun();
|
||||||
Channels[1]->DoRun(ch1buf, samples);
|
s32 ch1 = Channels[1]->DoRun();
|
||||||
Channels[2]->DoRun(ch2buf, samples);
|
s32 ch2 = Channels[2]->DoRun();
|
||||||
Channels[3]->DoRun(ch3buf, samples);
|
s32 ch3 = Channels[3]->DoRun();
|
||||||
|
|
||||||
// TODO: addition from capture registers
|
// TODO: addition from capture registers
|
||||||
Channels[0]->PanOutput(ch0buf, samples, leftbuf, rightbuf);
|
Channels[0]->PanOutput(ch0, left, right);
|
||||||
Channels[2]->PanOutput(ch2buf, samples, leftbuf, rightbuf);
|
Channels[2]->PanOutput(ch2, left, right);
|
||||||
|
|
||||||
if (!(Cnt & (1<<12))) Channels[1]->PanOutput(ch1buf, samples, leftbuf, rightbuf);
|
if (!(Cnt & (1<<12))) Channels[1]->PanOutput(ch1, left, right);
|
||||||
if (!(Cnt & (1<<13))) Channels[3]->PanOutput(ch3buf, samples, leftbuf, rightbuf);
|
if (!(Cnt & (1<<13))) Channels[3]->PanOutput(ch3, left, right);
|
||||||
|
|
||||||
for (int i = 4; i < 16; i++)
|
for (int i = 4; i < 16; i++)
|
||||||
{
|
{
|
||||||
Channel* chan = Channels[i];
|
Channel* chan = Channels[i];
|
||||||
|
|
||||||
chan->DoRun(channelbuf, samples);
|
s32 channel = chan->DoRun();
|
||||||
chan->PanOutput(channelbuf, samples, leftbuf, rightbuf);
|
chan->PanOutput(channel, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sound capture
|
// sound capture
|
||||||
|
@ -642,32 +631,24 @@ void Mix(u32 samples)
|
||||||
|
|
||||||
if (Capture[0]->Cnt & (1<<7))
|
if (Capture[0]->Cnt & (1<<7))
|
||||||
{
|
{
|
||||||
for (u32 s = 0; s < samples; s++)
|
s32 val = left;
|
||||||
{
|
|
||||||
s32 val = leftbuf[s];
|
|
||||||
|
|
||||||
val >>= 8;
|
val >>= 8;
|
||||||
if (val < -0x8000) val = -0x8000;
|
if (val < -0x8000) val = -0x8000;
|
||||||
else if (val > 0x7FFF) val = 0x7FFF;
|
else if (val > 0x7FFF) val = 0x7FFF;
|
||||||
|
|
||||||
Capture[0]->Run(val);
|
Capture[0]->Run(val);
|
||||||
if (!(Capture[0]->Cnt & (1<<7))) break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Capture[1]->Cnt & (1<<7))
|
if (Capture[1]->Cnt & (1<<7))
|
||||||
{
|
{
|
||||||
for (u32 s = 0; s < samples; s++)
|
s32 val = right;
|
||||||
{
|
|
||||||
s32 val = rightbuf[s];
|
|
||||||
|
|
||||||
val >>= 8;
|
val >>= 8;
|
||||||
if (val < -0x8000) val = -0x8000;
|
if (val < -0x8000) val = -0x8000;
|
||||||
else if (val > 0x7FFF) val = 0x7FFF;
|
else if (val > 0x7FFF) val = 0x7FFF;
|
||||||
|
|
||||||
Capture[1]->Run(val);
|
Capture[1]->Run(val);
|
||||||
if (!(Capture[1]->Cnt & (1<<7))) break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// final output
|
// final output
|
||||||
|
@ -675,31 +656,25 @@ void Mix(u32 samples)
|
||||||
switch (Cnt & 0x0300)
|
switch (Cnt & 0x0300)
|
||||||
{
|
{
|
||||||
case 0x0000: // left mixer
|
case 0x0000: // left mixer
|
||||||
{
|
leftoutput = left;
|
||||||
for (u32 s = 0; s < samples; s++)
|
|
||||||
leftoutput[s] = leftbuf[s];
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 0x0100: // channel 1
|
case 0x0100: // channel 1
|
||||||
{
|
{
|
||||||
s32 pan = 128 - Channels[1]->Pan;
|
s32 pan = 128 - Channels[1]->Pan;
|
||||||
for (u32 s = 0; s < samples; s++)
|
leftoutput = ((s64)ch1 * pan) >> 10;
|
||||||
leftoutput[s] = ((s64)ch1buf[s] * pan) >> 10;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0200: // channel 3
|
case 0x0200: // channel 3
|
||||||
{
|
{
|
||||||
s32 pan = 128 - Channels[3]->Pan;
|
s32 pan = 128 - Channels[3]->Pan;
|
||||||
for (u32 s = 0; s < samples; s++)
|
leftoutput = ((s64)ch3 * pan) >> 10;
|
||||||
leftoutput[s] = ((s64)ch3buf[s] * pan) >> 10;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0300: // channel 1+3
|
case 0x0300: // channel 1+3
|
||||||
{
|
{
|
||||||
s32 pan1 = 128 - Channels[1]->Pan;
|
s32 pan1 = 128 - Channels[1]->Pan;
|
||||||
s32 pan3 = 128 - Channels[3]->Pan;
|
s32 pan3 = 128 - Channels[3]->Pan;
|
||||||
for (u32 s = 0; s < samples; s++)
|
leftoutput = (((s64)ch1 * pan1) >> 10) + (((s64)ch3 * pan3) >> 10);
|
||||||
leftoutput[s] = (((s64)ch1buf[s] * pan1) >> 10) + (((s64)ch3buf[s] * pan3) >> 10);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -707,105 +682,122 @@ void Mix(u32 samples)
|
||||||
switch (Cnt & 0x0C00)
|
switch (Cnt & 0x0C00)
|
||||||
{
|
{
|
||||||
case 0x0000: // right mixer
|
case 0x0000: // right mixer
|
||||||
{
|
rightoutput = right;
|
||||||
for (u32 s = 0; s < samples; s++)
|
|
||||||
rightoutput[s] = rightbuf[s];
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 0x0400: // channel 1
|
case 0x0400: // channel 1
|
||||||
{
|
{
|
||||||
s32 pan = Channels[1]->Pan;
|
s32 pan = Channels[1]->Pan;
|
||||||
for (u32 s = 0; s < samples; s++)
|
rightoutput = ((s64)ch1 * pan) >> 10;
|
||||||
rightoutput[s] = ((s64)ch1buf[s] * pan) >> 10;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0800: // channel 3
|
case 0x0800: // channel 3
|
||||||
{
|
{
|
||||||
s32 pan = Channels[3]->Pan;
|
s32 pan = Channels[3]->Pan;
|
||||||
for (u32 s = 0; s < samples; s++)
|
rightoutput = ((s64)ch3 * pan) >> 10;
|
||||||
rightoutput[s] = ((s64)ch3buf[s] * pan) >> 10;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0C00: // channel 1+3
|
case 0x0C00: // channel 1+3
|
||||||
{
|
{
|
||||||
s32 pan1 = Channels[1]->Pan;
|
s32 pan1 = Channels[1]->Pan;
|
||||||
s32 pan3 = Channels[3]->Pan;
|
s32 pan3 = Channels[3]->Pan;
|
||||||
for (u32 s = 0; s < samples; s++)
|
rightoutput = (((s64)ch1 * pan1) >> 10) + (((s64)ch3 * pan3) >> 10);
|
||||||
rightoutput[s] = (((s64)ch1buf[s] * pan1) >> 10) + (((s64)ch3buf[s] * pan3) >> 10);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 s = 0; s < samples; s++)
|
leftoutput = ((s64)leftoutput * MasterVolume) >> 7;
|
||||||
{
|
rightoutput = ((s64)rightoutput * MasterVolume) >> 7;
|
||||||
s32 l = leftoutput[s];
|
|
||||||
s32 r = rightoutput[s];
|
|
||||||
|
|
||||||
l = ((s64)l * MasterVolume) >> 7;
|
leftoutput >>= 8;
|
||||||
r = ((s64)r * MasterVolume) >> 7;
|
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;
|
// OutputBufferFrame can never get full because it's
|
||||||
if (l < -0x8000) l = -0x8000;
|
// transfered to OutputBuffer at the end of the frame
|
||||||
else if (l > 0x7FFF) l = 0x7FFF;
|
OutputBackbuffer[OutputBackbufferWritePosition ] = leftoutput >> 1;
|
||||||
r >>= 8;
|
OutputBackbuffer[OutputBackbufferWritePosition + 1] = rightoutput >> 1;
|
||||||
if (r < -0x8000) r = -0x8000;
|
OutputBackbufferWritePosition += 2;
|
||||||
else if (r > 0x7FFF) r = 0x7FFF;
|
|
||||||
|
|
||||||
OutputBuffer[OutputWriteOffset ] = l >> 1;
|
NDS::ScheduleEvent(NDS::Event_SPU, true, 1024, Mix, 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
void TrimOutput()
|
||||||
{
|
{
|
||||||
|
Platform::Mutex_Lock(AudioLock);
|
||||||
const int halflimit = (OutputBufferSize / 2);
|
const int halflimit = (OutputBufferSize / 2);
|
||||||
|
|
||||||
int readpos = OutputWriteOffset - (halflimit*2);
|
int readpos = OutputFrontBufferWritePosition - (halflimit*2);
|
||||||
if (readpos < 0) readpos += (OutputBufferSize*2);
|
if (readpos < 0) readpos += (OutputBufferSize*2);
|
||||||
|
|
||||||
OutputReadOffset = readpos;
|
OutputFrontBufferReadPosition = readpos;
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrainOutput()
|
void DrainOutput()
|
||||||
{
|
{
|
||||||
OutputReadOffset = 0;
|
Platform::Mutex_Lock(AudioLock);
|
||||||
OutputWriteOffset = 0;
|
OutputFrontBufferWritePosition = 0;
|
||||||
|
OutputFrontBufferReadPosition = 0;
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitOutput()
|
void InitOutput()
|
||||||
{
|
{
|
||||||
memset(OutputBuffer, 0, 2*OutputBufferSize*2);
|
Platform::Mutex_Lock(AudioLock);
|
||||||
OutputReadOffset = 0;
|
memset(OutputBackbuffer, 0, 2*OutputBufferSize*2);
|
||||||
OutputWriteOffset = OutputBufferSize;
|
memset(OutputFrontBuffer, 0, 2*OutputBufferSize*2);
|
||||||
|
OutputFrontBufferReadPosition = 0;
|
||||||
|
OutputFrontBufferWritePosition = 0;
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetOutputSize()
|
int GetOutputSize()
|
||||||
{
|
{
|
||||||
|
Platform::Mutex_Lock(AudioLock);
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
if (OutputWriteOffset >= OutputReadOffset)
|
if (OutputFrontBufferWritePosition >= OutputFrontBufferReadPosition)
|
||||||
ret = OutputWriteOffset - OutputReadOffset;
|
ret = OutputFrontBufferWritePosition - OutputFrontBufferReadPosition;
|
||||||
else
|
else
|
||||||
ret = (OutputBufferSize*2) - OutputReadOffset + OutputWriteOffset;
|
ret = (OutputBufferSize*2) - OutputFrontBufferReadPosition + OutputFrontBufferWritePosition;
|
||||||
|
|
||||||
ret >>= 1;
|
ret >>= 1;
|
||||||
|
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sync(bool wait)
|
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
|
// sync to audio output in case the core is running too fast
|
||||||
// * wait=true: wait until enough audio data has been played
|
// * wait=true: wait until enough audio data has been played
|
||||||
// * wait=false: merely skip some audio data to avoid a FIFO overflow
|
// * wait=false: merely skip some audio data to avoid a FIFO overflow
|
||||||
|
@ -819,32 +811,42 @@ void Sync(bool wait)
|
||||||
}
|
}
|
||||||
else if (GetOutputSize() > halflimit)
|
else if (GetOutputSize() > halflimit)
|
||||||
{
|
{
|
||||||
int readpos = OutputWriteOffset - (halflimit*2);
|
Platform::Mutex_Lock(AudioLock);
|
||||||
|
|
||||||
|
int readpos = OutputFrontBufferWritePosition - (halflimit*2);
|
||||||
if (readpos < 0) readpos += (OutputBufferSize*2);
|
if (readpos < 0) readpos += (OutputBufferSize*2);
|
||||||
|
|
||||||
OutputReadOffset = readpos;
|
OutputFrontBufferReadPosition = readpos;
|
||||||
|
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReadOutput(s16* data, int samples)
|
int ReadOutput(s16* data, int samples)
|
||||||
{
|
{
|
||||||
if (OutputReadOffset == OutputWriteOffset)
|
Platform::Mutex_Lock(AudioLock);
|
||||||
|
if (OutputFrontBufferReadPosition == OutputFrontBufferWritePosition)
|
||||||
|
{
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < samples; i++)
|
for (int i = 0; i < samples; i++)
|
||||||
{
|
{
|
||||||
*data++ = OutputBuffer[OutputReadOffset];
|
*data++ = OutputFrontBuffer[OutputFrontBufferReadPosition];
|
||||||
*data++ = OutputBuffer[OutputReadOffset + 1];
|
*data++ = OutputFrontBuffer[OutputFrontBufferReadPosition + 1];
|
||||||
|
|
||||||
//if (OutputReadOffset != OutputWriteOffset)
|
OutputFrontBufferReadPosition += 2;
|
||||||
|
OutputFrontBufferReadPosition &= ((2*OutputBufferSize)-1);
|
||||||
|
|
||||||
|
if (OutputFrontBufferWritePosition == OutputFrontBufferReadPosition)
|
||||||
{
|
{
|
||||||
OutputReadOffset += 2;
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
OutputReadOffset &= ((2*OutputBufferSize)-1);
|
|
||||||
}
|
|
||||||
if (OutputReadOffset == OutputWriteOffset)
|
|
||||||
return i+1;
|
return i+1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
25
src/SPU.h
25
src/SPU.h
|
@ -33,7 +33,7 @@ void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
void SetBias(u16 bias);
|
void SetBias(u16 bias);
|
||||||
|
|
||||||
void Mix(u32 samples);
|
void Mix(u32 dummy);
|
||||||
|
|
||||||
void TrimOutput();
|
void TrimOutput();
|
||||||
void DrainOutput();
|
void DrainOutput();
|
||||||
|
@ -41,6 +41,7 @@ void InitOutput();
|
||||||
int GetOutputSize();
|
int GetOutputSize();
|
||||||
void Sync(bool wait);
|
void Sync(bool wait);
|
||||||
int ReadOutput(s16* data, int samples);
|
int ReadOutput(s16* data, int samples);
|
||||||
|
void TransferOutput();
|
||||||
|
|
||||||
u8 Read8(u32 addr);
|
u8 Read8(u32 addr);
|
||||||
u16 Read16(u32 addr);
|
u16 Read16(u32 addr);
|
||||||
|
@ -123,26 +124,24 @@ public:
|
||||||
void NextSample_PSG();
|
void NextSample_PSG();
|
||||||
void NextSample_Noise();
|
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)
|
switch ((Cnt >> 29) & 0x3)
|
||||||
{
|
{
|
||||||
case 0: Run<0>(buf, samples); break;
|
case 0: return Run<0>(); break;
|
||||||
case 1: Run<1>(buf, samples); break;
|
case 1: return Run<1>(); break;
|
||||||
case 2: Run<2>(buf, samples); break;
|
case 2: return Run<2>(); break;
|
||||||
case 3:
|
case 3:
|
||||||
if (Num >= 14) Run<4>(buf, samples);
|
if (Num >= 14) return Run<4>();
|
||||||
else if (Num >= 8) Run<3>(buf, samples);
|
else if (Num >= 8) return Run<3>();
|
||||||
break;
|
default:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanOutput(s32* inbuf, u32 samples, s32* leftbuf, s32* rightbuf);
|
void PanOutput(s32 in, s32& left, s32& right);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 (*BusRead32)(u32 addr);
|
u32 (*BusRead32)(u32 addr);
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef SHAREDCONFIG_H
|
||||||
|
#define SHAREDCONFIG_H
|
||||||
|
|
||||||
|
namespace Config
|
||||||
|
{
|
||||||
|
|
||||||
|
extern int ConsoleType;
|
||||||
|
extern int DirectBoot;
|
||||||
|
extern int SavestateRelocSRAM;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#include "FrontendUtil.h"
|
#include "FrontendUtil.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "qt_sdl/PlatformConfig.h" // FIXME!!!
|
#include "SharedConfig.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
|
||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
|
|
|
@ -95,6 +95,19 @@ if (PORTABLE)
|
||||||
add_definitions(-DPORTABLE)
|
add_definitions(-DPORTABLE)
|
||||||
endif()
|
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 ../../../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_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)
|
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_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_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(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)
|
||||||
|
|
|
@ -65,6 +65,9 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
|
||||||
ui->chkJITBranchOptimisations->setChecked(Config::JIT_BranchOptimisations != 0);
|
ui->chkJITBranchOptimisations->setChecked(Config::JIT_BranchOptimisations != 0);
|
||||||
ui->chkJITLiteralOptimisations->setChecked(Config::JIT_LiteralOptimisations != 0);
|
ui->chkJITLiteralOptimisations->setChecked(Config::JIT_LiteralOptimisations != 0);
|
||||||
ui->chkJITFastMemory->setChecked(Config::JIT_FastMemory != 0);
|
ui->chkJITFastMemory->setChecked(Config::JIT_FastMemory != 0);
|
||||||
|
#ifdef __APPLE__
|
||||||
|
ui->chkJITFastMemory->setDisabled(true);
|
||||||
|
#endif
|
||||||
ui->spnJITMaximumBlockSize->setValue(Config::JIT_MaxBlockSize);
|
ui->spnJITMaximumBlockSize->setValue(Config::JIT_MaxBlockSize);
|
||||||
#else
|
#else
|
||||||
ui->chkEnableJIT->setDisabled(true);
|
ui->chkEnableJIT->setDisabled(true);
|
||||||
|
@ -329,6 +332,8 @@ void EmuSettingsDialog::on_chkEnableJIT_toggled()
|
||||||
bool disabled = !ui->chkEnableJIT->isChecked();
|
bool disabled = !ui->chkEnableJIT->isChecked();
|
||||||
ui->chkJITBranchOptimisations->setDisabled(disabled);
|
ui->chkJITBranchOptimisations->setDisabled(disabled);
|
||||||
ui->chkJITLiteralOptimisations->setDisabled(disabled);
|
ui->chkJITLiteralOptimisations->setDisabled(disabled);
|
||||||
ui->chkJITFastMemory->setDisabled(disabled);
|
#ifndef __APPLE__
|
||||||
|
ui->chkJITFastMemory->setDisabled(disabled);
|
||||||
|
#endif
|
||||||
ui->spnJITMaximumBlockSize->setDisabled(disabled);
|
ui->spnJITMaximumBlockSize->setDisabled(disabled);
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,6 +216,7 @@ KeyMapButton::KeyMapButton(int* mapping, bool hotkey) : QPushButton()
|
||||||
|
|
||||||
setCheckable(true);
|
setCheckable(true);
|
||||||
setText(mappingText());
|
setText(mappingText());
|
||||||
|
setFocusPolicy(Qt::StrongFocus); //Fixes binding keys in macOS
|
||||||
|
|
||||||
connect(this, &KeyMapButton::clicked, this, &KeyMapButton::onClick);
|
connect(this, &KeyMapButton::clicked, this, &KeyMapButton::onClick);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,11 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
#include <netinet/in.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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,6 +70,9 @@ const char* PCapLibNames[] =
|
||||||
#ifdef __WIN32__
|
#ifdef __WIN32__
|
||||||
// TODO: name for npcap in non-WinPCap mode
|
// TODO: name for npcap in non-WinPCap mode
|
||||||
"wpcap.dll",
|
"wpcap.dll",
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
"libpcap.A.dylib",
|
||||||
|
"libpcap.dylib",
|
||||||
#else
|
#else
|
||||||
// Linux lib names
|
// Linux lib names
|
||||||
"libpcap.so.1",
|
"libpcap.so.1",
|
||||||
|
@ -276,6 +283,7 @@ bool Init(bool open_adapter)
|
||||||
struct sockaddr_in* sa = (sockaddr_in*)curaddr->ifa_addr;
|
struct sockaddr_in* sa = (sockaddr_in*)curaddr->ifa_addr;
|
||||||
memcpy(adata->IP_v4, &sa->sin_addr, 4);
|
memcpy(adata->IP_v4, &sa->sin_addr, 4);
|
||||||
}
|
}
|
||||||
|
#ifdef __linux__
|
||||||
else if (af == AF_PACKET)
|
else if (af == AF_PACKET)
|
||||||
{
|
{
|
||||||
struct sockaddr_ll* sa = (sockaddr_ll*)curaddr->ifa_addr;
|
struct sockaddr_ll* sa = (sockaddr_ll*)curaddr->ifa_addr;
|
||||||
|
@ -284,7 +292,16 @@ bool Init(bool open_adapter)
|
||||||
else
|
else
|
||||||
memcpy(adata->MAC, sa->sll_addr, 6);
|
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;
|
curaddr = curaddr->ifa_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QSemaphore>
|
#include <QSemaphore>
|
||||||
|
#include <QMutex>
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
|
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
@ -187,53 +188,77 @@ FILE* OpenLocalFile(const char* path, const char* mode)
|
||||||
return OpenFile(fullpath.toUtf8(), mode, mode[0] != 'w');
|
return OpenFile(fullpath.toUtf8(), mode, mode[0] != 'w');
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Thread_Create(void (* func)())
|
Thread* Thread_Create(void (* func)())
|
||||||
{
|
{
|
||||||
QThread* t = QThread::create(func);
|
QThread* t = QThread::create(func);
|
||||||
t->start();
|
t->start();
|
||||||
return (void*) t;
|
return (Thread*) t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread_Free(void* thread)
|
void Thread_Free(Thread* thread)
|
||||||
{
|
{
|
||||||
QThread* t = (QThread*) thread;
|
QThread* t = (QThread*) thread;
|
||||||
t->terminate();
|
t->terminate();
|
||||||
delete t;
|
delete t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread_Wait(void* thread)
|
void Thread_Wait(Thread* thread)
|
||||||
{
|
{
|
||||||
((QThread*) thread)->wait();
|
((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;
|
delete (QSemaphore*) sema;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Semaphore_Reset(void* sema)
|
void Semaphore_Reset(Semaphore* sema)
|
||||||
{
|
{
|
||||||
QSemaphore* s = (QSemaphore*) sema;
|
QSemaphore* s = (QSemaphore*) sema;
|
||||||
|
|
||||||
s->acquire(s->available());
|
s->acquire(s->available());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Semaphore_Wait(void* sema)
|
void Semaphore_Wait(Semaphore* sema)
|
||||||
{
|
{
|
||||||
((QSemaphore*) sema)->acquire();
|
((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)
|
void* GL_GetProcAddress(const char* proc)
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,7 +120,7 @@ ConfigEntry PlatformConfigFile[] =
|
||||||
{"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1, NULL, 0},
|
{"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1, NULL, 0},
|
||||||
{"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -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_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_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1, NULL, 0},
|
||||||
{"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, NULL, 0},
|
{"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, NULL, 0},
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(ne
|
||||||
LAN_Socket::Init();
|
LAN_Socket::Init();
|
||||||
haspcap = LAN_PCap::Init(false);
|
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->cbBindAnyAddr->setChecked(Config::SocketBindAnyAddr != 0);
|
||||||
ui->cbRandomizeMAC->setChecked(Config::RandomizeMAC != 0);
|
ui->cbRandomizeMAC->setChecked(Config::RandomizeMAC != 0);
|
||||||
|
@ -71,8 +71,9 @@ WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(ne
|
||||||
}
|
}
|
||||||
ui->cbxDirectAdapter->setCurrentIndex(sel);
|
ui->cbxDirectAdapter->setCurrentIndex(sel);
|
||||||
|
|
||||||
ui->cbDirectMode->setChecked(Config::DirectLAN != 0);
|
ui->rbDirectMode->setChecked(Config::DirectLAN != 0);
|
||||||
if (!haspcap) ui->cbDirectMode->setEnabled(false);
|
ui->rbIndirectMode->setChecked(Config::DirectLAN == 0);
|
||||||
|
if (!haspcap) ui->rbDirectMode->setEnabled(false);
|
||||||
|
|
||||||
updateAdapterControls();
|
updateAdapterControls();
|
||||||
}
|
}
|
||||||
|
@ -101,7 +102,7 @@ void WifiSettingsDialog::done(int r)
|
||||||
|
|
||||||
Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked() ? 1:0;
|
Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked() ? 1:0;
|
||||||
Config::RandomizeMAC = randommac;
|
Config::RandomizeMAC = randommac;
|
||||||
Config::DirectLAN = ui->cbDirectMode->isChecked() ? 1:0;
|
Config::DirectLAN = ui->rbDirectMode->isChecked() ? 1:0;
|
||||||
|
|
||||||
int sel = ui->cbxDirectAdapter->currentIndex();
|
int sel = ui->cbxDirectAdapter->currentIndex();
|
||||||
if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0;
|
if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0;
|
||||||
|
@ -125,11 +126,14 @@ void WifiSettingsDialog::done(int r)
|
||||||
closeDlg();
|
closeDlg();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiSettingsDialog::on_cbDirectMode_stateChanged(int state)
|
void WifiSettingsDialog::on_rbDirectMode_clicked()
|
||||||
|
{
|
||||||
|
updateAdapterControls();
|
||||||
|
}
|
||||||
|
void WifiSettingsDialog::on_rbIndirectMode_clicked()
|
||||||
{
|
{
|
||||||
updateAdapterControls();
|
updateAdapterControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiSettingsDialog::on_cbxDirectAdapter_currentIndexChanged(int sel)
|
void WifiSettingsDialog::on_cbxDirectAdapter_currentIndexChanged(int sel)
|
||||||
{
|
{
|
||||||
if (!haspcap) return;
|
if (!haspcap) return;
|
||||||
|
@ -153,7 +157,7 @@ void WifiSettingsDialog::on_cbxDirectAdapter_currentIndexChanged(int sel)
|
||||||
|
|
||||||
void WifiSettingsDialog::updateAdapterControls()
|
void WifiSettingsDialog::updateAdapterControls()
|
||||||
{
|
{
|
||||||
bool enable = haspcap && ui->cbDirectMode->isChecked();
|
bool enable = haspcap && ui->rbDirectMode->isChecked();
|
||||||
|
|
||||||
ui->cbxDirectAdapter->setEnabled(enable);
|
ui->cbxDirectAdapter->setEnabled(enable);
|
||||||
ui->lblAdapterMAC->setEnabled(enable);
|
ui->lblAdapterMAC->setEnabled(enable);
|
||||||
|
|
|
@ -55,7 +55,8 @@ public:
|
||||||
private slots:
|
private slots:
|
||||||
void done(int r);
|
void done(int r);
|
||||||
|
|
||||||
void on_cbDirectMode_stateChanged(int state);
|
void on_rbDirectMode_clicked();
|
||||||
|
void on_rbIndirectMode_clicked();
|
||||||
void on_cbxDirectAdapter_currentIndexChanged(int sel);
|
void on_cbxDirectAdapter_currentIndexChanged(int sel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>479</width>
|
<width>572</width>
|
||||||
<height>240</height>
|
<height>296</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -58,15 +58,81 @@
|
||||||
<string>Online</string>
|
<string>Online</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="2" column="0">
|
<item row="3" column="0" rowspan="3" colspan="2">
|
||||||
<widget class="QLabel" name="label_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><html><head/><body><p>Selects the network adapter through which to route network traffic under direct mode.</p></body></html></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><html><head/><body><p>Indirect mode uses libslirp. It requires no extra setup and is easy to use.</p></body></html></string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>MAC address:</string>
|
<string>Indirect Mode (uses libslirp, recommended)</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0" colspan="2">
|
<item row="2" column="0">
|
||||||
<widget class="QCheckBox" name="cbDirectMode">
|
<widget class="QRadioButton" name="rbDirectMode">
|
||||||
<property name="whatsThis">
|
<property name="whatsThis">
|
||||||
<string><html><head/><body><p>Direct mode directly routes network traffic to the host network. It is the most reliable, but requires an ethernet connection.</p><p><br/></p><p>Non-direct mode uses a layer of emulation to get around this, but is more prone to problems.</p></body></html></string>
|
<string><html><head/><body><p>Direct mode directly routes network traffic to the host network. It is the most reliable, but requires an ethernet connection.</p><p><br/></p><p>Non-direct mode uses a layer of emulation to get around this, but is more prone to problems.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -75,53 +141,6 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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><html><head/><body><p>Selects the network adapter through which to route network traffic under direct mode.</p></body></html></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>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -355,10 +355,10 @@ void EmuThread::run()
|
||||||
Input::Init();
|
Input::Init();
|
||||||
|
|
||||||
u32 nframes = 0;
|
u32 nframes = 0;
|
||||||
u32 starttick = SDL_GetTicks();
|
double perfCountsSec = 1.0 / SDL_GetPerformanceFrequency();
|
||||||
u32 lasttick = starttick;
|
double lastTime = SDL_GetPerformanceCounter() * perfCountsSec;
|
||||||
u32 lastmeasuretick = lasttick;
|
double frameLimitError = 0.0;
|
||||||
u32 fpslimitcount = 0;
|
double lastMeasureTime = lastTime;
|
||||||
|
|
||||||
char melontitle[100];
|
char melontitle[100];
|
||||||
|
|
||||||
|
@ -492,49 +492,43 @@ void EmuThread::run()
|
||||||
SDL_UnlockMutex(audioSyncLock);
|
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;
|
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();
|
double practicalFramelimit = limitfps ? frametimeStep : 1.0 / 1000.0;
|
||||||
fpslimitcount++;
|
|
||||||
if ((abs(wantedtickF - (float)wantedtick) < 0.001312) || (fpslimitcount > 60))
|
double curtime = SDL_GetPerformanceCounter() * perfCountsSec;
|
||||||
{
|
|
||||||
fpslimitcount = 0;
|
frameLimitError += practicalFramelimit - (curtime - lastTime);
|
||||||
starttick = lasttick;
|
if (frameLimitError < -practicalFramelimit)
|
||||||
}
|
frameLimitError = -practicalFramelimit;
|
||||||
}
|
if (frameLimitError > practicalFramelimit)
|
||||||
else
|
frameLimitError = practicalFramelimit;
|
||||||
|
|
||||||
|
if (round(frameLimitError * 1000.0) > 0.0)
|
||||||
{
|
{
|
||||||
if (delay < 1) SDL_Delay(1);
|
SDL_Delay(round(frameLimitError * 1000.0));
|
||||||
lasttick = SDL_GetTicks();
|
double timeBeforeSleep = curtime;
|
||||||
|
curtime = SDL_GetPerformanceCounter() * perfCountsSec;
|
||||||
|
frameLimitError -= curtime - timeBeforeSleep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastTime = curtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
nframes++;
|
nframes++;
|
||||||
if (nframes >= 30)
|
if (nframes >= 30)
|
||||||
{
|
{
|
||||||
u32 tick = SDL_GetTicks();
|
double time = SDL_GetPerformanceCounter() * perfCountsSec;
|
||||||
u32 diff = tick - lastmeasuretick;
|
double dt = time - lastMeasureTime;
|
||||||
lastmeasuretick = tick;
|
lastMeasureTime = time;
|
||||||
|
|
||||||
u32 fps;
|
u32 fps = round(nframes / dt);
|
||||||
if (diff < 1) fps = 77777;
|
|
||||||
else fps = (nframes * 1000) / diff;
|
|
||||||
nframes = 0;
|
nframes = 0;
|
||||||
|
|
||||||
float fpstarget;
|
float fpstarget = 1.0/frametimeStep;
|
||||||
if (framerate < 1) fpstarget = 999;
|
|
||||||
else fpstarget = 1000.0f/framerate;
|
|
||||||
|
|
||||||
sprintf(melontitle, "[%d/%.0f] melonDS " MELONDS_VERSION, fps, fpstarget);
|
sprintf(melontitle, "[%d/%.0f] melonDS " MELONDS_VERSION, fps, fpstarget);
|
||||||
changeWindowTitle(melontitle);
|
changeWindowTitle(melontitle);
|
||||||
|
@ -544,10 +538,8 @@ void EmuThread::run()
|
||||||
{
|
{
|
||||||
// paused
|
// paused
|
||||||
nframes = 0;
|
nframes = 0;
|
||||||
lasttick = SDL_GetTicks();
|
lastTime = SDL_GetPerformanceCounter() * perfCountsSec;
|
||||||
starttick = lasttick;
|
lastMeasureTime = lastTime;
|
||||||
lastmeasuretick = lasttick;
|
|
||||||
fpslimitcount = 0;
|
|
||||||
|
|
||||||
emit windowUpdate();
|
emit windowUpdate();
|
||||||
|
|
||||||
|
@ -1354,7 +1346,7 @@ void MainWindow::dragEnterEvent(QDragEnterEvent* event)
|
||||||
QString filename = urls.at(0).toLocalFile();
|
QString filename = urls.at(0).toLocalFile();
|
||||||
QString ext = filename.right(3);
|
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();
|
event->acceptProposedAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue