Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cb38a7897 | ||
|
|
f285fd2d23 | ||
|
|
23103340f9 | ||
|
|
e5fd48cf3d | ||
|
|
6df81095d0 | ||
|
|
261b8294a0 | ||
|
|
8a66aadb40 | ||
|
|
ba9c2e5fab | ||
|
|
073f7f848c | ||
|
|
82f1c82ee4 | ||
|
|
6a3640b8be | ||
|
|
3e2e477fe8 | ||
|
|
b66c372192 | ||
|
|
12f0bad824 | ||
|
|
79c3c21ae0 | ||
|
|
39c5d58564 | ||
|
|
d8c58b45f0 | ||
|
|
4727139e0e | ||
|
|
b461145fe4 | ||
|
|
5a82b0f480 | ||
|
|
3d028d792f | ||
|
|
66c8e3a9d3 | ||
|
|
51e9269865 | ||
|
|
bc02f20762 | ||
|
|
e26d1b20b5 | ||
|
|
6ae8cea6f3 | ||
|
|
41e94455f4 | ||
|
|
d283ddf4ee | ||
|
|
6a4c709dec | ||
|
|
2c91ae2557 | ||
|
|
c629a1d5d5 | ||
|
|
1e54c2d16f | ||
|
|
42efa1f2c8 | ||
|
|
c9f4113534 | ||
|
|
e3bf553566 | ||
|
|
e2478660f3 | ||
|
|
9106cad14a | ||
|
|
8a361cf927 | ||
|
|
427873116b | ||
|
|
6c5cd094c3 | ||
|
|
9b270b2e90 | ||
|
|
b4bef088d4 | ||
|
|
e5fa7f9c72 | ||
|
|
746479d359 | ||
|
|
7f6c14f92d | ||
|
|
1e0a244b49 | ||
|
|
5b9f29296e | ||
|
|
2674267589 | ||
|
|
d64c746dab | ||
|
|
d54205dec8 | ||
|
|
6b48083ad9 | ||
|
|
7d9eb2aaa9 | ||
|
|
d7aa2d00ba | ||
|
|
743dad5f37 | ||
|
|
19dc6a68b3 | ||
|
|
8d9e822bbe | ||
|
|
5d7258a00a | ||
|
|
2b5601d154 | ||
|
|
a51d471f2d | ||
|
|
0f5ca5d8b0 | ||
|
|
f85b736c97 | ||
|
|
72547b1b59 | ||
|
|
4987298f79 | ||
|
|
b1b0be886e | ||
|
|
208688afe1 | ||
|
|
82de44df54 | ||
|
|
6207d77349 | ||
|
|
afc390bacf | ||
|
|
4b2ae15efc | ||
|
|
0fda662370 | ||
|
|
4e59c3375e | ||
|
|
2e7ffc2c52 | ||
|
|
b98ccb2a30 | ||
|
|
813a488844 | ||
|
|
4faa814ee1 | ||
|
|
f80e56fa0f | ||
|
|
a43905d7f4 | ||
|
|
616238e847 | ||
|
|
fd8cc416ab | ||
|
|
8dc445e744 | ||
|
|
218b203a0b | ||
|
|
65e71909ed | ||
|
|
f08d7c7ac9 | ||
|
|
b451b65251 | ||
|
|
9add83f2c8 | ||
|
|
023b013828 | ||
|
|
07af0e4457 | ||
|
|
164f5bff2e | ||
|
|
5e35318f07 | ||
|
|
fe73054771 | ||
|
|
a6adbfc8c6 | ||
|
|
f997b35b1a | ||
|
|
af37c253b1 | ||
|
|
600fc5885b | ||
|
|
8d751c0564 | ||
|
|
555726e417 | ||
|
|
1c90390262 | ||
|
|
98e6a28620 | ||
|
|
d7e03e6464 | ||
|
|
a435b5bb45 | ||
|
|
8e5c9b58e2 | ||
|
|
8d25d238b6 | ||
|
|
6a9150c447 | ||
|
|
2316a9eb63 | ||
|
|
2e403acf3e |
@@ -1,21 +0,0 @@
|
||||
BasedOnStyle: Chromium
|
||||
AlignAfterOpenBracket: true
|
||||
AlignOperands: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
ColumnLimit: 160
|
||||
ContinuationIndentWidth: 4
|
||||
DerivePointerAlignment: false
|
||||
IndentWidth: 4
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PointerBindsToType: false
|
||||
PointerAlignment: Right
|
||||
SpacesInContainerLiterals: true
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
name: Build VoidLink IPA
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "feat/frame_pacing_metal" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build VoidLink IPA
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Checkout submodules
|
||||
run: "git submodule update --init --recursive"
|
||||
|
||||
- name: Build VoidLink
|
||||
run: |
|
||||
xcodebuild -verbose -scheme VoidLink -sdk iphoneos -configuration Debug archive -archivePath $PWD/build/VoidLink.xcarchive CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED="NO" CODE_SIGN_ENTITLEMENTS="" CODE_SIGNING_ALLOWED="NO"
|
||||
mkdir -p ./build/IPA && mkdir -p ./build/IPA/Payload
|
||||
cp -r ./build/VoidLink.xcarchive/Products/Applications/VoidLink.app ./build/IPA/Payload/VoidLink.app
|
||||
cd ./build/IPA && zip -r ../../build/VoidLink.ipa ./Payload/* && cd ../..
|
||||
|
||||
- name: Upload VoidLink IPA to Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: VoidLink.ipa
|
||||
path: build/VoidLink.ipa
|
||||
@@ -1,9 +1,6 @@
|
||||
**/xcuserdata/
|
||||
**/Moonlight.xcscmblueprint
|
||||
**/xcschemes/*.xcscheme
|
||||
.DS_Store
|
||||
Build
|
||||
DerivedData
|
||||
*.xccheckout
|
||||
.github
|
||||
README.md
|
||||
@@ -1,9 +1,6 @@
|
||||
[submodule "moonlight-common/moonlight-common-c"]
|
||||
path = moonlight-common/moonlight-common-c
|
||||
url=https://github.com/TrueZhuangJia/voidlink-c.git
|
||||
url = https://github.com/moonlight-stream/moonlight-common-c.git
|
||||
[submodule "X1Kit"]
|
||||
path = X1Kit
|
||||
url = https://github.com/cgutman/X1Kit.git
|
||||
[submodule "third_party/imgui"]
|
||||
path = third_party/imgui
|
||||
url = https://github.com/ocornut/imgui.git
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
// dear imgui: Renderer Backend for Metal
|
||||
// This needs to be used along with a Platform Backend (e.g. OSX)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ObjC API
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef __OBJC__
|
||||
|
||||
@class MTLRenderPassDescriptor;
|
||||
@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;
|
||||
|
||||
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id<MTLDevice> device);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData,
|
||||
id<MTLCommandBuffer> commandBuffer,
|
||||
id<MTLRenderCommandEncoder> commandEncoder);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
|
||||
|
||||
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex);
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// C++ API
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Enable Metal C++ binding support with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file
|
||||
// More info about using Metal from C++: https://developer.apple.com/metal/cpp/
|
||||
|
||||
#ifdef IMGUI_IMPL_METAL_CPP
|
||||
#include <Metal/Metal.hpp>
|
||||
#ifndef __OBJC__
|
||||
|
||||
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(MTL::Device* device);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
|
||||
MTL::CommandBuffer* commandBuffer,
|
||||
MTL::RenderCommandEncoder* commandEncoder);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
|
||||
|
||||
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
@@ -1,657 +0,0 @@
|
||||
// dear imgui: Renderer Backend for Metal
|
||||
// This needs to be used along with a Platform Backend (e.g. OSX)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplMetal_CreateFontsTexture() and ImGui_ImplMetal_DestroyFontsTexture().
|
||||
// 2025-02-03: Metal: Crash fix. (#8367)
|
||||
// 2024-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419).
|
||||
// 2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'.
|
||||
// 2022-07-05: Metal: Add dispatch synchronization.
|
||||
// 2022-06-30: Metal: Use __bridge for ARC based systems.
|
||||
// 2022-06-01: Metal: Fixed null dereference on exit inside command buffer completion handler.
|
||||
// 2022-04-27: Misc: Store backend data in a per-context struct, allowing to use this backend with multiple contexts.
|
||||
// 2022-01-03: Metal: Ignore ImDrawCmd where ElemCount == 0 (very rare but can technically be manufactured by user code).
|
||||
// 2021-12-30: Metal: Added Metal C++ support. Enable with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file.
|
||||
// 2021-08-24: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted. (#4464)
|
||||
// 2021-05-19: Metal: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-02-18: Metal: Change blending equation to preserve alpha in output buffer.
|
||||
// 2021-01-25: Metal: Fixed texture storage mode when building on Mac Catalyst.
|
||||
// 2019-05-29: Metal: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: Metal: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-02-11: Metal: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-07-05: Metal: Added new Metal backend implementation.
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui_impl_metal.h"
|
||||
#import <time.h>
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
#pragma mark - Support classes
|
||||
|
||||
// A wrapper around a MTLBuffer object that knows the last time it was reused
|
||||
@interface MetalBuffer : NSObject
|
||||
@property (nonatomic, strong) id<MTLBuffer> buffer;
|
||||
@property (nonatomic, assign) double lastReuseTime;
|
||||
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer;
|
||||
@end
|
||||
|
||||
// An object that encapsulates the data necessary to uniquely identify a
|
||||
// render pipeline state. These are used as cache keys.
|
||||
@interface FramebufferDescriptor : NSObject<NSCopying>
|
||||
@property (nonatomic, assign) unsigned long sampleCount;
|
||||
@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;
|
||||
@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;
|
||||
@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;
|
||||
- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor;
|
||||
@end
|
||||
|
||||
@interface MetalTexture : NSObject
|
||||
@property (nonatomic, strong) id<MTLTexture> metalTexture;
|
||||
- (instancetype)initWithTexture:(id<MTLTexture>)metalTexture;
|
||||
@end
|
||||
|
||||
// A singleton that stores long-lived objects that are needed by the Metal
|
||||
// renderer backend. Stores the render pipeline state cache and the default
|
||||
// font texture, and manages the reusable buffer cache.
|
||||
@interface MetalContext : NSObject
|
||||
@property (nonatomic, strong) id<MTLDevice> device;
|
||||
@property (nonatomic, strong) id<MTLDepthStencilState> depthStencilState;
|
||||
@property (nonatomic, strong) FramebufferDescriptor* framebufferDescriptor; // framebuffer descriptor for current frame; transient
|
||||
@property (nonatomic, strong) NSMutableDictionary* renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors
|
||||
@property (nonatomic, strong) NSMutableArray<MetalBuffer*>* bufferCache;
|
||||
@property (nonatomic, assign) double lastBufferCachePurge;
|
||||
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;
|
||||
- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device;
|
||||
@end
|
||||
|
||||
struct ImGui_ImplMetal_Data
|
||||
{
|
||||
MetalContext* SharedMetalContext;
|
||||
|
||||
ImGui_ImplMetal_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
static ImGui_ImplMetal_Data* ImGui_ImplMetal_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplMetal_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; }
|
||||
static void ImGui_ImplMetal_DestroyBackendData(){ IM_DELETE(ImGui_ImplMetal_GetBackendData()); }
|
||||
|
||||
// XXX Work around missing clock symbols on iOS. The NSDate version is the method this function used previously.
|
||||
#if defined(CLOCK_UPTIME_RAW)
|
||||
static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return (CFTimeInterval)(double)(clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1e9); }
|
||||
#else
|
||||
static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return (CFTimeInterval)[NSDate date].timeIntervalSince1970; }
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_METAL_CPP
|
||||
|
||||
#pragma mark - Dear ImGui Metal C++ Backend API
|
||||
|
||||
bool ImGui_ImplMetal_Init(MTL::Device* device)
|
||||
{
|
||||
return ImGui_ImplMetal_Init((__bridge id<MTLDevice>)(device));
|
||||
}
|
||||
|
||||
void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor)
|
||||
{
|
||||
ImGui_ImplMetal_NewFrame((__bridge MTLRenderPassDescriptor*)(renderPassDescriptor));
|
||||
}
|
||||
|
||||
void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
|
||||
MTL::CommandBuffer* commandBuffer,
|
||||
MTL::RenderCommandEncoder* commandEncoder)
|
||||
{
|
||||
ImGui_ImplMetal_RenderDrawData(draw_data,
|
||||
(__bridge id<MTLCommandBuffer>)(commandBuffer),
|
||||
(__bridge id<MTLRenderCommandEncoder>)(commandEncoder));
|
||||
|
||||
}
|
||||
|
||||
bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device)
|
||||
{
|
||||
return ImGui_ImplMetal_CreateDeviceObjects((__bridge id<MTLDevice>)(device));
|
||||
}
|
||||
|
||||
#endif // #ifdef IMGUI_IMPL_METAL_CPP
|
||||
|
||||
#pragma mark - Dear ImGui Metal Backend API
|
||||
|
||||
bool ImGui_ImplMetal_Init(id<MTLDevice> device)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IMGUI_CHECKVERSION();
|
||||
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||
|
||||
ImGui_ImplMetal_Data* bd = IM_NEW(ImGui_ImplMetal_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_metal";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||
|
||||
bd->SharedMetalContext = [[MetalContext alloc] init];
|
||||
bd->SharedMetalContext.device = device;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplMetal_Shutdown()
|
||||
{
|
||||
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||
IM_UNUSED(bd);
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGui_ImplMetal_DestroyDeviceObjects();
|
||||
ImGui_ImplMetal_DestroyBackendData();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
||||
}
|
||||
|
||||
void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor)
|
||||
{
|
||||
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||
IM_ASSERT(bd != nil && "Context or backend not initialized! Did you call ImGui_ImplMetal_Init()?");
|
||||
#ifdef IMGUI_IMPL_METAL_CPP
|
||||
bd->SharedMetalContext.framebufferDescriptor = [[[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor]autorelease];
|
||||
#else
|
||||
bd->SharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor];
|
||||
#endif
|
||||
if (bd->SharedMetalContext.depthStencilState == nil)
|
||||
ImGui_ImplMetal_CreateDeviceObjects(bd->SharedMetalContext.device);
|
||||
}
|
||||
|
||||
static void ImGui_ImplMetal_SetupRenderState(ImDrawData* draw_data, id<MTLCommandBuffer> commandBuffer,
|
||||
id<MTLRenderCommandEncoder> commandEncoder, id<MTLRenderPipelineState> renderPipelineState,
|
||||
MetalBuffer* vertexBuffer, size_t vertexBufferOffset)
|
||||
{
|
||||
IM_UNUSED(commandBuffer);
|
||||
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||
[commandEncoder setCullMode:MTLCullModeNone];
|
||||
[commandEncoder setDepthStencilState:bd->SharedMetalContext.depthStencilState];
|
||||
|
||||
// Setup viewport, orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to
|
||||
// draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
|
||||
MTLViewport viewport =
|
||||
{
|
||||
.originX = 0.0,
|
||||
.originY = 0.0,
|
||||
.width = (double)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x),
|
||||
.height = (double)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y),
|
||||
.znear = 0.0,
|
||||
.zfar = 1.0
|
||||
};
|
||||
[commandEncoder setViewport:viewport];
|
||||
|
||||
float L = draw_data->DisplayPos.x;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||
float T = draw_data->DisplayPos.y;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||
float N = (float)viewport.znear;
|
||||
float F = (float)viewport.zfar;
|
||||
const float ortho_projection[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, 1/(F-N), 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f },
|
||||
};
|
||||
[commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1];
|
||||
|
||||
[commandEncoder setRenderPipelineState:renderPipelineState];
|
||||
|
||||
[commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0];
|
||||
[commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];
|
||||
}
|
||||
|
||||
// Metal Render function.
|
||||
void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer> commandBuffer, id<MTLRenderCommandEncoder> commandEncoder)
|
||||
{
|
||||
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||
MetalContext* ctx = bd->SharedMetalContext;
|
||||
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
||||
if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdListsCount == 0)
|
||||
return;
|
||||
|
||||
// Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
|
||||
// (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
|
||||
if (draw_data->Textures != nullptr)
|
||||
for (ImTextureData* tex : *draw_data->Textures)
|
||||
if (tex->Status != ImTextureStatus_OK)
|
||||
ImGui_ImplMetal_UpdateTexture(tex);
|
||||
|
||||
// Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame
|
||||
// The hit rate for this cache should be very near 100%.
|
||||
id<MTLRenderPipelineState> renderPipelineState = ctx.renderPipelineStateCache[ctx.framebufferDescriptor];
|
||||
if (renderPipelineState == nil)
|
||||
{
|
||||
// No luck; make a new render pipeline state
|
||||
renderPipelineState = [ctx renderPipelineStateForFramebufferDescriptor:ctx.framebufferDescriptor device:commandBuffer.device];
|
||||
|
||||
// Cache render pipeline state for later reuse
|
||||
ctx.renderPipelineStateCache[ctx.framebufferDescriptor] = renderPipelineState;
|
||||
}
|
||||
|
||||
size_t vertexBufferLength = (size_t)draw_data->TotalVtxCount * sizeof(ImDrawVert);
|
||||
size_t indexBufferLength = (size_t)draw_data->TotalIdxCount * sizeof(ImDrawIdx);
|
||||
MetalBuffer* vertexBuffer = [ctx dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];
|
||||
MetalBuffer* indexBuffer = [ctx dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
|
||||
|
||||
ImGui_ImplMetal_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, 0);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||
|
||||
// Render command lists
|
||||
size_t vertexBufferOffset = 0;
|
||||
size_t indexBufferOffset = 0;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* draw_list = draw_data->CmdLists[n];
|
||||
|
||||
memcpy((char*)vertexBuffer.buffer.contents + vertexBufferOffset, draw_list->VtxBuffer.Data, (size_t)draw_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||
memcpy((char*)indexBuffer.buffer.contents + indexBufferOffset, draw_list->IdxBuffer.Data, (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
|
||||
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplMetal_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, vertexBufferOffset);
|
||||
else
|
||||
pcmd->UserCallback(draw_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
|
||||
// Clamp to viewport as setScissorRect() won't accept values that are off bounds
|
||||
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
|
||||
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
|
||||
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
|
||||
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
|
||||
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||
continue;
|
||||
if (pcmd->ElemCount == 0) // drawIndexedPrimitives() validation doesn't accept this
|
||||
continue;
|
||||
|
||||
// Apply scissor/clipping rectangle
|
||||
MTLScissorRect scissorRect =
|
||||
{
|
||||
.x = NSUInteger(clip_min.x),
|
||||
.y = NSUInteger(clip_min.y),
|
||||
.width = NSUInteger(clip_max.x - clip_min.x),
|
||||
.height = NSUInteger(clip_max.y - clip_min.y)
|
||||
};
|
||||
[commandEncoder setScissorRect:scissorRect];
|
||||
|
||||
// Bind texture, Draw
|
||||
if (ImTextureID tex_id = pcmd->GetTexID())
|
||||
[commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(void*)(intptr_t)(tex_id) atIndex:0];
|
||||
|
||||
[commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];
|
||||
[commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:pcmd->ElemCount
|
||||
indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
|
||||
indexBuffer:indexBuffer.buffer
|
||||
indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];
|
||||
}
|
||||
}
|
||||
|
||||
vertexBufferOffset += (size_t)draw_list->VtxBuffer.Size * sizeof(ImDrawVert);
|
||||
indexBufferOffset += (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx);
|
||||
}
|
||||
|
||||
MetalContext* sharedMetalContext = bd->SharedMetalContext;
|
||||
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>)
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
@synchronized(sharedMetalContext.bufferCache)
|
||||
{
|
||||
[sharedMetalContext.bufferCache addObject:vertexBuffer];
|
||||
[sharedMetalContext.bufferCache addObject:indexBuffer];
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
static void ImGui_ImplMetal_DestroyTexture(ImTextureData* tex)
|
||||
{
|
||||
MetalTexture* backend_tex = (__bridge_transfer MetalTexture*)(tex->BackendUserData);
|
||||
if (backend_tex == nullptr)
|
||||
return;
|
||||
IM_ASSERT(backend_tex.metalTexture == (__bridge id<MTLTexture>)(void*)(intptr_t)tex->TexID);
|
||||
backend_tex.metalTexture = nil;
|
||||
|
||||
// Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
|
||||
tex->SetTexID(ImTextureID_Invalid);
|
||||
tex->SetStatus(ImTextureStatus_Destroyed);
|
||||
tex->BackendUserData = nullptr;
|
||||
}
|
||||
|
||||
void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex)
|
||||
{
|
||||
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||
if (tex->Status == ImTextureStatus_WantCreate)
|
||||
{
|
||||
// Create and upload new texture to graphics system
|
||||
//IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
|
||||
IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
|
||||
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
|
||||
|
||||
// We are retrieving and uploading the font atlas as a 4-channels RGBA texture here.
|
||||
// In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth.
|
||||
// However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures.
|
||||
// You can make that change in your implementation.
|
||||
MTLTextureDescriptor* textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
|
||||
width:(NSUInteger)tex->Width
|
||||
height:(NSUInteger)tex->Height
|
||||
mipmapped:NO];
|
||||
textureDescriptor.usage = MTLTextureUsageShaderRead;
|
||||
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
|
||||
textureDescriptor.storageMode = MTLStorageModeManaged;
|
||||
#else
|
||||
textureDescriptor.storageMode = MTLStorageModeShared;
|
||||
#endif
|
||||
id <MTLTexture> texture = [bd->SharedMetalContext.device newTextureWithDescriptor:textureDescriptor];
|
||||
[texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)tex->Width, (NSUInteger)tex->Height) mipmapLevel:0 withBytes:tex->Pixels bytesPerRow:(NSUInteger)tex->Width * 4];
|
||||
MetalTexture* backend_tex = [[MetalTexture alloc] initWithTexture:texture];
|
||||
|
||||
// Store identifiers
|
||||
tex->SetTexID((ImTextureID)(intptr_t)texture);
|
||||
tex->SetStatus(ImTextureStatus_OK);
|
||||
tex->BackendUserData = (__bridge_retained void*)(backend_tex);
|
||||
}
|
||||
else if (tex->Status == ImTextureStatus_WantUpdates)
|
||||
{
|
||||
// Update selected blocks. We only ever write to textures regions which have never been used before!
|
||||
// This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region.
|
||||
MetalTexture* backend_tex = (__bridge MetalTexture*)(tex->BackendUserData);
|
||||
for (ImTextureRect& r : tex->Updates)
|
||||
{
|
||||
[backend_tex.metalTexture replaceRegion:MTLRegionMake2D((NSUInteger)r.x, (NSUInteger)r.y, (NSUInteger)r.w, (NSUInteger)r.h)
|
||||
mipmapLevel:0
|
||||
withBytes:tex->GetPixelsAt(r.x, r.y)
|
||||
bytesPerRow:(NSUInteger)tex->Width * 4];
|
||||
}
|
||||
tex->SetStatus(ImTextureStatus_OK);
|
||||
}
|
||||
else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0)
|
||||
{
|
||||
ImGui_ImplMetal_DestroyTexture(tex);
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device)
|
||||
{
|
||||
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||
MTLDepthStencilDescriptor* depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];
|
||||
depthStencilDescriptor.depthWriteEnabled = NO;
|
||||
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
|
||||
bd->SharedMetalContext.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
|
||||
#ifdef IMGUI_IMPL_METAL_CPP
|
||||
[depthStencilDescriptor release];
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplMetal_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||
|
||||
// Destroy all textures
|
||||
for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
|
||||
if (tex->RefCount == 1)
|
||||
ImGui_ImplMetal_DestroyTexture(tex);
|
||||
|
||||
[bd->SharedMetalContext.renderPipelineStateCache removeAllObjects];
|
||||
}
|
||||
|
||||
#pragma mark - MetalBuffer implementation
|
||||
|
||||
@implementation MetalBuffer
|
||||
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_buffer = buffer;
|
||||
_lastReuseTime = GetMachAbsoluteTimeInSeconds();
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
#pragma mark - FramebufferDescriptor implementation
|
||||
|
||||
@implementation FramebufferDescriptor
|
||||
- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount;
|
||||
_colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat;
|
||||
_depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat;
|
||||
_stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nonnull id)copyWithZone:(nullable NSZone*)zone
|
||||
{
|
||||
FramebufferDescriptor* copy = [[FramebufferDescriptor allocWithZone:zone] init];
|
||||
copy.sampleCount = self.sampleCount;
|
||||
copy.colorPixelFormat = self.colorPixelFormat;
|
||||
copy.depthPixelFormat = self.depthPixelFormat;
|
||||
copy.stencilPixelFormat = self.stencilPixelFormat;
|
||||
return copy;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
NSUInteger sc = _sampleCount & 0x3;
|
||||
NSUInteger cf = _colorPixelFormat & 0x3FF;
|
||||
NSUInteger df = _depthPixelFormat & 0x3FF;
|
||||
NSUInteger sf = _stencilPixelFormat & 0x3FF;
|
||||
NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc;
|
||||
return hash;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
FramebufferDescriptor* other = object;
|
||||
if (![other isKindOfClass:[FramebufferDescriptor class]])
|
||||
return NO;
|
||||
return other.sampleCount == self.sampleCount &&
|
||||
other.colorPixelFormat == self.colorPixelFormat &&
|
||||
other.depthPixelFormat == self.depthPixelFormat &&
|
||||
other.stencilPixelFormat == self.stencilPixelFormat;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - MetalTexture implementation
|
||||
|
||||
@implementation MetalTexture
|
||||
- (instancetype)initWithTexture:(id<MTLTexture>)metalTexture
|
||||
{
|
||||
if ((self = [super init]))
|
||||
self.metalTexture = metalTexture;
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - MetalContext implementation
|
||||
|
||||
@implementation MetalContext
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
self.renderPipelineStateCache = [NSMutableDictionary dictionary];
|
||||
self.bufferCache = [NSMutableArray array];
|
||||
_lastBufferCachePurge = GetMachAbsoluteTimeInSeconds();
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device
|
||||
{
|
||||
uint64_t now = GetMachAbsoluteTimeInSeconds();
|
||||
|
||||
@synchronized(self.bufferCache)
|
||||
{
|
||||
// Purge old buffers that haven't been useful for a while
|
||||
if (now - self.lastBufferCachePurge > 1.0)
|
||||
{
|
||||
NSMutableArray* survivors = [NSMutableArray array];
|
||||
for (MetalBuffer* candidate in self.bufferCache)
|
||||
if (candidate.lastReuseTime > self.lastBufferCachePurge)
|
||||
[survivors addObject:candidate];
|
||||
self.bufferCache = [survivors mutableCopy];
|
||||
self.lastBufferCachePurge = now;
|
||||
}
|
||||
|
||||
// See if we have a buffer we can reuse
|
||||
MetalBuffer* bestCandidate = nil;
|
||||
for (MetalBuffer* candidate in self.bufferCache)
|
||||
if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime))
|
||||
bestCandidate = candidate;
|
||||
|
||||
if (bestCandidate != nil)
|
||||
{
|
||||
[self.bufferCache removeObject:bestCandidate];
|
||||
bestCandidate.lastReuseTime = now;
|
||||
return bestCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
// No luck; make a new buffer
|
||||
id<MTLBuffer> backing = [device newBufferWithLength:length options:MTLResourceStorageModeShared];
|
||||
return [[MetalBuffer alloc] initWithBuffer:backing];
|
||||
}
|
||||
|
||||
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
|
||||
- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device
|
||||
{
|
||||
NSError* error = nil;
|
||||
|
||||
NSString* shaderSource = @""
|
||||
"#include <metal_stdlib>\n"
|
||||
"using namespace metal;\n"
|
||||
"\n"
|
||||
"struct Uniforms {\n"
|
||||
" float4x4 projectionMatrix;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"struct VertexIn {\n"
|
||||
" float2 position [[attribute(0)]];\n"
|
||||
" float2 texCoords [[attribute(1)]];\n"
|
||||
" uchar4 color [[attribute(2)]];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"struct VertexOut {\n"
|
||||
" float4 position [[position]];\n"
|
||||
" float2 texCoords;\n"
|
||||
" float4 color;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"vertex VertexOut vertex_main(VertexIn in [[stage_in]],\n"
|
||||
" constant Uniforms &uniforms [[buffer(1)]]) {\n"
|
||||
" VertexOut out;\n"
|
||||
" out.position = uniforms.projectionMatrix * float4(in.position, 0, 1);\n"
|
||||
" out.texCoords = in.texCoords;\n"
|
||||
" out.color = float4(in.color) / float4(255.0);\n"
|
||||
" return out;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fragment half4 fragment_main(VertexOut in [[stage_in]],\n"
|
||||
" texture2d<half, access::sample> texture [[texture(0)]]) {\n"
|
||||
" constexpr sampler linearSampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear);\n"
|
||||
" half4 texColor = texture.sample(linearSampler, in.texCoords);\n"
|
||||
" return half4(in.color) * texColor;\n"
|
||||
"}\n";
|
||||
|
||||
id<MTLLibrary> library = [device newLibraryWithSource:shaderSource options:nil error:&error];
|
||||
if (library == nil)
|
||||
{
|
||||
NSLog(@"Error: failed to create Metal library: %@", error);
|
||||
return nil;
|
||||
}
|
||||
|
||||
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"vertex_main"];
|
||||
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"fragment_main"];
|
||||
|
||||
if (vertexFunction == nil || fragmentFunction == nil)
|
||||
{
|
||||
NSLog(@"Error: failed to find Metal shader functions in library: %@", error);
|
||||
return nil;
|
||||
}
|
||||
|
||||
MTLVertexDescriptor* vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];
|
||||
vertexDescriptor.attributes[0].offset = offsetof(ImDrawVert, pos);
|
||||
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position
|
||||
vertexDescriptor.attributes[0].bufferIndex = 0;
|
||||
vertexDescriptor.attributes[1].offset = offsetof(ImDrawVert, uv);
|
||||
vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; // texCoords
|
||||
vertexDescriptor.attributes[1].bufferIndex = 0;
|
||||
vertexDescriptor.attributes[2].offset = offsetof(ImDrawVert, col);
|
||||
vertexDescriptor.attributes[2].format = MTLVertexFormatUChar4; // color
|
||||
vertexDescriptor.attributes[2].bufferIndex = 0;
|
||||
vertexDescriptor.layouts[0].stepRate = 1;
|
||||
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||
vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert);
|
||||
|
||||
MTLRenderPipelineDescriptor* pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||
pipelineDescriptor.vertexFunction = vertexFunction;
|
||||
pipelineDescriptor.fragmentFunction = fragmentFunction;
|
||||
pipelineDescriptor.vertexDescriptor = vertexDescriptor;
|
||||
pipelineDescriptor.rasterSampleCount = self.framebufferDescriptor.sampleCount;
|
||||
pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat;
|
||||
pipelineDescriptor.colorAttachments[0].blendingEnabled = YES;
|
||||
pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
|
||||
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||
pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||
pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
|
||||
pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
|
||||
pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||
pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat;
|
||||
pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat;
|
||||
|
||||
id<MTLRenderPipelineState> renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
|
||||
if (error != nil)
|
||||
NSLog(@"Error: failed to create Metal pipeline state: %@", error);
|
||||
|
||||
return renderPipelineState;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
@@ -21,6 +21,5 @@
|
||||
- (void)saveContext;
|
||||
- (NSURL *)applicationDocumentsDirectory;
|
||||
- (NSURL*) getStoreURL;
|
||||
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0));
|
||||
|
||||
@end
|
||||
@@ -5,13 +5,8 @@
|
||||
// Created by Diego Waxemberg on 1/17/14.
|
||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
// Modified by True砖家 since 2024.7.12
|
||||
// Copyright © 2024 True砖家 @ Bilibili. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "MainFrameViewController.h"
|
||||
#import "VoidLink-Swift.h"
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
@@ -27,64 +22,17 @@ static NSString* DB_NAME = @"Moonlight_tvOS.bin";
|
||||
static NSString* DB_NAME = @"Limelight_iOS.sqlite";
|
||||
#endif
|
||||
|
||||
#pragma mark - UISceneSession lifecycle
|
||||
|
||||
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0)){
|
||||
return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions API_AVAILABLE(ios(13.0)){
|
||||
}
|
||||
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
/*
|
||||
// orietation limitatioin test
|
||||
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
|
||||
UIViewController *topController = window.rootViewController;
|
||||
while (topController.presentedViewController) {
|
||||
topController = topController.presentedViewController;
|
||||
}
|
||||
return [topController supportedInterfaceOrientations];
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
|
||||
NSLog(@"orientation limit");
|
||||
return UIInterfaceOrientationMaskLandscape;
|
||||
}
|
||||
*/
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
// Override point for command tool customization after application launch (works only when user default is nil)
|
||||
[CommandManager presetDefaultCommands];
|
||||
|
||||
// For iOS 12 and below, we need to manually create the window
|
||||
if (@available(iOS 13.0, *)) {
|
||||
// Scene delegate will handle window creation
|
||||
} else {
|
||||
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
|
||||
NSString *storyboardName;
|
||||
if (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
|
||||
storyboardName = @"iPad";
|
||||
} else {
|
||||
storyboardName = @"iPhone";
|
||||
}
|
||||
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
|
||||
UIViewController *initialViewController = [storyboard instantiateInitialViewController];
|
||||
|
||||
self.window.rootViewController = initialViewController;
|
||||
[self.window makeKeyAndVisible];
|
||||
#if !TARGET_OS_TV
|
||||
UIApplicationShortcutItem* shortcut = [launchOptions valueForKey:UIApplicationLaunchOptionsShortcutItemKey];
|
||||
if (shortcut != nil) {
|
||||
_pcUuidToLoad = (NSString*)[shortcut.userInfo objectForKey:@"UUID"];
|
||||
}
|
||||
|
||||
#endif
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded))completionHandler {
|
||||
_pcUuidToLoad = (NSString*)[shortcutItem.userInfo objectForKey:@"UUID"];
|
||||
_shortcutCompletionHandler = completionHandler;
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// ComputerScrollView.h
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Diego Waxemberg on 9/30/15.
|
||||
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ComputerScrollView : UIScrollView
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// ComputerScrollView.m
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Diego Waxemberg on 9/30/15.
|
||||
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ComputerScrollView.h"
|
||||
|
||||
@implementation ComputerScrollView
|
||||
|
||||
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
|
||||
if ([view isKindOfClass:[UIButton class]]) {
|
||||
return YES;
|
||||
}
|
||||
return [super touchesShouldCancelInContentView:view];
|
||||
}
|
||||
|
||||
/*
|
||||
// Only override drawRect: if you perform custom drawing.
|
||||
// An empty implementation adversely affects performance during animation.
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
// Drawing code
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
@@ -96,7 +96,6 @@ static NSData* p12 = nil;
|
||||
|
||||
bio = BIO_new(BIO_s_mem());
|
||||
i2d_X509_bio(bio, x509);
|
||||
X509_free(x509);
|
||||
|
||||
BUF_MEM* mem;
|
||||
BIO_get_mem_ptr(bio, &mem);
|
||||
@@ -223,7 +222,6 @@ static NSData* p12 = nil;
|
||||
+ (NSData *)getSignatureFromCert:(NSData *)cert {
|
||||
BIO* bio = BIO_new_mem_buf([cert bytes], (int)[cert length]);
|
||||
X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
|
||||
if (!x509) {
|
||||
Log(LOG_E, @"Unable to parse certificate in memory!");
|
||||
@@ -4,12 +4,10 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <OpenSSL/provider.h>
|
||||
#include <OpenSSL/rsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <OpenSSL/rand.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
static const int NUM_BITS = 2048;
|
||||
static const int SERIAL = 0;
|
||||
@@ -63,30 +61,22 @@ void mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
|
||||
}
|
||||
|
||||
struct CertKeyPair generateCertKeyPair(void) {
|
||||
BIO *bio_err;
|
||||
X509 *x509 = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
PKCS12 *p12 = NULL;
|
||||
|
||||
bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
|
||||
|
||||
mkcert(&x509, &pkey, NUM_BITS, SERIAL, NUM_YEARS);
|
||||
|
||||
char* pass = "limelight";
|
||||
p12 = PKCS12_create(pass,
|
||||
"GameStream",
|
||||
pkey,
|
||||
x509,
|
||||
NULL,
|
||||
NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
|
||||
-1, // disable certificate encryption
|
||||
2048,
|
||||
-1, // disable the automatic MAC
|
||||
0);
|
||||
// MAC it ourselves with SHA1 since iOS refuses to load anything else.
|
||||
PKCS12_set_mac(p12, pass, -1, NULL, 0, 1, EVP_sha1());
|
||||
|
||||
|
||||
p12 = PKCS12_create("limelight", "GameStream", pkey, x509, NULL, 0, 0, 0, 0, 0);
|
||||
if (p12 == NULL) {
|
||||
printf("Error generating a valid PKCS12 certificate.\n");
|
||||
}
|
||||
|
||||
BIO_free(bio_err);
|
||||
|
||||
return (CertKeyPair){x509, pkey, p12};
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#ifndef Limelight_mkcert_h
|
||||
#define Limelight_mkcert_h
|
||||
|
||||
#include <sys/_types/_time_t.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/pkcs12.h>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// DataManager.h
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/28/14.
|
||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "TemporaryHost.h"
|
||||
#import "TemporaryApp.h"
|
||||
#import "TemporarySettings.h"
|
||||
|
||||
@interface DataManager : NSObject
|
||||
|
||||
- (void) saveSettingsWithBitrate:(NSInteger)bitrate
|
||||
framerate:(NSInteger)framerate
|
||||
height:(NSInteger)height
|
||||
width:(NSInteger)width
|
||||
audioConfig:(NSInteger)audioConfig
|
||||
onscreenControls:(NSInteger)onscreenControls
|
||||
keyboardToggleFingers:(NSInteger)keyboardToggleFingers
|
||||
swipeExitScreenEdge:(NSInteger)swipeExitScreenEdge
|
||||
swipeToExitDistance:(CGFloat)swipeToExitDistance
|
||||
pointerVelocityModeDivider:(CGFloat)pointerVelocityModeDivider
|
||||
touchPointerVelocityFactor:(CGFloat)touchPointerVelocityFactor
|
||||
liftStreamViewForKeyboard:(BOOL)liftStreamViewForKeyboard
|
||||
showKeyboardToolbar:(BOOL)showKeyboardToolbar
|
||||
optimizeGames:(BOOL)optimizeGames
|
||||
multiController:(BOOL)multiController
|
||||
swapABXYButtons:(BOOL)swapABXYButtons
|
||||
audioOnPC:(BOOL)audioOnPC
|
||||
preferredCodec:(uint32_t)preferredCodec
|
||||
useFramePacing:(BOOL)useFramePacing
|
||||
enableHdr:(BOOL)enableHdr
|
||||
btMouseSupport:(BOOL)btMouseSupport
|
||||
absoluteTouchMode:(BOOL)absoluteTouchMode
|
||||
statsOverlay:(BOOL)statsOverlay;
|
||||
|
||||
- (NSArray*) getHosts;
|
||||
- (void) updateHost:(TemporaryHost*)host;
|
||||
- (void) updateAppsForExistingHost:(TemporaryHost *)host;
|
||||
- (void) removeHost:(TemporaryHost*)host;
|
||||
- (void) removeApp:(TemporaryApp*)app;
|
||||
|
||||
- (TemporarySettings*) getSettings;
|
||||
|
||||
- (void) updateUniqueId:(NSString*)uniqueId;
|
||||
- (NSString*) getUniqueId;
|
||||
|
||||
@end
|
||||
@@ -5,9 +5,6 @@
|
||||
// Created by Diego Waxemberg on 10/28/14.
|
||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
// Modified by True砖家 since 2024.6.1
|
||||
// Copyright © 2024 True砖家 @ Bilibili. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DataManager.h"
|
||||
#import "TemporaryApp.h"
|
||||
@@ -61,19 +58,11 @@
|
||||
width:(NSInteger)width
|
||||
audioConfig:(NSInteger)audioConfig
|
||||
onscreenControls:(NSInteger)onscreenControls
|
||||
gyroMode:(NSInteger)gyroMode
|
||||
emulatedControllerType:(NSInteger)emulatedControllerType
|
||||
keyboardToggleFingers:(NSInteger)keyboardToggleFingers
|
||||
oscLayoutToolFingers:(NSInteger)oscLayoutToolFingers
|
||||
slideToSettingsScreenEdge:(NSInteger)slideToSettingsScreenEdge
|
||||
slideToSettingsDistance:(CGFloat)slideToSettingsDistance
|
||||
swipeExitScreenEdge:(NSInteger)swipeExitScreenEdge
|
||||
swipeToExitDistance:(CGFloat)swipeToExitDistance
|
||||
pointerVelocityModeDivider:(CGFloat)pointerVelocityModeDivider
|
||||
touchPointerVelocityFactor:(CGFloat)touchPointerVelocityFactor
|
||||
mousePointerVelocityFactor:(CGFloat)mousePointerVelocityFactor
|
||||
gyroSensitivity:(CGFloat)gyroSensitivity
|
||||
touchMoveEventInterval:(NSInteger)touchMoveEventInterval
|
||||
reverseMouseWheelDirection:(BOOL)reverseMouseWheelDirection
|
||||
asyncNativeTouchPriority:(NSInteger)asyncNativeTouchPriority
|
||||
liftStreamViewForKeyboard:(BOOL)liftStreamViewForKeyboard
|
||||
showKeyboardToolbar:(BOOL)showKeyboardToolbar
|
||||
optimizeGames:(BOOL)optimizeGames
|
||||
@@ -81,25 +70,12 @@
|
||||
swapABXYButtons:(BOOL)swapABXYButtons
|
||||
audioOnPC:(BOOL)audioOnPC
|
||||
preferredCodec:(uint32_t)preferredCodec
|
||||
enableYUV444:(BOOL)enableYUV444
|
||||
enablePIP:(BOOL)enablePIP
|
||||
useFramePacing:(BOOL)useFramePacing
|
||||
enableHdr:(BOOL)enableHdr
|
||||
btMouseSupport:(BOOL)btMouseSupport
|
||||
// absoluteTouchMode:(BOOL)absoluteTouchMode
|
||||
touchMode:(NSInteger)touchMode
|
||||
statsOverlayLevel:(NSInteger)statsOverlayLevel
|
||||
statsOverlayEnabled:(BOOL)statsOverlayEnabled
|
||||
unlockDisplayOrientation:(BOOL)unlockDisplayOrientation
|
||||
resolutionSelected:(NSInteger)resolutionSelected
|
||||
externalDisplayMode:(NSInteger)externalDisplayMode
|
||||
localMousePointerMode:(NSInteger)localMousePointerMode
|
||||
frameQueueSize:(NSInteger)frameQueueSize
|
||||
enableGraphs:(BOOL)enableGraphs
|
||||
graphOpacity:(NSInteger)graphOpacity
|
||||
renderingBackend:(NSInteger)renderingBackend
|
||||
framePacingMode:(NSInteger)framePacingMode
|
||||
backgroundSessionTimer:(NSInteger)backgroundSessionTimer{
|
||||
|
||||
absoluteTouchMode:(BOOL)absoluteTouchMode
|
||||
statsOverlay:(BOOL)statsOverlay {
|
||||
|
||||
[_managedObjectContext performBlockAndWait:^{
|
||||
Settings* settingsToSave = [self retrieveSettings];
|
||||
settingsToSave.framerate = [NSNumber numberWithInteger:framerate];
|
||||
@@ -108,19 +84,11 @@
|
||||
settingsToSave.width = [NSNumber numberWithInteger:width];
|
||||
settingsToSave.audioConfig = [NSNumber numberWithInteger:audioConfig];
|
||||
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
|
||||
settingsToSave.gyroMode = [NSNumber numberWithInteger:gyroMode];
|
||||
settingsToSave.emulatedControllerType = [NSNumber numberWithInteger:emulatedControllerType];
|
||||
settingsToSave.keyboardToggleFingers = [NSNumber numberWithInteger:(uint16_t)keyboardToggleFingers];
|
||||
settingsToSave.oscLayoutToolFingers = [NSNumber numberWithInteger:(uint16_t)oscLayoutToolFingers];
|
||||
settingsToSave.slideToSettingsScreenEdge = [NSNumber numberWithInteger:(uint32_t)slideToSettingsScreenEdge];
|
||||
settingsToSave.slideToSettingsDistance = [NSNumber numberWithFloat:slideToSettingsDistance];
|
||||
settingsToSave.swipeExitScreenEdge = [NSNumber numberWithInteger:(uint32_t)swipeExitScreenEdge];
|
||||
settingsToSave.swipeToExitDistance = [NSNumber numberWithFloat:swipeToExitDistance];
|
||||
settingsToSave.pointerVelocityModeDivider = [NSNumber numberWithFloat:pointerVelocityModeDivider];
|
||||
settingsToSave.touchPointerVelocityFactor = [NSNumber numberWithFloat:touchPointerVelocityFactor];
|
||||
settingsToSave.mousePointerVelocityFactor = [NSNumber numberWithFloat:mousePointerVelocityFactor];
|
||||
settingsToSave.gyroSensitivity = [NSNumber numberWithFloat:gyroSensitivity];
|
||||
settingsToSave.touchMoveEventInterval = [NSNumber numberWithInteger:touchMoveEventInterval];
|
||||
settingsToSave.reverseMouseWheelDirection = reverseMouseWheelDirection;
|
||||
settingsToSave.asyncNativeTouchPriority = [NSNumber numberWithInteger:asyncNativeTouchPriority];
|
||||
settingsToSave.liftStreamViewForKeyboard = liftStreamViewForKeyboard;
|
||||
settingsToSave.showKeyboardToolbar = showKeyboardToolbar;
|
||||
settingsToSave.optimizeGames = optimizeGames;
|
||||
@@ -128,25 +96,12 @@
|
||||
settingsToSave.swapABXYButtons = swapABXYButtons;
|
||||
settingsToSave.playAudioOnPC = audioOnPC;
|
||||
settingsToSave.preferredCodec = preferredCodec;
|
||||
settingsToSave.enableYUV444 = enableYUV444;
|
||||
settingsToSave.enablePIP = enablePIP;
|
||||
settingsToSave.useFramePacing = useFramePacing;
|
||||
settingsToSave.enableHdr = enableHdr;
|
||||
settingsToSave.btMouseSupport = btMouseSupport;
|
||||
// settingsToSave.absoluteTouchMode = absoluteTouchMode;
|
||||
settingsToSave.touchMode = [NSNumber numberWithInteger:(uint16_t)touchMode];
|
||||
settingsToSave.statsOverlayEnabled = statsOverlayEnabled;
|
||||
settingsToSave.statsOverlayLevel = [NSNumber numberWithInteger:(uint16_t)statsOverlayLevel];
|
||||
settingsToSave.unlockDisplayOrientation = unlockDisplayOrientation;
|
||||
settingsToSave.resolutionSelected = [NSNumber numberWithInteger:resolutionSelected];
|
||||
settingsToSave.externalDisplayMode = [NSNumber numberWithInteger:externalDisplayMode];
|
||||
settingsToSave.localMousePointerMode = [NSNumber numberWithInteger:localMousePointerMode];
|
||||
settingsToSave.backroundSessionTimer = [NSNumber numberWithInteger:backgroundSessionTimer];
|
||||
|
||||
settingsToSave.frameQueueSize = [NSNumber numberWithInteger:frameQueueSize];
|
||||
settingsToSave.enableGraphs = enableGraphs;
|
||||
settingsToSave.graphOpacity = [NSNumber numberWithInteger:graphOpacity];
|
||||
settingsToSave.renderingBackend = [NSNumber numberWithInteger:renderingBackend];
|
||||
settingsToSave.framePacingMode = [NSNumber numberWithInteger:framePacingMode];
|
||||
settingsToSave.absoluteTouchMode = absoluteTouchMode;
|
||||
settingsToSave.statsOverlay = statsOverlay;
|
||||
|
||||
[self saveData];
|
||||
}];
|
||||
}
|
||||
@@ -5,9 +5,6 @@
|
||||
// Created by Cameron Gutman on 12/1/15.
|
||||
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
// Modified by True砖家 since 2024.8.3
|
||||
// Copyright © 2024 True砖家 @ Bilibili. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DataManager.h"
|
||||
#import "TemporaryHost.h"
|
||||
@@ -31,7 +28,7 @@
|
||||
self.externalAddress = host.externalAddress;
|
||||
self.localAddress = host.localAddress;
|
||||
self.ipv6Address = host.ipv6Address;
|
||||
if(!(host.mac == nil || [host.mac isEqualToString:@"00:00:00:00:00:00"])) self.mac = host.mac; // try to fix invalid mac happens in some cases
|
||||
self.mac = host.mac;
|
||||
self.name = host.name;
|
||||
self.uuid = host.uuid;
|
||||
self.serverCodecModeSupport = host.serverCodecModeSupport;
|
||||
@@ -73,9 +70,9 @@
|
||||
if (self.ipv6Address != nil) {
|
||||
parentHost.ipv6Address = self.ipv6Address;
|
||||
}
|
||||
// try to fix invalid mac happens in some cases
|
||||
// 添加主机crash问题重点关注
|
||||
if (!(self.mac == nil || [self.mac isEqualToString:@"00:00:00:00:00:00"])) parentHost.mac = self.mac;
|
||||
if (self.mac != nil) {
|
||||
parentHost.mac = self.mac;
|
||||
}
|
||||
if (self.serverCert != nil) {
|
||||
parentHost.serverCert = self.serverCert;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// TemporarySettings.h
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Cameron Gutman on 12/1/15.
|
||||
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Settings+CoreDataClass.h"
|
||||
|
||||
@interface TemporarySettings : NSObject
|
||||
|
||||
@property (nonatomic, retain) Settings * parent;
|
||||
|
||||
@property (nonatomic, retain) NSNumber * bitrate;
|
||||
@property (nonatomic, retain) NSNumber * framerate;
|
||||
@property (nonatomic, retain) NSNumber * height;
|
||||
@property (nonatomic, retain) NSNumber * width;
|
||||
@property (nonatomic, retain) NSNumber * audioConfig;
|
||||
@property (nonatomic, retain) NSNumber * onscreenControls;
|
||||
@property (nonatomic, retain) NSNumber * keyboardToggleFingers;
|
||||
@property (nonatomic, retain) NSNumber * swipeExitScreenEdge;
|
||||
@property (nonatomic, retain) NSNumber * swipeToExitDistance;
|
||||
@property (nonatomic, retain) NSNumber * touchPointerVelocityFactor;
|
||||
@property (nonatomic, retain) NSNumber * pointerVelocityModeDivider;
|
||||
@property (nonatomic, retain) NSString * uniqueId;
|
||||
@property (nonatomic) enum {
|
||||
CODEC_PREF_AUTO,
|
||||
CODEC_PREF_H264,
|
||||
CODEC_PREF_HEVC,
|
||||
CODEC_PREF_AV1,
|
||||
} preferredCodec;
|
||||
@property (nonatomic) BOOL useFramePacing;
|
||||
@property (nonatomic) BOOL multiController;
|
||||
@property (nonatomic) BOOL swapABXYButtons;
|
||||
@property (nonatomic) BOOL playAudioOnPC;
|
||||
@property (nonatomic) BOOL optimizeGames;
|
||||
@property (nonatomic) BOOL enableHdr;
|
||||
@property (nonatomic) BOOL btMouseSupport;
|
||||
@property (nonatomic) BOOL absoluteTouchMode;
|
||||
@property (nonatomic) BOOL statsOverlay;
|
||||
@property (nonatomic) BOOL liftStreamViewForKeyboard;
|
||||
@property (nonatomic) BOOL showKeyboardToolbar;
|
||||
|
||||
|
||||
- (id) initFromSettings:(Settings*)settings;
|
||||
|
||||
@end
|
||||
@@ -5,9 +5,6 @@
|
||||
// Created by Cameron Gutman on 12/1/15.
|
||||
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
// Modified by True砖家 since 2024.6.1
|
||||
// Copyright © 2024 True砖家 @ Bilibili. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TemporarySettings.h"
|
||||
#import "OnScreenControls.h"
|
||||
@@ -35,14 +32,12 @@
|
||||
|
||||
self.bitrate = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"bitrate"]];
|
||||
assert([self.bitrate intValue] != 0);
|
||||
self.framerate = [NSNumber numberWithDouble:[[NSUserDefaults standardUserDefaults] doubleForKey:@"framerate"]];
|
||||
assert([self.framerate doubleValue] != 0.0);
|
||||
self.framerate = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"framerate"]];
|
||||
assert([self.framerate intValue] != 0);
|
||||
self.audioConfig = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"audioConfig"]];
|
||||
assert([self.audioConfig intValue] != 0);
|
||||
self.preferredCodec = (typeof(self.preferredCodec))[[NSUserDefaults standardUserDefaults] integerForKey:@"preferredCodec"];
|
||||
self.enableYUV444 = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableYUV444"];
|
||||
self.enablePIP = [[NSUserDefaults standardUserDefaults] boolForKey:@"enablePIP"];
|
||||
self.frameQueueSize = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"frameQueueSize"]];
|
||||
self.useFramePacing = [[NSUserDefaults standardUserDefaults] integerForKey:@"useFramePacing"] != 0;
|
||||
self.playAudioOnPC = [[NSUserDefaults standardUserDefaults] boolForKey:@"audioOnPC"];
|
||||
self.enableHdr = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableHdr"];
|
||||
self.optimizeGames = [[NSUserDefaults standardUserDefaults] boolForKey:@"optimizeGames"];
|
||||
@@ -50,19 +45,7 @@
|
||||
self.swapABXYButtons = [[NSUserDefaults standardUserDefaults] boolForKey:@"swapABXYButtons"];
|
||||
self.btMouseSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"btMouseSupport"];
|
||||
self.statsOverlay = [[NSUserDefaults standardUserDefaults] boolForKey:@"statsOverlay"];
|
||||
self.enableGraphs = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableGraphs"];
|
||||
self.graphOpacity = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"graphOpacity"]];
|
||||
// Set rendering backend based on iOS version and user preference
|
||||
NSInteger savedBackend = [[NSUserDefaults standardUserDefaults] integerForKey:@"renderingBackend"];
|
||||
if (@available(iOS 17.0, *)) {
|
||||
// iOS 17+ can use Performance mode (Metal renderer)
|
||||
self.renderingBackend = [NSNumber numberWithInteger:savedBackend];
|
||||
} else {
|
||||
// iOS < 17 must use Balanced mode (AVSB renderer)
|
||||
self.renderingBackend = [NSNumber numberWithInteger:RENDER_AVSB];
|
||||
}
|
||||
self.framePacingMode = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"framePacingMode"]];
|
||||
|
||||
|
||||
NSInteger _screenSize = [[NSUserDefaults standardUserDefaults] integerForKey:@"streamResolution"];
|
||||
switch (_screenSize) {
|
||||
case 0:
|
||||
@@ -86,52 +69,29 @@
|
||||
}
|
||||
self.onscreenControls = [NSNumber numberWithInteger:OnScreenControlsLevelOff];
|
||||
#else
|
||||
self.settingsMenuMode = settings.settingsMenuMode;
|
||||
self.settingsMenuWidth = settings.settingsMenuWidth;
|
||||
self.bitrate = settings.bitrate;
|
||||
self.framerate = settings.framerate;
|
||||
self.height = settings.height;
|
||||
self.width = settings.width;
|
||||
self.audioConfig = settings.audioConfig;
|
||||
self.preferredCodec = settings.preferredCodec;
|
||||
self.enableYUV444 = settings.enableYUV444;
|
||||
self.enablePIP = settings.enablePIP;
|
||||
self.frameQueueSize = settings.frameQueueSize;
|
||||
self.useFramePacing = settings.useFramePacing;
|
||||
self.playAudioOnPC = settings.playAudioOnPC;
|
||||
self.enableHdr = settings.enableHdr;
|
||||
self.optimizeGames = settings.optimizeGames;
|
||||
self.multiController = settings.multiController;
|
||||
self.swapABXYButtons = settings.swapABXYButtons;
|
||||
self.onscreenControls = settings.onscreenControls;
|
||||
self.gyroMode = settings.gyroMode;
|
||||
self.emulatedControllerType = settings.emulatedControllerType;
|
||||
self.reverseMouseWheelDirection = settings.reverseMouseWheelDirection;
|
||||
self.asyncNativeTouchPriority = settings.asyncNativeTouchPriority;
|
||||
self.btMouseSupport = settings.btMouseSupport;
|
||||
// self.absoluteTouchMode = settings.absoluteTouchMode;
|
||||
self.touchMode = settings.touchMode;
|
||||
self.statsOverlayLevel = settings.statsOverlayLevel;
|
||||
self.statsOverlayEnabled = settings.statsOverlayEnabled;
|
||||
self.absoluteTouchMode = settings.absoluteTouchMode;
|
||||
self.statsOverlay = settings.statsOverlay;
|
||||
self.keyboardToggleFingers = settings.keyboardToggleFingers;
|
||||
self.oscLayoutToolFingers = settings.oscLayoutToolFingers;
|
||||
self.slideToSettingsScreenEdge = settings.slideToSettingsScreenEdge;
|
||||
self.slideToSettingsDistance = settings.slideToSettingsDistance;
|
||||
self.swipeExitScreenEdge = settings.swipeExitScreenEdge;
|
||||
self.swipeToExitDistance = settings.swipeToExitDistance;
|
||||
self.liftStreamViewForKeyboard = settings.liftStreamViewForKeyboard;
|
||||
self.showKeyboardToolbar = settings.showKeyboardToolbar;
|
||||
self.touchMoveEventInterval = settings.touchMoveEventInterval;
|
||||
self.touchPointerVelocityFactor = settings.touchPointerVelocityFactor;
|
||||
self.mousePointerVelocityFactor = settings.mousePointerVelocityFactor;
|
||||
self.gyroSensitivity = settings.gyroSensitivity;
|
||||
self.pointerVelocityModeDivider = settings.pointerVelocityModeDivider;
|
||||
self.unlockDisplayOrientation = settings.unlockDisplayOrientation;
|
||||
self.resolutionSelected = settings.resolutionSelected;
|
||||
self.externalDisplayMode = settings.externalDisplayMode;
|
||||
self.localMousePointerMode = settings.localMousePointerMode;
|
||||
self.enableGraphs = settings.enableGraphs;
|
||||
self.graphOpacity = settings.graphOpacity;
|
||||
self.renderingBackend = settings.renderingBackend;
|
||||
self.framePacingMode = settings.framePacingMode;
|
||||
self.backgroundSessionTimer = settings.backroundSessionTimer;
|
||||
#endif
|
||||
self.uniqueId = settings.uniqueId;
|
||||
|
||||
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 32 KiB |
@@ -1,116 +1,112 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Icon-App-40x40@1x 2.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-20x20@3x 1.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "29x29"
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "40x40"
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "60x60"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "60x60"
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-20x20@1x 1.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Icon-App-40x40@1x 1.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "29x29"
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@2x-1.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@1x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "40x40"
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@2x-1.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@1x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "76x76"
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "76x76"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "83.5x83.5"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "1024x icon.png",
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"scale" : "1x",
|
||||
"size" : "1024x1024"
|
||||
"filename" : "1024x icon.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 405 B After Width: | Height: | Size: 405 B |
|
Before Width: | Height: | Size: 455 B After Width: | Height: | Size: 455 B |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 525 B After Width: | Height: | Size: 525 B |
|
After Width: | Height: | Size: 1.1 KiB |