Merge remote-tracking branch 'origin/master' into dev
This commit is contained in:
commit
5b3a414987
|
@ -30,8 +30,8 @@ jobs:
|
|||
- name: Set up build environment (macOS)
|
||||
run: |
|
||||
brew update
|
||||
brew install libao ldid libomp ninja pulseaudio
|
||||
wget https://sdk.lunarg.com/sdk/download/1.3.204.1/mac/vulkansdk-macos-1.3.204.1.dmg
|
||||
brew install libao ldid ninja pulseaudio
|
||||
wget https://sdk.lunarg.com/sdk/download/1.3.211.0/mac/vulkansdk-macos-1.3.211.0.dmg
|
||||
hdiutil attach ./vulkansdk-macos-*.dmg
|
||||
sudo /Volumes/vulkansdk-macos-*/InstallVulkan.app/Contents/MacOS/InstallVulkan --root $HOME/VulkanSDK --accept-licenses --default-answer --confirm-command install
|
||||
hdiutil detach /Volumes/vulkansdk-macos-*
|
||||
|
@ -67,6 +67,10 @@ jobs:
|
|||
fetch-depth: 0
|
||||
submodules: true
|
||||
|
||||
- name: Compile a universal OpenMP
|
||||
run: brew reinstall --build-from-source --formula ./shell/apple/libomp.rb
|
||||
if: runner.os == 'macOS'
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
|
|
|
@ -201,20 +201,22 @@ if(NOT LIBRETRO)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_CXX_FOUND AND NOT APPLE AND USE_OPENMP)
|
||||
if(MINGW)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE "-static -lgomp -lpthread")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -fopenmp)
|
||||
elseif(ANDROID)
|
||||
# Reference: https://android.googlesource.com/platform/ndk/+/refs/heads/master/tests/device/openmp/CMakeLists.txt
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_OPTIONS -fopenmp)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE -fopenmp -static-openmp)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX)
|
||||
if(USE_OPENMP)
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
if(MINGW)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE "-static -lgomp -lpthread")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -fopenmp)
|
||||
elseif(ANDROID)
|
||||
# Reference: https://android.googlesource.com/platform/ndk/+/refs/heads/master/tests/device/openmp/CMakeLists.txt
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_OPTIONS -fopenmp)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE -fopenmp -static-openmp)
|
||||
elseif(APPLE)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX -static-openmp)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE TARGET_NO_OPENMP)
|
||||
endif()
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared library" OFF)
|
||||
|
@ -891,6 +893,8 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/wsi/context.h
|
||||
core/wsi/libretro.cpp
|
||||
core/wsi/libretro.h
|
||||
core/wsi/switcher.cpp)
|
||||
|
||||
if(USE_OPENGL)
|
||||
|
@ -900,8 +904,6 @@ if(USE_OPENGL)
|
|||
core/wsi/egl.h
|
||||
core/wsi/gl_context.cpp
|
||||
core/wsi/gl_context.h
|
||||
core/wsi/libretro.cpp
|
||||
core/wsi/libretro.h
|
||||
core/wsi/osx.cpp
|
||||
core/wsi/osx.h
|
||||
core/wsi/sdl.cpp
|
||||
|
@ -1394,13 +1396,15 @@ if(NOT LIBRETRO)
|
|||
find_library(AUDIO_TOOLBOX_LIBRARY AudioToolbox)
|
||||
find_library(OPENGL_LIBRARY OpenGL)
|
||||
find_library(IOSURFACE_LIBRARY IOSurface)
|
||||
find_library(MULTITOUCH_SUPPORT_LIBRARY MultitouchSupport /System/Library/PrivateFrameworks)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
${AUDIO_UNIT_LIBRARY}
|
||||
${FOUNDATION_LIBRARY}
|
||||
${AUDIO_TOOLBOX_LIBRARY}
|
||||
${OPENGL_LIBRARY}
|
||||
${IOSURFACE_LIBRARY})
|
||||
${IOSURFACE_LIBRARY}
|
||||
${MULTITOUCH_SUPPORT_LIBRARY})
|
||||
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "$ENV{VULKAN_SDK}/lib/libMoltenVK.dylib"
|
||||
|
@ -1439,7 +1443,7 @@ if(NOT LIBRETRO)
|
|||
set_target_properties(${PROJECT_NAME} PROPERTIES RESOURCE "${ResourceFiles}")
|
||||
else()
|
||||
target_sources(${PROJECT_NAME} PRIVATE shell/windows/flycast.rc)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE dsound opengl32 winmm ws2_32 wsock32 xinput9_1_0)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE dsound opengl32 winmm ws2_32 wsock32 xinput9_1_0 cfgmgr32)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
|
20
README.md
20
README.md
|
@ -7,7 +7,7 @@
|
|||
|
||||

|
||||
|
||||
**Flycast** is a multi-platform Sega Dreamcast, Naomi and Atomiswave emulator derived from [**reicast**](https://reicast.com/).
|
||||
**Flycast** is a multi-platform Sega Dreamcast, Naomi, Naomi 2, and Atomiswave emulator derived from [**reicast**](https://github.com/skmp/reicast-emulator).
|
||||
|
||||
Information about configuration and supported features can be found on [**TheArcadeStriker's flycast wiki**](https://github.com/TheArcadeStriker/flycast-wiki/wiki).
|
||||
|
||||
|
@ -17,27 +17,31 @@ Join us on our [**Discord server**](https://discord.gg/X8YWP8w) for a chat.
|
|||
|
||||
### Flatpak (Linux)
|
||||
|
||||
1. [Set up Flatpak](https://www.flatpak.org/setup/)
|
||||
1. [Set up Flatpak](https://www.flatpak.org/setup/).
|
||||
|
||||
2. Install Flycast from [Flathub](https://flathub.org/apps/details/org.flycast.Flycast)
|
||||
2. Install Flycast from [Flathub](https://flathub.org/apps/details/org.flycast.Flycast):
|
||||
|
||||
`flatpak install -y org.flycast.Flycast`
|
||||
|
||||
3. Run Flycast
|
||||
3. Run Flycast:
|
||||
|
||||
`flatpak run org.flycast.Flycast`
|
||||
|
||||
### Homebrew (MacOS)
|
||||
|
||||
1. [Set up Homebrew](https://brew.sh)
|
||||
1. [Set up Homebrew](https://brew.sh).
|
||||
|
||||
2. Install Flycast via Homebrew
|
||||
2. Install Flycast via Homebrew:
|
||||
|
||||
`brew install --cask flycast`
|
||||
|
||||
### Xbox One
|
||||
### Xbox One/Series
|
||||
|
||||
Open [**gamr13's github page**](https://gamr13.github.io/) from your console.
|
||||
#### Retail:
|
||||
Open [**gamr13's github page**](https://gamr13.github.io/) from your Xbox console.
|
||||
|
||||
#### Dev Mode:
|
||||
Grab the latest build from [**the builds page**](https://flyinghead.github.io/flycast-builds/), or the [**GitHub Actions**](https://github.com/flyinghead/flycast/actions/workflows/uwp.yml). Then install it using the **Xbox Device Portal**.
|
||||
|
||||
### Binaries
|
||||
|
||||
|
|
|
@ -129,6 +129,8 @@ Option<int> GGPODelay("GGPODelay", 0, "network");
|
|||
Option<bool> NetworkStats("Stats", true, "network");
|
||||
Option<int> GGPOAnalogAxes("GGPOAnalogAxes", 0, "network");
|
||||
Option<bool> GGPOChat("GGPOChat", true, "network");
|
||||
Option<bool> GGPOChatTimeoutToggle("GGPOChatTimeoutToggle", true, "network");
|
||||
Option<int> GGPOChatTimeout("GGPOChatTimeout", 10, "network");
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
Option<bool> DispmanxMaintainAspect("maintain_aspect", true, "dispmanx");
|
||||
|
|
|
@ -487,6 +487,8 @@ extern Option<int> GGPODelay;
|
|||
extern Option<bool> NetworkStats;
|
||||
extern Option<int> GGPOAnalogAxes;
|
||||
extern Option<bool> GGPOChat;
|
||||
extern Option<bool> GGPOChatTimeoutToggle;
|
||||
extern Option<int> GGPOChatTimeout;
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
extern Option<bool> DispmanxMaintainAspect;
|
||||
|
|
|
@ -83,7 +83,7 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
|||
{ "T8116D 50", nullptr, { 0x2E5530 }, { 0x43700000 } }, // Dead or Alive 2 (PAL)
|
||||
{ "T3601N", nullptr, { 0x2F0670 }, { 0x43700000 } }, // Dead or Alive 2 (USA)
|
||||
{ "T3602M", nullptr, { 0x2FF798 }, { 0x43700000 } }, // Dead or Alive 2 (JP)
|
||||
{ "T3601M", nullptr, { 0x2FBBD0, 0x1E6658 }, { 0x43700000, 0x4414C000 } }, // Dead or Alive 2: Limited Edition (JP) (code 1 fixes HUD)
|
||||
{ "T3601M", nullptr, { 0x2FBBD0 }, { 0x43700000 } }, // Dead or Alive 2: Limited Edition (JP)
|
||||
{ "T2401N", nullptr, { 0x8BD5B4, 0x8BD5E4 }, { 0x43F00000, 0x3F400000 } }, // Death Crimson OX (USA)
|
||||
{ "T23201M", nullptr, { 0x819F44, 0x819F74 }, { 0x43F00000, 0x3F400000 } }, // Death Crimson 2 (JP)
|
||||
{ "T17714D50", nullptr, { 0x0D2ED0, 0x0D2ED4 }, { 0x3FAAAAAB, 0x3F400000 } }, // Donald Duck: Quack Attack (PAL) (Code 1 corrects the HUD)
|
||||
|
@ -92,6 +92,7 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
|||
{ "T17720N", nullptr, { 0xF97F40, 0x08DCF4 }, { 0x00000168, 0 } }, // Dragonriders: Chronicles of Pern (USA) (Code 1 removes black bars)
|
||||
{ "MK-5101350", nullptr, { 0x4FCBC0 }, { 0x43700000 } }, // Dynamite Cop (PAL)
|
||||
{ "MK-51013", nullptr, { 0x4FCBC0 }, { 0x43700000 } }, // Dynamite Cop (USA)
|
||||
{ "HDR-0020", nullptr, { 0x4FA848 }, { 0x43700000 } }, // Dynamite Deka 2 (JP)
|
||||
// Draconus: Cult of the Wyrm (USA)
|
||||
// Code 1-2 increases drawing distance
|
||||
{ "T40203N", nullptr, { 0x49D7F4, 0x49D8CC, 0x49D6F8 }, { 0x3F07C3BB, 0x447A0000, 0x3FAAAAAB } },
|
||||
|
@ -302,7 +303,7 @@ const WidescreenCheat CheatManager::naomi_widescreen_cheats[] =
|
|||
{ "TOY FIGHTER", nullptr, { 0x133E58 }, { 0x43700000 } },
|
||||
{ "LUPIN THE THIRD -THE SHOOTING-", nullptr, { 0x045490 }, { 0x3F400000 } },
|
||||
{ "VF4 FINAL TUNED JAPAN", nullptr, { 0x02B834, 0x0AFB90 }, { 0x3FE38E39, 0x3FE38E39 } },
|
||||
{ "DYNAMITE DEKA EX", nullptr, { 0x0E3598 }, { 0x3FE38E38 } },
|
||||
{ "DYNAMITE DEKA EX", nullptr, { 0x0E3598, 0x0C8E84 }, { 0x3FE38E38, 0x3FE38E38 } },
|
||||
{ "DEAD OR ALIVE 2", "doa2m", { 0x085B5C, 0x086AE8 }, { 0x3FE38E39, 0x3FE38E39 } },
|
||||
{ "SLASHOUT JAPAN VERSION", nullptr, { 0x3DDBE4 }, { 0x43CFDC86 } },
|
||||
{ "SPIKERS BATTLE JAPAN VERSION", nullptr, { 0x3626C4 }, { 0x43A551B0 } },
|
||||
|
@ -312,6 +313,8 @@ const WidescreenCheat CheatManager::naomi_widescreen_cheats[] =
|
|||
{ "INITIAL D Ver.3", "initdv3e", { 0x1D0B34 }, { 0x3FE38E39 } },
|
||||
{ "AIRLINE PILOTS IN JAPAN", "alpilotj", { 0x1D62550 }, { 0x43700000 } },
|
||||
{ "MONKEY BALL JAPAN VERSION", nullptr, { 0x345B4, 0x45244, 0x454CC }, { 0x3FE38E39, 0x3FE38E39, 0x3FE38E39 } },
|
||||
{ "ZOMBIE REVENGE IN JAPAN", "zombrvn", { 0x7A4808 }, { 0x43700000 } },
|
||||
{ "ZOMBIE REVENGE IN JAPAN", "zombrvno", { 0x7A2E50 }, { 0x43700000 } },
|
||||
|
||||
{ nullptr },
|
||||
};
|
||||
|
|
|
@ -56,9 +56,9 @@ struct Cheat
|
|||
bool builtIn;
|
||||
|
||||
Cheat(Type type = Type::disabled, const std::string& description = "", bool enabled = false, u32 size = 0, u32 address = 0,
|
||||
u8 valueMask = 0, u32 repeatCount = 1, u32 repeatValueIncrement = 0,
|
||||
u32 value = 0, u8 valueMask = 0, u32 repeatCount = 1, u32 repeatValueIncrement = 0,
|
||||
u32 repeatAddressIncrement = 0, u32 destAddress = 0, bool builtIn = false)
|
||||
: type(type), description(description), enabled(enabled), size(size), address(address), valueMask(valueMask),
|
||||
: type(type), description(description), enabled(enabled), size(size), address(address), value(value), valueMask(valueMask),
|
||||
repeatCount(repeatCount), repeatValueIncrement(repeatValueIncrement), repeatAddressIncrement(repeatAddressIncrement),
|
||||
destAddress(destAddress), builtIn(builtIn)
|
||||
{
|
||||
|
|
|
@ -152,7 +152,8 @@ struct flash_syscfg_block {
|
|||
// last set time (seconds since 1/1/1950 00:00)
|
||||
u16 time_lo;
|
||||
u16 time_hi;
|
||||
u8 unknown1;
|
||||
// in 15 mins increment, from -48 (West) to +52 (East), unused
|
||||
int8_t time_zone;
|
||||
u8 lang;
|
||||
u8 mono;
|
||||
u8 autostart;
|
||||
|
|
|
@ -140,6 +140,7 @@ static void fixUpDCFlash()
|
|||
memset(&syscfg, 0xff, sizeof(syscfg));
|
||||
syscfg.time_lo = 0;
|
||||
syscfg.time_hi = 0;
|
||||
syscfg.time_zone = 0;
|
||||
syscfg.lang = 0;
|
||||
syscfg.mono = 0;
|
||||
syscfg.autostart = 1;
|
||||
|
@ -160,12 +161,27 @@ static void fixUpDCFlash()
|
|||
if (!memcmp(console_id, "\377\377\377\377\377\377", 6))
|
||||
{
|
||||
srand(now);
|
||||
u8 sum = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
console_id[i] = rand();
|
||||
console_id[i + 0xA0] = console_id[i]; // copy at 1A0F8
|
||||
sum += console_id[i];
|
||||
}
|
||||
console_id[-1] = console_id[0xA0 - 1] = sum;
|
||||
console_id[-2] = console_id[0xA0 - 2] = ~sum;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix checksum
|
||||
u8 sum = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
sum += console_id[i];
|
||||
console_id[-1] = console_id[0xA0 - 1] = sum;
|
||||
console_id[-2] = console_id[0xA0 - 2] = ~sum;
|
||||
}
|
||||
// must be != 0xff
|
||||
console_id[7] = console_id[0xA0 + 7] = 0xfe;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -234,6 +234,8 @@ void rend_start_render(TA_context *ctx)
|
|||
FillBGP(ctx);
|
||||
|
||||
ctx->rend.isRTT = (FB_W_SOF1 & 0x1000000) != 0;
|
||||
ctx->rend.fb_W_SOF1 = FB_W_SOF1;
|
||||
ctx->rend.fb_W_CTRL.full = FB_W_CTRL.full;
|
||||
|
||||
ctx->rend.fb_X_CLIP = FB_X_CLIP;
|
||||
ctx->rend.fb_Y_CLIP = FB_Y_CLIP;
|
||||
|
@ -268,8 +270,7 @@ void rend_vblank()
|
|||
if (!render_called && fb_dirty && FB_R_CTRL.fb_enable)
|
||||
{
|
||||
DEBUG_LOG(PVR, "Direct framebuffer write detected");
|
||||
TA_context *ctx = new TA_context();
|
||||
ctx->Alloc();
|
||||
TA_context *ctx = tactx_Alloc();
|
||||
ctx->rend.isRenderFramebuffer = true;
|
||||
rend_start_render(ctx);
|
||||
fb_dirty = false;
|
||||
|
|
|
@ -1319,7 +1319,7 @@ static void sendPolygon(ICHList *list)
|
|||
{
|
||||
PolyParam pp{};
|
||||
pp.pcw.Shadow = list->pcw.shadow;
|
||||
pp.pcw.Texture = list->pcw.texture;
|
||||
pp.pcw.Texture = 0;
|
||||
pp.pcw.Offset = list->pcw.offset;
|
||||
pp.pcw.Gouraud = list->pcw.gouraud;
|
||||
pp.pcw.Volume = list->pcw.volume;
|
||||
|
@ -1395,7 +1395,7 @@ static void sendPolygon(ICHList *list)
|
|||
break;
|
||||
PolyParam pp{};
|
||||
pp.pcw.Shadow = list->pcw.shadow;
|
||||
pp.pcw.Texture = list->pcw.texture;
|
||||
pp.pcw.Texture = 0;
|
||||
pp.pcw.Offset = list->pcw.offset;
|
||||
pp.pcw.Gouraud = list->pcw.gouraud;
|
||||
pp.pcw.Volume = list->pcw.volume;
|
||||
|
@ -1582,6 +1582,12 @@ static void executeCommand(u8 *data, int size)
|
|||
if (link->offset & 0x80000000)
|
||||
{
|
||||
// elan v10 only
|
||||
if (link->size > VRAM_SIZE)
|
||||
{
|
||||
WARN_LOG(PVR, "Texture DMA from %x to %x (%x invalid)", DMAC_SAR(2), link->vramAddress & 0x1ffffff8, link->size);
|
||||
size = 0;
|
||||
break;
|
||||
}
|
||||
DEBUG_LOG(PVR, "Texture DMA from %x to %x (%x)", DMAC_SAR(2), link->vramAddress & 0x1ffffff8, link->size);
|
||||
memcpy(&vram[link->vramAddress & VRAM_MASK], &mem_b[DMAC_SAR(2) & RAM_MASK], link->size);
|
||||
reg74 |= 1;
|
||||
|
@ -1589,6 +1595,12 @@ static void executeCommand(u8 *data, int size)
|
|||
else if (link->offset & 0x20000000)
|
||||
{
|
||||
// elan v10 only
|
||||
if (link->size > VRAM_SIZE)
|
||||
{
|
||||
WARN_LOG(PVR, "Texture DMA from eram %x -> %x (%x invalid)", link->offset & ELAN_RAM_MASK, link->vramAddress & VRAM_MASK, link->size);
|
||||
size = 0;
|
||||
break;
|
||||
}
|
||||
DEBUG_LOG(PVR, "Texture DMA from eram %x -> %x (%x)", link->offset & ELAN_RAM_MASK, link->vramAddress & VRAM_MASK, link->size);
|
||||
memcpy(&vram[link->vramAddress & VRAM_MASK], &RAM[link->offset & ELAN_RAM_MASK], link->size);
|
||||
reg74 |= 1;
|
||||
|
|
|
@ -101,13 +101,28 @@ void FinishRender(TA_context* ctx)
|
|||
frame_finished.Set();
|
||||
}
|
||||
|
||||
static std::mutex mtx_pool;
|
||||
|
||||
static std::vector<TA_context*> ctx_pool;
|
||||
static std::vector<TA_context*> ctx_list;
|
||||
|
||||
static TA_context *tactx_Alloc()
|
||||
TA_context *tactx_Alloc()
|
||||
{
|
||||
TA_context *ctx = new TA_context();
|
||||
ctx->Alloc();
|
||||
TA_context *ctx = nullptr;
|
||||
|
||||
mtx_pool.lock();
|
||||
if (!ctx_pool.empty())
|
||||
{
|
||||
ctx = ctx_pool.back();
|
||||
ctx_pool.pop_back();
|
||||
}
|
||||
mtx_pool.unlock();
|
||||
|
||||
if (ctx == nullptr)
|
||||
{
|
||||
ctx = new TA_context();
|
||||
ctx->Alloc();
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
@ -115,7 +130,17 @@ static void tactx_Recycle(TA_context* ctx)
|
|||
{
|
||||
if (ctx->nextContext != nullptr)
|
||||
tactx_Recycle(ctx->nextContext);
|
||||
delete ctx;
|
||||
mtx_pool.lock();
|
||||
if (ctx_pool.size() > 3)
|
||||
{
|
||||
delete ctx;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->Reset();
|
||||
ctx_pool.push_back(ctx);
|
||||
}
|
||||
mtx_pool.unlock();
|
||||
}
|
||||
|
||||
static TA_context *tactx_Find(u32 addr, bool allocnew)
|
||||
|
@ -162,6 +187,12 @@ void tactx_Term()
|
|||
for (TA_context *ctx : ctx_list)
|
||||
delete ctx;
|
||||
ctx_list.clear();
|
||||
|
||||
mtx_pool.lock();
|
||||
for (TA_context *ctx : ctx_pool)
|
||||
delete ctx;
|
||||
ctx_pool.clear();
|
||||
mtx_pool.unlock();
|
||||
}
|
||||
|
||||
const u32 NULL_CONTEXT = ~0u;
|
||||
|
|
|
@ -232,6 +232,8 @@ struct rend_context
|
|||
FB_X_CLIP_type fb_X_CLIP;
|
||||
FB_Y_CLIP_type fb_Y_CLIP;
|
||||
u32 fb_W_LINESTRIDE;
|
||||
u32 fb_W_SOF1;
|
||||
FB_W_CTRL_type fb_W_CTRL;
|
||||
|
||||
RGBAColor fog_clamp_min;
|
||||
RGBAColor fog_clamp_max;
|
||||
|
@ -327,19 +329,19 @@ struct TA_context
|
|||
{
|
||||
tad.Reset((u8*)allocAligned(32, TA_DATA_SIZE));
|
||||
|
||||
rend.verts.InitBytes(16 * 1024 * 1024, &rend.Overrun, "verts"); //up to 4 mb of vtx data/frame = ~ 96k vtx/frame
|
||||
rend.idx.Init(512 * 1024, &rend.Overrun, "idx"); //up to 120K indexes ( idx have stripification overhead )
|
||||
rend.global_param_op.Init(32768, &rend.Overrun, "global_param_op");
|
||||
rend.verts.Init(320 * 1024, &rend.Overrun, "verts");
|
||||
rend.idx.Init(320 * 1024, &rend.Overrun, "idx");
|
||||
rend.global_param_op.Init(16384, &rend.Overrun, "global_param_op");
|
||||
rend.global_param_pt.Init(5120, &rend.Overrun, "global_param_pt");
|
||||
rend.global_param_mvo.Init(4096, &rend.Overrun, "global_param_mvo");
|
||||
rend.global_param_tr.Init(32768, &rend.Overrun, "global_param_tr");
|
||||
rend.global_param_tr.Init(10240, &rend.Overrun, "global_param_tr");
|
||||
rend.global_param_mvo_tr.Init(4096, &rend.Overrun, "global_param_mvo_tr");
|
||||
|
||||
rend.modtrig.Init(16384, &rend.Overrun, "modtrig");
|
||||
|
||||
rend.render_passes.Init(sizeof(RenderPass) * MAX_PASSES, &rend.Overrun, "render_passes"); // 10 render passes
|
||||
rend.matrices.Init(2000, &rend.Overrun, "matrices");
|
||||
rend.lightModels.Init(100, &rend.Overrun, "lightModels");
|
||||
rend.lightModels.Init(150, &rend.Overrun, "lightModels");
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
@ -348,6 +350,7 @@ struct TA_context
|
|||
{
|
||||
verify(tad.End() - tad.thd_root <= TA_DATA_SIZE);
|
||||
tad.Clear();
|
||||
nextContext = nullptr;
|
||||
rend_inuse.lock();
|
||||
rend.Clear();
|
||||
rend.proc_end = rend.proc_start = tad.thd_root;
|
||||
|
@ -377,6 +380,7 @@ extern tad_context ta_tad;
|
|||
|
||||
TA_context* tactx_Pop(u32 addr);
|
||||
void tactx_Term();
|
||||
TA_context *tactx_Alloc();
|
||||
|
||||
/*
|
||||
Ta Context
|
||||
|
|
|
@ -54,6 +54,16 @@ void os_SetupInput()
|
|||
#endif
|
||||
}
|
||||
|
||||
void os_TermInput()
|
||||
{
|
||||
#if defined(USE_EVDEV)
|
||||
input_evdev_close();
|
||||
#endif
|
||||
#if defined(USE_SDL)
|
||||
input_sdl_quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void UpdateInputState()
|
||||
{
|
||||
#if defined(USE_EVDEV)
|
||||
|
@ -399,9 +409,6 @@ int main(int argc, char* argv[])
|
|||
|
||||
mainui_loop();
|
||||
|
||||
#if defined(USE_EVDEV)
|
||||
input_evdev_close();
|
||||
#endif
|
||||
#if defined(SUPPORT_X11)
|
||||
x11_window_destroy();
|
||||
#endif
|
||||
|
|
|
@ -91,6 +91,7 @@ bool NaomiNetwork::startNetwork()
|
|||
|
||||
if (config::ActAsServer)
|
||||
{
|
||||
enableNetworkBroadcast(true);
|
||||
const auto timeout = seconds(20);
|
||||
NOTICE_LOG(NETWORK, "Waiting for slave connections");
|
||||
steady_clock::time_point start_time = steady_clock::now();
|
||||
|
@ -110,6 +111,7 @@ bool NaomiNetwork::startNetwork()
|
|||
break;
|
||||
std::this_thread::sleep_for(milliseconds(20));
|
||||
}
|
||||
enableNetworkBroadcast(false);
|
||||
if (!slaves.empty())
|
||||
{
|
||||
NOTICE_LOG(NETWORK, "Master starting: %zd slaves", slaves.size());
|
||||
|
|
|
@ -50,6 +50,7 @@ public:
|
|||
|
||||
void shutdown()
|
||||
{
|
||||
enableNetworkBroadcast(false);
|
||||
emu.setNetworkState(false);
|
||||
closesocket(sock);
|
||||
sock = INVALID_SOCKET;
|
||||
|
|
|
@ -125,3 +125,9 @@ static inline const char *inet_ntop(int af, const void* src, char* dst, int cnt)
|
|||
return dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__) && !defined(LIBRETRO)
|
||||
void enableNetworkBroadcast(bool enable);
|
||||
#else
|
||||
static inline void enableNetworkBroadcast(bool enable) {}
|
||||
#endif
|
||||
|
|
|
@ -90,7 +90,9 @@ struct MaxSpeedNetPipe : public SerialPipe
|
|||
return true;
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
void shutdown()
|
||||
{
|
||||
enableNetworkBroadcast(false);
|
||||
if (VALID(sock))
|
||||
closesocket(sock);
|
||||
sock = INVALID_SOCKET;
|
||||
|
@ -174,6 +176,7 @@ private:
|
|||
{
|
||||
peerAddress.sin_addr.s_addr = addr.sin_addr.s_addr;
|
||||
peerAddress.sin_port = addr.sin_port;
|
||||
enableNetworkBroadcast(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -235,6 +238,8 @@ private:
|
|||
freeaddrinfo(resultAddr);
|
||||
}
|
||||
}
|
||||
else
|
||||
enableNetworkBroadcast(true);
|
||||
|
||||
serial_setPipe(this);
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ void flycast_term()
|
|||
lua::term();
|
||||
emu.term();
|
||||
gui_term();
|
||||
os_TermInput();
|
||||
}
|
||||
|
||||
void dc_savestate(int index)
|
||||
|
|
|
@ -10,6 +10,7 @@ double os_GetSeconds();
|
|||
void os_DoEvents();
|
||||
void os_CreateWindow();
|
||||
void os_SetupInput();
|
||||
void os_TermInput();
|
||||
void os_InstallFaultHandler();
|
||||
void os_UninstallFaultHandler();
|
||||
|
||||
|
|
|
@ -692,9 +692,7 @@ void gdrom_hle_op()
|
|||
discType = 0;
|
||||
break;
|
||||
default:
|
||||
if (gd_hle_state.status == GDC_BUSY)
|
||||
status = GD_STAT_BUSY;
|
||||
else if (gd_hle_state.status == GDC_CONTINUE || SecNumber.Status == GD_PLAY)
|
||||
if (gd_hle_state.status == GDC_CONTINUE || SecNumber.Status == GD_PLAY)
|
||||
status = GD_STAT_PLAY;
|
||||
else
|
||||
status = GD_STAT_PAUSE;
|
||||
|
|
|
@ -198,8 +198,7 @@ static void reios_sys_system() {
|
|||
debugf("reios_sys_system: SYSINFO_INIT");
|
||||
// 0x00-0x07: system_id
|
||||
// 0x08-0x0c: system_props
|
||||
// 0x0d-0x0f: padding (zeroed out)
|
||||
// 0x10-0x17: settings
|
||||
// 0x0d-0x17: padding (zeroed out)
|
||||
u8 data[24] = {0};
|
||||
|
||||
// read system_id from 0x0001a056
|
||||
|
@ -210,11 +209,6 @@ static void reios_sys_system() {
|
|||
for (u32 i = 0; i < 5; i++)
|
||||
data[8 + i] = flashrom->Read8(0x1a000 + i);
|
||||
|
||||
// system settings
|
||||
flash_syscfg_block syscfg{};
|
||||
verify(static_cast<DCFlashChip*>(flashrom)->ReadBlock(FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg));
|
||||
memcpy(&data[16], &syscfg.time_lo, 8);
|
||||
|
||||
memcpy(GetMemPtr(0x8c000068, sizeof(data)), data, sizeof(data));
|
||||
|
||||
p_sh4rcb->cntx.r[0] = 0;
|
||||
|
@ -308,7 +302,7 @@ static void reios_sys_flashrom() {
|
|||
r5 = pointer to destination buffer
|
||||
r6 = number of bytes to read
|
||||
Returns:
|
||||
r0 = number of read bytes if successful, -1 if read failed
|
||||
r0 = 0 if successful, -1 if read failed
|
||||
*/
|
||||
u32 offset = p_sh4rcb->cntx.r[4];
|
||||
u32 dest = p_sh4rcb->cntx.r[5];
|
||||
|
@ -318,7 +312,7 @@ static void reios_sys_flashrom() {
|
|||
for (u32 i = 0; i < size; i++)
|
||||
WriteMem8(dest++, flashrom->Read8(offset + i));
|
||||
|
||||
p_sh4rcb->cntx.r[0] = size;
|
||||
p_sh4rcb->cntx.r[0] = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <mutex>
|
||||
#include <xxhash.h>
|
||||
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
|
@ -28,7 +28,6 @@ float fb_scale_x, fb_scale_y;
|
|||
const std::array<f32, 16> D_Adjust_LoD_Bias = {
|
||||
0.f, -4.f, -2.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f
|
||||
};
|
||||
static void rend_text_invl(vram_block* bl);
|
||||
|
||||
u32 detwiddle[2][11][1024];
|
||||
//input : address in the yyyyyxxxxx format
|
||||
|
@ -214,39 +213,6 @@ void vramlock_list_add(vram_block* block)
|
|||
|
||||
std::mutex vramlist_lock;
|
||||
|
||||
void libCore_vramlock_Lock(u32 start_offset64, u32 end_offset64, BaseTextureCacheData *texture)
|
||||
{
|
||||
if (end_offset64 > VRAM_SIZE - 1)
|
||||
{
|
||||
WARN_LOG(PVR, "vramlock_Lock_64: end_offset64>(VRAM_SIZE-1) \n Tried to lock area out of vram , possibly bug on the pvr plugin");
|
||||
end_offset64 = VRAM_SIZE - 1;
|
||||
}
|
||||
|
||||
if (start_offset64 > end_offset64)
|
||||
{
|
||||
WARN_LOG(PVR, "vramlock_Lock_64: start_offset64>end_offset64 \n Tried to lock negative block , possibly bug on the pvr plugin");
|
||||
return;
|
||||
}
|
||||
|
||||
vram_block *block = new vram_block();
|
||||
block->end = end_offset64;
|
||||
block->start = start_offset64;
|
||||
block->texture = texture;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(vramlist_lock);
|
||||
|
||||
if (texture->lock_block == nullptr)
|
||||
{
|
||||
// This also protects vram if needed
|
||||
vramlock_list_add(block);
|
||||
texture->lock_block = block;
|
||||
}
|
||||
else
|
||||
delete block;
|
||||
}
|
||||
}
|
||||
|
||||
bool VramLockedWriteOffset(size_t offset)
|
||||
{
|
||||
if (offset >= VRAM_SIZE)
|
||||
|
@ -262,7 +228,7 @@ bool VramLockedWriteOffset(size_t offset)
|
|||
{
|
||||
if (lock != nullptr)
|
||||
{
|
||||
rend_text_invl(lock);
|
||||
lock->texture->invalidate();
|
||||
|
||||
if (lock != nullptr)
|
||||
{
|
||||
|
@ -295,7 +261,7 @@ static void libCore_vramlock_Unlock_block_wb(vram_block* block)
|
|||
delete block;
|
||||
}
|
||||
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
static inline int getThreadCount()
|
||||
{
|
||||
int tcount = omp_get_num_procs() - 1;
|
||||
|
@ -324,7 +290,7 @@ static struct xbrz::ScalerCfg xbrz_cfg;
|
|||
|
||||
void UpscalexBRZ(int factor, u32* source, u32* dest, int width, int height, bool has_alpha)
|
||||
{
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
parallelize([=](int start, int end) {
|
||||
xbrz::scale(factor, source, dest, width, height, has_alpha ? xbrz::ColorFormat::ARGB : xbrz::ColorFormat::RGB,
|
||||
xbrz_cfg, start, end);
|
||||
|
@ -445,25 +411,66 @@ bool BaseTextureCacheData::NeedsUpdate() {
|
|||
return rc;
|
||||
}
|
||||
|
||||
void BaseTextureCacheData::protectVRam()
|
||||
{
|
||||
u32 end = sa + size - 1;
|
||||
if (end >= VRAM_SIZE)
|
||||
{
|
||||
WARN_LOG(PVR, "protectVRam: end >= VRAM_SIZE. Tried to lock area out of vram");
|
||||
end = VRAM_SIZE - 1;
|
||||
}
|
||||
|
||||
if (sa_tex > end)
|
||||
{
|
||||
WARN_LOG(PVR, "vramlock_Lock: sa_tex > end. Tried to lock negative block");
|
||||
return;
|
||||
}
|
||||
|
||||
vram_block *block = new vram_block();
|
||||
block->end = end;
|
||||
block->start = sa_tex;
|
||||
block->texture = this;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(vramlist_lock);
|
||||
|
||||
if (lock_block == nullptr)
|
||||
{
|
||||
// This also protects vram if needed
|
||||
vramlock_list_add(block);
|
||||
lock_block = block;
|
||||
}
|
||||
else
|
||||
delete block;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseTextureCacheData::unprotectVRam()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(vramlist_lock);
|
||||
if (lock_block)
|
||||
libCore_vramlock_Unlock_block_wb(lock_block);
|
||||
lock_block = nullptr;
|
||||
}
|
||||
|
||||
bool BaseTextureCacheData::Delete()
|
||||
{
|
||||
if (custom_load_in_progress > 0)
|
||||
return false;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(vramlist_lock);
|
||||
if (lock_block)
|
||||
libCore_vramlock_Unlock_block_wb(lock_block);
|
||||
lock_block = nullptr;
|
||||
}
|
||||
unprotectVRam();
|
||||
|
||||
free(custom_image_data);
|
||||
custom_image_data = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BaseTextureCacheData::Create()
|
||||
BaseTextureCacheData::BaseTextureCacheData(TSP tsp, TCW tcw)
|
||||
{
|
||||
this->tsp = tsp;
|
||||
this->tcw = tcw;
|
||||
|
||||
//Reset state info ..
|
||||
Updates = 0;
|
||||
dirty = FrameCount;
|
||||
|
@ -777,7 +784,7 @@ void BaseTextureCacheData::Update()
|
|||
height = original_h;
|
||||
|
||||
//lock the texture to detect changes in it
|
||||
libCore_vramlock_Lock(sa_tex, sa + size - 1, this);
|
||||
protectVRam();
|
||||
|
||||
UploadToGPU(upscaled_w, upscaled_h, (u8*)temp_tex_buffer, IsMipmapped(), mipmapped);
|
||||
if (config::DumpTextures)
|
||||
|
@ -931,14 +938,9 @@ template void ReadFramebuffer<RGBAPacker>(PixelBuffer<u32>& pb, int& width, int&
|
|||
template void ReadFramebuffer<BGRAPacker>(PixelBuffer<u32>& pb, int& width, int& height);
|
||||
|
||||
template<int Red, int Green, int Blue, int Alpha>
|
||||
void WriteTextureToVRam(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl_in, u32 linestride)
|
||||
void WriteTextureToVRam(u32 width, u32 height, u8 *data, u16 *dst, FB_W_CTRL_type fb_w_ctrl, u32 linestride)
|
||||
{
|
||||
FB_W_CTRL_type fb_w_ctrl;
|
||||
if (fb_w_ctrl_in != ~0u)
|
||||
fb_w_ctrl.full = fb_w_ctrl_in;
|
||||
else
|
||||
fb_w_ctrl = FB_W_CTRL;
|
||||
u32 padding = (linestride == ~0u ? FB_W_LINESTRIDE.stride * 8 : linestride);
|
||||
u32 padding = linestride;
|
||||
if (padding / 2 > width)
|
||||
padding = padding / 2 - width;
|
||||
else
|
||||
|
@ -980,16 +982,33 @@ void WriteTextureToVRam(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl
|
|||
dst += padding;
|
||||
}
|
||||
}
|
||||
template void WriteTextureToVRam<0, 1, 2, 3>(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl_in, u32 linestride);
|
||||
template void WriteTextureToVRam<2, 1, 0, 3>(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl_in, u32 linestride);
|
||||
template void WriteTextureToVRam<0, 1, 2, 3>(u32 width, u32 height, u8 *data, u16 *dst, FB_W_CTRL_type fb_w_ctrl, u32 linestride);
|
||||
template void WriteTextureToVRam<2, 1, 0, 3>(u32 width, u32 height, u8 *data, u16 *dst, FB_W_CTRL_type fb_w_ctrl, u32 linestride);
|
||||
|
||||
static void rend_text_invl(vram_block* bl)
|
||||
void BaseTextureCacheData::invalidate()
|
||||
{
|
||||
BaseTextureCacheData* texture = bl->texture;
|
||||
texture->dirty = FrameCount;
|
||||
texture->lock_block = nullptr;
|
||||
dirty = FrameCount;
|
||||
|
||||
libCore_vramlock_Unlock_block_wb(bl);
|
||||
libCore_vramlock_Unlock_block_wb(lock_block);
|
||||
lock_block = nullptr;
|
||||
}
|
||||
|
||||
void getRenderToTextureDimensions(u32& width, u32& height, u32& pow2Width, u32& pow2Height)
|
||||
{
|
||||
pow2Width = 8;
|
||||
while (pow2Width < width)
|
||||
pow2Width *= 2;
|
||||
pow2Height = 8;
|
||||
while (pow2Height < height)
|
||||
pow2Height *= 2;
|
||||
if (!config::RenderToTextureBuffer)
|
||||
{
|
||||
float upscale = config::RenderResolution / 480.f;
|
||||
width *= upscale;
|
||||
height *= upscale;
|
||||
pow2Width *= upscale;
|
||||
pow2Height *= upscale;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_AUTOMATION
|
||||
|
|
|
@ -564,7 +564,6 @@ struct vram_block
|
|||
|
||||
bool VramLockedWriteOffset(size_t offset);
|
||||
bool VramLockedWrite(u8* address);
|
||||
void libCore_vramlock_Lock(u32 start_offset, u32 end_offset, BaseTextureCacheData *texture);
|
||||
|
||||
void UpscalexBRZ(int factor, u32* source, u32* dest, int width, int height, bool has_alpha);
|
||||
|
||||
|
@ -573,7 +572,37 @@ enum class TextureType { _565, _5551, _4444, _8888, _8 };
|
|||
|
||||
class BaseTextureCacheData
|
||||
{
|
||||
protected:
|
||||
BaseTextureCacheData(TSP tsp, TCW tcw);
|
||||
|
||||
public:
|
||||
BaseTextureCacheData(BaseTextureCacheData&& other)
|
||||
{
|
||||
tsp = other.tsp;
|
||||
tcw = other.tcw;
|
||||
tex_type = other.tex_type;
|
||||
sa_tex = other.sa_tex;
|
||||
dirty = other.dirty;
|
||||
std::swap(lock_block, other.lock_block);
|
||||
sa = other.sa;
|
||||
width = other.width;
|
||||
height = other.height;
|
||||
size = other.size;
|
||||
tex = other.tex;
|
||||
texconv = other.texconv;
|
||||
texconv32 = other.texconv32;
|
||||
texconv8 = other.texconv8;
|
||||
Updates = other.Updates;
|
||||
palette_hash = other.palette_hash;
|
||||
texture_hash = other.texture_hash;
|
||||
old_texture_hash = other.old_texture_hash;
|
||||
std::swap(custom_image_data, other.custom_image_data);
|
||||
custom_width = other.custom_width;
|
||||
custom_height = other.custom_height;
|
||||
custom_load_in_progress = 0;
|
||||
gpuPalette = other.gpuPalette;
|
||||
}
|
||||
|
||||
TSP tsp; //dreamcast texture parameters
|
||||
TCW tcw;
|
||||
|
||||
|
@ -638,7 +667,6 @@ public:
|
|||
return custom_load_in_progress == 0 && custom_image_data != NULL;
|
||||
}
|
||||
|
||||
void Create();
|
||||
void ComputeHash();
|
||||
void Update();
|
||||
virtual void UploadToGPU(int width, int height, u8 *temp_tex_buffer, bool mipmapped, bool mipmapsIncluded = false) = 0;
|
||||
|
@ -648,6 +676,10 @@ public:
|
|||
bool NeedsUpdate();
|
||||
virtual bool Delete();
|
||||
virtual ~BaseTextureCacheData() = default;
|
||||
void protectVRam();
|
||||
void unprotectVRam();
|
||||
void invalidate();
|
||||
|
||||
static bool IsGpuHandledPaletted(TSP tsp, TCW tcw)
|
||||
{
|
||||
// Some palette textures are handled on the GPU
|
||||
|
@ -692,15 +724,36 @@ public:
|
|||
}
|
||||
else //create if not existing
|
||||
{
|
||||
texture = &cache[key];
|
||||
|
||||
texture->tsp = tsp;
|
||||
texture->tcw = tcw;
|
||||
texture = &cache.emplace(std::make_pair(key, Texture(tsp, tcw))).first->second;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
Texture *getRTTexture(u32 address, u32 fb_packmode, u32 width, u32 height)
|
||||
{
|
||||
// TexAddr : (address), Reserved : 0, StrideSel : 0, ScanOrder : 1
|
||||
TCW tcw{ { address >> 3, 0, 0, 1 } };
|
||||
switch (fb_packmode)
|
||||
{
|
||||
case 0:
|
||||
case 3:
|
||||
tcw.PixelFmt = Pixel1555;
|
||||
break;
|
||||
case 1:
|
||||
tcw.PixelFmt = Pixel565;
|
||||
break;
|
||||
case 2:
|
||||
tcw.PixelFmt = Pixel4444;
|
||||
break;
|
||||
}
|
||||
TSP tsp{};
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8u << tsp.TexU) < width; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8u << tsp.TexV) < height; tsp.TexV++);
|
||||
|
||||
return getTextureCacheData(tsp, tcw);
|
||||
}
|
||||
|
||||
void CollectCleanup()
|
||||
{
|
||||
std::vector<u64> list;
|
||||
|
@ -718,7 +771,7 @@ public:
|
|||
|
||||
for (u64 id : list)
|
||||
{
|
||||
if (cache[id].Delete())
|
||||
if (cache.find(id)->second.Delete())
|
||||
cache.erase(id);
|
||||
}
|
||||
}
|
||||
|
@ -745,7 +798,8 @@ protected:
|
|||
template<typename Packer = RGBAPacker>
|
||||
void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height);
|
||||
template<int Red = 0, int Green = 1, int Blue = 2, int Alpha = 3>
|
||||
void WriteTextureToVRam(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl = -1, u32 linestride = -1);
|
||||
void WriteTextureToVRam(u32 width, u32 height, u8 *data, u16 *dst, FB_W_CTRL_type fb_w_ctrl, u32 linestride);
|
||||
void getRenderToTextureDimensions(u32& width, u32& height, u32& pow2Width, u32& pow2Height);
|
||||
|
||||
static inline void MakeFogTexture(u8 *tex_data)
|
||||
{
|
||||
|
|
|
@ -282,9 +282,6 @@ BaseTextureCacheData *DX11Renderer::GetTexture(TSP tsp, TCW tcw)
|
|||
//lookup texture
|
||||
DX11Texture* tf = texCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
if (tf->texture == nullptr)
|
||||
tf->Create();
|
||||
|
||||
//update if needed
|
||||
if (tf->NeedsUpdate())
|
||||
tf->Update();
|
||||
|
@ -325,7 +322,7 @@ void DX11Renderer::configVertexShader()
|
|||
|
||||
if (pvrrc.isRTT)
|
||||
{
|
||||
prepareRttRenderTarget(FB_W_SOF1 & VRAM_MASK);
|
||||
prepareRttRenderTarget(pvrrc.fb_W_SOF1 & VRAM_MASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -416,8 +413,6 @@ void DX11Renderer::setupPixelShaderConstants()
|
|||
|
||||
bool DX11Renderer::Render()
|
||||
{
|
||||
u32 texAddress = FB_W_SOF1 & VRAM_MASK;
|
||||
|
||||
// make sure to unbind the framebuffer view before setting it as render target
|
||||
ID3D11ShaderResourceView *nullView = nullptr;
|
||||
deviceContext->PSSetShaderResources(0, 1, &nullView);
|
||||
|
@ -450,7 +445,7 @@ bool DX11Renderer::Render()
|
|||
|
||||
if (is_rtt)
|
||||
{
|
||||
readRttRenderTarget(texAddress);
|
||||
readRttRenderTarget(pvrrc.fb_W_SOF1 & VRAM_MASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1047,21 +1042,11 @@ void DX11Renderer::prepareRttRenderTarget(u32 texAddress)
|
|||
u32 fbw = pvrrc.getFramebufferWidth();
|
||||
u32 fbh = pvrrc.getFramebufferHeight();
|
||||
DEBUG_LOG(RENDERER, "RTT packmode=%d stride=%d - %d x %d @ %06x",
|
||||
FB_W_CTRL.fb_packmode, pvrrc.fb_W_LINESTRIDE * 8, fbw, fbh, texAddress);
|
||||
// Find the smallest power of two texture that fits the viewport
|
||||
u32 fbh2 = 2;
|
||||
while (fbh2 < fbh)
|
||||
fbh2 *= 2;
|
||||
u32 fbw2 = 2;
|
||||
while (fbw2 < fbw)
|
||||
fbw2 *= 2;
|
||||
if (!config::RenderToTextureBuffer)
|
||||
{
|
||||
fbw = (u32)(fbw * config::RenderResolution / 480.f);
|
||||
fbh = (u32)(fbh * config::RenderResolution / 480.f);
|
||||
fbw2 = (u32)(fbw2 * config::RenderResolution / 480.f);
|
||||
fbh2 = (u32)(fbh2 * config::RenderResolution / 480.f);
|
||||
}
|
||||
pvrrc.fb_W_CTRL.fb_packmode, pvrrc.fb_W_LINESTRIDE * 8, fbw, fbh, texAddress);
|
||||
u32 fbw2;
|
||||
u32 fbh2;
|
||||
getRenderToTextureDimensions(fbw, fbh, fbw2, fbh2);
|
||||
|
||||
createTexAndRenderTarget(rttTexture, rttRenderTarget, fbw2, fbh2);
|
||||
createDepthTexAndView(rttDepthTex, rttDepthTexView, fbw2, fbh2);
|
||||
deviceContext->ClearDepthStencilView(rttDepthTexView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.f, 0);
|
||||
|
@ -1080,7 +1065,6 @@ void DX11Renderer::readRttRenderTarget(u32 texAddress)
|
|||
{
|
||||
u32 w = pvrrc.getFramebufferWidth();
|
||||
u32 h = pvrrc.getFramebufferHeight();
|
||||
const u8 fb_packmode = FB_W_CTRL.fb_packmode;
|
||||
if (config::RenderToTextureBuffer)
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
|
@ -1125,37 +1109,14 @@ void DX11Renderer::readRttRenderTarget(u32 texAddress)
|
|||
deviceContext->Unmap(stagingTex, 0);
|
||||
|
||||
u16 *dst = (u16 *)&vram[texAddress];
|
||||
WriteTextureToVRam<2, 1, 0, 3>(w, h, (u8 *)tmp_buf.data(), dst, -1, pvrrc.fb_W_LINESTRIDE * 8);
|
||||
WriteTextureToVRam<2, 1, 0, 3>(w, h, (u8 *)tmp_buf.data(), dst, pvrrc.fb_W_CTRL, pvrrc.fb_W_LINESTRIDE * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
//memset(&vram[gl.rtt.texAddress], 0, size);
|
||||
if (w <= 1024 && h <= 1024)
|
||||
{
|
||||
// TexAddr : (address), Reserved : 0, StrideSel : 0, ScanOrder : 1
|
||||
TCW tcw = { { texAddress >> 3, 0, 0, 1 } };
|
||||
switch (fb_packmode) {
|
||||
case 0:
|
||||
case 3:
|
||||
tcw.PixelFmt = Pixel1555;
|
||||
break;
|
||||
case 1:
|
||||
tcw.PixelFmt = Pixel565;
|
||||
break;
|
||||
case 2:
|
||||
tcw.PixelFmt = Pixel4444;
|
||||
break;
|
||||
}
|
||||
TSP tsp = { 0 };
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8u << tsp.TexU) < w; tsp.TexU++)
|
||||
;
|
||||
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8u << tsp.TexV) < h; tsp.TexV++)
|
||||
;
|
||||
|
||||
DX11Texture* texture = texCache.getTextureCacheData(tsp, tcw);
|
||||
if (!texture->texture)
|
||||
texture->Create();
|
||||
DX11Texture* texture = texCache.getRTTexture(texAddress, pvrrc.fb_W_CTRL.fb_packmode, w, h);
|
||||
|
||||
texture->texture = rttTexture;
|
||||
rttTexture.reset();
|
||||
|
@ -1168,7 +1129,7 @@ void DX11Renderer::readRttRenderTarget(u32 texAddress)
|
|||
device->CreateShaderResourceView(texture->texture, &viewDesc, &texture->textureView.get());
|
||||
|
||||
texture->dirty = 0;
|
||||
libCore_vramlock_Lock(texture->sa_tex, texture->sa + texture->size - 1, texture);
|
||||
texture->protectVRam();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,12 @@
|
|||
class DX11Texture final : public BaseTextureCacheData
|
||||
{
|
||||
public:
|
||||
DX11Texture(TSP tsp = {}, TCW tcw = {}) : BaseTextureCacheData(tsp, tcw) {}
|
||||
DX11Texture(DX11Texture&& other) : BaseTextureCacheData(std::move(other)) {
|
||||
std::swap(texture, other.texture);
|
||||
std::swap(textureView, other.textureView);
|
||||
}
|
||||
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
ComPtr<ID3D11ShaderResourceView> textureView;
|
||||
|
||||
|
|
|
@ -126,6 +126,8 @@ struct DX11OITRenderer : public DX11Renderer
|
|||
depthView.reset();
|
||||
viewDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
|
||||
device->CreateShaderResourceView(depthStencilTex2, &viewDesc, &depthView.get());
|
||||
|
||||
createDepthTexAndView(depthTex, depthTexView, maxWidth, maxHeight, DXGI_FORMAT_R32G8X24_TYPELESS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -635,11 +637,10 @@ struct DX11OITRenderer : public DX11Renderer
|
|||
ID3D11ShaderResourceView *p = nullptr;
|
||||
deviceContext->PSSetShaderResources(0, 1, &p);
|
||||
// To avoid DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET warnings
|
||||
deviceContext->OMSetRenderTargets(1, &fbRenderTarget.get(), depthTexView);
|
||||
deviceContext->OMSetRenderTargets(1, &fbRenderTarget.get(), nullptr);
|
||||
configVertexShader();
|
||||
|
||||
bool is_rtt = pvrrc.isRTT;
|
||||
u32 texAddress = FB_W_SOF1 & VRAM_MASK;
|
||||
|
||||
deviceContext->IASetInputLayout(mainInputLayout);
|
||||
|
||||
|
@ -662,7 +663,7 @@ struct DX11OITRenderer : public DX11Renderer
|
|||
|
||||
if (is_rtt)
|
||||
{
|
||||
readRttRenderTarget(texAddress);
|
||||
readRttRenderTarget(pvrrc.fb_W_SOF1 & VRAM_MASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -218,9 +218,6 @@ BaseTextureCacheData *D3DRenderer::GetTexture(TSP tsp, TCW tcw)
|
|||
//lookup texture
|
||||
D3DTexture* tf = texCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
if (tf->texture == nullptr)
|
||||
tf->Create();
|
||||
|
||||
//update if needed
|
||||
if (tf->NeedsUpdate())
|
||||
tf->Update();
|
||||
|
@ -868,21 +865,11 @@ void D3DRenderer::prepareRttRenderTarget(u32 texAddress)
|
|||
u32 fbw = pvrrc.getFramebufferWidth();
|
||||
u32 fbh = pvrrc.getFramebufferHeight();
|
||||
DEBUG_LOG(RENDERER, "RTT packmode=%d stride=%d - %d x %d @ %06x",
|
||||
FB_W_CTRL.fb_packmode, pvrrc.fb_W_LINESTRIDE * 8, fbw, fbh, texAddress);
|
||||
// Find the smallest power of two texture that fits the viewport
|
||||
u32 fbh2 = 2;
|
||||
while (fbh2 < fbh)
|
||||
fbh2 *= 2;
|
||||
u32 fbw2 = 2;
|
||||
while (fbw2 < fbw)
|
||||
fbw2 *= 2;
|
||||
if (!config::RenderToTextureBuffer)
|
||||
{
|
||||
fbw = (u32)(fbw * config::RenderResolution / 480.f);
|
||||
fbh = (u32)(fbh * config::RenderResolution / 480.f);
|
||||
fbw2 = (u32)(fbw2 * config::RenderResolution / 480.f);
|
||||
fbh2 = (u32)(fbh2 * config::RenderResolution / 480.f);
|
||||
}
|
||||
pvrrc.fb_W_CTRL.fb_packmode, pvrrc.fb_W_LINESTRIDE * 8, fbw, fbh, texAddress);
|
||||
u32 fbw2;
|
||||
u32 fbh2;
|
||||
getRenderToTextureDimensions(fbw, fbh, fbw2, fbh2);
|
||||
|
||||
rttTexture.reset();
|
||||
device->CreateTexture(fbw2, fbh2, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &rttTexture.get(), NULL);
|
||||
|
||||
|
@ -903,7 +890,6 @@ void D3DRenderer::readRttRenderTarget(u32 texAddress)
|
|||
{
|
||||
u32 w = pvrrc.getFramebufferWidth();
|
||||
u32 h = pvrrc.getFramebufferHeight();
|
||||
const u8 fb_packmode = FB_W_CTRL.fb_packmode;
|
||||
if (config::RenderToTextureBuffer)
|
||||
{
|
||||
D3DSURFACE_DESC rttDesc;
|
||||
|
@ -934,41 +920,17 @@ void D3DRenderer::readRttRenderTarget(u32 texAddress)
|
|||
verifyWin(offscreenSurface->UnlockRect());
|
||||
|
||||
u16 *dst = (u16 *)&vram[texAddress];
|
||||
WriteTextureToVRam<2, 1, 0, 3>(w, h, (u8 *)tmp_buf.data(), dst, -1, pvrrc.fb_W_LINESTRIDE * 8);
|
||||
WriteTextureToVRam<2, 1, 0, 3>(w, h, (u8 *)tmp_buf.data(), dst, pvrrc.fb_W_CTRL, pvrrc.fb_W_LINESTRIDE * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
//memset(&vram[gl.rtt.texAddress], 0, size);
|
||||
if (w <= 1024 && h <= 1024)
|
||||
{
|
||||
// TexAddr : (address), Reserved : 0, StrideSel : 0, ScanOrder : 1
|
||||
TCW tcw = { { texAddress >> 3, 0, 0, 1 } };
|
||||
switch (fb_packmode) {
|
||||
case 0:
|
||||
case 3:
|
||||
tcw.PixelFmt = Pixel1555;
|
||||
break;
|
||||
case 1:
|
||||
tcw.PixelFmt = Pixel565;
|
||||
break;
|
||||
case 2:
|
||||
tcw.PixelFmt = Pixel4444;
|
||||
break;
|
||||
}
|
||||
TSP tsp = { 0 };
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8u << tsp.TexU) < w; tsp.TexU++)
|
||||
;
|
||||
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8u << tsp.TexV) < h; tsp.TexV++)
|
||||
;
|
||||
|
||||
D3DTexture* texture = texCache.getTextureCacheData(tsp, tcw);
|
||||
if (!texture->texture)
|
||||
texture->Create();
|
||||
|
||||
D3DTexture* texture = texCache.getRTTexture(texAddress, pvrrc.fb_W_CTRL.fb_packmode, w, h);
|
||||
texture->texture = rttTexture;
|
||||
texture->dirty = 0;
|
||||
libCore_vramlock_Lock(texture->sa_tex, texture->sa + texture->size - 1, texture);
|
||||
texture->protectVRam();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -981,7 +943,7 @@ bool D3DRenderer::Render()
|
|||
|
||||
backbuffer.reset();
|
||||
verifyWin(device->GetRenderTarget(0, &backbuffer.get()));
|
||||
u32 texAddress = FB_W_SOF1 & VRAM_MASK;
|
||||
u32 texAddress = pvrrc.fb_W_SOF1 & VRAM_MASK;
|
||||
if (is_rtt)
|
||||
{
|
||||
prepareRttRenderTarget(texAddress);
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
class D3DTexture final : public BaseTextureCacheData
|
||||
{
|
||||
public:
|
||||
D3DTexture(TSP tsp = {}, TCW tcw = {}) : BaseTextureCacheData(tsp, tcw) {}
|
||||
D3DTexture(D3DTexture&& other) : BaseTextureCacheData(std::move(other)) {
|
||||
std::swap(texture, other.texture);
|
||||
}
|
||||
|
||||
ComPtr<IDirect3DTexture9> texture;
|
||||
std::string GetId() override { return std::to_string((uintptr_t)texture.get()); }
|
||||
void UploadToGPU(int width, int height, u8* temp_tex_buffer, bool mipmapped,
|
||||
|
|
|
@ -209,7 +209,7 @@ struct gl_ctx
|
|||
bool directXfer;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 fb_w_ctrl;
|
||||
FB_W_CTRL_type fb_w_ctrl;
|
||||
u32 linestride;
|
||||
} rtt;
|
||||
|
||||
|
@ -337,6 +337,12 @@ extern struct ShaderUniforms_t
|
|||
class TextureCacheData final : public BaseTextureCacheData
|
||||
{
|
||||
public:
|
||||
TextureCacheData(TSP tsp, TCW tcw) : BaseTextureCacheData(tsp, tcw), texID(glcache.GenTexture()) {
|
||||
}
|
||||
TextureCacheData(TextureCacheData&& other) : BaseTextureCacheData(std::move(other)) {
|
||||
std::swap(texID, other.texID);
|
||||
}
|
||||
|
||||
GLuint texID; //gl texture
|
||||
std::string GetId() override { return std::to_string(texID); }
|
||||
void UploadToGPU(int width, int height, u8 *temp_tex_buffer, bool mipmapped, bool mipmapsIncluded = false) override;
|
||||
|
|
|
@ -123,7 +123,7 @@ bool TextureCacheData::Delete()
|
|||
GLuint BindRTT(bool withDepthBuffer)
|
||||
{
|
||||
GLenum channels, format;
|
||||
switch(FB_W_CTRL.fb_packmode)
|
||||
switch(pvrrc.fb_W_CTRL.fb_packmode)
|
||||
{
|
||||
case 0: //0x0 0555 KRGB 16 bit (default) Bit 15 is the value of fb_kval[7].
|
||||
channels = GL_RGBA;
|
||||
|
@ -148,7 +148,7 @@ GLuint BindRTT(bool withDepthBuffer)
|
|||
case 4: //0x4 888 RGB 24 bit packed
|
||||
case 5: //0x5 0888 KRGB 32 bit K is the value of fk_kval.
|
||||
case 6: //0x6 8888 ARGB 32 bit
|
||||
WARN_LOG(RENDERER, "Unsupported render to texture format: %d", FB_W_CTRL.fb_packmode);
|
||||
WARN_LOG(RENDERER, "Unsupported render to texture format: %d", pvrrc.fb_W_CTRL.fb_packmode);
|
||||
return 0;
|
||||
|
||||
case 7: //7 invalid
|
||||
|
@ -157,8 +157,8 @@ GLuint BindRTT(bool withDepthBuffer)
|
|||
}
|
||||
u32 fbw = pvrrc.getFramebufferWidth();
|
||||
u32 fbh = pvrrc.getFramebufferHeight();
|
||||
u32 texAddress = FB_W_SOF1 & VRAM_MASK;
|
||||
DEBUG_LOG(RENDERER, "RTT packmode=%d stride=%d - %d x %d @ %06x", FB_W_CTRL.fb_packmode, pvrrc.fb_W_LINESTRIDE * 8,
|
||||
u32 texAddress = pvrrc.fb_W_SOF1 & VRAM_MASK;
|
||||
DEBUG_LOG(RENDERER, "RTT packmode=%d stride=%d - %d x %d @ %06x", pvrrc.fb_W_CTRL.fb_packmode, pvrrc.fb_W_LINESTRIDE * 8,
|
||||
fbw, fbh, texAddress);
|
||||
|
||||
if (gl.rtt.texAddress != ~0u)
|
||||
|
@ -172,20 +172,9 @@ GLuint BindRTT(bool withDepthBuffer)
|
|||
if (gl.rtt.depthb != 0)
|
||||
glDeleteRenderbuffers(1, &gl.rtt.depthb);
|
||||
|
||||
// Find the smallest power of two texture that fits the viewport
|
||||
u32 fbh2 = 2;
|
||||
while (fbh2 < fbh)
|
||||
fbh2 *= 2;
|
||||
u32 fbw2 = 2;
|
||||
while (fbw2 < fbw)
|
||||
fbw2 *= 2;
|
||||
if (!config::RenderToTextureBuffer)
|
||||
{
|
||||
fbw *= config::RenderResolution / 480.f;
|
||||
fbh *= config::RenderResolution / 480.f;
|
||||
fbw2 *= config::RenderResolution / 480.f;
|
||||
fbh2 *= config::RenderResolution / 480.f;
|
||||
}
|
||||
u32 fbw2;
|
||||
u32 fbh2;
|
||||
getRenderToTextureDimensions(fbw, fbh, fbw2, fbh2);
|
||||
|
||||
#ifdef GL_PIXEL_PACK_BUFFER
|
||||
if (gl.gl_major >= 3 && config::RenderToTextureBuffer)
|
||||
|
@ -269,7 +258,7 @@ void ReadRTTBuffer()
|
|||
u32 w = pvrrc.getFramebufferWidth();
|
||||
u32 h = pvrrc.getFramebufferHeight();
|
||||
|
||||
const u8 fb_packmode = FB_W_CTRL.fb_packmode;
|
||||
const u8 fb_packmode = pvrrc.fb_W_CTRL.fb_packmode;
|
||||
|
||||
if (config::RenderToTextureBuffer)
|
||||
{
|
||||
|
@ -313,7 +302,7 @@ void ReadRTTBuffer()
|
|||
gl.rtt.directXfer = false;
|
||||
if (gl.gl_major >= 3)
|
||||
{
|
||||
gl.rtt.fb_w_ctrl = FB_W_CTRL.full;
|
||||
gl.rtt.fb_w_ctrl = pvrrc.fb_W_CTRL;
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
}
|
||||
else
|
||||
|
@ -324,7 +313,7 @@ void ReadRTTBuffer()
|
|||
u8 *p = (u8 *)tmp_buf.data();
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
|
||||
|
||||
WriteTextureToVRam(w, h, p, dst, -1, gl.rtt.linestride);
|
||||
WriteTextureToVRam(w, h, p, dst, pvrrc.fb_W_CTRL, gl.rtt.linestride);
|
||||
gl.rtt.texAddress = ~0;
|
||||
}
|
||||
}
|
||||
|
@ -338,33 +327,12 @@ void ReadRTTBuffer()
|
|||
//memset(&vram[gl.rtt.texAddress], 0, size);
|
||||
if (w <= 1024 && h <= 1024)
|
||||
{
|
||||
// TexAddr : (address), Reserved : 0, StrideSel : 0, ScanOrder : 1
|
||||
TCW tcw = { { gl.rtt.texAddress >> 3, 0, 0, 1 } };
|
||||
switch (fb_packmode) {
|
||||
case 0:
|
||||
case 3:
|
||||
tcw.PixelFmt = Pixel1555;
|
||||
break;
|
||||
case 1:
|
||||
tcw.PixelFmt = Pixel565;
|
||||
break;
|
||||
case 2:
|
||||
tcw.PixelFmt = Pixel4444;
|
||||
break;
|
||||
}
|
||||
TSP tsp = { 0 };
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8u << tsp.TexU) < w; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8u << tsp.TexV) < h; tsp.TexV++);
|
||||
|
||||
TextureCacheData *texture_data = TexCache.getTextureCacheData(tsp, tcw);
|
||||
if (texture_data->texID != 0)
|
||||
glcache.DeleteTextures(1, &texture_data->texID);
|
||||
else
|
||||
texture_data->Create();
|
||||
TextureCacheData *texture_data = TexCache.getRTTexture(gl.rtt.texAddress, fb_packmode, w, h);
|
||||
glcache.DeleteTextures(1, &texture_data->texID);
|
||||
texture_data->texID = gl.rtt.tex;
|
||||
gl.rtt.tex = 0;
|
||||
texture_data->dirty = 0;
|
||||
libCore_vramlock_Lock(texture_data->sa_tex, texture_data->sa + texture_data->size - 1, texture_data);
|
||||
texture_data->protectVRam();
|
||||
}
|
||||
gl.rtt.texAddress = ~0;
|
||||
}
|
||||
|
@ -413,11 +381,6 @@ BaseTextureCacheData *gl_GetTexture(TSP tsp, TCW tcw)
|
|||
//lookup texture
|
||||
TextureCacheData* tf = TexCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
if (tf->texID == 0)
|
||||
{
|
||||
tf->Create();
|
||||
tf->texID = glcache.GenTexture();
|
||||
}
|
||||
readAsyncPixelBuffer(tf->sa_tex);
|
||||
|
||||
//update if needed
|
||||
|
|
|
@ -1908,7 +1908,7 @@ static void gui_display_settings()
|
|||
ImGui::Spacing();
|
||||
header("Texture Upscaling");
|
||||
{
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
OptionArrowButtons("Texture Upscaling", config::TextureUpscale, 1, 8,
|
||||
"Upscale textures with the xBRZ algorithm. Only on fast platforms and for certain 2D games");
|
||||
OptionSlider("Texture Max Size", config::MaxFilteredTextureSize, 8, 1024,
|
||||
|
@ -2100,6 +2100,19 @@ static void gui_display_settings()
|
|||
OptionRadioButton<int>("Full", config::GGPOAnalogAxes, 2, "Use the left thumbstick horizontal and vertical axes");
|
||||
|
||||
OptionCheckbox("Enable Chat", config::GGPOChat, "Open the chat window when a chat message is received");
|
||||
if (config::GGPOChat)
|
||||
{
|
||||
OptionCheckbox("Enable Chat Window Timeout", config::GGPOChatTimeoutToggle, "Automatically close chat window after 20 seconds");
|
||||
if (config::GGPOChatTimeoutToggle)
|
||||
{
|
||||
char chatTimeout[256];
|
||||
sprintf(chatTimeout, "%d", (int)config::GGPOChatTimeout);
|
||||
ImGui::InputText("Chat Window Timeout (seconds)", chatTimeout, sizeof(chatTimeout), ImGuiInputTextFlags_CharsDecimal, nullptr, nullptr);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Sets duration that chat window stays open after new message is received.");
|
||||
config::GGPOChatTimeout.set(atoi(chatTimeout));
|
||||
}
|
||||
}
|
||||
OptionCheckbox("Network Statistics", config::NetworkStats,
|
||||
"Display network statistics on screen");
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "gui.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "network/ggpo.h"
|
||||
#include <chrono>
|
||||
|
||||
class Chat
|
||||
{
|
||||
|
@ -34,6 +35,10 @@ class Chat
|
|||
const ImVec4 WHITE { 1, 1, 1, 1 };
|
||||
const ImVec4 YELLOW { 1, 1, 0, 1 };
|
||||
|
||||
bool manual_open = false;
|
||||
bool enable_timeout = false;
|
||||
std::chrono::steady_clock::time_point launch_time;
|
||||
|
||||
std::string playerName(bool remote)
|
||||
{
|
||||
if (remote)
|
||||
|
@ -43,6 +48,15 @@ class Chat
|
|||
}
|
||||
|
||||
public:
|
||||
void toggle_timeout()
|
||||
{
|
||||
if (config::GGPOChatTimeoutToggle && !manual_open)
|
||||
{
|
||||
enable_timeout = true;
|
||||
launch_time = std::chrono::steady_clock::now();
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
visible = false;
|
||||
|
@ -51,6 +65,16 @@ public:
|
|||
|
||||
void display()
|
||||
{
|
||||
auto timeout = std::chrono::seconds(config::GGPOChatTimeout.get());
|
||||
|
||||
if (enable_timeout &&
|
||||
std::chrono::steady_clock::now() - launch_time > timeout)
|
||||
{
|
||||
visible = false;
|
||||
enable_timeout = false;
|
||||
manual_open = false;
|
||||
}
|
||||
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
|
@ -85,6 +109,7 @@ public:
|
|||
lines.push_back(std::make_pair(WHITE, line));
|
||||
buf[0] = '\0';
|
||||
newMessage = true;
|
||||
enable_timeout = false;
|
||||
}
|
||||
ImGui::SetKeyboardFocusHere(-1);
|
||||
}
|
||||
|
@ -101,17 +126,22 @@ public:
|
|||
|
||||
void receive(int playerNum, const std::string& msg)
|
||||
{
|
||||
if (config::GGPOChat)
|
||||
if (config::GGPOChat && !visible)
|
||||
{
|
||||
visible = true;
|
||||
toggle_timeout();
|
||||
}
|
||||
std::string line = "<" + playerName(true) + "> " + msg;
|
||||
lines.push_back(std::make_pair(YELLOW, line));
|
||||
newMessage = true;
|
||||
}
|
||||
|
||||
void toggle()
|
||||
void toggle(bool manual = false)
|
||||
{
|
||||
visible = !visible;
|
||||
focus = visible;
|
||||
if (manual)
|
||||
manual_open = manual;
|
||||
}
|
||||
|
||||
void setLocalPlayerName(const std::string& name) {
|
||||
|
|
|
@ -170,7 +170,6 @@ void select_file_popup(const char *prompt, StringCallback callback,
|
|||
if (entry->d_type == DT_DIR)
|
||||
is_dir = true;
|
||||
if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK)
|
||||
#endif
|
||||
{
|
||||
struct stat st;
|
||||
if (flycast::stat(child_path.c_str(), &st) != 0)
|
||||
|
@ -178,11 +177,28 @@ void select_file_popup(const char *prompt, StringCallback callback,
|
|||
if (S_ISDIR(st.st_mode))
|
||||
is_dir = true;
|
||||
}
|
||||
if (is_dir && flycast::access(child_path.c_str(), R_OK) == 0)
|
||||
#else // _WIN32
|
||||
nowide::wstackstring wname;
|
||||
if (wname.convert(child_path.c_str()))
|
||||
{
|
||||
DWORD attr = GetFileAttributesW(wname.c_str());
|
||||
if (attr != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
if (attr & FILE_ATTRIBUTE_HIDDEN)
|
||||
continue;
|
||||
if (attr & FILE_ATTRIBUTE_DIRECTORY)
|
||||
is_dir = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (is_dir)
|
||||
{
|
||||
if (name == "..")
|
||||
dotdot_seen = true;
|
||||
subfolders.push_back(name);
|
||||
if (flycast::access(child_path.c_str(), R_OK) == 0)
|
||||
{
|
||||
if (name == "..")
|
||||
dotdot_seen = true;
|
||||
subfolders.push_back(name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -270,7 +286,7 @@ void select_file_popup(const char *prompt, StringCallback callback,
|
|||
#endif
|
||||
child_path = path + native_separator + name;
|
||||
}
|
||||
if (ImGui::Selectable(name.c_str()))
|
||||
if (ImGui::Selectable(name == ".." ? ".. Up to Parent Directory" : name.c_str()))
|
||||
{
|
||||
subfolders_read = false;
|
||||
select_current_directory = child_path;
|
||||
|
|
|
@ -376,26 +376,18 @@ void TextureDrawer::Init(SamplerManager *samplerManager, ShaderManager *shaderMa
|
|||
|
||||
vk::CommandBuffer TextureDrawer::BeginRenderPass()
|
||||
{
|
||||
DEBUG_LOG(RENDERER, "RenderToTexture packmode=%d stride=%d - %d x %d @ %06x", FB_W_CTRL.fb_packmode, pvrrc.fb_W_LINESTRIDE * 8,
|
||||
pvrrc.fb_X_CLIP.max + 1, pvrrc.fb_Y_CLIP.max + 1, FB_W_SOF1 & VRAM_MASK);
|
||||
DEBUG_LOG(RENDERER, "RenderToTexture packmode=%d stride=%d - %d x %d @ %06x", pvrrc.fb_W_CTRL.fb_packmode, pvrrc.fb_W_LINESTRIDE * 8,
|
||||
pvrrc.fb_X_CLIP.max + 1, pvrrc.fb_Y_CLIP.max + 1, pvrrc.fb_W_SOF1 & VRAM_MASK);
|
||||
matrices.CalcMatrices(&pvrrc);
|
||||
|
||||
textureAddr = FB_W_SOF1 & VRAM_MASK;
|
||||
textureAddr = pvrrc.fb_W_SOF1 & VRAM_MASK;
|
||||
u32 origWidth = pvrrc.getFramebufferWidth();
|
||||
u32 origHeight = pvrrc.getFramebufferHeight();
|
||||
u32 heightPow2 = 8;
|
||||
while (heightPow2 < origHeight)
|
||||
heightPow2 *= 2;
|
||||
u32 widthPow2 = 8;
|
||||
while (widthPow2 < origWidth)
|
||||
widthPow2 *= 2;
|
||||
float upscale = 1.f;
|
||||
if (!config::RenderToTextureBuffer)
|
||||
upscale = config::RenderResolution / 480.f;
|
||||
u32 upscaledWidth = origWidth * upscale;
|
||||
u32 upscaledHeight = origHeight * upscale;
|
||||
widthPow2 *= upscale;
|
||||
heightPow2 *= upscale;
|
||||
u32 upscaledWidth = origWidth;
|
||||
u32 upscaledHeight = origHeight;
|
||||
u32 widthPow2;
|
||||
u32 heightPow2;
|
||||
getRenderToTextureDimensions(upscaledWidth, upscaledHeight, widthPow2, heightPow2);
|
||||
|
||||
rttPipelineManager->CheckSettingsChange();
|
||||
VulkanContext *context = GetContext();
|
||||
|
@ -420,33 +412,8 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass()
|
|||
|
||||
if (!config::RenderToTextureBuffer)
|
||||
{
|
||||
// TexAddr : fb_rtt.TexAddr, Reserved : 0, StrideSel : 0, ScanOrder : 1
|
||||
TCW tcw = { { textureAddr >> 3, 0, 0, 1 } };
|
||||
switch (FB_W_CTRL.fb_packmode) {
|
||||
case 0:
|
||||
case 3:
|
||||
tcw.PixelFmt = Pixel1555;
|
||||
break;
|
||||
case 1:
|
||||
tcw.PixelFmt = Pixel565;
|
||||
break;
|
||||
case 2:
|
||||
tcw.PixelFmt = Pixel4444;
|
||||
break;
|
||||
}
|
||||
|
||||
TSP tsp = { { 0 } };
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8u << tsp.TexU) < origWidth; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8u << tsp.TexV) < origHeight; tsp.TexV++);
|
||||
|
||||
texture = textureCache->getTextureCacheData(tsp, tcw);
|
||||
if (texture->IsNew())
|
||||
{
|
||||
texture->Create();
|
||||
texture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
texture->SetDevice(device);
|
||||
}
|
||||
else if (textureCache->IsInFlight(texture))
|
||||
texture = textureCache->getRTTexture(textureAddr, pvrrc.fb_W_CTRL.fb_packmode, origWidth, origHeight);
|
||||
if (textureCache->IsInFlight(texture))
|
||||
{
|
||||
texture->readOnlyImageView = *texture->imageView;
|
||||
textureCache->DestroyLater(texture);
|
||||
|
@ -503,8 +470,10 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass()
|
|||
commandBuffer.beginRenderPass(vk::RenderPassBeginInfo(rttPipelineManager->GetRenderPass(), *framebuffers[GetCurrentImage()],
|
||||
vk::Rect2D( { 0, 0 }, { width, height }), 2, clear_colors), vk::SubpassContents::eInline);
|
||||
commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, (float)upscaledWidth, (float)upscaledHeight, 1.0f, 0.0f));
|
||||
baseScissor = vk::Rect2D(vk::Offset2D(pvrrc.fb_X_CLIP.min * upscale, pvrrc.fb_Y_CLIP.min * upscale),
|
||||
vk::Extent2D(upscaledWidth, upscaledHeight));
|
||||
u32 minX = pvrrc.fb_X_CLIP.min;
|
||||
u32 minY = pvrrc.fb_Y_CLIP.min;
|
||||
getRenderToTextureDimensions(minX, minY, widthPow2, heightPow2);
|
||||
baseScissor = vk::Rect2D(vk::Offset2D(minX, minY), vk::Extent2D(upscaledWidth, upscaledHeight));
|
||||
commandBuffer.setScissor(0, baseScissor);
|
||||
currentCommandBuffer = commandBuffer;
|
||||
|
||||
|
@ -551,14 +520,14 @@ void TextureDrawer::EndRenderPass()
|
|||
PixelBuffer<u32> tmpBuf;
|
||||
tmpBuf.init(clippedWidth, clippedHeight);
|
||||
colorAttachment->GetBufferData()->download(clippedWidth * clippedHeight * 4, tmpBuf.data());
|
||||
WriteTextureToVRam(clippedWidth, clippedHeight, (u8 *)tmpBuf.data(), dst, -1, pvrrc.fb_W_LINESTRIDE * 8);
|
||||
WriteTextureToVRam(clippedWidth, clippedHeight, (u8 *)tmpBuf.data(), dst, pvrrc.fb_W_CTRL, pvrrc.fb_W_LINESTRIDE * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
//memset(&vram[fb_rtt.TexAddr << 3], '\0', size);
|
||||
|
||||
texture->dirty = 0;
|
||||
libCore_vramlock_Lock(texture->sa_tex, texture->sa + texture->size - 1, texture);
|
||||
texture->protectVRam();
|
||||
}
|
||||
Drawer::EndRenderPass();
|
||||
}
|
||||
|
|
|
@ -143,17 +143,20 @@ protected:
|
|||
|
||||
vk::DeviceSize packNaomi2Lights(BufferPacker& packer)
|
||||
{
|
||||
constexpr static N2LightModel noLight{};
|
||||
vk::DeviceSize offset = packer.addUniform(&noLight, sizeof(noLight));
|
||||
|
||||
size_t n2LightSize = sizeof(N2LightModel) + align(sizeof(N2LightModel), GetContext()->GetUniformBufferAlignment());
|
||||
if (n2LightSize == sizeof(N2LightModel))
|
||||
return packer.addUniform(pvrrc.lightModels.head(), pvrrc.lightModels.bytes());
|
||||
|
||||
vk::DeviceSize offset = (vk::DeviceSize)-1;
|
||||
for (const N2LightModel& model : pvrrc.lightModels)
|
||||
{
|
||||
vk::DeviceSize o = packer.addUniform(&model, sizeof(N2LightModel));
|
||||
if (offset == (vk::DeviceSize)-1)
|
||||
offset = o;
|
||||
packer.addUniform(pvrrc.lightModels.head(), pvrrc.lightModels.bytes());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const N2LightModel& model : pvrrc.lightModels)
|
||||
packer.addUniform(&model, sizeof(N2LightModel));
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
|
|
@ -273,6 +273,7 @@ bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
|
|||
|
||||
currentScissor = vk::Rect2D();
|
||||
|
||||
bool firstFrameAfterInit = oitBuffers->isFirstFrameAfterInit();
|
||||
oitBuffers->OnNewFrame(cmdBuffer);
|
||||
|
||||
setFirstProvokingVertex(pvrrc);
|
||||
|
@ -362,7 +363,7 @@ bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
|
|||
// TR
|
||||
if (current_pass.autosort)
|
||||
{
|
||||
if (!oitBuffers->isFirstFrameAfterInit())
|
||||
if (!firstFrameAfterInit)
|
||||
DrawList(cmdBuffer, ListType_Translucent, true, Pass::OIT, pvrrc.global_param_tr, previous_pass.tr_count, current_pass.tr_count);
|
||||
}
|
||||
else
|
||||
|
@ -382,7 +383,7 @@ bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
|
|||
}
|
||||
SetScissor(cmdBuffer, baseScissor);
|
||||
|
||||
if (oitBuffers->isFirstFrameAfterInit())
|
||||
if (firstFrameAfterInit)
|
||||
{
|
||||
// missing the transparent stuff on the first frame cuz I'm lazy
|
||||
// Clear
|
||||
|
@ -393,6 +394,7 @@ bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
|
|||
vk::MemoryBarrier memoryBarrier(vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
|
||||
cmdBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader, vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::DependencyFlagBits::eByRegion, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
|
||||
firstFrameAfterInit = false;
|
||||
}
|
||||
// Tr modifier volumes
|
||||
if (GetContext()->GetVendorID() != VulkanContext::VENDOR_QUALCOMM) // Adreno bug
|
||||
|
@ -457,7 +459,7 @@ void OITDrawer::MakeBuffers(int width, int height)
|
|||
depthAttachments[1]->GetImageView(),
|
||||
};
|
||||
vk::FramebufferCreateInfo createInfo(vk::FramebufferCreateFlags(), pipelineManager->GetRenderPass(true, true),
|
||||
ARRAY_SIZE(attachments), attachments, width, height, 1);
|
||||
ARRAY_SIZE(attachments), attachments, maxWidth, maxHeight, 1);
|
||||
tempFramebuffers[0] = GetContext()->GetDevice().createFramebufferUnique(createInfo);
|
||||
attachments[0] = attachments[1];
|
||||
attachments[1] = colorAttachments[1]->GetImageView();
|
||||
|
@ -497,29 +499,20 @@ void OITScreenDrawer::MakeFramebuffers(const vk::Extent2D& viewport)
|
|||
|
||||
vk::CommandBuffer OITTextureDrawer::NewFrame()
|
||||
{
|
||||
DEBUG_LOG(RENDERER, "RenderToTexture packmode=%d stride=%d - %d x %d @ %06x", FB_W_CTRL.fb_packmode, pvrrc.fb_W_LINESTRIDE * 8,
|
||||
pvrrc.fb_X_CLIP.max + 1, pvrrc.fb_Y_CLIP.max + 1, FB_W_SOF1 & VRAM_MASK);
|
||||
DEBUG_LOG(RENDERER, "RenderToTexture packmode=%d stride=%d - %d x %d @ %06x", pvrrc.fb_W_CTRL.fb_packmode, pvrrc.fb_W_LINESTRIDE * 8,
|
||||
pvrrc.fb_X_CLIP.max + 1, pvrrc.fb_Y_CLIP.max + 1, pvrrc.fb_W_SOF1 & VRAM_MASK);
|
||||
NewImage();
|
||||
|
||||
matrices.CalcMatrices(&pvrrc);
|
||||
|
||||
textureAddr = FB_W_SOF1 & VRAM_MASK;
|
||||
textureAddr = pvrrc.fb_W_SOF1 & VRAM_MASK;
|
||||
u32 origWidth = pvrrc.getFramebufferWidth();
|
||||
u32 origHeight = pvrrc.getFramebufferHeight();
|
||||
|
||||
float upscale = 1.f;
|
||||
if (!config::RenderToTextureBuffer)
|
||||
upscale = config::RenderResolution / 480.f;
|
||||
u32 heightPow2 = 8;
|
||||
while (heightPow2 < origHeight)
|
||||
heightPow2 *= 2;
|
||||
u32 widthPow2 = 8;
|
||||
while (widthPow2 < origWidth)
|
||||
widthPow2 *= 2;
|
||||
u32 upscaledWidth = origWidth * upscale;
|
||||
u32 upscaledHeight = origHeight * upscale;
|
||||
widthPow2 *= upscale;
|
||||
heightPow2 *= upscale;
|
||||
u32 upscaledWidth = origWidth;
|
||||
u32 upscaledHeight = origHeight;
|
||||
u32 widthPow2;
|
||||
u32 heightPow2;
|
||||
getRenderToTextureDimensions(upscaledWidth, upscaledHeight, widthPow2, heightPow2);
|
||||
|
||||
rttPipelineManager->CheckSettingsChange();
|
||||
VulkanContext *context = GetContext();
|
||||
|
@ -535,33 +528,8 @@ vk::CommandBuffer OITTextureDrawer::NewFrame()
|
|||
|
||||
if (!config::RenderToTextureBuffer)
|
||||
{
|
||||
// TexAddr : fb_rtt.TexAddr, Reserved : 0, StrideSel : 0, ScanOrder : 1
|
||||
TCW tcw = { { textureAddr >> 3, 0, 0, 1 } };
|
||||
switch (FB_W_CTRL.fb_packmode) {
|
||||
case 0:
|
||||
case 3:
|
||||
tcw.PixelFmt = Pixel1555;
|
||||
break;
|
||||
case 1:
|
||||
tcw.PixelFmt = Pixel565;
|
||||
break;
|
||||
case 2:
|
||||
tcw.PixelFmt = Pixel4444;
|
||||
break;
|
||||
}
|
||||
|
||||
TSP tsp = {};
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8u << tsp.TexU) < origWidth; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8u << tsp.TexV) < origHeight; tsp.TexV++);
|
||||
|
||||
texture = textureCache->getTextureCacheData(tsp, tcw);
|
||||
if (texture->IsNew())
|
||||
{
|
||||
texture->Create();
|
||||
texture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
texture->SetDevice(device);
|
||||
}
|
||||
else if (textureCache->IsInFlight(texture))
|
||||
texture = textureCache->getRTTexture(textureAddr, pvrrc.fb_W_CTRL.fb_packmode, origWidth, origHeight);
|
||||
if (textureCache->IsInFlight(texture))
|
||||
{
|
||||
texture->readOnlyImageView = *texture->imageView;
|
||||
textureCache->DestroyLater(texture);
|
||||
|
@ -619,8 +587,10 @@ vk::CommandBuffer OITTextureDrawer::NewFrame()
|
|||
rttPipelineManager->GetRenderPass(true, true), ARRAY_SIZE(imageViews), imageViews, widthPow2, heightPow2, 1));
|
||||
|
||||
commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, (float)upscaledWidth, (float)upscaledHeight, 1.0f, 0.0f));
|
||||
baseScissor = vk::Rect2D(vk::Offset2D(pvrrc.fb_X_CLIP.min * upscale, pvrrc.fb_Y_CLIP.min * upscale),
|
||||
vk::Extent2D(upscaledWidth, upscaledHeight));
|
||||
u32 minX = pvrrc.fb_X_CLIP.min;
|
||||
u32 minY = pvrrc.fb_Y_CLIP.min;
|
||||
getRenderToTextureDimensions(minX, minY, widthPow2, heightPow2);
|
||||
baseScissor = vk::Rect2D(vk::Offset2D(minX, minY), vk::Extent2D(upscaledWidth, upscaledHeight));
|
||||
commandBuffer.setScissor(0, baseScissor);
|
||||
currentCommandBuffer = commandBuffer;
|
||||
|
||||
|
@ -669,14 +639,14 @@ void OITTextureDrawer::EndFrame()
|
|||
PixelBuffer<u32> tmpBuf;
|
||||
tmpBuf.init(clippedWidth, clippedHeight);
|
||||
colorAttachment->GetBufferData()->download(clippedWidth * clippedHeight * 4, tmpBuf.data());
|
||||
WriteTextureToVRam(clippedWidth, clippedHeight, (u8 *)tmpBuf.data(), dst, -1, pvrrc.fb_W_LINESTRIDE * 8);
|
||||
WriteTextureToVRam(clippedWidth, clippedHeight, (u8 *)tmpBuf.data(), dst, pvrrc.fb_W_CTRL, pvrrc.fb_W_LINESTRIDE * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
//memset(&vram[fb_rtt.TexAddr << 3], '\0', size);
|
||||
|
||||
texture->dirty = 0;
|
||||
libCore_vramlock_Lock(texture->sa_tex, texture->sa + texture->size - 1, texture);
|
||||
texture->protectVRam();
|
||||
}
|
||||
OITDrawer::EndFrame();
|
||||
}
|
||||
|
|
|
@ -186,13 +186,13 @@ public:
|
|||
uniBufferInfo = vk::DescriptorBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) };
|
||||
writeDescriptorSets.emplace_back(perPolyDescSet, 2, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &uniBufferInfo, nullptr);
|
||||
|
||||
size = sizeof(N2LightModel) + align(sizeof(N2LightModel), uniformAlignment);
|
||||
// light at index 0 is no light
|
||||
if (poly.lightModel != nullptr)
|
||||
{
|
||||
size = sizeof(N2LightModel) + align(sizeof(N2LightModel), uniformAlignment);
|
||||
lightBufferInfo = vk::DescriptorBufferInfo{ buffer, lightOffset + (poly.lightModel - pvrrc.lightModels.head()) * size, sizeof(N2LightModel) };
|
||||
writeDescriptorSets.emplace_back(perPolyDescSet, 3, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &lightBufferInfo, nullptr);
|
||||
}
|
||||
// TODO no light
|
||||
lightBufferInfo = vk::DescriptorBufferInfo{ buffer, lightOffset + (poly.lightModel - pvrrc.lightModels.head() + 1) * size, sizeof(N2LightModel) };
|
||||
else
|
||||
lightBufferInfo = vk::DescriptorBufferInfo{ buffer, lightOffset, sizeof(N2LightModel) };
|
||||
writeDescriptorSets.emplace_back(perPolyDescSet, 3, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &lightBufferInfo, nullptr);
|
||||
}
|
||||
|
||||
getContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr);
|
||||
|
|
|
@ -54,11 +54,8 @@ void VulkanOverlay::Term()
|
|||
|
||||
std::unique_ptr<Texture> VulkanOverlay::createTexture(vk::CommandBuffer commandBuffer, int width, int height, u8 *data)
|
||||
{
|
||||
VulkanContext *context = VulkanContext::Instance();
|
||||
auto texture = std::unique_ptr<Texture>(new Texture());
|
||||
texture->tex_type = TextureType::_8888;
|
||||
texture->SetDevice(context->GetDevice());
|
||||
texture->SetPhysicalDevice(context->GetPhysicalDevice());
|
||||
texture->SetCommandBuffer(commandBuffer);
|
||||
texture->UploadToGPU(width, height, data, false);
|
||||
texture->SetCommandBuffer(nullptr);
|
||||
|
@ -198,6 +195,7 @@ void VulkanOverlay::Draw(vk::CommandBuffer commandBuffer, vk::Extent2D viewport,
|
|||
if (crosshair && crosshairsNeeded())
|
||||
{
|
||||
pipeline->BindPipeline(commandBuffer);
|
||||
bool imageViewBound = false;
|
||||
for (size_t i = 0; i < config::CrosshairColor.size(); i++)
|
||||
{
|
||||
if (config::CrosshairColor[i] == 0)
|
||||
|
@ -228,7 +226,8 @@ void VulkanOverlay::Draw(vk::CommandBuffer commandBuffer, vk::Extent2D viewport,
|
|||
((color >> 16) & 0xff) / 255.f,
|
||||
((color >> 24) & 0xff) / 255.f
|
||||
};
|
||||
xhairDrawer->Draw(commandBuffer, i == 0 ? xhairTexture->GetImageView() : vk::ImageView(), vtx, true, xhairColor);
|
||||
xhairDrawer->Draw(commandBuffer, !imageViewBound ? xhairTexture->GetImageView() : vk::ImageView(), vtx, true, xhairColor);
|
||||
imageViewBound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,13 +103,13 @@ public:
|
|||
uniBufferInfo = vk::DescriptorBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) };
|
||||
writeDescriptorSets.emplace_back(perPolyDescSet, 2, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &uniBufferInfo, nullptr);
|
||||
|
||||
size = sizeof(N2LightModel) + align(sizeof(N2LightModel), uniformAlignment);
|
||||
// light at index 0 is no light
|
||||
if (poly.lightModel != nullptr)
|
||||
{
|
||||
size = sizeof(N2LightModel) + align(sizeof(N2LightModel), uniformAlignment);
|
||||
lightBufferInfo = vk::DescriptorBufferInfo{ buffer, lightOffset + (poly.lightModel - pvrrc.lightModels.head()) * size, sizeof(N2LightModel) };
|
||||
writeDescriptorSets.emplace_back(perPolyDescSet, 3, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &lightBufferInfo, nullptr);
|
||||
}
|
||||
// TODO no light
|
||||
lightBufferInfo = vk::DescriptorBufferInfo{ buffer, lightOffset + (poly.lightModel - pvrrc.lightModels.head() + 1) * size, sizeof(N2LightModel) };
|
||||
else
|
||||
lightBufferInfo = vk::DescriptorBufferInfo{ buffer, lightOffset, sizeof(N2LightModel) };
|
||||
writeDescriptorSets.emplace_back(perPolyDescSet, 3, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &lightBufferInfo, nullptr);
|
||||
}
|
||||
|
||||
getContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr);
|
||||
|
|
|
@ -36,18 +36,33 @@ void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk:
|
|||
class Texture final : public BaseTextureCacheData
|
||||
{
|
||||
public:
|
||||
Texture(TSP tsp = {}, TCW tcw = {}) : BaseTextureCacheData(tsp, tcw) {
|
||||
this->physicalDevice = VulkanContext::Instance()->GetPhysicalDevice();
|
||||
this->device = VulkanContext::Instance()->GetDevice();
|
||||
}
|
||||
Texture(Texture&& other) : BaseTextureCacheData(std::move(other)) {
|
||||
std::swap(format, other.format);
|
||||
std::swap(extent, other.extent);
|
||||
std::swap(mipmapLevels, other.mipmapLevels);
|
||||
std::swap(needsStaging, other.needsStaging);
|
||||
std::swap(stagingBufferData, other.stagingBufferData);
|
||||
std::swap(commandBuffer, other.commandBuffer);
|
||||
std::swap(allocation, other.allocation);
|
||||
std::swap(image, other.image);
|
||||
std::swap(imageView, other.imageView);
|
||||
std::swap(readOnlyImageView, other.readOnlyImageView);
|
||||
std::swap(physicalDevice, other.physicalDevice);
|
||||
std::swap(device, other.device);
|
||||
}
|
||||
|
||||
void UploadToGPU(int width, int height, u8 *data, bool mipmapped, bool mipmapsIncluded = false) override;
|
||||
u64 GetIntId() { return (u64)reinterpret_cast<uintptr_t>(this); }
|
||||
std::string GetId() override { char s[20]; sprintf(s, "%p", this); return s; }
|
||||
bool IsNew() const { return !image.get(); }
|
||||
vk::ImageView GetImageView() const { return *imageView; }
|
||||
vk::ImageView GetReadOnlyImageView() const { return readOnlyImageView ? readOnlyImageView : *imageView; }
|
||||
void SetCommandBuffer(vk::CommandBuffer commandBuffer) { this->commandBuffer = commandBuffer; }
|
||||
bool Force32BitTexture(TextureType type) const override { return !VulkanContext::Instance()->IsFormatSupported(type); }
|
||||
|
||||
void SetPhysicalDevice(vk::PhysicalDevice physicalDevice) { this->physicalDevice = physicalDevice; }
|
||||
void SetDevice(vk::Device device) { this->device = device; }
|
||||
|
||||
private:
|
||||
void Init(u32 width, u32 height, vk::Format format ,u32 dataSize, bool mipmapped, bool mipmapsIncluded);
|
||||
void SetImage(u32 size, void *data, bool isNew, bool genMipmaps);
|
||||
|
|
|
@ -436,10 +436,10 @@ bool VulkanContext::InitDevice()
|
|||
{ vk::DescriptorType::eUniformTexelBuffer, 2 },
|
||||
{ vk::DescriptorType::eStorageTexelBuffer, 2 },
|
||||
{ vk::DescriptorType::eUniformBuffer, 80000 },
|
||||
{ vk::DescriptorType::eStorageBuffer, 50 },
|
||||
{ vk::DescriptorType::eStorageBuffer, 100 },
|
||||
{ vk::DescriptorType::eUniformBufferDynamic, 2 },
|
||||
{ vk::DescriptorType::eStorageBufferDynamic, 2 },
|
||||
{ vk::DescriptorType::eInputAttachment, 50 }
|
||||
{ vk::DescriptorType::eInputAttachment, 100 }
|
||||
};
|
||||
descriptorPool = device->createDescriptorPoolUnique(vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
|
||||
40000, ARRAY_SIZE(pool_sizes), pool_sizes));
|
||||
|
|
|
@ -45,10 +45,6 @@ protected:
|
|||
texCommandPool.BeginFrame();
|
||||
vjoyTexture = std::unique_ptr<Texture>(new Texture());
|
||||
vjoyTexture->tex_type = TextureType::_8888;
|
||||
vjoyTexture->tcw.full = 0;
|
||||
vjoyTexture->tsp.full = 0;
|
||||
vjoyTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
vjoyTexture->SetDevice(GetContext()->GetDevice());
|
||||
vk::CommandBuffer cmdBuffer = texCommandPool.Allocate();
|
||||
cmdBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit));
|
||||
vjoyTexture->SetCommandBuffer(cmdBuffer);
|
||||
|
@ -97,13 +93,6 @@ public:
|
|||
{
|
||||
Texture* tf = textureCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
if (tf->IsNew())
|
||||
{
|
||||
tf->Create();
|
||||
tf->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
tf->SetDevice(GetContext()->GetDevice());
|
||||
}
|
||||
|
||||
//update if needed
|
||||
if (tf->NeedsUpdate())
|
||||
{
|
||||
|
@ -247,10 +236,6 @@ protected:
|
|||
{
|
||||
curTexture = std::unique_ptr<Texture>(new Texture());
|
||||
curTexture->tex_type = TextureType::_8888;
|
||||
curTexture->tcw.full = 0;
|
||||
curTexture->tsp.full = 0;
|
||||
curTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
curTexture->SetDevice(GetContext()->GetDevice());
|
||||
}
|
||||
curTexture->SetCommandBuffer(texCommandBuffer);
|
||||
curTexture->UploadToGPU(width, height, (u8*)pb.data(), false);
|
||||
|
@ -325,8 +310,6 @@ protected:
|
|||
if (!fogTexture)
|
||||
{
|
||||
fogTexture = std::unique_ptr<Texture>(new Texture());
|
||||
fogTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
fogTexture->SetDevice(GetContext()->GetDevice());
|
||||
fogTexture->tex_type = TextureType::_8;
|
||||
fog_needs_update = true;
|
||||
}
|
||||
|
@ -347,8 +330,6 @@ protected:
|
|||
if (!paletteTexture)
|
||||
{
|
||||
paletteTexture = std::unique_ptr<Texture>(new Texture());
|
||||
paletteTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
paletteTexture->SetDevice(GetContext()->GetDevice());
|
||||
paletteTexture->tex_type = TextureType::_8888;
|
||||
forcePaletteUpdate();
|
||||
}
|
||||
|
|
|
@ -44,6 +44,16 @@ static bool gameRunning;
|
|||
static bool mouseCaptured;
|
||||
static std::string clipboardText;
|
||||
|
||||
static struct SDLDeInit
|
||||
{
|
||||
~SDLDeInit() {
|
||||
if (initialized)
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
bool initialized = false;
|
||||
} sqlDeinit;
|
||||
|
||||
static void sdl_open_joystick(int index)
|
||||
{
|
||||
SDL_Joystick *pJoystick = SDL_JoystickOpen(index);
|
||||
|
@ -176,8 +186,8 @@ void input_sdl_init()
|
|||
|
||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
|
||||
die("SDL: error initializing Joystick subsystem");
|
||||
|
||||
}
|
||||
sqlDeinit.initialized = true;
|
||||
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
|
||||
|
@ -211,6 +221,12 @@ void input_sdl_init()
|
|||
}
|
||||
}
|
||||
|
||||
void input_sdl_quit()
|
||||
{
|
||||
SDLGamepad::closeAllGamepads();
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
}
|
||||
|
||||
inline void SDLMouse::setAbsPos(int x, int y) {
|
||||
int width, height;
|
||||
SDL_GetWindowSize(window, &width, &height);
|
||||
|
@ -603,6 +619,7 @@ void sdl_window_create()
|
|||
SDL_Vulkan_LoadLibrary("libvulkan.dylib");
|
||||
#endif
|
||||
}
|
||||
sqlDeinit.initialized = true;
|
||||
initRenderApi();
|
||||
// ImGui copy & paste
|
||||
ImGui::GetIO().GetClipboardTextFn = getClipboardText;
|
||||
|
@ -622,4 +639,5 @@ void sdl_window_destroy()
|
|||
#endif
|
||||
termRenderApi();
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
void input_sdl_init();
|
||||
void input_sdl_handle();
|
||||
void input_sdl_quit();
|
||||
void sdl_window_create();
|
||||
void sdl_window_set_text(const char* text);
|
||||
void sdl_window_destroy();
|
||||
|
|
|
@ -365,6 +365,11 @@ public:
|
|||
else
|
||||
return NULL;
|
||||
}
|
||||
static void closeAllGamepads()
|
||||
{
|
||||
while (!sdl_gamepads.empty())
|
||||
sdl_gamepads.begin()->second->close();
|
||||
}
|
||||
static void UpdateRumble()
|
||||
{
|
||||
for (auto& pair : sdl_gamepads)
|
||||
|
|
|
@ -2,6 +2,25 @@
|
|||
#include "input/keyboard_device.h"
|
||||
#include "sdl.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOTypes.h>
|
||||
#include <stack>
|
||||
// Rumbling Taptic Engine by Private MultitouchSupport.framework
|
||||
extern "C" {
|
||||
typedef void *MTDeviceRef;
|
||||
bool MTDeviceIsAvailable(void);
|
||||
MTDeviceRef MTDeviceCreateDefault(void);
|
||||
OSStatus MTDeviceGetDeviceID(MTDeviceRef, uint64_t*) __attribute__ ((weak_import));
|
||||
CFTypeRef MTActuatorCreateFromDeviceID(UInt64 deviceID);
|
||||
IOReturn MTActuatorOpen(CFTypeRef actuatorRef);
|
||||
IOReturn MTActuatorClose(CFTypeRef actuatorRef);
|
||||
IOReturn MTActuatorActuate(CFTypeRef actuatorRef, SInt32 actuationID, UInt32 unknown1, Float32 unknown2, Float32 unknown3);
|
||||
bool MTActuatorIsOpen(CFTypeRef actuatorRef);
|
||||
enum ActuatePattern { minimal = 3, weak = 5, medium = 4, strong = 6 };
|
||||
}
|
||||
#endif
|
||||
|
||||
class SDLKeyboardDevice : public KeyboardDeviceTemplate<SDL_Scancode>
|
||||
{
|
||||
public:
|
||||
|
@ -35,6 +54,12 @@ public:
|
|||
}
|
||||
else
|
||||
input_mapper = getDefaultMapping();
|
||||
|
||||
#ifdef __APPLE__
|
||||
uint64_t deviceID;
|
||||
if ( MTDeviceIsAvailable() && MTDeviceGetDeviceID(MTDeviceCreateDefault(), &deviceID) == 0 && (vib_device = MTActuatorCreateFromDeviceID(deviceID)) != NULL && MTActuatorOpen(vib_device) == kIOReturnSuccess)
|
||||
rumbleEnabled = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *get_button_name(u32 code) override
|
||||
|
@ -45,6 +70,59 @@ public:
|
|||
return name;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
void rumble(float power, float inclination, u32 duration_ms) override
|
||||
{
|
||||
if (rumbleEnabled)
|
||||
{
|
||||
vib_stop_time = os_GetSeconds() + duration_ms / 1000.0;
|
||||
|
||||
__block int pattern;
|
||||
if (power >= 0.75)
|
||||
pattern = ActuatePattern::strong;
|
||||
else if (power >= 0.5)
|
||||
pattern = ActuatePattern::medium;
|
||||
else if (power >= 0.25)
|
||||
pattern = ActuatePattern::weak;
|
||||
else if (power > 0)
|
||||
pattern = ActuatePattern::minimal;
|
||||
else
|
||||
{
|
||||
while(!vib_timer_stack.empty())
|
||||
{
|
||||
dispatch_source_cancel(vib_timer_stack.top());
|
||||
vib_timer_stack.pop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Since the Actuator API does not support duration
|
||||
// using a interval timer with `10ms * rumblePower percentage` to fake it
|
||||
__block dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
|
||||
vib_timer_stack.push(_timer);
|
||||
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 10 * NSEC_PER_MSEC * rumblePower / 100.f, 0);
|
||||
|
||||
dispatch_source_set_event_handler(_timer, ^{
|
||||
if ( vib_stop_time - os_GetSeconds() < 0 )
|
||||
{
|
||||
dispatch_source_cancel(_timer);
|
||||
return;
|
||||
}
|
||||
MTActuatorActuate(vib_device, pattern, 0, 0.0, 0.0);
|
||||
});
|
||||
|
||||
dispatch_resume(_timer);
|
||||
}
|
||||
}
|
||||
|
||||
~SDLKeyboardDevice() {
|
||||
if (rumbleEnabled)
|
||||
{
|
||||
MTActuatorClose(vib_device);
|
||||
CFRelease(vib_device);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
u8 convert_keycode(SDL_Scancode scancode) override
|
||||
{
|
||||
|
@ -53,4 +131,11 @@ protected:
|
|||
else
|
||||
return (u8)scancode;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
private:
|
||||
std::stack<dispatch_source_t> vib_timer_stack;
|
||||
CFTypeRef vib_device = NULL;
|
||||
double vib_stop_time = 0;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
#ifndef TARGET_UWP
|
||||
#include <hidusage.h>
|
||||
#include <map>
|
||||
#include <cfgmgr32.h>
|
||||
#include <initguid.h>
|
||||
#include <devpkey.h>
|
||||
#include "hw/maple/maple_devs.h"
|
||||
|
||||
#ifndef CALLBACK
|
||||
|
@ -324,6 +327,17 @@ static void destroyWindow()
|
|||
UnregisterClassA("flycastRawInput", nullptr);
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
// missing from mingw's cfgmgr32.h
|
||||
extern "C" CMAPI CONFIGRET CM_Get_Device_Interface_PropertyW(
|
||||
LPCWSTR pszDeviceInterface,
|
||||
const DEVPROPKEY *PropertyKey,
|
||||
DEVPROPTYPE *PropertyType,
|
||||
PBYTE PropertyBuffer,
|
||||
PULONG PropertyBufferSize,
|
||||
ULONG ulFlags);
|
||||
#endif
|
||||
|
||||
static void findDevices()
|
||||
{
|
||||
u32 numDevices;
|
||||
|
@ -338,10 +352,10 @@ static void findDevices()
|
|||
RAWINPUTDEVICELIST& device = deviceList[i];
|
||||
if (device.dwType == RIM_TYPEMOUSE || device.dwType == RIM_TYPEKEYBOARD)
|
||||
{
|
||||
// Get the device name
|
||||
// Get the device interface instance id
|
||||
std::string name;
|
||||
std::string uniqueId;
|
||||
u32 size;
|
||||
u32 size = 0;
|
||||
GetRawInputDeviceInfo(device.hDevice, RIDI_DEVICENAME, nullptr, &size);
|
||||
if (size > 0)
|
||||
{
|
||||
|
@ -349,13 +363,50 @@ static void findDevices()
|
|||
u32 res = GetRawInputDeviceInfo(device.hDevice, RIDI_DEVICENAME, &deviceNameData[0], &size);
|
||||
if (res != (u32)-1)
|
||||
{
|
||||
std::string deviceName(&deviceNameData[0], std::strlen(&deviceNameData[0]));
|
||||
if (deviceName.substr(0, 8) == "\\\\?\\HID#")
|
||||
deviceName = deviceName.substr(8);
|
||||
uniqueId = (device.dwType == RIM_TYPEMOUSE ? "raw_mouse_" : "raw_keyboard_") + deviceName;
|
||||
if (deviceName.length() > 17 && deviceName.substr(0, 4) == "VID_" && deviceName.substr(8, 5) == "&PID_")
|
||||
deviceName = deviceName.substr(0, 17);
|
||||
name = (device.dwType == RIM_TYPEMOUSE ? "Mouse " : "Keyboard ") + deviceName;
|
||||
std::string deviceId(&deviceNameData[0], std::strlen(&deviceNameData[0]));
|
||||
|
||||
// Now get the device instance id from the interface instance
|
||||
nowide::wstackstring wname;
|
||||
if (wname.convert(deviceId.c_str()))
|
||||
{
|
||||
DEVPROPTYPE propType;
|
||||
ULONG bufSize = 0;
|
||||
if (CM_Get_Device_Interface_PropertyW(wname.c_str(), &DEVPKEY_Device_InstanceId, &propType, nullptr, &bufSize, 0) == CR_BUFFER_SMALL)
|
||||
{
|
||||
std::vector<wchar_t> buf;
|
||||
buf.resize(bufSize / sizeof(wchar_t));
|
||||
if (CM_Get_Device_Interface_PropertyW(wname.c_str(), &DEVPKEY_Device_InstanceId, &propType, (PBYTE)buf.data(), &bufSize, 0) == CR_SUCCESS)
|
||||
{
|
||||
// Locate the device using the device instance id
|
||||
DEVINST devInst;
|
||||
if (CM_Locate_DevNodeW(&devInst, &buf[0], CM_LOCATE_DEVNODE_NORMAL) == CR_SUCCESS)
|
||||
{
|
||||
// Finally, get the "friendly" device name
|
||||
bufSize = 0;
|
||||
if (CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_NAME, &propType, nullptr, &bufSize, 0) == CR_BUFFER_SMALL)
|
||||
{
|
||||
buf.resize(bufSize / sizeof(wchar_t));
|
||||
if (CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_NAME, &propType, (PBYTE)buf.data(), &bufSize, 0) == CR_SUCCESS)
|
||||
{
|
||||
nowide::stackstring nwname;
|
||||
if (nwname.convert(&buf[0]))
|
||||
name = nwname.c_str();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deviceId.substr(0, 8) == "\\\\?\\HID#")
|
||||
deviceId = deviceId.substr(8);
|
||||
uniqueId = (device.dwType == RIM_TYPEMOUSE ? "raw_mouse_" : "raw_keyboard_") + deviceId;
|
||||
if (name.empty())
|
||||
{
|
||||
name = deviceId;
|
||||
if (name.length() > 17 && name.substr(0, 4) == "VID_" && name.substr(8, 5) == "&PID_")
|
||||
name = name.substr(0, 17);
|
||||
name = (device.dwType == RIM_TYPEMOUSE ? "Mouse " : "Keyboard ") + name;
|
||||
}
|
||||
}
|
||||
}
|
||||
uintptr_t handle = (uintptr_t)device.hDevice;
|
||||
|
|
|
@ -217,6 +217,16 @@ void os_SetupInput()
|
|||
#endif
|
||||
}
|
||||
|
||||
void os_TermInput()
|
||||
{
|
||||
#if defined(USE_SDL)
|
||||
input_sdl_quit();
|
||||
#endif
|
||||
#ifndef TARGET_UWP
|
||||
if (config::UseRawInput)
|
||||
rawinput::term();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void setupPath()
|
||||
{
|
||||
|
|
|
@ -19,7 +19,14 @@
|
|||
#include "libretro.h"
|
||||
|
||||
#ifdef LIBRETRO
|
||||
|
||||
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
|
||||
LibretroGraphicsContext theGLContext;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_D3D11) && !(defined(HAVE_OPENGL) || defined(HAVE_OPENGLES))
|
||||
#include "context.h"
|
||||
#endif
|
||||
|
||||
GraphicsContext *GraphicsContext::instance;
|
||||
#endif
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef LIBRETRO
|
||||
#if defined(LIBRETRO) && (defined(HAVE_OPENGL) || defined(HAVE_OPENGLES))
|
||||
#include "gl_context.h"
|
||||
#include <libretro.h>
|
||||
#include <glsm/glsm.h>
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
|
||||
<uses-feature
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.reicast.emulator;
|
|||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
|
@ -14,6 +15,8 @@ import com.reicast.emulator.emu.JNIdc;
|
|||
public class Emulator extends Application {
|
||||
private static Context context;
|
||||
private static BaseGLActivity currentActivity;
|
||||
private WifiManager wifiManager = null;
|
||||
private WifiManager.MulticastLock multicastLock = null;
|
||||
|
||||
// see MapleDeviceType in hw/maple/maple_devs.h
|
||||
public static final int MDT_Microphone = 2;
|
||||
|
@ -92,4 +95,20 @@ public class Emulator extends Application {
|
|||
static {
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||
}
|
||||
|
||||
public void enableNetworkBroadcast(boolean enable) {
|
||||
if (enable) {
|
||||
if (wifiManager == null)
|
||||
wifiManager = (WifiManager)Emulator.context.getSystemService(Context.WIFI_SERVICE);
|
||||
if (multicastLock == null)
|
||||
multicastLock = wifiManager.createMulticastLock("Flycast");
|
||||
if (multicastLock != null && !multicastLock.isHeld())
|
||||
multicastLock.acquire();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (multicastLock != null && multicastLock.isHeld())
|
||||
multicastLock.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,6 +130,9 @@ void common_linux_setup();
|
|||
void os_SetupInput()
|
||||
{
|
||||
}
|
||||
void os_TermInput()
|
||||
{
|
||||
}
|
||||
|
||||
void os_SetWindowText(char const *Text)
|
||||
{
|
||||
|
@ -626,3 +629,10 @@ extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setButtons
|
|||
memcpy(DefaultOSDButtons.data(), b, len);
|
||||
env->ReleaseByteArrayElements(data, b, JNI_ABORT);
|
||||
}
|
||||
|
||||
void enableNetworkBroadcast(bool enable)
|
||||
{
|
||||
JNIEnv *env = jvm_attacher.getEnv();
|
||||
jmethodID enableNetworkBroadcastMID = env->GetMethodID(env->GetObjectClass(g_emulator), "enableNetworkBroadcast", "(Z)V");
|
||||
env->CallVoidMethod(g_emulator, enableNetworkBroadcastMID, enable);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import Foundation
|
||||
import Network
|
||||
|
||||
@available(iOS 12, tvOS 12, watchOS 5, macOS 10.14, *)
|
||||
public class NetworkConnection: NSObject, Connection
|
||||
{
|
||||
public let nwConnection: NWConnection
|
||||
|
@ -52,11 +53,8 @@ public class NetworkConnection: NSObject, Connection
|
|||
default: self.nwConnection.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NetworkConnection
|
||||
{
|
||||
override public var description: String {
|
||||
override public var description: String {
|
||||
return "\(self.nwConnection.endpoint) (Network)"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
// Created by Riley Testut on 5/30/19.
|
||||
// Copyright © 2019 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Network
|
||||
|
||||
|
@ -15,327 +14,340 @@ import UIKit
|
|||
|
||||
public enum ConnectionError: LocalizedError
|
||||
{
|
||||
case serverNotFound
|
||||
case connectionFailed(Server)
|
||||
case connectionDropped(Server)
|
||||
case unknownUDID
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self
|
||||
{
|
||||
case .serverNotFound: return NSLocalizedString("Could not find AltServer.", comment: "")
|
||||
case .connectionFailed: return NSLocalizedString("Could not connect to AltServer.", comment: "")
|
||||
case .connectionDropped: return NSLocalizedString("The connection to AltServer was dropped.", comment: "")
|
||||
case .unknownUDID: return NSLocalizedString("This device's UDID could not be determined.", comment: "")
|
||||
}
|
||||
}
|
||||
case serverNotFound
|
||||
case connectionFailed(Server)
|
||||
case connectionDropped(Server)
|
||||
case unknownUDID
|
||||
case unsupportedOS
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self
|
||||
{
|
||||
case .serverNotFound: return NSLocalizedString("Could not find AltServer.", comment: "")
|
||||
case .connectionFailed: return NSLocalizedString("Could not connect to AltServer.", comment: "")
|
||||
case .connectionDropped: return NSLocalizedString("The connection to AltServer was dropped.", comment: "")
|
||||
case .unknownUDID: return NSLocalizedString("This device's UDID could not be determined.", comment: "")
|
||||
case .unsupportedOS: return NSLocalizedString("This device's OS version is too old to run AltKit.", comment: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc(ALTServerManager) @objcMembers
|
||||
public class ServerManager: NSObject
|
||||
{
|
||||
public static let shared = ServerManager()
|
||||
|
||||
private(set) var isDiscovering = false
|
||||
private(set) var discoveredServers = [Server]()
|
||||
|
||||
public var discoveredServerHandler: ((Server) -> Void)?
|
||||
public var lostServerHandler: ((Server) -> Void)?
|
||||
|
||||
public var callbackQueue: DispatchQueue = .main
|
||||
|
||||
// Allow other AltKit queues to target this one.
|
||||
internal let dispatchQueue = DispatchQueue(label: "io.altstore.altkit.ServerManager", qos: .utility, autoreleaseFrequency: .workItem)
|
||||
|
||||
private let serviceBrowser = NetServiceBrowser()
|
||||
private var resolvingServices = Set<NetService>()
|
||||
|
||||
private var autoconnectGroup: DispatchGroup?
|
||||
private var ignoredServers = Set<Server>()
|
||||
|
||||
private override init()
|
||||
{
|
||||
super.init()
|
||||
|
||||
self.serviceBrowser.delegate = self
|
||||
self.serviceBrowser.includesPeerToPeer = false
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(ServerManager.didEnterBackground(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(ServerManager.willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
}
|
||||
public static let shared = ServerManager()
|
||||
|
||||
public private(set) dynamic var isDiscovering = false
|
||||
public private(set) dynamic var discoveredServers = [Server]()
|
||||
|
||||
public var discoveredServerHandler: ((Server) -> Void)?
|
||||
public var lostServerHandler: ((Server) -> Void)?
|
||||
|
||||
public var callbackQueue: DispatchQueue = .main
|
||||
|
||||
// Allow other AltKit queues to target this one.
|
||||
internal let dispatchQueue = DispatchQueue(label: "io.altstore.altkit.ServerManager", qos: .utility, autoreleaseFrequency: .workItem)
|
||||
|
||||
private var serviceBrowser: NetServiceBrowser?
|
||||
private var resolvingServices = Set<NetService>()
|
||||
|
||||
private var autoconnectGroup: DispatchGroup?
|
||||
private var ignoredServers = Set<Server>()
|
||||
|
||||
private override init()
|
||||
{
|
||||
super.init()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(ServerManager.didEnterBackground(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(ServerManager.willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
public extension ServerManager
|
||||
{
|
||||
@objc
|
||||
func startDiscovering()
|
||||
{
|
||||
guard !self.isDiscovering else { return }
|
||||
self.isDiscovering = true
|
||||
|
||||
self.serviceBrowser.searchForServices(ofType: ALTServerServiceType, inDomain: "")
|
||||
}
|
||||
|
||||
@objc
|
||||
func stopDiscovering()
|
||||
{
|
||||
guard self.isDiscovering else { return }
|
||||
self.isDiscovering = false
|
||||
|
||||
self.discoveredServers.removeAll()
|
||||
self.ignoredServers.removeAll()
|
||||
self.resolvingServices.removeAll()
|
||||
|
||||
self.serviceBrowser.stop()
|
||||
}
|
||||
|
||||
func connect(to server: Server, completion: @escaping (Result<ServerConnection, Error>) -> Void)
|
||||
{
|
||||
var didFinish = false
|
||||
|
||||
func finish(_ result: Result<ServerConnection, Error>)
|
||||
{
|
||||
guard !didFinish else { return }
|
||||
didFinish = true
|
||||
|
||||
self.ignoredServers.insert(server)
|
||||
|
||||
self.callbackQueue.async {
|
||||
completion(result)
|
||||
}
|
||||
}
|
||||
|
||||
self.dispatchQueue.async {
|
||||
|
||||
print("Connecting to service:", server.service)
|
||||
|
||||
let connection = NWConnection(to: .service(name: server.service.name, type: server.service.type, domain: server.service.domain, interface: nil), using: .tcp)
|
||||
connection.stateUpdateHandler = { [unowned connection] (state) in
|
||||
switch state
|
||||
{
|
||||
case .failed(let error):
|
||||
print("Failed to connect to service \(server.service.name).", error)
|
||||
finish(.failure(ConnectionError.connectionFailed(server)))
|
||||
|
||||
case .cancelled: finish(.failure(CocoaError(.userCancelled)))
|
||||
|
||||
case .ready:
|
||||
let networkConnection = NetworkConnection(connection)
|
||||
let serverConnection = ServerConnection(server: server, connection: networkConnection)
|
||||
finish(.success(serverConnection))
|
||||
|
||||
case .waiting: break
|
||||
case .setup: break
|
||||
case .preparing: break
|
||||
@unknown default: break
|
||||
}
|
||||
}
|
||||
|
||||
connection.start(queue: self.dispatchQueue)
|
||||
}
|
||||
}
|
||||
|
||||
func autoconnect(completion: @escaping (Result<ServerConnection, Error>) -> Void)
|
||||
{
|
||||
self.dispatchQueue.async {
|
||||
if case let availableServers = self.discoveredServers.filter({ !self.ignoredServers.contains($0) }),
|
||||
let server = availableServers.first(where: { $0.isPreferred }) ?? availableServers.first
|
||||
{
|
||||
return self.connect(to: server, completion: completion)
|
||||
}
|
||||
|
||||
self.autoconnectGroup = DispatchGroup()
|
||||
self.autoconnectGroup?.enter()
|
||||
self.autoconnectGroup?.notify(queue: self.dispatchQueue) {
|
||||
self.autoconnectGroup = nil
|
||||
|
||||
guard
|
||||
case let availableServers = self.discoveredServers.filter({ !self.ignoredServers.contains($0) }),
|
||||
let server = availableServers.first(where: { $0.isPreferred }) ?? availableServers.first
|
||||
else { return self.autoconnect(completion: completion) }
|
||||
|
||||
self.connect(to: server, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
@objc
|
||||
func startDiscovering()
|
||||
{
|
||||
guard !self.isDiscovering else { return }
|
||||
self.isDiscovering = true
|
||||
|
||||
DispatchQueue.main.async {
|
||||
// NetServiceBrowser must be initialized on main thread.
|
||||
// https://stackoverflow.com/questions/3526661/nsnetservicebrowser-delegate-not-called-when-searching
|
||||
|
||||
let serviceBrowser = NetServiceBrowser()
|
||||
serviceBrowser.delegate = self
|
||||
serviceBrowser.includesPeerToPeer = false
|
||||
serviceBrowser.searchForServices(ofType: ALTServerServiceType, inDomain: "")
|
||||
|
||||
self.serviceBrowser = serviceBrowser
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
func stopDiscovering()
|
||||
{
|
||||
guard self.isDiscovering else { return }
|
||||
self.isDiscovering = false
|
||||
|
||||
self.discoveredServers.removeAll()
|
||||
self.ignoredServers.removeAll()
|
||||
self.resolvingServices.removeAll()
|
||||
|
||||
self.serviceBrowser?.stop()
|
||||
self.serviceBrowser = nil
|
||||
}
|
||||
|
||||
func connect(to server: Server, completion: @escaping (Result<ServerConnection, Error>) -> Void)
|
||||
{
|
||||
var didFinish = false
|
||||
|
||||
func finish(_ result: Result<ServerConnection, Error>)
|
||||
{
|
||||
guard !didFinish else { return }
|
||||
didFinish = true
|
||||
|
||||
self.ignoredServers.insert(server)
|
||||
|
||||
self.callbackQueue.async {
|
||||
completion(result)
|
||||
}
|
||||
}
|
||||
|
||||
self.dispatchQueue.async {
|
||||
guard #available(iOS 12, tvOS 12, watchOS 5, macOS 10.14, *) else {
|
||||
finish(.failure(ConnectionError.unsupportedOS))
|
||||
return
|
||||
}
|
||||
print("Connecting to service:", server.service)
|
||||
|
||||
let connection = NWConnection(to: .service(name: server.service.name, type: server.service.type, domain: server.service.domain, interface: nil), using: .tcp)
|
||||
connection.stateUpdateHandler = { [unowned connection] (state) in
|
||||
switch state
|
||||
{
|
||||
case .failed(let error):
|
||||
print("Failed to connect to service \(server.service.name).", error)
|
||||
finish(.failure(ConnectionError.connectionFailed(server)))
|
||||
|
||||
case .cancelled: finish(.failure(CocoaError(.userCancelled)))
|
||||
|
||||
case .ready:
|
||||
let networkConnection = NetworkConnection(connection)
|
||||
let serverConnection = ServerConnection(server: server, connection: networkConnection)
|
||||
finish(.success(serverConnection))
|
||||
|
||||
case .waiting: break
|
||||
case .setup: break
|
||||
case .preparing: break
|
||||
@unknown default: break
|
||||
}
|
||||
}
|
||||
|
||||
connection.start(queue: self.dispatchQueue)
|
||||
}
|
||||
}
|
||||
|
||||
func autoconnect(completion: @escaping (Result<ServerConnection, Error>) -> Void)
|
||||
{
|
||||
self.dispatchQueue.async {
|
||||
if case let availableServers = self.discoveredServers.filter({ !self.ignoredServers.contains($0) }),
|
||||
let server = availableServers.first(where: { $0.isPreferred }) ?? availableServers.first
|
||||
{
|
||||
return self.connect(to: server, completion: completion)
|
||||
}
|
||||
|
||||
self.autoconnectGroup = DispatchGroup()
|
||||
self.autoconnectGroup?.enter()
|
||||
self.autoconnectGroup?.notify(queue: self.dispatchQueue) {
|
||||
self.autoconnectGroup = nil
|
||||
|
||||
guard
|
||||
case let availableServers = self.discoveredServers.filter({ !self.ignoredServers.contains($0) }),
|
||||
let server = availableServers.first(where: { $0.isPreferred }) ?? availableServers.first
|
||||
else { return self.autoconnect(completion: completion) }
|
||||
|
||||
self.connect(to: server, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension ServerManager
|
||||
{
|
||||
@objc(sharedManager)
|
||||
class var __shared: ServerManager {
|
||||
return ServerManager.shared
|
||||
}
|
||||
|
||||
@objc(connectToServer:completionHandler:)
|
||||
func __connect(to server: Server, completion: @escaping (ServerConnection?, Error?) -> Void)
|
||||
{
|
||||
self.connect(to: server) { result in
|
||||
completion(result.value, result.error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc(autoconnectWithCompletionHandler:)
|
||||
func __autoconnect(completion: @escaping (ServerConnection?, Error?) -> Void)
|
||||
{
|
||||
self.autoconnect { result in
|
||||
completion(result.value, result.error)
|
||||
}
|
||||
}
|
||||
@objc(sharedManager)
|
||||
class var __shared: ServerManager {
|
||||
return ServerManager.shared
|
||||
}
|
||||
|
||||
@objc(connectToServer:completionHandler:)
|
||||
func __connect(to server: Server, completion: @escaping (ServerConnection?, Error?) -> Void)
|
||||
{
|
||||
self.connect(to: server) { result in
|
||||
completion(result.value, result.error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc(autoconnectWithCompletionHandler:)
|
||||
func __autoconnect(completion: @escaping (ServerConnection?, Error?) -> Void)
|
||||
{
|
||||
self.autoconnect { result in
|
||||
completion(result.value, result.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension ServerManager
|
||||
{
|
||||
func addDiscoveredServer(_ server: Server)
|
||||
{
|
||||
self.dispatchQueue.async {
|
||||
let serverID = Bundle.main.object(forInfoDictionaryKey: "ALTServerID") as? String
|
||||
server.isPreferred = (server.id == serverID)
|
||||
|
||||
guard !self.discoveredServers.contains(server) else { return }
|
||||
|
||||
self.discoveredServers.append(server)
|
||||
|
||||
if let callback = self.discoveredServerHandler
|
||||
{
|
||||
self.callbackQueue.async {
|
||||
callback(server)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeDiscoveredServer(_ server: Server)
|
||||
{
|
||||
self.dispatchQueue.async {
|
||||
guard let index = self.discoveredServers.firstIndex(of: server) else { return }
|
||||
|
||||
self.discoveredServers.remove(at: index)
|
||||
|
||||
if let callback = self.lostServerHandler
|
||||
{
|
||||
self.callbackQueue.async {
|
||||
callback(server)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func addDiscoveredServer(_ server: Server)
|
||||
{
|
||||
self.dispatchQueue.async {
|
||||
let serverID = Bundle.main.object(forInfoDictionaryKey: "ALTServerID") as? String
|
||||
server.isPreferred = (server.id == serverID)
|
||||
|
||||
guard !self.discoveredServers.contains(server) else { return }
|
||||
|
||||
self.discoveredServers.append(server)
|
||||
|
||||
if let callback = self.discoveredServerHandler
|
||||
{
|
||||
self.callbackQueue.async {
|
||||
callback(server)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeDiscoveredServer(_ server: Server)
|
||||
{
|
||||
self.dispatchQueue.async {
|
||||
guard let index = self.discoveredServers.firstIndex(of: server) else { return }
|
||||
|
||||
self.discoveredServers.remove(at: index)
|
||||
|
||||
if let callback = self.lostServerHandler
|
||||
{
|
||||
self.callbackQueue.async {
|
||||
callback(server)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
private extension ServerManager
|
||||
{
|
||||
@objc
|
||||
func didEnterBackground(_ notification: Notification)
|
||||
{
|
||||
guard self.isDiscovering else { return }
|
||||
|
||||
self.resolvingServices.removeAll()
|
||||
self.discoveredServers.removeAll()
|
||||
self.serviceBrowser.stop()
|
||||
}
|
||||
|
||||
@objc
|
||||
func willEnterForeground(_ notification: Notification)
|
||||
{
|
||||
guard self.isDiscovering else { return }
|
||||
|
||||
self.serviceBrowser.searchForServices(ofType: ALTServerServiceType, inDomain: "")
|
||||
}
|
||||
@objc
|
||||
func didEnterBackground(_ notification: Notification)
|
||||
{
|
||||
guard self.isDiscovering else { return }
|
||||
|
||||
self.resolvingServices.removeAll()
|
||||
self.discoveredServers.removeAll()
|
||||
self.serviceBrowser?.stop()
|
||||
}
|
||||
|
||||
@objc
|
||||
func willEnterForeground(_ notification: Notification)
|
||||
{
|
||||
guard self.isDiscovering else { return }
|
||||
|
||||
self.serviceBrowser?.searchForServices(ofType: ALTServerServiceType, inDomain: "")
|
||||
}
|
||||
}
|
||||
|
||||
extension ServerManager: NetServiceBrowserDelegate
|
||||
{
|
||||
public func netServiceBrowserWillSearch(_ browser: NetServiceBrowser)
|
||||
{
|
||||
print("Discovering servers...")
|
||||
}
|
||||
|
||||
public func netServiceBrowserDidStopSearch(_ browser: NetServiceBrowser)
|
||||
{
|
||||
print("Stopped discovering servers.")
|
||||
}
|
||||
|
||||
public func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber])
|
||||
{
|
||||
print("Failed to discover servers.", errorDict)
|
||||
}
|
||||
|
||||
public func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool)
|
||||
{
|
||||
self.dispatchQueue.async {
|
||||
service.delegate = self
|
||||
|
||||
if let txtData = service.txtRecordData(), let server = Server(service: service, txtData: txtData)
|
||||
{
|
||||
self.addDiscoveredServer(server)
|
||||
}
|
||||
else
|
||||
{
|
||||
service.resolve(withTimeout: 3.0)
|
||||
self.resolvingServices.insert(service)
|
||||
}
|
||||
|
||||
self.autoconnectGroup?.enter()
|
||||
|
||||
if !moreComing
|
||||
{
|
||||
self.autoconnectGroup?.leave()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool)
|
||||
{
|
||||
if let server = self.discoveredServers.first(where: { $0.service == service })
|
||||
{
|
||||
self.removeDiscoveredServer(server)
|
||||
}
|
||||
}
|
||||
public func netServiceBrowserWillSearch(_ browser: NetServiceBrowser)
|
||||
{
|
||||
print("Discovering servers...")
|
||||
}
|
||||
|
||||
public func netServiceBrowserDidStopSearch(_ browser: NetServiceBrowser)
|
||||
{
|
||||
print("Stopped discovering servers.")
|
||||
}
|
||||
|
||||
public func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber])
|
||||
{
|
||||
print("Failed to discover servers.", errorDict)
|
||||
}
|
||||
|
||||
public func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool)
|
||||
{
|
||||
self.dispatchQueue.async {
|
||||
service.delegate = self
|
||||
|
||||
if let txtData = service.txtRecordData(), let server = Server(service: service, txtData: txtData)
|
||||
{
|
||||
self.addDiscoveredServer(server)
|
||||
}
|
||||
else
|
||||
{
|
||||
service.resolve(withTimeout: 3.0)
|
||||
self.resolvingServices.insert(service)
|
||||
}
|
||||
|
||||
self.autoconnectGroup?.enter()
|
||||
|
||||
if !moreComing
|
||||
{
|
||||
self.autoconnectGroup?.leave()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool)
|
||||
{
|
||||
if let server = self.discoveredServers.first(where: { $0.service == service })
|
||||
{
|
||||
self.removeDiscoveredServer(server)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ServerManager: NetServiceDelegate
|
||||
{
|
||||
public func netServiceDidResolveAddress(_ service: NetService)
|
||||
{
|
||||
defer {
|
||||
self.dispatchQueue.async {
|
||||
guard self.resolvingServices.contains(service) else { return }
|
||||
self.resolvingServices.remove(service)
|
||||
|
||||
self.autoconnectGroup?.leave()
|
||||
}
|
||||
}
|
||||
|
||||
guard let data = service.txtRecordData(), let server = Server(service: service, txtData: data) else { return }
|
||||
self.addDiscoveredServer(server)
|
||||
}
|
||||
|
||||
public func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber])
|
||||
{
|
||||
print("Error resolving net service \(sender).", errorDict)
|
||||
|
||||
self.dispatchQueue.async {
|
||||
guard self.resolvingServices.contains(sender) else { return }
|
||||
self.resolvingServices.remove(sender)
|
||||
|
||||
self.autoconnectGroup?.leave()
|
||||
}
|
||||
}
|
||||
|
||||
public func netService(_ sender: NetService, didUpdateTXTRecord data: Data)
|
||||
{
|
||||
let txtDict = NetService.dictionary(fromTXTRecord: data)
|
||||
print("Service \(sender) updated TXT Record:", txtDict)
|
||||
}
|
||||
|
||||
public func netServiceDidStop(_ sender: NetService)
|
||||
{
|
||||
self.dispatchQueue.async {
|
||||
guard self.resolvingServices.contains(sender) else { return }
|
||||
self.resolvingServices.remove(sender)
|
||||
|
||||
self.autoconnectGroup?.leave()
|
||||
}
|
||||
}
|
||||
public func netServiceDidResolveAddress(_ service: NetService)
|
||||
{
|
||||
defer {
|
||||
self.dispatchQueue.async {
|
||||
guard self.resolvingServices.contains(service) else { return }
|
||||
self.resolvingServices.remove(service)
|
||||
|
||||
self.autoconnectGroup?.leave()
|
||||
}
|
||||
}
|
||||
|
||||
guard let data = service.txtRecordData(), let server = Server(service: service, txtData: data) else { return }
|
||||
self.addDiscoveredServer(server)
|
||||
}
|
||||
|
||||
public func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber])
|
||||
{
|
||||
print("Error resolving net service \(sender).", errorDict)
|
||||
|
||||
self.dispatchQueue.async {
|
||||
guard self.resolvingServices.contains(sender) else { return }
|
||||
self.resolvingServices.remove(sender)
|
||||
|
||||
self.autoconnectGroup?.leave()
|
||||
}
|
||||
}
|
||||
|
||||
public func netService(_ sender: NetService, didUpdateTXTRecord data: Data)
|
||||
{
|
||||
let txtDict = NetService.dictionary(fromTXTRecord: data)
|
||||
print("Service \(sender) updated TXT Record:", txtDict)
|
||||
}
|
||||
|
||||
public func netServiceDidStop(_ sender: NetService)
|
||||
{
|
||||
self.dispatchQueue.async {
|
||||
guard self.resolvingServices.contains(sender) else { return }
|
||||
self.resolvingServices.remove(sender)
|
||||
|
||||
self.autoconnectGroup?.leave()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
UITouch *joyTouch;
|
||||
CGPoint joyBias;
|
||||
std::shared_ptr<IOSVirtualGamepad> virtualGamepad;
|
||||
NSMutableDictionary *touchToButton;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -38,10 +39,23 @@
|
|||
[super viewDidLoad];
|
||||
virtualGamepad = std::make_shared<IOSVirtualGamepad>();
|
||||
GamepadDevice::Register(virtualGamepad);
|
||||
touchToButton = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
|
||||
- (void)showController:(UIView *)parentView
|
||||
{
|
||||
if (!cfgLoadBool("help", "PauseGameTip", false))
|
||||
{
|
||||
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Help Tip"
|
||||
message:@"To pause the game, press Up+Down or Left+Right on the virtual DPad."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
cfgSaveBool("help", "PauseGameTip", true);
|
||||
}];
|
||||
[alert addAction:defaultAction];
|
||||
}
|
||||
[parentView addSubview:self.view];
|
||||
}
|
||||
|
||||
|
@ -55,16 +69,6 @@
|
|||
return self.view.window != nil;
|
||||
}
|
||||
|
||||
- (IBAction)keycodeDown:(id)sender
|
||||
{
|
||||
virtualGamepad->gamepad_btn_input((u32)((UIButton *)sender).tag, true);
|
||||
}
|
||||
|
||||
- (IBAction)keycodeUp:(id)sender
|
||||
{
|
||||
virtualGamepad->gamepad_btn_input((u32)((UIButton *)sender).tag, false);
|
||||
}
|
||||
|
||||
- (void)resetTouch
|
||||
{
|
||||
joyTouch = nil;
|
||||
|
@ -76,29 +80,42 @@
|
|||
|
||||
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
|
||||
{
|
||||
if (joyTouch == nil) {
|
||||
for (UITouch *touch in touches) {
|
||||
CGPoint loc = [touch locationInView:[self joystickBackground]];
|
||||
for (UITouch *touch in touches) {
|
||||
if (joyTouch == nil) {
|
||||
CGPoint loc = [touch locationInView:self.joystickBackground];
|
||||
if ([self.joystickBackground pointInside:loc withEvent:event]) {
|
||||
joyTouch = touch;
|
||||
joyBias = loc;
|
||||
virtualGamepad->gamepad_axis_input(IOS_AXIS_LX, 0);
|
||||
virtualGamepad->gamepad_axis_input(IOS_AXIS_LY, 0);
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
CGPoint point = [touch locationInView:self.view];
|
||||
UIView *touchedView = [self.view hitTest:point withEvent:nil];
|
||||
NSValue *key = [NSValue valueWithPointer:(const void *)touch];
|
||||
if (touchedView.tag != 0 && touchToButton[key] == nil) {
|
||||
touchToButton[key] = touchedView;
|
||||
// button down
|
||||
virtualGamepad->gamepad_btn_input((u32)touchedView.tag, true);
|
||||
}
|
||||
}
|
||||
[super touchesBegan:touches withEvent:event];
|
||||
}
|
||||
|
||||
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
|
||||
{
|
||||
if (joyTouch != nil) {
|
||||
for (UITouch *touch in touches) {
|
||||
if (touch == joyTouch) {
|
||||
[self resetTouch];
|
||||
break;
|
||||
}
|
||||
for (UITouch *touch in touches) {
|
||||
if (touch == joyTouch) {
|
||||
[self resetTouch];
|
||||
continue;
|
||||
}
|
||||
NSValue *key = [NSValue valueWithPointer:(const void *)touch];
|
||||
UIView *button = touchToButton[key];
|
||||
if (button != nil) {
|
||||
[touchToButton removeObjectForKey:key];
|
||||
// button up
|
||||
virtualGamepad->gamepad_btn_input((u32)button.tag, false);
|
||||
}
|
||||
}
|
||||
[super touchesEnded:touches withEvent:event];
|
||||
|
@ -106,20 +123,35 @@
|
|||
|
||||
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
|
||||
{
|
||||
if (joyTouch != nil) {
|
||||
for (UITouch *touch in touches) {
|
||||
if (touch == joyTouch) {
|
||||
CGPoint pos = [touch locationInView:[self joystickBackground]];
|
||||
pos.x -= joyBias.x;
|
||||
pos.y -= joyBias.y;
|
||||
pos.x = std::max<CGFloat>(std::min<CGFloat>(25.0, pos.x), -25.0);
|
||||
pos.y = std::max<CGFloat>(std::min<CGFloat>(25.0, pos.y), -25.0);
|
||||
self.joyXConstraint.constant = pos.x;
|
||||
self.joyYConstraint.constant = pos.y;
|
||||
virtualGamepad->gamepad_axis_input(IOS_AXIS_LX, (s8)std::round(pos.x * 32767.0 / 25.0));
|
||||
virtualGamepad->gamepad_axis_input(IOS_AXIS_LY, (s8)std::round(pos.y * 32767.0 / 25.0));
|
||||
break;
|
||||
}
|
||||
for (UITouch *touch in touches) {
|
||||
if (touch == joyTouch) {
|
||||
CGPoint pos = [touch locationInView:[self joystickBackground]];
|
||||
pos.x -= joyBias.x;
|
||||
pos.y -= joyBias.y;
|
||||
pos.x = std::max<CGFloat>(std::min<CGFloat>(25.0, pos.x), -25.0);
|
||||
pos.y = std::max<CGFloat>(std::min<CGFloat>(25.0, pos.y), -25.0);
|
||||
self.joyXConstraint.constant = pos.x;
|
||||
self.joyYConstraint.constant = pos.y;
|
||||
virtualGamepad->gamepad_axis_input(IOS_AXIS_LX, (s8)std::round(pos.x * 32767.0 / 25.0));
|
||||
virtualGamepad->gamepad_axis_input(IOS_AXIS_LY, (s8)std::round(pos.y * 32767.0 / 25.0));
|
||||
continue;
|
||||
}
|
||||
CGPoint point = [touch locationInView:self.view];
|
||||
UIView *touchedView = [self.view hitTest:point withEvent:nil];
|
||||
NSValue *key = [NSValue valueWithPointer:(const void *)touch];
|
||||
UIView *button = touchToButton[key];
|
||||
if (button != nil && touchedView.tag != button.tag) {
|
||||
// button up
|
||||
virtualGamepad->gamepad_btn_input((u32)button.tag, false);
|
||||
touchToButton[key] = touchedView;
|
||||
// button down
|
||||
virtualGamepad->gamepad_btn_input((u32)touchedView.tag, true);
|
||||
}
|
||||
else if (button == nil && touchedView.tag != 0)
|
||||
{
|
||||
touchToButton[key] = touchedView;
|
||||
// button down
|
||||
virtualGamepad->gamepad_btn_input((u32)touchedView.tag, true);
|
||||
}
|
||||
}
|
||||
[super touchesMoved:touches withEvent:event];
|
||||
|
@ -127,12 +159,17 @@
|
|||
|
||||
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
|
||||
{
|
||||
if (joyTouch != nil) {
|
||||
for (UITouch *touch in touches) {
|
||||
if (touch == joyTouch) {
|
||||
[self resetTouch];
|
||||
break;
|
||||
}
|
||||
for (UITouch *touch in touches) {
|
||||
if (touch == joyTouch) {
|
||||
[self resetTouch];
|
||||
continue;
|
||||
}
|
||||
NSValue *key = [NSValue valueWithPointer:(const void *)touch];
|
||||
UIView *button = touchToButton[key];
|
||||
if (button != nil) {
|
||||
[touchToButton removeObjectForKey:key];
|
||||
// button up
|
||||
virtualGamepad->gamepad_btn_input((u32)button.tag, false);
|
||||
}
|
||||
}
|
||||
[super touchesCancelled:touches withEvent:event];
|
||||
|
|
|
@ -21,16 +21,9 @@
|
|||
<view multipleTouchEnabled="YES" alpha="0.5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3M7-1s-N5r">
|
||||
<rect key="frame" x="0.0" y="0.0" width="812" height="375"/>
|
||||
<subviews>
|
||||
<button opaque="NO" multipleTouchEnabled="YES" tag="14" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8Gl-Iv-u8L" userLabel="LT-Button">
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="14" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8Gl-Iv-u8L" userLabel="LT-Button">
|
||||
<rect key="frame" x="598" y="146" width="80" height="40"/>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="keycodeDown:" destination="-1" eventType="touchDown" id="34L-sO-g81"/>
|
||||
<action selector="keycodeUp:" destination="-1" eventType="touchUpInside" id="iDv-U3-6OX"/>
|
||||
</connections>
|
||||
</button>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="RTrigger" translatesAutoresizingMaskIntoConstraints="NO" id="Cjn-zx-eSs">
|
||||
<rect key="frame" x="688" y="146" width="80" height="40"/>
|
||||
<constraints>
|
||||
|
@ -38,16 +31,9 @@
|
|||
<constraint firstAttribute="height" constant="40" id="uA3-z1-wS7"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" multipleTouchEnabled="YES" tag="15" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="V8J-vG-dlF" userLabel="RT-Button">
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="15" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="V8J-vG-dlF" userLabel="RT-Button">
|
||||
<rect key="frame" x="688" y="146" width="80" height="40"/>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="keycodeDown:" destination="-1" eventType="touchDown" id="vPf-qF-m13"/>
|
||||
<action selector="keycodeUp:" destination="-1" eventType="touchUpInside" id="hQh-8f-5jG"/>
|
||||
</connections>
|
||||
</button>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="JoystickButton" translatesAutoresizingMaskIntoConstraints="NO" id="ivh-8r-bw3" userLabel="JoystickThumbpad">
|
||||
<rect key="frame" x="64" y="255" width="100" height="100"/>
|
||||
<constraints>
|
||||
|
@ -65,62 +51,43 @@
|
|||
<constraint firstAttribute="height" constant="140" id="fly-c3-Ajo"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" multipleTouchEnabled="YES" tag="7" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rp6-Nd-1qa" userLabel="L-Button">
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="10" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bc4-Lc-Ghm" userLabel="UR-Button">
|
||||
<rect key="frame" x="134" y="85" width="50" height="50"/>
|
||||
</view>
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="11" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7rQ-cq-4t8" userLabel="UL-Button">
|
||||
<rect key="frame" x="44" y="85" width="50" height="50"/>
|
||||
</view>
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="12" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="f6y-OJ-0oT" userLabel="DL-Button">
|
||||
<rect key="frame" x="44" y="175" width="50" height="50"/>
|
||||
</view>
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="7" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rp6-Nd-1qa" userLabel="L-Button">
|
||||
<rect key="frame" x="44" y="135" width="46" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="46" id="MX4-af-OJg"/>
|
||||
<constraint firstAttribute="height" constant="40" id="yGw-c7-7x8"/>
|
||||
</constraints>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="keycodeDown:" destination="-1" eventType="touchDown" id="3Yw-AP-xVf"/>
|
||||
<action selector="keycodeUp:" destination="-1" eventType="touchUpInside" id="5gI-j0-ANf"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" multipleTouchEnabled="YES" tag="8" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CVH-hw-R8F" userLabel="R-Button">
|
||||
</view>
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="8" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="CVH-hw-R8F" userLabel="R-Button">
|
||||
<rect key="frame" x="138" y="135" width="46" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="9OW-42-b64"/>
|
||||
<constraint firstAttribute="width" constant="46" id="grQ-i7-YHe"/>
|
||||
</constraints>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="keycodeDown:" destination="-1" eventType="touchDown" id="2Dv-zb-f8V"/>
|
||||
<action selector="keycodeUp:" destination="-1" eventType="touchUpInside" id="woi-3Y-IfD"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" multipleTouchEnabled="YES" tag="5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WMD-Fv-ibu" userLabel="U-Button">
|
||||
</view>
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WMD-Fv-ibu" userLabel="U-Button">
|
||||
<rect key="frame" x="94" y="85" width="40" height="46"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="46" id="2gU-xW-ddx"/>
|
||||
<constraint firstAttribute="width" constant="40" id="oUv-ex-E9I"/>
|
||||
</constraints>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="keycodeDown:" destination="-1" eventType="touchDown" id="kT6-yy-ZtY"/>
|
||||
<action selector="keycodeUp:" destination="-1" eventType="touchUpInside" id="R0R-dl-GAG"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" multipleTouchEnabled="YES" tag="6" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="s7g-nq-lRU" userLabel="D-Button">
|
||||
</view>
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="6" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="s7g-nq-lRU" userLabel="D-Button">
|
||||
<rect key="frame" x="94" y="179" width="40" height="46"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="40" id="3IG-k8-ER3"/>
|
||||
<constraint firstAttribute="height" constant="46" id="4vu-3O-H8J"/>
|
||||
</constraints>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="keycodeDown:" destination="-1" eventType="touchDown" id="Wck-mk-4Py"/>
|
||||
<action selector="keycodeUp:" destination="-1" eventType="touchUpInside" id="Qox-hz-p3A"/>
|
||||
</connections>
|
||||
</button>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ABXYPad" translatesAutoresizingMaskIntoConstraints="NO" id="xbP-E4-fCE">
|
||||
<rect key="frame" x="608" y="205" width="160" height="160"/>
|
||||
<constraints>
|
||||
|
@ -128,62 +95,34 @@
|
|||
<constraint firstAttribute="height" constant="160" id="lVn-RY-tWm"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" multipleTouchEnabled="YES" tag="3" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="iwO-7q-c8H" userLabel="X-Button">
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="3" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iwO-7q-c8H" userLabel="X-Button">
|
||||
<rect key="frame" x="608" y="255" width="60" height="60"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="4Yf-ri-Ccb"/>
|
||||
<constraint firstAttribute="width" constant="60" id="mnO-1S-Phd"/>
|
||||
</constraints>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="keycodeDown:" destination="-1" eventType="touchDown" id="IBH-TK-vfV"/>
|
||||
<action selector="keycodeUp:" destination="-1" eventType="touchUpInside" id="dhr-NT-lcF"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" multipleTouchEnabled="YES" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7LB-OY-vh3" userLabel="B-Button">
|
||||
</view>
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="2" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7LB-OY-vh3" userLabel="B-Button">
|
||||
<rect key="frame" x="708" y="255" width="60" height="60"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="60" id="1YC-G4-kwg"/>
|
||||
<constraint firstAttribute="height" constant="60" id="LHC-wi-Yap"/>
|
||||
</constraints>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="keycodeDown:" destination="-1" eventType="touchDown" id="dhg-58-L8C"/>
|
||||
<action selector="keycodeUp:" destination="-1" eventType="touchUpInside" id="zqg-KK-Wxb"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" multipleTouchEnabled="YES" tag="4" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hGZ-v7-VA5" userLabel="Y-Button">
|
||||
</view>
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="4" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hGZ-v7-VA5" userLabel="Y-Button">
|
||||
<rect key="frame" x="658" y="205" width="60" height="60"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="60" id="gv4-it-7ly"/>
|
||||
<constraint firstAttribute="height" constant="60" id="hx2-N9-Lba"/>
|
||||
</constraints>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="keycodeDown:" destination="-1" eventType="touchDown" id="tyb-H4-TqJ"/>
|
||||
<action selector="keycodeUp:" destination="-1" eventType="touchUpInside" id="oai-Xb-scl"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" multipleTouchEnabled="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="iKO-3z-Ias" userLabel="A-Button">
|
||||
</view>
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="1" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iKO-3z-Ias" userLabel="A-Button">
|
||||
<rect key="frame" x="658" y="305" width="60" height="60"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="Dgi-6d-cHy"/>
|
||||
<constraint firstAttribute="width" constant="60" id="L1S-2O-QBB"/>
|
||||
</constraints>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="keycodeDown:" destination="-1" eventType="touchDown" id="Ysa-m4-KnN"/>
|
||||
<action selector="keycodeUp:" destination="-1" eventType="touchUpInside" id="MTf-ND-WNy"/>
|
||||
</connections>
|
||||
</button>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Start" translatesAutoresizingMaskIntoConstraints="NO" id="9K0-cV-7zu">
|
||||
<rect key="frame" x="366" y="310" width="80" height="40"/>
|
||||
<constraints>
|
||||
|
@ -191,20 +130,13 @@
|
|||
<constraint firstAttribute="width" constant="80" id="BpH-iH-but"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" multipleTouchEnabled="YES" tag="9" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="VtI-tC-PSX" userLabel="S-Button">
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="9" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="VtI-tC-PSX" userLabel="S-Button">
|
||||
<rect key="frame" x="379" y="310" width="54" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="54" id="HjR-fP-Q1s"/>
|
||||
<constraint firstAttribute="height" constant="40" id="MK6-rm-vpj"/>
|
||||
</constraints>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="keycodeDown:" destination="-1" eventType="touchDown" id="kwd-jB-5Wn"/>
|
||||
<action selector="keycodeUp:" destination="-1" eventType="touchUpInside" id="gHx-tA-QlF"/>
|
||||
</connections>
|
||||
</button>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LTrigger" translatesAutoresizingMaskIntoConstraints="NO" id="H57-MD-elm">
|
||||
<rect key="frame" x="598" y="146" width="80" height="40"/>
|
||||
<constraints>
|
||||
|
@ -212,25 +144,37 @@
|
|||
<constraint firstAttribute="width" constant="80" id="Pj7-YU-3Ze"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<view opaque="NO" multipleTouchEnabled="YES" tag="13" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ccY-OZ-Jlp" userLabel="DR-Button">
|
||||
<rect key="frame" x="134" y="175" width="50" height="50"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="DJj-LJ-xnv"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="WMD-Fv-ibu" firstAttribute="leading" secondItem="7rQ-cq-4t8" secondAttribute="trailing" id="1Qw-rO-H58"/>
|
||||
<constraint firstItem="f6y-OJ-0oT" firstAttribute="top" secondItem="rp6-Nd-1qa" secondAttribute="bottom" id="2bH-uq-Rdf"/>
|
||||
<constraint firstItem="f6y-OJ-0oT" firstAttribute="leading" secondItem="FLe-Gr-hny" secondAttribute="leading" id="2hm-bn-5R6"/>
|
||||
<constraint firstItem="s7g-nq-lRU" firstAttribute="centerX" secondItem="FLe-Gr-hny" secondAttribute="centerX" id="4bj-Mc-SN7"/>
|
||||
<constraint firstItem="7rQ-cq-4t8" firstAttribute="leading" secondItem="FLe-Gr-hny" secondAttribute="leading" id="4xu-d6-7ej"/>
|
||||
<constraint firstItem="bc4-Lc-Ghm" firstAttribute="trailing" secondItem="FLe-Gr-hny" secondAttribute="trailing" id="6Hu-3B-LKi"/>
|
||||
<constraint firstItem="V8J-vG-dlF" firstAttribute="height" secondItem="Cjn-zx-eSs" secondAttribute="height" id="77t-Hb-AxC"/>
|
||||
<constraint firstItem="DJj-LJ-xnv" firstAttribute="trailing" secondItem="xbP-E4-fCE" secondAttribute="trailing" id="84h-PU-NtS"/>
|
||||
<constraint firstItem="OMP-L6-n0A" firstAttribute="top" secondItem="FLe-Gr-hny" secondAttribute="bottom" constant="20" id="9o9-R0-BDC"/>
|
||||
<constraint firstItem="ivh-8r-bw3" firstAttribute="centerY" secondItem="OMP-L6-n0A" secondAttribute="centerY" id="AGO-kZ-c5L"/>
|
||||
<constraint firstItem="8Gl-Iv-u8L" firstAttribute="height" secondItem="H57-MD-elm" secondAttribute="height" id="BMW-0T-VdJ"/>
|
||||
<constraint firstItem="ccY-OZ-Jlp" firstAttribute="bottom" secondItem="FLe-Gr-hny" secondAttribute="bottom" id="CKI-9B-7L9"/>
|
||||
<constraint firstItem="8Gl-Iv-u8L" firstAttribute="width" secondItem="H57-MD-elm" secondAttribute="width" id="DV9-P9-Sxd"/>
|
||||
<constraint firstItem="Cjn-zx-eSs" firstAttribute="leading" secondItem="H57-MD-elm" secondAttribute="trailing" constant="10" id="ENl-Fx-mge"/>
|
||||
<constraint firstItem="iwO-7q-c8H" firstAttribute="centerY" secondItem="xbP-E4-fCE" secondAttribute="centerY" id="Eo6-Na-ui9"/>
|
||||
<constraint firstItem="xbP-E4-fCE" firstAttribute="top" secondItem="Cjn-zx-eSs" secondAttribute="bottom" constant="19" id="FSR-y8-8rc"/>
|
||||
<constraint firstItem="Cjn-zx-eSs" firstAttribute="centerY" secondItem="V8J-vG-dlF" secondAttribute="centerY" id="FfW-WI-ybP"/>
|
||||
<constraint firstItem="CVH-hw-R8F" firstAttribute="trailing" secondItem="FLe-Gr-hny" secondAttribute="trailing" id="Ftp-zB-WsM"/>
|
||||
<constraint firstItem="ccY-OZ-Jlp" firstAttribute="trailing" secondItem="FLe-Gr-hny" secondAttribute="trailing" id="GAa-0J-bbN"/>
|
||||
<constraint firstItem="7rQ-cq-4t8" firstAttribute="top" secondItem="FLe-Gr-hny" secondAttribute="top" id="GJc-OP-hcg"/>
|
||||
<constraint firstItem="FLe-Gr-hny" firstAttribute="leading" secondItem="DJj-LJ-xnv" secondAttribute="leading" id="Gw8-6c-aZQ"/>
|
||||
<constraint firstItem="rp6-Nd-1qa" firstAttribute="centerY" secondItem="FLe-Gr-hny" secondAttribute="centerY" id="HGb-0C-429"/>
|
||||
<constraint firstItem="hGZ-v7-VA5" firstAttribute="centerX" secondItem="xbP-E4-fCE" secondAttribute="centerX" id="IgA-69-RT3"/>
|
||||
<constraint firstItem="CVH-hw-R8F" firstAttribute="top" secondItem="bc4-Lc-Ghm" secondAttribute="bottom" id="Isi-K8-3p0"/>
|
||||
<constraint firstItem="7LB-OY-vh3" firstAttribute="trailing" secondItem="xbP-E4-fCE" secondAttribute="trailing" id="JtE-KF-Pdd"/>
|
||||
<constraint firstItem="7LB-OY-vh3" firstAttribute="centerY" secondItem="xbP-E4-fCE" secondAttribute="centerY" id="LG8-OE-Xe1"/>
|
||||
<constraint firstItem="H57-MD-elm" firstAttribute="centerY" secondItem="8Gl-Iv-u8L" secondAttribute="centerY" id="Mhe-dn-JZ9"/>
|
||||
|
@ -238,11 +182,17 @@
|
|||
<constraint firstItem="iKO-3z-Ias" firstAttribute="centerX" secondItem="xbP-E4-fCE" secondAttribute="centerX" id="UCC-w9-GvH"/>
|
||||
<constraint firstItem="Cjn-zx-eSs" firstAttribute="centerY" secondItem="H57-MD-elm" secondAttribute="centerY" id="UEI-il-naq"/>
|
||||
<constraint firstItem="9K0-cV-7zu" firstAttribute="centerX" secondItem="3M7-1s-N5r" secondAttribute="centerX" id="VeR-d1-FAy"/>
|
||||
<constraint firstItem="f6y-OJ-0oT" firstAttribute="bottom" secondItem="FLe-Gr-hny" secondAttribute="bottom" id="X7u-ha-keM"/>
|
||||
<constraint firstItem="ccY-OZ-Jlp" firstAttribute="top" secondItem="CVH-hw-R8F" secondAttribute="bottom" id="YVx-Ts-phy"/>
|
||||
<constraint firstItem="s7g-nq-lRU" firstAttribute="bottom" secondItem="FLe-Gr-hny" secondAttribute="bottom" id="Ygo-58-kU2"/>
|
||||
<constraint firstItem="WMD-Fv-ibu" firstAttribute="top" secondItem="FLe-Gr-hny" secondAttribute="top" id="YzW-LZ-S7F"/>
|
||||
<constraint firstItem="s7g-nq-lRU" firstAttribute="leading" secondItem="f6y-OJ-0oT" secondAttribute="trailing" id="axe-4o-r6w"/>
|
||||
<constraint firstItem="bc4-Lc-Ghm" firstAttribute="top" secondItem="FLe-Gr-hny" secondAttribute="top" id="eXk-0E-XgT"/>
|
||||
<constraint firstAttribute="bottom" secondItem="OMP-L6-n0A" secondAttribute="bottom" constant="10" id="gDw-g8-7jn"/>
|
||||
<constraint firstItem="bc4-Lc-Ghm" firstAttribute="leading" secondItem="WMD-Fv-ibu" secondAttribute="trailing" id="gHk-lh-K78"/>
|
||||
<constraint firstItem="iKO-3z-Ias" firstAttribute="bottom" secondItem="xbP-E4-fCE" secondAttribute="bottom" id="gba-91-EY6"/>
|
||||
<constraint firstItem="iwO-7q-c8H" firstAttribute="leading" secondItem="xbP-E4-fCE" secondAttribute="leading" id="iBC-eZ-hcV"/>
|
||||
<constraint firstItem="rp6-Nd-1qa" firstAttribute="top" secondItem="7rQ-cq-4t8" secondAttribute="bottom" id="kbU-bz-reP"/>
|
||||
<constraint firstItem="VtI-tC-PSX" firstAttribute="centerX" secondItem="9K0-cV-7zu" secondAttribute="centerX" id="lJs-z7-uYy"/>
|
||||
<constraint firstItem="Cjn-zx-eSs" firstAttribute="centerX" secondItem="V8J-vG-dlF" secondAttribute="centerX" id="lmY-iZ-lW5"/>
|
||||
<constraint firstAttribute="bottom" secondItem="xbP-E4-fCE" secondAttribute="bottom" constant="10" id="ner-TB-GTz"/>
|
||||
|
@ -250,6 +200,7 @@
|
|||
<constraint firstItem="DJj-LJ-xnv" firstAttribute="trailing" secondItem="Cjn-zx-eSs" secondAttribute="trailing" id="qTc-91-kbO"/>
|
||||
<constraint firstItem="H57-MD-elm" firstAttribute="centerX" secondItem="8Gl-Iv-u8L" secondAttribute="centerX" id="sNB-9U-qXY"/>
|
||||
<constraint firstItem="V8J-vG-dlF" firstAttribute="width" secondItem="Cjn-zx-eSs" secondAttribute="width" id="sxe-fC-pvB"/>
|
||||
<constraint firstItem="ccY-OZ-Jlp" firstAttribute="leading" secondItem="s7g-nq-lRU" secondAttribute="trailing" id="t0o-uL-23I"/>
|
||||
<constraint firstItem="DJj-LJ-xnv" firstAttribute="bottom" secondItem="9K0-cV-7zu" secondAttribute="bottom" constant="4" id="wWR-HB-aLq"/>
|
||||
<constraint firstItem="WMD-Fv-ibu" firstAttribute="centerX" secondItem="FLe-Gr-hny" secondAttribute="centerX" id="xqT-1Z-AQx"/>
|
||||
<constraint firstItem="rp6-Nd-1qa" firstAttribute="leading" secondItem="FLe-Gr-hny" secondAttribute="leading" id="zVb-6D-06l"/>
|
||||
|
@ -257,7 +208,7 @@
|
|||
<constraint firstItem="CVH-hw-R8F" firstAttribute="centerY" secondItem="FLe-Gr-hny" secondAttribute="centerY" id="zjZ-0S-Tq9"/>
|
||||
<constraint firstItem="OMP-L6-n0A" firstAttribute="centerX" secondItem="FLe-Gr-hny" secondAttribute="centerX" id="zow-El-03l"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="608.69565217391312" y="48.214285714285715"/>
|
||||
<point key="canvasLocation" x="608.12807881773404" y="47.200000000000003"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
|
|
|
@ -50,7 +50,13 @@ enum IOSButton {
|
|||
IOS_BTN_PADDLE4,
|
||||
IOS_BTN_TOUCHPAD,
|
||||
|
||||
IOS_BTN_MAX
|
||||
IOS_BTN_MAX,
|
||||
|
||||
IOS_BTN_UP_RIGHT = 10,
|
||||
IOS_BTN_UP_LEFT,
|
||||
IOS_BTN_DOWN_LEFT,
|
||||
IOS_BTN_DOWN_RIGHT,
|
||||
|
||||
};
|
||||
enum IOSAxis {
|
||||
IOS_AXIS_L1 = 1,
|
||||
|
@ -555,6 +561,27 @@ public:
|
|||
if (code == IOS_BTN_Y)
|
||||
code = IOS_BTN_X; // btn3
|
||||
}
|
||||
switch (code)
|
||||
{
|
||||
case IOS_BTN_UP_RIGHT:
|
||||
GamepadDevice::gamepad_btn_input(IOS_BTN_UP, pressed);
|
||||
code = IOS_BTN_RIGHT;
|
||||
break;
|
||||
case IOS_BTN_DOWN_RIGHT:
|
||||
GamepadDevice::gamepad_btn_input(IOS_BTN_DOWN, pressed);
|
||||
code = IOS_BTN_RIGHT;
|
||||
break;
|
||||
case IOS_BTN_DOWN_LEFT:
|
||||
GamepadDevice::gamepad_btn_input(IOS_BTN_DOWN, pressed);
|
||||
code = IOS_BTN_LEFT;
|
||||
break;
|
||||
case IOS_BTN_UP_LEFT:
|
||||
GamepadDevice::gamepad_btn_input(IOS_BTN_UP, pressed);
|
||||
code = IOS_BTN_LEFT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return GamepadDevice::gamepad_btn_input(code, pressed);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,8 @@ void UpdateInputState() {
|
|||
|
||||
void os_SetupInput() {
|
||||
}
|
||||
void os_TermInput() {
|
||||
}
|
||||
|
||||
std::string os_Locale(){
|
||||
return [[[NSLocale preferredLanguages] objectAtIndex:0] UTF8String];
|
||||
|
|
|
@ -72,6 +72,13 @@ void os_SetupInput()
|
|||
#endif
|
||||
}
|
||||
|
||||
void os_TermInput()
|
||||
{
|
||||
#if defined(USE_SDL)
|
||||
input_sdl_quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void common_linux_setup();
|
||||
static int emu_flycast_init();
|
||||
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
class Libomp < Formula
|
||||
desc "LLVM's OpenMP runtime library"
|
||||
homepage "https://openmp.llvm.org/"
|
||||
url "https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.0/openmp-14.0.0.src.tar.xz"
|
||||
sha256 "28a1cbdd3dfdd331e4ed2dda2b4477fc418e455c883bd0d1d6acc331118e4688"
|
||||
license "MIT"
|
||||
|
||||
livecheck do
|
||||
url "https://llvm.org/"
|
||||
regex(/LLVM (\d+\.\d+\.\d+)/i)
|
||||
end
|
||||
|
||||
bottle do
|
||||
sha256 cellar: :any, arm64_monterey: "cf1058b26e1a778e523d51562c99b4145aea1b1cb89f1c60b3315677a86c7a08"
|
||||
sha256 cellar: :any, arm64_big_sur: "bbf77a1a151f00a18e340ab1f655fb87fe787a85834518f1dc44bf0c52ae7d4c"
|
||||
sha256 cellar: :any, monterey: "e66d2009d6d205c19499dcb453dfac4376ab6bdba805987be00ddbbab65a0818"
|
||||
sha256 cellar: :any, big_sur: "ed9dc636a5fc8c2a0cfb1643f7932d742ae4805c3f193a9e56cab7d7cf7342e7"
|
||||
sha256 cellar: :any, catalina: "c72ce9beecde09052e7eac3550b0286ed9bfb2d14f1dd5954705ab5fb25f231b"
|
||||
sha256 cellar: :any_skip_relocation, x86_64_linux: "9fe14d5f4c8b472de1fad74278da6ba38da7322775b8a88ac61de0c373c4ad10"
|
||||
end
|
||||
|
||||
depends_on "cmake" => :build
|
||||
depends_on :xcode => :build # Sometimes CLT cannot build arm64
|
||||
uses_from_macos "llvm" => :build
|
||||
|
||||
on_linux do
|
||||
keg_only "provided by LLVM, which is not keg-only on Linux"
|
||||
end
|
||||
|
||||
def install
|
||||
# Disable LIBOMP_INSTALL_ALIASES, otherwise the library is installed as
|
||||
# libgomp alias which can conflict with GCC's libgomp.
|
||||
|
||||
args = ["-DLIBOMP_INSTALL_ALIASES=OFF"]
|
||||
args << "-DOPENMP_ENABLE_LIBOMPTARGET=OFF" if OS.linux?
|
||||
|
||||
# Build universal binary
|
||||
ENV.permit_arch_flags
|
||||
ENV.runtime_cpu_detection
|
||||
args << "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64"
|
||||
|
||||
# system "cmake", "-S", "openmp-#{version}.src", "-B", "build/shared", *std_cmake_args, *args
|
||||
# system "cmake", "--build", "build/shared"
|
||||
# system "cmake", "--install", "build/shared"
|
||||
|
||||
system "cmake", "-S", "openmp-#{version}.src", "-B", "build/static",
|
||||
"-DLIBOMP_ENABLE_SHARED=OFF",
|
||||
*std_cmake_args, *args
|
||||
system "cmake", "--build", "build/static"
|
||||
system "cmake", "--install", "build/static"
|
||||
end
|
||||
|
||||
test do
|
||||
(testpath/"test.cpp").write <<~EOS
|
||||
#include <omp.h>
|
||||
#include <array>
|
||||
int main (int argc, char** argv) {
|
||||
std::array<size_t,2> arr = {0,0};
|
||||
#pragma omp parallel num_threads(2)
|
||||
{
|
||||
size_t tid = omp_get_thread_num();
|
||||
arr.at(tid) = tid + 1;
|
||||
}
|
||||
if(arr.at(0) == 1 && arr.at(1) == 2)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
EOS
|
||||
system ENV.cxx, "-Werror", "-Xpreprocessor", "-fopenmp", "test.cpp", "-std=c++11",
|
||||
"-L#{lib}", "-lomp", "-o", "test"
|
||||
system "./test"
|
||||
end
|
||||
end
|
|
@ -24,8 +24,33 @@
|
|||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
/* Detect output refresh rate changes by monitoring
|
||||
* the last 'VSYNC_SWAP_INTERVAL_FRAMES' frames:
|
||||
* - Measure average (mean) audio samples per upload
|
||||
* operation
|
||||
* - Determine vsync swap interval based on
|
||||
* expected samples at 60 (or 50) Hz
|
||||
* - Check that vsync swap interval remains
|
||||
* 'stable' for at least 'VSYNC_SWAP_INTERVAL_FRAMES' */
|
||||
#define VSYNC_SWAP_INTERVAL_FRAMES 6
|
||||
/* Calculated swap interval is 'valid' if it is
|
||||
* within 'VSYNC_SWAP_INTERVAL_THRESHOLD' of an integer
|
||||
* value */
|
||||
#define VSYNC_SWAP_INTERVAL_THRESHOLD 0.05f
|
||||
|
||||
extern void setAVInfo(retro_system_av_info& avinfo);
|
||||
|
||||
extern retro_environment_t environ_cb;
|
||||
extern retro_audio_sample_batch_t audio_batch_cb;
|
||||
|
||||
extern float libretro_expected_audio_samples_per_run;
|
||||
extern unsigned libretro_vsync_swap_interval;
|
||||
extern bool libretro_detect_vsync_swap_interval;
|
||||
|
||||
static float audio_samples_per_frame_avg;
|
||||
static unsigned vsync_swap_interval_last;
|
||||
static unsigned vsync_swap_interval_conter;
|
||||
|
||||
static std::mutex audio_buffer_mutex;
|
||||
static std::vector<int16_t> audio_buffer;
|
||||
static size_t audio_buffer_idx;
|
||||
|
@ -57,6 +82,10 @@ void retro_audio_init(void)
|
|||
audio_out_buffer = (int16_t*)malloc(audio_buffer_size * sizeof(int16_t));
|
||||
|
||||
drop_samples = false;
|
||||
|
||||
audio_samples_per_frame_avg = 0.0f;
|
||||
vsync_swap_interval_last = 1;
|
||||
vsync_swap_interval_conter = 0;
|
||||
}
|
||||
|
||||
void retro_audio_deinit(void)
|
||||
|
@ -72,6 +101,10 @@ void retro_audio_deinit(void)
|
|||
audio_out_buffer = nullptr;
|
||||
|
||||
drop_samples = true;
|
||||
|
||||
audio_samples_per_frame_avg = 0.0f;
|
||||
vsync_swap_interval_last = 1;
|
||||
vsync_swap_interval_conter = 0;
|
||||
}
|
||||
|
||||
void retro_audio_flush_buffer(void)
|
||||
|
@ -100,6 +133,65 @@ void retro_audio_upload(void)
|
|||
|
||||
audio_buffer_mutex.unlock();
|
||||
|
||||
/* Attempt to detect changes in output refresh rate */
|
||||
if (libretro_detect_vsync_swap_interval &&
|
||||
(num_frames > 0))
|
||||
{
|
||||
/* Simple running average (leaky-integrator) */
|
||||
audio_samples_per_frame_avg = ((1.0f / (float)VSYNC_SWAP_INTERVAL_FRAMES) * (float)num_frames) +
|
||||
((1.0f - (1.0f / (float)VSYNC_SWAP_INTERVAL_FRAMES)) * audio_samples_per_frame_avg);
|
||||
|
||||
float swap_ratio = audio_samples_per_frame_avg /
|
||||
libretro_expected_audio_samples_per_run;
|
||||
unsigned swap_integer;
|
||||
float swap_remainder;
|
||||
|
||||
/* If internal frame rate is equal to (within threshold)
|
||||
* or higher than the default 60 (or 50) Hz, fall back
|
||||
* to a swap interval of 1 */
|
||||
if (swap_ratio < (1.0f + VSYNC_SWAP_INTERVAL_THRESHOLD))
|
||||
{
|
||||
swap_integer = 1;
|
||||
swap_remainder = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
swap_integer = (unsigned)(swap_ratio + 0.5f);
|
||||
swap_remainder = swap_ratio - (float)swap_integer;
|
||||
swap_remainder = (swap_remainder < 0.0f) ?
|
||||
-swap_remainder : swap_remainder;
|
||||
}
|
||||
|
||||
/* > Swap interval is considered 'valid' if it is
|
||||
* within VSYNC_SWAP_INTERVAL_THRESHOLD of an integer
|
||||
* value
|
||||
* > If valid, check if new swap interval differs from
|
||||
* previously logged value */
|
||||
if ((swap_remainder <= VSYNC_SWAP_INTERVAL_THRESHOLD) &&
|
||||
(swap_integer != libretro_vsync_swap_interval))
|
||||
{
|
||||
vsync_swap_interval_conter =
|
||||
(swap_integer == vsync_swap_interval_last) ?
|
||||
(vsync_swap_interval_conter + 1) : 0;
|
||||
|
||||
/* Check whether swap interval is 'stable' */
|
||||
if (vsync_swap_interval_conter >= VSYNC_SWAP_INTERVAL_FRAMES)
|
||||
{
|
||||
libretro_vsync_swap_interval = swap_integer;
|
||||
vsync_swap_interval_conter = 0;
|
||||
|
||||
/* Notify frontend */
|
||||
retro_system_av_info avinfo;
|
||||
setAVInfo(avinfo);
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avinfo);
|
||||
}
|
||||
|
||||
vsync_swap_interval_last = swap_integer;
|
||||
}
|
||||
else
|
||||
vsync_swap_interval_conter = 0;
|
||||
}
|
||||
|
||||
int16_t *audio_out_buffer_ptr = audio_out_buffer;
|
||||
while (num_frames > 0)
|
||||
{
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
|
||||
#include <glsm/glsm.h>
|
||||
#include "wsi/gl_context.h"
|
||||
#endif
|
||||
#ifdef HAVE_VULKAN
|
||||
#include "rend/vulkan/vulkan_context.h"
|
||||
|
@ -62,7 +63,6 @@
|
|||
#include "rend/CustomTexture.h"
|
||||
#include "rend/osd.h"
|
||||
#include "cfg/option.h"
|
||||
#include "wsi/gl_context.h"
|
||||
#include "version.h"
|
||||
|
||||
constexpr char slash = path_default_slash_c();
|
||||
|
@ -120,7 +120,8 @@ static bool platformIsDreamcast = true;
|
|||
static bool platformIsArcade = false;
|
||||
static bool threadedRenderingEnabled = true;
|
||||
static bool oitEnabled = false;
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
static bool autoSkipFrameEnabled = false;
|
||||
#ifdef _OPENMP
|
||||
static bool textureUpscaleEnabled = false;
|
||||
#endif
|
||||
static bool vmuScreenSettingsShown = true;
|
||||
|
@ -164,6 +165,10 @@ static int framebufferHeight;
|
|||
static int maxFramebufferWidth;
|
||||
static int maxFramebufferHeight;
|
||||
|
||||
float libretro_expected_audio_samples_per_run;
|
||||
unsigned libretro_vsync_swap_interval = 1;
|
||||
bool libretro_detect_vsync_swap_interval = false;
|
||||
|
||||
static retro_perf_callback perf_cb;
|
||||
static retro_get_cpu_features_t perf_get_cpu_features_cb;
|
||||
|
||||
|
@ -172,8 +177,8 @@ static retro_log_printf_t log_cb;
|
|||
static retro_video_refresh_t video_cb;
|
||||
static retro_input_poll_t poll_cb;
|
||||
static retro_input_state_t input_cb;
|
||||
retro_audio_sample_batch_t audio_batch_cb;
|
||||
static retro_environment_t environ_cb;
|
||||
retro_audio_sample_batch_t audio_batch_cb;
|
||||
retro_environment_t environ_cb;
|
||||
|
||||
static retro_rumble_interface rumble;
|
||||
|
||||
|
@ -357,11 +362,14 @@ void retro_deinit()
|
|||
platformIsArcade = false;
|
||||
threadedRenderingEnabled = true;
|
||||
oitEnabled = false;
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
autoSkipFrameEnabled = false;
|
||||
#ifdef _OPENMP
|
||||
textureUpscaleEnabled = false;
|
||||
#endif
|
||||
vmuScreenSettingsShown = true;
|
||||
lightgunSettingsShown = true;
|
||||
libretro_vsync_swap_interval = 1;
|
||||
libretro_detect_vsync_swap_interval = false;
|
||||
LogManager::Shutdown();
|
||||
|
||||
retro_audio_deinit();
|
||||
|
@ -483,7 +491,7 @@ static bool set_variable_visibility(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
// Only if texture upscaling is enabled
|
||||
bool textureUpscaleWasEnabled = textureUpscaleEnabled;
|
||||
textureUpscaleEnabled = false;
|
||||
|
@ -500,6 +508,24 @@ static bool set_variable_visibility(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
// Only if automatic frame skipping is disabled
|
||||
bool autoSkipFrameWasEnabled = autoSkipFrameEnabled;
|
||||
|
||||
autoSkipFrameEnabled = false;
|
||||
var.key = CORE_OPTION_NAME "_auto_skip_frame";
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && strcmp(var.value, "disabled"))
|
||||
autoSkipFrameEnabled = true;
|
||||
|
||||
if (first_run ||
|
||||
(autoSkipFrameEnabled != autoSkipFrameWasEnabled) ||
|
||||
(threadedRenderingEnabled != threadedRenderingWasEnabled))
|
||||
{
|
||||
option_display.visible = (!autoSkipFrameEnabled || !threadedRenderingEnabled);
|
||||
option_display.key = CORE_OPTION_NAME "_detect_vsync_swap_interval";
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// If categories are supported, no further action is required
|
||||
if (categoriesSupported)
|
||||
return updated;
|
||||
|
@ -596,11 +622,16 @@ static void setGameGeometry(retro_game_geometry& geometry)
|
|||
geometry.base_height = 480;
|
||||
}
|
||||
|
||||
static void setAVInfo(retro_system_av_info& avinfo)
|
||||
void setAVInfo(retro_system_av_info& avinfo)
|
||||
{
|
||||
double sample_rate = 44100.0;
|
||||
double fps = SPG_CONTROL.NTSC ? 59.94 : SPG_CONTROL.PAL ? 50.0 : 60.0;
|
||||
|
||||
setGameGeometry(avinfo.geometry);
|
||||
avinfo.timing.sample_rate = 44100.0;
|
||||
avinfo.timing.fps = SPG_CONTROL.NTSC ? 59.94 : SPG_CONTROL.PAL ? 50.0 : 60.0;
|
||||
avinfo.timing.sample_rate = sample_rate;
|
||||
avinfo.timing.fps = fps / (double)libretro_vsync_swap_interval;
|
||||
|
||||
libretro_expected_audio_samples_per_run = sample_rate / fps;
|
||||
}
|
||||
|
||||
static void setRotation()
|
||||
|
@ -628,6 +659,7 @@ static void update_variables(bool first_startup)
|
|||
int prevMaxFramebufferHeight = maxFramebufferHeight;
|
||||
int prevMaxFramebufferWidth = maxFramebufferWidth;
|
||||
bool prevRotateScreen = rotate_screen;
|
||||
bool prevDetectVsyncSwapInterval = libretro_detect_vsync_swap_interval;
|
||||
config::Settings::instance().setRetroEnvironment(environ_cb);
|
||||
config::Settings::instance().setOptionDefinitions(option_defs_us);
|
||||
config::Settings::instance().load(false);
|
||||
|
@ -749,6 +781,22 @@ static void update_variables(bool first_startup)
|
|||
config::PixelBufferSize = 0x20000000u;
|
||||
#endif
|
||||
|
||||
if ((config::AutoSkipFrame != 0) && config::ThreadedRendering)
|
||||
libretro_detect_vsync_swap_interval = false;
|
||||
else
|
||||
{
|
||||
var.key = CORE_OPTION_NAME "_detect_vsync_swap_interval";
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||
{
|
||||
if (!strcmp(var.value, "enabled"))
|
||||
libretro_detect_vsync_swap_interval = true;
|
||||
else if (!strcmp(var.value, "disabled"))
|
||||
libretro_detect_vsync_swap_interval = false;
|
||||
}
|
||||
else
|
||||
libretro_detect_vsync_swap_interval = false;
|
||||
}
|
||||
|
||||
if (first_startup)
|
||||
{
|
||||
if (config::ThreadedRendering)
|
||||
|
@ -972,6 +1020,16 @@ static void update_variables(bool first_startup)
|
|||
if (rotate_game)
|
||||
config::Widescreen.override(false);
|
||||
setFramebufferSize();
|
||||
|
||||
bool avInfoChanged = false;
|
||||
if ((libretro_detect_vsync_swap_interval != prevDetectVsyncSwapInterval) &&
|
||||
!libretro_detect_vsync_swap_interval &&
|
||||
(libretro_vsync_swap_interval != 1))
|
||||
{
|
||||
libretro_vsync_swap_interval = 1;
|
||||
avInfoChanged = true;
|
||||
}
|
||||
|
||||
if ((prevMaxFramebufferWidth < maxFramebufferWidth || prevMaxFramebufferHeight < maxFramebufferHeight)
|
||||
// TODO crash with dx11
|
||||
&& config::RendererType != RenderType::DirectX11 && config::RendererType != RenderType::DirectX11_OIT)
|
||||
|
@ -980,6 +1038,7 @@ static void update_variables(bool first_startup)
|
|||
setAVInfo(avinfo);
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avinfo);
|
||||
rend_resize_renderer();
|
||||
avInfoChanged = false;
|
||||
}
|
||||
else if (prevFramebufferWidth != framebufferWidth || prevFramebufferHeight != framebufferHeight || geometryChanged)
|
||||
{
|
||||
|
@ -988,6 +1047,13 @@ static void update_variables(bool first_startup)
|
|||
environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &geometry);
|
||||
rend_resize_renderer();
|
||||
}
|
||||
|
||||
if (avInfoChanged)
|
||||
{
|
||||
retro_system_av_info avinfo;
|
||||
setAVInfo(avinfo);
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -473,6 +473,20 @@ struct retro_core_option_v2_definition option_defs_us[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
{
|
||||
CORE_OPTION_NAME "_detect_vsync_swap_interval",
|
||||
"Detect Frame Rate Changes",
|
||||
NULL,
|
||||
"Notify frontend when internal frame rate changes (e.g. from 60 fps to 30 fps). Improves frame pacing in games that run at a locked 30 fps or 20 fps, but should be disabled for games with unlocked (unstable) frame rates (e.g. Ecco the Dolphin, Unreal Tournament). Note: Unavailable when 'Auto Skip Frame' is enabled.",
|
||||
NULL,
|
||||
"video",
|
||||
{
|
||||
{ "disabled", NULL },
|
||||
{ "enabled", NULL },
|
||||
{ NULL, NULL },
|
||||
},
|
||||
"disabled",
|
||||
},
|
||||
{
|
||||
CORE_OPTION_NAME "_pvr2_filtering",
|
||||
"PowerVR2 Post-processing Filter",
|
||||
|
@ -487,7 +501,7 @@ struct retro_core_option_v2_definition option_defs_us[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
"Texture Upscaling (xBRZ)",
|
||||
|
|
|
@ -643,7 +643,7 @@ struct retro_core_option_v2_definition option_defs_ar[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_AR,
|
||||
|
@ -2178,7 +2178,7 @@ struct retro_core_option_v2_definition option_defs_ast[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_AST,
|
||||
|
@ -3713,7 +3713,7 @@ struct retro_core_option_v2_definition option_defs_ca[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_CA,
|
||||
|
@ -5248,7 +5248,7 @@ struct retro_core_option_v2_definition option_defs_chs[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_CHS,
|
||||
|
@ -6783,7 +6783,7 @@ struct retro_core_option_v2_definition option_defs_cht[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_CHT,
|
||||
|
@ -8318,7 +8318,7 @@ struct retro_core_option_v2_definition option_defs_cs[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_CS,
|
||||
|
@ -9853,7 +9853,7 @@ struct retro_core_option_v2_definition option_defs_cy[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_CY,
|
||||
|
@ -11388,7 +11388,7 @@ struct retro_core_option_v2_definition option_defs_da[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_DA,
|
||||
|
@ -12923,7 +12923,7 @@ struct retro_core_option_v2_definition option_defs_de[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_DE,
|
||||
|
@ -14458,7 +14458,7 @@ struct retro_core_option_v2_definition option_defs_el[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_EL,
|
||||
|
@ -15993,7 +15993,7 @@ struct retro_core_option_v2_definition option_defs_eo[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_EO,
|
||||
|
@ -17528,7 +17528,7 @@ struct retro_core_option_v2_definition option_defs_es[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_ES,
|
||||
|
@ -19063,7 +19063,7 @@ struct retro_core_option_v2_definition option_defs_fa[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_FA,
|
||||
|
@ -20598,7 +20598,7 @@ struct retro_core_option_v2_definition option_defs_fi[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_FI,
|
||||
|
@ -22133,7 +22133,7 @@ struct retro_core_option_v2_definition option_defs_fr[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_FR,
|
||||
|
@ -23668,7 +23668,7 @@ struct retro_core_option_v2_definition option_defs_gl[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_GL,
|
||||
|
@ -25203,7 +25203,7 @@ struct retro_core_option_v2_definition option_defs_he[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_HE,
|
||||
|
@ -26738,7 +26738,7 @@ struct retro_core_option_v2_definition option_defs_hu[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_HU,
|
||||
|
@ -28273,7 +28273,7 @@ struct retro_core_option_v2_definition option_defs_id[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_ID,
|
||||
|
@ -29808,7 +29808,7 @@ struct retro_core_option_v2_definition option_defs_it[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_IT,
|
||||
|
@ -31343,7 +31343,7 @@ struct retro_core_option_v2_definition option_defs_ja[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_JA,
|
||||
|
@ -32878,7 +32878,7 @@ struct retro_core_option_v2_definition option_defs_ko[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_KO,
|
||||
|
@ -34413,7 +34413,7 @@ struct retro_core_option_v2_definition option_defs_mt[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_MT,
|
||||
|
@ -35948,7 +35948,7 @@ struct retro_core_option_v2_definition option_defs_nl[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_NL,
|
||||
|
@ -37483,7 +37483,7 @@ struct retro_core_option_v2_definition option_defs_no[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_NO,
|
||||
|
@ -39018,7 +39018,7 @@ struct retro_core_option_v2_definition option_defs_oc[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_OC,
|
||||
|
@ -40553,7 +40553,7 @@ struct retro_core_option_v2_definition option_defs_pl[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_PL,
|
||||
|
@ -42088,7 +42088,7 @@ struct retro_core_option_v2_definition option_defs_pt_br[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_PT_BR,
|
||||
|
@ -43623,7 +43623,7 @@ struct retro_core_option_v2_definition option_defs_pt_pt[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_PT_PT,
|
||||
|
@ -45158,7 +45158,7 @@ struct retro_core_option_v2_definition option_defs_ro[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_RO,
|
||||
|
@ -46693,7 +46693,7 @@ struct retro_core_option_v2_definition option_defs_ru[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_RU,
|
||||
|
@ -48228,7 +48228,7 @@ struct retro_core_option_v2_definition option_defs_si[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_SI,
|
||||
|
@ -49763,7 +49763,7 @@ struct retro_core_option_v2_definition option_defs_sk[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_SK,
|
||||
|
@ -51298,7 +51298,7 @@ struct retro_core_option_v2_definition option_defs_sr[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_SR,
|
||||
|
@ -52833,7 +52833,7 @@ struct retro_core_option_v2_definition option_defs_sv[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_SV,
|
||||
|
@ -54368,7 +54368,7 @@ struct retro_core_option_v2_definition option_defs_tr[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_TR,
|
||||
|
@ -55903,7 +55903,7 @@ struct retro_core_option_v2_definition option_defs_uk[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_UK,
|
||||
|
@ -57438,7 +57438,7 @@ struct retro_core_option_v2_definition option_defs_val[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_VAL,
|
||||
|
@ -58973,7 +58973,7 @@ struct retro_core_option_v2_definition option_defs_vn[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#ifdef _OPENMP
|
||||
{
|
||||
CORE_OPTION_NAME "_texupscale",
|
||||
CORE_OPTION_NAME_TEXUPSCALE_LABEL_VN,
|
||||
|
|
|
@ -22,6 +22,9 @@ HWND getNativeHwnd()
|
|||
void os_SetupInput()
|
||||
{
|
||||
}
|
||||
void os_TermInput()
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateInputState()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue