[GPU/Metal] Snapshot native MSL and iOS app work
@@ -0,0 +1,228 @@
|
||||
# Codebase Discovery Report: Xenia (Xbox 360 Emulator) — iOS/Metal Port
|
||||
|
||||
> Generated by the `porting-discover` methodology (Game Porting Toolkit 4 skills).
|
||||
> **Framing caveat:** This is **not a greenfield port**. Xenia already has a mature, largely
|
||||
> complete Metal backend on Metal 3 (metal-cpp). This report is therefore a **Metal 4 / GPTK-4
|
||||
> modernization readiness** assessment, not a from-scratch porting discovery. A completed discovery
|
||||
> should have no unresolved [PENDING] entries.
|
||||
|
||||
## Summary
|
||||
|
||||
Xenia-edge-ios-msl is an Xbox 360 emulator with a substantial, working Metal backend (~41 files in
|
||||
`src/xenia/gpu/metal/`) written in **metal-cpp** + Obj-C++ (`.mm`) glue, targeting **iOS 18.0** /
|
||||
macOS 15.0. It already uses several Metal 4-era APIs (`MTLResidencySet`, `MTLSharedEvent`, bindless
|
||||
argument buffers) on the Metal 3 command model, with a dual-path shader translator (Metal Shader
|
||||
Converter DXBC→DXIL→metallib, plus a native MSL emitter).
|
||||
|
||||
Most of the immediately useful GPTK-4 surface is **version-agnostic** and ships on the current
|
||||
iOS 18 / Metal 3 build with **no deployment-target change**: Metal validation, GPU capture/inspection,
|
||||
the rendering-diagnosis playbook, Metal Shader Converter tuning, metal-cpp lifetime hygiene, and
|
||||
un-gating the (already-wired) MetalFX **spatial** scaler on iOS. The **Metal 4 command-model**
|
||||
adoption (flexible PSOs, explicit barriers, `MTL4ArgumentTable`) is a separate, medium-term track,
|
||||
gated on iOS 26 and scoped as a **runtime-gated dual backend** (decided — path C, no device loss).
|
||||
|
||||
## Recommended Work Tracks
|
||||
|
||||
**Track 1 — Version-agnostic, ships at iOS 18 / Metal 3 (do first; highest ROI):**
|
||||
1. Enable Metal validation (env-vars) — catches memory errors in generated shaders.
|
||||
2. Capture a `.gputrace` (you have none) — rendering ground truth for correctness work.
|
||||
3. Apply the `debugging-rendering-issues` symptom router to current visual bugs.
|
||||
4. Metal Shader Converter tuning (minimum compatibility flags, min GPU/OS target, layout choice).
|
||||
5. Un-gate the MetalFX spatial scaler on iOS (`metal_presenter.mm:42`).
|
||||
6. metal-cpp lifetime audit at the `.mm`/metal-cpp boundary; frame-pacing review.
|
||||
|
||||
**Track 2 — Metal 4, runtime-gated iOS 26+ (dual backend, decided; medium-term):**
|
||||
1. Finish the Metal 3 explicit hazard model + run under `_validate` on trace titles (prereq).
|
||||
2. `MTL4Compiler` flexible PSOs + color-attachment mapping → collapse format/blend PSO permutations.
|
||||
3. Promote the hazard model to Metal 4 queue/intra-pass barriers.
|
||||
4. `MTL4ArgumentTable` + queue-level residency; replace Metal-4-removed APIs (`setVertexBytes`, per-encoder binds).
|
||||
|
||||
## Skills Loaded
|
||||
|
||||
- `porting-methodology` — milestone/goal framing for the recommendations below.
|
||||
- `translating-to-metal4-api` — Metal 3 → Metal 4 mapping; TBDR considerations; removed APIs.
|
||||
- `creating-metal4-shader-pipelines` — assessed pipeline cache against `MTL4Compiler`, flexible PSOs, `MTL4Archive`.
|
||||
- `managing-metal4-synchronization` — assessed current fence/event/useResource model vs. Metal 4 explicit barriers.
|
||||
- `using-metal-validation` — API/shader validation env-vars and per-pipeline scoping (version-agnostic).
|
||||
- `debugging-rendering-issues` — symptom→cause router for visual bugs (largely version-agnostic).
|
||||
- `using-gpucapture` / `using-gpudebug` — CLI `.gputrace` capture + inspection.
|
||||
- `managing-metal-cpp-lifetimes` — `NS::TransferPtr`/`RetainPtr` ownership at the ARC boundary.
|
||||
- `using-metalfx-temporal-upscaler` / `using-metalfx-frame-interpolation` — MetalFX availability + applicability.
|
||||
- Metal Shader Converter `docs/metal-shader-converter/performance.md` — codegen tuning knobs.
|
||||
- MetalFX + `MTL4CommandQueue` availability cross-checked against Apple reference (sosumi.ai).
|
||||
|
||||
## Game Porting Toolkit Evaluation Findings
|
||||
|
||||
Not directly applicable — this is an emulator, not a Windows game running under the GPTK evaluation
|
||||
environment. The relevant "source" is the guest Xbox 360 GPU (Xenos) command stream, already handled
|
||||
by Xenia's existing D3D12/Vulkan/Metal backends.
|
||||
|
||||
## Trace Analysis
|
||||
|
||||
Instruments traces are present in `scratch/` and are usable for performance planning. The MSC perf
|
||||
guide recommends Metal System Trace to evaluate shader-execution overlap / TLAB serialization, so
|
||||
these can be mined directly:
|
||||
|
||||
| Trace | Type | Use |
|
||||
|---|---|---|
|
||||
| `mirrors-edge-time-profiler.trace` | Time Profiler | CPU hotspots |
|
||||
| `mw2-ios-msl.trace` | Metal System Trace (iOS, MSL path) | CPU/GPU timing on device |
|
||||
| `halo3-odst.trace` | Metal System Trace | per-pass GPU timing |
|
||||
| `ios-runs.trace` | Metal System Trace | device run timing |
|
||||
| `xctrace_exports/` | xctrace CSV/exports | scripted analysis |
|
||||
|
||||
**Gap:** no `.gputrace` (GPU frame capture) found — that is the rendering ground truth for
|
||||
correctness validation. Recommend capturing one via the `using-gpucapture` workflow (`gpucapture` CLI,
|
||||
macOS 27) for any rendering-correctness milestone. This is a **Track 1** item.
|
||||
|
||||
## Reference Artifacts
|
||||
|
||||
| Artifact Type | Path | Notes |
|
||||
|---|---|---|
|
||||
| Metal System Trace (.trace) | `scratch/*.trace` | timing only, no frame capture |
|
||||
| xctrace exports | `scratch/xctrace_exports/` | derived timing data |
|
||||
| MSL AIR repro | `scratch/msl_air_repro/` | shader compile repro case |
|
||||
| Hazard-model design doc | `scratch/metal_hazard_model_design.md` | in-progress explicit-sync design |
|
||||
| GPU frame capture (.gputrace) | — | **not collected — recommend capturing** |
|
||||
|
||||
## Platform Readiness
|
||||
|
||||
| Area | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| macOS build | Ready | macOS 15.0 target; Metal + MetalKit linked |
|
||||
| iOS build | Ready | `build-ios-xcode/`, CMake presets; iOS 18.0 target |
|
||||
| Platform layer (windowing) | Ready | `ui/ios/` (UIKit + CAMetalLayer), `ui/metal/metal_presenter.mm` |
|
||||
| Content pipeline | Ready | emulator consumes guest assets at runtime; n/a |
|
||||
| Required libraries | Ready | metal-cpp + metal-shader-converter vendored in `third_party/` |
|
||||
| Deployment target | Keep 18.0 (dual backend) | Floor stays iOS 18.0; Metal 4 path (iOS 26+) added behind a runtime `supports…()`/OS gate — **path C chosen**, no device loss |
|
||||
|
||||
## Graphics Backend Analysis
|
||||
|
||||
> "Opportunity" column covers both version-agnostic (T1) and Metal-4 (T2) work.
|
||||
|
||||
| # | Category | Finding | Apple-platform opportunity |
|
||||
|---|----------|---------|----------------------------|
|
||||
| 1 | Existing backends | `d3d12`, `vulkan`, `metal`, `null` under `src/xenia/gpu/` | Metal is the iOS target; others unaffected |
|
||||
| 2 | API abstraction | Strong: `CommandProcessor`/`GraphicsSystem` abstraction with per-backend impls | Any Metal 4 work is contained to the metal backend; a runtime gate fits the existing seams |
|
||||
| 3 | Shader language | Dual: MSC (DXBC→DXIL→metallib) + native MSL emitter (`msl_shader_translator.cc`) | **T1:** MSC tuning + DXBC→DXIL intermediate-transform caveat argues for native MSL on hot shaders. **T2:** MSC path already Metal-4-ABI-compatible |
|
||||
| 4 | Shader pipeline | `metal_pipeline_cache` (Metal 3 `MTL::RenderPipelineState`, async pool, `MTL::BinaryArchive`) + `metal_stage_compile_cache` (persistent MSC cache) | **T1:** async + caching already solved; tune MSC codegen. **T2:** flexible PSOs + color-attachment mapping collapse format/blend permutations |
|
||||
| 5 | Existing Metal backend | Mature: command processor, RT cache, texture cache, shared-memory/EDRAM, geometry/tessellation emulation | Modernization + hardening, not bring-up |
|
||||
| 6 | Binding model | Bindless argument buffers — MSC top-level argument buffer + native MSL texture/sampler heaps (65536/2048 slots) | **T1:** linear-layout vs root-signature tradeoff (occupancy). **T2:** maps to `MTL4ArgumentTable` |
|
||||
| 7 | Render graph | None formal — imperative command processor translating guest draws | Explicit barriers (T2) must be inserted at the command-processor level |
|
||||
| 8 | Synchronization | Metal 3: `MTL::Fence` (`shared_memory_fence_`), `MTL::SharedEvent`, `useResource`/`useResources`/`useHeap`; **experimental explicit hazard model** behind `metal_backend_hazard_model` (+ `_validate`) | **T1:** finish + validate the hazard model on Metal 3. **T2:** direct on-ramp to Metal 4 queue/intra-pass barriers |
|
||||
| 9 | Threading | Async pipeline-compile thread pool (`creation_threads_`, priority queue); Xenia command-processor thread | `MTL4Compiler` is multithreaded by default; existing pool may be simplified (T2) |
|
||||
| 10 | Memory management | `MTL::Heap` pools, `MTLResidencySet` (`AddResidencySetHeap`), shared-memory buffers for EDRAM | Already Metal-4-style residency; extend to queue-level residency sets (T2) |
|
||||
| 11 | Language conventions | metal-cpp (manual ref-counting) + `.mm` ARC glue (`metal_presenter.mm`, `ir_runtime_impl.mm`) | **T1:** `managing-metal-cpp-lifetimes` audit at the bridge boundary |
|
||||
| 12 | ObjC/ARC | Mixed ARC (`.mm`) and metal-cpp (`NS::`); CAMetalLayer/drawable handling in ObjC | **T1:** watch `NS::TransferPtr` vs `RetainPtr` ownership at boundaries |
|
||||
|
||||
## Platform Gap Analysis
|
||||
|
||||
- **Debugging / correctness tooling** → biggest under-used surface: Metal validation (`using-metal-validation`), GPU capture/inspect (`using-gpucapture` / `using-gpudebug`), rendering diagnosis (`debugging-rendering-issues`). All version-agnostic, all Track 1.
|
||||
- **Windowing/presentation** → already on `CAMetalLayer` (iOS via `ui/ios/`). Frame pacing/vsync/EDR review available without Metal 4. Skill: `presenting-metal-drawables`.
|
||||
- **Input** → `GameController` framework already linked (`ui/ios/CMakeLists.txt`); touch model present. Skill: `using-game-controller`.
|
||||
- **Graphics (Metal 4 deltas)** → flexible PSOs, explicit barriers, `MTL4ArgumentTable` — Track 2 only. Skills: `translating-to-metal4-api`, `managing-metal4-synchronization`, `creating-metal4-shader-pipelines`, `managing-metal4-resources`.
|
||||
- **Upscaling** → MetalFX **spatial** present but disabled on iOS (Track 1 un-gate); temporal/frame-gen need motion vectors the emulator doesn't produce. Skills: `using-metalfx-temporal-upscaler`.
|
||||
- **Audio / file system / threading** → handled by Xenia's existing cross-platform base layers; no Apple-specific gap surfaced.
|
||||
|
||||
## Feature Coverage Matrix
|
||||
|
||||
> Function counts not enumerated; status reflects presence/maturity in the Metal backend.
|
||||
|
||||
| Feature Domain | Status | Essential | Notes |
|
||||
|----------------|--------|-----------|-------|
|
||||
| Device / Init | Present | Yes | `metal_provider`, `metal_command_processor` |
|
||||
| Buffers | Present | Yes | shared-memory / upload pools |
|
||||
| Textures | Present | Yes | texture cache w/ format conversion |
|
||||
| Render Targets | Present | Yes | `metal_render_target_cache` (EDRAM emulation) |
|
||||
| Samplers | Present | Yes | bindless sampler heap |
|
||||
| Pipeline State | Present | Yes | Metal 3 PSOs; **flexible-PSO opportunity** |
|
||||
| Descriptor Binding | Present | Yes | bindless argument buffers (MSC TLAB + native heaps) |
|
||||
| Command Encoding (Draw) | Present | Yes | standard / geometry / tessellation / native-mesh paths |
|
||||
| Command Encoding (Dispatch) | Present | Depends | compute used for emulation passes |
|
||||
| Resource Copy (Blit) | Present | Yes | shared-memory upload, gamma compute |
|
||||
| Synchronization | Present (transitional) | Yes | fences/events/useResource + experimental hazard model |
|
||||
| Presentation / Swap Chain | Present | Yes | CAMetalLayer; SharedEvent-gated mailbox |
|
||||
| Queries (Timestamp/Occlusion) | Partial | Optional | verify counter sampling coverage |
|
||||
| Debug Markers / Labels | Present | Yes (early) | labels used for capture readability |
|
||||
| Compute | Present | Depends | emulation + gamma/upscale |
|
||||
| Raytracing | Absent | Optional | not used by Xenos emulation |
|
||||
| Indirect Draw/Dispatch | Partial | Optional | confirm against guest indirect paths |
|
||||
|
||||
## Practical Porting Advice (tailored)
|
||||
|
||||
**Correctness tooling (Track 1):**
|
||||
- **Metal validation** — enable `MTL_DEBUG_LAYER=1` broadly (cheap, CPU-side). Add `MTL_SHADER_VALIDATION=1` selectively for GPU-side memory errors in generated shaders — and **pair it with `MTL_SHADER_VALIDATION_REPORT_TO_STDERR=1`** or errors only hit the system log. For this pre-Metal-4 build, per-pipeline scoping is the env allow/deny list `MTL_SHADER_VALIDATION_ENABLE_PIPELINES` / `_DISABLE_PIPELINES` (the `MTL4PipelineOptions.shaderValidation` route is Metal-4-only).
|
||||
- **Rendering diagnosis** — the `debugging-rendering-issues` symptom router maps onto classic Xenos→Metal traps: BGRA↔RGBA channel order + `MTLTextureSwizzleChannels`; sRGB/gamma double-encode (you have gamma-ramp compute); reversed-depth z-fighting (clear value + compare must change together); premultiplied alpha on the drawable; Y-flip/winding; `D24_UNORM_S8_UINT` not universal on Apple GPUs → prefer `Depth32Float_Stencil8`; `COLOR_WRITE_ENABLE`→`MTLColorWriteMask` bit-layout reversal.
|
||||
|
||||
**Metal Shader Converter tuning (Track 1, not Metal 4):** the perf guide maps onto knobs already in `MetalStageCompileKey` (`compatibility_flags`, `minimum_gpu_family`, `minimum_os`, `validation_flags`):
|
||||
- Use the **minimum** compatibility flags (`IRCompilerSetCompatibilityFlags`) — each costs runtime perf.
|
||||
- Set `IRCompilerSetMinimumGPUFamily` / `SetMinimumDeploymentTarget` — newer targets let MSC emit more optimal IR.
|
||||
- Favor the **linear resource layout** over root-signature bindless for shaders that don't need bindless (single indirection, lower register pressure).
|
||||
- The guide warns against **intermediate IR transforms** — your DXBC→DXIL(dxilconv)→MSC chain is exactly that, a concrete argument for maturing the **native-MSL path** on hot shaders.
|
||||
|
||||
**Pipeline / sync (Track 2):**
|
||||
- PSO compile stutter is the canonical emulator problem; you've already attacked it (async pool + binary archive + persistent stage cache). The remaining lever is **reducing PSO count** via flexible PSOs / color-attachment mapping — your `MetalPipelineDescription` bakes `color_formats[4]`, `depth/stencil_format`, `sample_count`, `normalized_color_mask`, `blendcontrol[4]` into the key, exactly the axes flexible PSOs defer.
|
||||
- The experimental `metal_backend_hazard_model` is effectively a Metal 4 barrier model in Metal 3 clothing; finish it now so the Metal 4 port is a primitive swap, not a redesign.
|
||||
|
||||
## Stub Candidates
|
||||
|
||||
Not applicable in the usual sense (mature port). Equivalent "feature flags already present": MetalFX
|
||||
(`metal_presenter_use_metalfx`), hazard model (`metal_backend_hazard_model`), native-MSL vs MSC backend
|
||||
selection (`MetalShader::Backend`). These gate experimental paths and are the natural milestone toggles.
|
||||
|
||||
## Quick Wins
|
||||
|
||||
Ordered by ROI; all of Track 1, none require a deployment-target change:
|
||||
|
||||
1. **Enable Metal validation** — env-vars only, no code. Catches memory errors in generated MSL/metallib (`MTL_DEBUG_LAYER`, `MTL_SHADER_VALIDATION` + `…_REPORT_TO_STDERR`).
|
||||
2. **Capture a `.gputrace`** via `gpucapture` — you currently have none; this is rendering ground truth for any correctness work.
|
||||
3. **Un-gate MetalFX spatial on iOS** — `metal_presenter.mm:42` (`#if !XE_PLATFORM_IOS`) compiles it out, but `MTLFXSpatialScaler`/`MTLFXTemporalScaler` are iOS **16.0+** (verified). The spatial path is already wired; un-gating lights up internal-res→display upscaling. First checkpoint: it compiles clean on the iOS path (never built there before).
|
||||
4. **MSC codegen tuning** — audit compatibility flags down to the minimum; tune min GPU family/OS.
|
||||
5. **MSC programmable blending / framebuffer fetch in HLSL** for EDRAM on TBDR tile memory — reduces render-target round-trips. Skill: `compiling-with-metal-shaderconverter`.
|
||||
6. **Refresh vendored metal-cpp** to the GPTK-4 (iOS 27) drop for Apple10 GPU family + Metal 4 surface.
|
||||
|
||||
## Parallel Work Opportunities
|
||||
|
||||
- Mine the existing `.trace` captures (MW2, Halo 3 ODST, Mirror's Edge) to rank the heaviest GPU passes and to evaluate MSC TLAB-induced shader serialization (per the MSC perf guide) before investing in flexible PSOs or upscaling.
|
||||
- Run the hazard model under `_validate` on those titles to find missed hazards on Metal 3 — de-risks the eventual Metal 4 barrier swap independent of the deployment-target decision.
|
||||
- Stand up the validation env-vars in the dev launch path so every run surfaces shader/API misuse.
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
- **Correctness regressions are hard to see without ground truth:** no `.gputrace` collected. Mitigation: capture one (Track 1) and enable Metal validation before correctness-sensitive changes.
|
||||
- **Explicit sync correctness (T2):** Metal 4 has no driver hazard tracking — under-barriering → GPU faults, over-barriering → perf loss. The skill calls this the longest phase of a port. Mitigation: finish + `_validate` the Metal 3 hazard model first (Track 1).
|
||||
- **metal-cpp/ARC boundary:** mixed ownership models across `.mm`/metal-cpp risk use-after-free; audit with `managing-metal-cpp-lifetimes`. Mitigation: Metal validation + leak instruments (Track 1). See Known Blockers for the specific sites.
|
||||
- **Deployment-target tension (T2):** Metal 4 APIs are iOS 26+ (`MTL4CommandQueue` verified). Resolved via the dual-backend gate (path C) — no device loss, at the cost of maintaining two paths.
|
||||
- **Native MSL emitter maintenance:** owning an MSL emitter means Metal version/behavior changes land on you, not on MSC.
|
||||
|
||||
## Dependency Graph
|
||||
|
||||
- Track 1 items (validation, `.gputrace`, rendering diagnosis, MSC tuning, MetalFX un-gate, lifetime audit): **all independent**, ship at iOS 18.
|
||||
- Hazard-model completion: **independent** (Metal 3), and a **prerequisite** for Metal 4 sync.
|
||||
- Flexible PSOs / Metal 4 command model: **blocked on** the iOS 26 runtime gate (dual backend).
|
||||
- Full Metal 4 command model: **depends on** explicit sync being complete (no implicit hazard tracking) and on replacing Metal-4-removed APIs (`setVertexBytes`, per-encoder binds).
|
||||
|
||||
## Key Files
|
||||
|
||||
- `src/xenia/gpu/metal/metal_command_processor.{h,cc}` — submission, sync, residency, encoders.
|
||||
- `src/xenia/gpu/metal/metal_pipeline_cache.{h,cc}` — PSO creation/caching/async pool/binary archive.
|
||||
- `src/xenia/gpu/metal/metal_stage_compile_cache.{h,cc}` — persistent MSC metallib cache.
|
||||
- `src/xenia/gpu/msl_shader_translator.{h,cc}` — native MSL emitter.
|
||||
- `src/xenia/ui/metal/metal_presenter.mm` — CAMetalLayer presentation + MetalFX (gated, line 42).
|
||||
- `src/xenia/ui/metal/metal_immediate_drawer.mm` — UI drawing; `__bridge`/`CFRelease` buffer lifetime site.
|
||||
- `scratch/metal_hazard_model_design.md` — explicit-sync design in progress.
|
||||
|
||||
## Scope Decisions (from user)
|
||||
|
||||
- **Language:** metal-cpp + `.mm` glue. Confirmed by ownership model in `src/xenia/ui/metal/` and `src/xenia/gpu/metal/`.
|
||||
- **Off-limits:** None stated by the user yet. Suggested local policy for this milestone: treat `third_party/` and external SDK vendoring as out-of-scope unless the user explicitly asks for version/ABI updates.
|
||||
- **Abstraction strategy:** Existing abstraction (multi-backend `CommandProcessor`). No new layer needed.
|
||||
- **Metal 4 adoption path:** **C — runtime-gated dual backend** (decided). Metal 3 path serves iOS 18–25; a Metal 4 path (flexible PSOs + explicit barriers + `MTL4ArgumentTable`) is added behind a runtime iOS 26+ / `supports…()` gate. No device loss.
|
||||
- **Reference available:** Yes. Behavioral parity for graphics behavior is already encoded in the existing Xenia D3D12 path (`src/xenia/gpu/d3d12/`) and mirrored by this mature Metal path; also has platform trace references in `scratch/*.trace` and export logs.
|
||||
|
||||
## Known Blockers / Constraints
|
||||
|
||||
- **`metal-cpp` / ARC ownership mismatch risk:** runtime-safe but fragile boundaries exist where Objective-C ownership crosses into metal-cpp raw pointers. In `metal_presenter.mm`, the queue is intentionally non-owning (`__bridge` from provider) and never released there. In `metal_immediate_drawer.mm`, temporary `MTLBuffer` values are stored as `void*` via `__bridge` and released with `CFRelease` in `EndDrawBatch()`, which is correct only if retain counts are consistent and should be audited carefully in future Metal4 changes.
|
||||
- **No `gputrace` capture yet:** only timing traces exist in `scratch/`; render-correctness and exact object-lifetime confirmation is incomplete until a `.gputrace` is collected.
|
||||
- **API-migration blocker for full Metal 4 parity:** several renderer paths still use APIs removed in Metal 4 (for example `setVertexBytes` and per-encoder resource binding); converting these is a hard requirement for true MTL4 path parity.
|
||||
- **Target-floor constraint:** `iOS 18.0` and legacy devices are only covered by Metal 3 path; Metal 4 features remain runtime-gated to `iOS 26+`.
|
||||
@@ -1,176 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x",
|
||||
"filename" : "iphone-notification-20@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x",
|
||||
"filename" : "iphone-notification-20@3x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x",
|
||||
"filename" : "iphone-settings-29@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x",
|
||||
"filename" : "iphone-settings-29@3x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x",
|
||||
"filename" : "iphone-spotlight-40@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x",
|
||||
"filename" : "iphone-spotlight-40@3x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x",
|
||||
"filename" : "iphone-app-60@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x",
|
||||
"filename" : "iphone-app-60@3x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x",
|
||||
"filename" : "ipad-notification-20.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x",
|
||||
"filename" : "ipad-notification-20@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x",
|
||||
"filename" : "ipad-settings-29.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x",
|
||||
"filename" : "ipad-settings-29@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x",
|
||||
"filename" : "ipad-spotlight-40.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x",
|
||||
"filename" : "ipad-spotlight-40@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x",
|
||||
"filename" : "ipad-app-76.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x",
|
||||
"filename" : "ipad-app-76@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x",
|
||||
"filename" : "ipad-pro-app-83.5@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x",
|
||||
"filename" : "ios-marketing-1024.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"scale" : "1x",
|
||||
"filename" : "mac-16.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"scale" : "2x",
|
||||
"filename" : "mac-16@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"scale" : "1x",
|
||||
"filename" : "mac-32.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"scale" : "2x",
|
||||
"filename" : "mac-32@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"scale" : "1x",
|
||||
"filename" : "mac-128.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"scale" : "2x",
|
||||
"filename" : "mac-128@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"scale" : "1x",
|
||||
"filename" : "mac-256.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"scale" : "2x",
|
||||
"filename" : "mac-256@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"scale" : "1x",
|
||||
"filename" : "mac-512.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"scale" : "2x",
|
||||
"filename" : "mac-512@2x.png"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 55 KiB |