diff --git a/assets/l10n/en.json b/assets/l10n/en.json index 61c60a5..51b84f9 100644 --- a/assets/l10n/en.json +++ b/assets/l10n/en.json @@ -799,6 +799,8 @@ "만화 · 그림용": "Comics · art", "만화 · 그림용은 가볍고 빠르며, 사진용은 사진의 질감을 더 잘 살리지만 그래픽카드가 없으면 느립니다.": "Comics · art is light and fast. Photos keeps photo texture better but is slow without a graphics card.", "만화 보기": "Read as comic", + "많이 (빠름)": "High (faster)", + "많이 (빠름): {0} - 다른 앱이 많이 켜져 있으면 Android 가 이 앱을 끌 수 있습니다": "High (faster): {0} - if many other apps are open, Android may close this app", "말레이어": "Malay", "맞추기 (검은 여백)": "Fit (black bars)", "맞추기 (비율이 다를 때)": "Conform (when the aspect differs)", @@ -952,6 +954,8 @@ "보안": "Security", "보일 버튼을 고르고, 끌어서 순서를 바꿉니다.": "Choose the buttons to show and drag to reorder.", "보정은 다시 인코딩해야 해서 코덱을 \"원본 유지\" 에서 H.264 로 바꿨습니다.": "Adjustments require re-encoding, so the codec was changed from \"Keep original\" to H.264.", + "보통": "Normal", + "보통: {0}": "Normal: {0}", "복사": "Copy", "복사 (붙여넣기로)": "Copy (to paste)", "복사 · rsync": "Copy · rsync", @@ -1402,6 +1406,7 @@ "이 그림을 바탕으로 (그림 → 그림)": "Use this as the base (image → image)", "이 기기 (SD1.5 + LCM)": "This device (SD1.5 + LCM)", "이 기기 ({0})": "This device ({0})", + "이 기기 메모리 {0}GB 기준:": "For this device's {0}GB of memory:", "이 기기에는 원문이 아니라 되돌릴 수 없는 해시만 남습니다.": "Only an irreversible hash is stored on this device, not the password itself.", "이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "About {0} per image on this device (based on last time)", "이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "About {0} per image, {1} in total on this device (based on last time)", @@ -1628,6 +1633,8 @@ "저장했습니다": "Saved", "저장했습니다: {0}": "Saved: {0}", "저장했습니다: {0} (MKV 에 반영됨)": "Saved: {0} (applied to MKV)", + "적게 (느림)": "Low (slower)", + "적게 (느림): {0}": "Low (slower): {0}", "적용": "Apply", "전체 {0}개 중 {1}번째": "Item {1} of {0}", "전체 만들기": "Make all", @@ -1842,6 +1849,8 @@ "키 있음": "Key saved", "타갈로그어": "Tagalog", "타밀어": "Tamil", + "타일 {0} · 약 {1}GB": "tile {0} · about {1}GB", + "타일이 작을수록 느립니다 (예: 16GB 폰에서 1024×768 을 2배로 - 512 약 4분 · 320 약 9분 30초).": "Smaller tiles are slower (e.g. doubling 1024×768 on a 16GB phone: 512 about 4 min · 320 about 9 min 30 s).", "탐색기": "Explorer", "탐색기 오른쪽 클릭 메뉴": "Explorer right-click menu", "탐색기에서 동영상을 열 때": "When opening a video from Explorer", @@ -1971,6 +1980,7 @@ "할 일": "Task", "항목 {0}/{1}": "Items {0}/{1}", "항목마다 따로 (기본)": "Each item separately (default)", + "해상도 올리기 메모리": "Upscaling memory", "해상도 올리기 모델": "Upscaling model", "해상도 올리기 모델을 받아 주세요 (환경 설정 > AI 그림)": "Download an upscaling model (Settings > AI images)", "해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "An upscaling model is needed. Which one should be downloaded?", diff --git a/assets/l10n/ja.json b/assets/l10n/ja.json index fc88d3b..94c8957 100644 --- a/assets/l10n/ja.json +++ b/assets/l10n/ja.json @@ -799,6 +799,8 @@ "만화 · 그림용": "漫画・イラスト用", "만화 · 그림용은 가볍고 빠르며, 사진용은 사진의 질감을 더 잘 살리지만 그래픽카드가 없으면 느립니다.": "漫画・イラスト用は軽くて速く、写真用は写真の質感をよく保ちますが、グラフィックカードがないと遅くなります。", "만화 보기": "マンガ表示", + "많이 (빠름)": "多め (速い)", + "많이 (빠름): {0} - 다른 앱이 많이 켜져 있으면 Android 가 이 앱을 끌 수 있습니다": "多め (速い): {0} - 他のアプリが多く開いていると Android がこのアプリを終了することがあります", "말레이어": "マレー語", "맞추기 (검은 여백)": "フィット(黒い余白)", "맞추기 (비율이 다를 때)": "合わせ方(比率が違うとき)", @@ -952,6 +954,8 @@ "보안": "セキュリティ", "보일 버튼을 고르고, 끌어서 순서를 바꿉니다.": "表示するボタンを選び、ドラッグで順序を変えます。", "보정은 다시 인코딩해야 해서 코덱을 \"원본 유지\" 에서 H.264 로 바꿨습니다.": "補正には再エンコードが必要なため、コーデックを「元のまま」から H.264 に変更しました。", + "보통": "普通", + "보통: {0}": "普通: {0}", "복사": "コピー", "복사 (붙여넣기로)": "コピー (貼り付け用)", "복사 · rsync": "コピー · rsync", @@ -1402,6 +1406,7 @@ "이 그림을 바탕으로 (그림 → 그림)": "この画像を元に (画像 → 画像)", "이 기기 (SD1.5 + LCM)": "この端末 (SD1.5 + LCM)", "이 기기 ({0})": "この端末 ({0})", + "이 기기 메모리 {0}GB 기준:": "この端末のメモリ {0}GB の場合:", "이 기기에는 원문이 아니라 되돌릴 수 없는 해시만 남습니다.": "この端末にはパスワード自体ではなく、元に戻せないハッシュだけが残ります。", "이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "この端末で 1 枚約 {0} (前回の所要時間から)", "이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "この端末で 1 枚約 {0}・全部で約 {1} (前回の所要時間から)", @@ -1628,6 +1633,8 @@ "저장했습니다": "保存しました", "저장했습니다: {0}": "保存しました: {0}", "저장했습니다: {0} (MKV 에 반영됨)": "保存しました: {0}(MKV に反映済み)", + "적게 (느림)": "少なめ (遅い)", + "적게 (느림): {0}": "少なめ (遅い): {0}", "적용": "適用", "전체 {0}개 중 {1}번째": "全 {0} 件中 {1} 件目", "전체 만들기": "すべて作成", @@ -1842,6 +1849,8 @@ "키 있음": "キーあり", "타갈로그어": "タガログ語", "타밀어": "タミル語", + "타일 {0} · 약 {1}GB": "タイル {0} · 約 {1}GB", + "타일이 작을수록 느립니다 (예: 16GB 폰에서 1024×768 을 2배로 - 512 약 4분 · 320 약 9분 30초).": "タイルが小さいほど遅くなります (例: 16GB のスマホで 1024×768 を 2 倍に - 512 で約 4 分 · 320 で約 9 分 30 秒)。", "탐색기": "エクスプローラー", "탐색기 오른쪽 클릭 메뉴": "エクスプローラーの右クリックメニュー", "탐색기에서 동영상을 열 때": "エクスプローラーで動画を開いたとき", @@ -1971,6 +1980,7 @@ "할 일": "内容", "항목 {0}/{1}": "項目 {0}/{1}", "항목마다 따로 (기본)": "項目ごとに (既定)", + "해상도 올리기 메모리": "高解像度化のメモリ", "해상도 올리기 모델": "高解像度化モデル", "해상도 올리기 모델을 받아 주세요 (환경 설정 > AI 그림)": "高解像度化モデルをダウンロードしてください (環境設定 > AI 画像)", "해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "解像度アップのモデルが必要です。どれをダウンロードしますか?", diff --git a/assets/l10n/zh-Hans.json b/assets/l10n/zh-Hans.json index a4ef776..be046ca 100644 --- a/assets/l10n/zh-Hans.json +++ b/assets/l10n/zh-Hans.json @@ -799,6 +799,8 @@ "만화 · 그림용": "漫画 · 插画", "만화 · 그림용은 가볍고 빠르며, 사진용은 사진의 질감을 더 잘 살리지만 그래픽카드가 없으면 느립니다.": "漫画 · 插画模型轻巧快速;照片模型更能保留照片质感,但没有显卡时较慢。", "만화 보기": "漫画阅读", + "많이 (빠름)": "多(较快)", + "많이 (빠름): {0} - 다른 앱이 많이 켜져 있으면 Android 가 이 앱을 끌 수 있습니다": "多(较快):{0} - 若打开了很多其他应用,Android 可能会关闭本应用", "말레이어": "马来语", "맞추기 (검은 여백)": "适应(黑边)", "맞추기 (비율이 다를 때)": "适配方式(比例不同时)", @@ -952,6 +954,8 @@ "보안": "安全", "보일 버튼을 고르고, 끌어서 순서를 바꿉니다.": "选择要显示的按钮,拖动以调整顺序。", "보정은 다시 인코딩해야 해서 코덱을 \"원본 유지\" 에서 H.264 로 바꿨습니다.": "调整需要重新编码,因此编解码器已从“保持原样”改为 H.264。", + "보통": "普通", + "보통: {0}": "普通:{0}", "복사": "复制", "복사 (붙여넣기로)": "复制 (用于粘贴)", "복사 · rsync": "复制 · rsync", @@ -1402,6 +1406,7 @@ "이 그림을 바탕으로 (그림 → 그림)": "以此图片为基础 (图片 → 图片)", "이 기기 (SD1.5 + LCM)": "本设备 (SD1.5 + LCM)", "이 기기 ({0})": "本设备 ({0})", + "이 기기 메모리 {0}GB 기준:": "按本设备内存 {0}GB:", "이 기기에는 원문이 아니라 되돌릴 수 없는 해시만 남습니다.": "本设备只保存无法还原的哈希值,而不是密码本身。", "이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "本设备每张约 {0} (按上次耗时)", "이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "本设备每张约 {0} · 共约 {1} (按上次耗时)", @@ -1628,6 +1633,8 @@ "저장했습니다": "已保存", "저장했습니다: {0}": "已保存: {0}", "저장했습니다: {0} (MKV 에 반영됨)": "已保存: {0}(已应用到 MKV)", + "적게 (느림)": "少(较慢)", + "적게 (느림): {0}": "少(较慢):{0}", "적용": "应用", "전체 {0}개 중 {1}번째": "共 {0} 个中的第 {1} 个", "전체 만들기": "全部制作", @@ -1842,6 +1849,8 @@ "키 있음": "已有密钥", "타갈로그어": "他加禄语", "타밀어": "泰米尔语", + "타일 {0} · 약 {1}GB": "分块 {0} · 约 {1}GB", + "타일이 작을수록 느립니다 (예: 16GB 폰에서 1024×768 을 2배로 - 512 약 4분 · 320 약 9분 30초).": "图块越小越慢(例如:在 16GB 手机上将 1024×768 放大 2 倍 - 512 约 4 分钟 · 320 约 9 分 30 秒)。", "탐색기": "文件管理", "탐색기 오른쪽 클릭 메뉴": "资源管理器右键菜单", "탐색기에서 동영상을 열 때": "从资源管理器打开视频时", @@ -1971,6 +1980,7 @@ "할 일": "任务", "항목 {0}/{1}": "项目 {0}/{1}", "항목마다 따로 (기본)": "逐个项目 (默认)", + "해상도 올리기 메모리": "提升分辨率内存", "해상도 올리기 모델": "提高分辨率模型", "해상도 올리기 모델을 받아 주세요 (환경 설정 > AI 그림)": "请下载提高分辨率模型 (设置 > AI 图片)", "해상도 올리기 모델을 받아야 합니다. 어느 것을 받을까요?": "需要放大模型。要下载哪一个?", diff --git a/lib/app/ai_upscale.dart b/lib/app/ai_upscale.dart index c06692d..5a229e3 100644 --- a/lib/app/ai_upscale.dart +++ b/lib/app/ai_upscale.dart @@ -71,20 +71,30 @@ Uint8List _finish((Uint8List, int, int, int, String, int) a) { /// 그 밖 (Windows · GPU) 은 엔진 기본값 bool _androidCpu(SdDevice d) => Platform.isAndroid && d.backend == 'cpu'; int upscaleThreads(SdDevice d) => _androidCpu(d) ? Platform.numberOfProcessors : 0; -int upscaleTileSize(SdDevice d, {int? memTotalMb, int? longSide}) => - _androidCpu(d) ? androidUpscaleTile(memTotalMb: memTotalMb, longSide: longSide) : 0; +int upscaleTileSize(SdDevice d, {int? memTotalMb, int? longSide, double share = 0.30}) => + _androidCpu(d) ? androidUpscaleTile(memTotalMb: memTotalMb, longSide: longSide, share: share) : 0; + +/// 176: 환경 설정의 해상도 올리기 메모리 → 기기 메모리 중 쓸 몫 +double upscaleMemoryShare(String setting) => switch (setting) { + 'low' => 0.20, + 'high' => 0.45, + _ => 0.30, + }; /// 176: Android CPU 타일 크기 - 메모리는 타일 넓이에 비례한다 (S10 실측: 타일 512 에서 엔진 6.6GB, 기기의 45%). -/// 기기 전체 메모리의 20% 안에 드는 가장 큰 타일 (512 · 384 · 320 · 256 · 192). 메모리를 모르면 큰 그림 (긴 변 1000 이상) 은 256. -int androidUpscaleTile({int? memTotalMb, int? longSide}) { - const at512Mb = 6600; +/// 기기 전체 메모리의 [share] 안에 드는 가장 큰 타일 (512 · 384 · 320 · 256 · 192). 메모리를 모르면 큰 그림 (긴 변 1000 이상) 은 256. +/// 타일이 작을수록 느리다 (S10 1024×768 2배: 512 약 4분, 320 약 9분 30초) +int androidUpscaleTile({int? memTotalMb, int? longSide, double share = 0.30}) { if (memTotalMb == null || memTotalMb <= 0) return (longSide ?? 0) >= 1000 ? 256 : 512; for (final t in const [512, 384, 320, 256]) { - if (at512Mb * (t / 512) * (t / 512) <= memTotalMb * 0.20) return t; + if (upscaleTileMemoryMb(t) <= memTotalMb * share) return t; } return 192; } +/// 타일 크기 → 엔진이 쓸 메모리 어림 (MB, S10 실측 512 → 6.6GB 에서 넓이 비례) +int upscaleTileMemoryMb(int tile) => (6600 * (tile / 512) * (tile / 512)).round(); + /// 기기 전체 메모리 (MB, /proc/meminfo - Android · Linux). 모르면 null int? deviceMemTotalMb() { try { @@ -96,7 +106,8 @@ int? deviceMemTotalMb() { } /// 156-2: 걸린 시간을 기억할 열쇠 (처리 장치 · 모델이 같아야 비교가 된다) -String upscaleSpeedKey(AiUpscaler up) => '${up.device.backend}|${up.modelId}'; +/// 176: Android CPU 는 메모리 설정 (타일 크기) 에 따라 빠르기가 달라 그것도 열쇠에 (다른 설정의 시간으로 어림하지 않게) +String upscaleSpeedKey(AiUpscaler up) => '${up.device.backend}|${up.modelId}${_androidCpu(up.device) ? '|${up.memory}' : ''}'; /// 그림의 화소 수 (백만 단위, 머리만 읽음 - 모르면 null) double? megapixels(Uint8List bytes) { @@ -135,7 +146,10 @@ bool isFourTimes(Uint8List input, Uint8List result) { /// 그림 한 장 올리기. [input] 은 이 기기의 파일 (ZIP · WebDAV 의 그림은 부르는 쪽이 임시 파일로). /// 결과를 [save] 가 true 면 저장하고 그 경로를, 아니면 임시 파일 경로를 돌려준다 (비교해 보고 저장할 때). class AiUpscaler { - AiUpscaler({required this.device, required this.modelPath, this.modelId = '', this.runner = runSdCli}); + AiUpscaler({required this.device, required this.modelPath, this.modelId = '', this.runner = runSdCli, this.memory = 'normal'}); + + /// 176: 환경 설정의 해상도 올리기 메모리 ('low' · 'normal' · 'high') - Android CPU 타일 크기 + final String memory; final SdDevice device; final String modelPath; @@ -165,7 +179,8 @@ class AiUpscaler { final info = img.findDecoderForData(Uint8List.fromList(bytes))?.startDecode(Uint8List.fromList(bytes)); if (info != null) longSide = info.width > info.height ? info.width : info.height; } catch (_) {} - final tile = upscaleTileSize(device, memTotalMb: Platform.isAndroid ? deviceMemTotalMb() : null, longSide: longSide); + final tile = upscaleTileSize(device, + memTotalMb: Platform.isAndroid ? deviceMemTotalMb() : null, longSide: longSide, share: upscaleMemoryShare(memory)); await runner(device.exe, sdUpscaleArgs(model: modelPath, input: input, out: out, backend: device.backend, threads: upscaleThreads(device), tileSize: tile), onProgress: (prog) { final (v, left) = upscaleProgressOf(prog); @@ -240,10 +255,11 @@ Future pickUpscaleDevice(AiStore store, {String device = 'auto'}) asy } /// 해상도 올리기에 쓸 장치 · 모델 (없으면 null - 받을 것을 묻는다) -Future prepareUpscaler(AiStore store, {required String modelSetting, String device = 'auto', String autoDevice = ''}) async { +Future prepareUpscaler(AiStore store, + {required String modelSetting, String device = 'auto', String autoDevice = '', String memory = 'normal'}) async { final dev = await pickUpscaleDevice(store, device: device); if (dev == null) return null; final id = installedUpscaleModel(store.isInstalled, modelSetting, gpu: dev.backend != 'cpu'); if (id == null) return null; - return AiUpscaler(device: dev, modelPath: store.pathOf(aiFile(id)), modelId: id); + return AiUpscaler(device: dev, modelPath: store.pathOf(aiFile(id)), modelId: id, memory: memory); } diff --git a/lib/app/settings.dart b/lib/app/settings.dart index a7f01d8..26fb839 100644 --- a/lib/app/settings.dart +++ b/lib/app/settings.dart @@ -516,6 +516,9 @@ class AppSettings { /// 모델 'auto' (GPU 면 사진용, CPU 뿐이면 가볍고 빠른 만화용) · 'photo' · 'anime' String aiUpModel = 'auto'; + /// 176: 해상도 올리기 메모리 (Android CPU 타일 크기) - 'low' 20% · 'normal' 30% (처음 값) · 'high' 45% (기기 메모리 중) + String aiUpMemory = 'normal'; + /// 156-2: 해상도 올리기에 걸린 시간 (처리 장치|모델 → 원본 100만 화소당 초) - "한 장 약 n초" 를 미리 알리려고 Map aiUpSecPerMp = {}; @@ -712,6 +715,7 @@ class AppSettings { 'aiSaveDir': aiSaveDir, 'aiAgreed': aiAgreed, 'aiUpModel': aiUpModel, + 'aiUpMemory': aiUpMemory, 'aiUpSecPerMp': aiUpSecPerMp, 'aiUpScale': aiUpScale, 'aiUpFormat': aiUpFormat, @@ -905,6 +909,7 @@ class AppSettings { ..aiSaveDir = j['aiSaveDir'] as String? ?? '' ..aiAgreed = [for (final x in (j['aiAgreed'] as List?) ?? const []) '$x'] ..aiUpModel = const ['photo', 'anime'].contains(j['aiUpModel']) ? j['aiUpModel'] as String : 'auto' + ..aiUpMemory = const ['low', 'high'].contains(j['aiUpMemory']) ? j['aiUpMemory'] as String : 'normal' ..aiUpSecPerMp = { if (j['aiUpSecPerMp'] case final Map m) for (final e in m.entries) diff --git a/lib/ui/ai_settings.dart b/lib/ui/ai_settings.dart index 5bead91..695ac0a 100644 --- a/lib/ui/ai_settings.dart +++ b/lib/ui/ai_settings.dart @@ -15,6 +15,7 @@ import 'folder_picker.dart'; import 'license_texts.dart' show showLicenseDocument; import 'setting_tile.dart'; import 'theme.dart'; +import '../app/ai_upscale.dart' show androidUpscaleTile, upscaleMemoryShare, upscaleTileMemoryMb, deviceMemTotalMb; /// 기기 안에서 그리는 데 아직 받지 않은 파일 (Windows 는 실행 파일까지, TAESD 포함) - AI 그림 화면 · 받기 화면이 같은 값을 보인다 (139) List aiMissingFiles(AiStore store) => [ @@ -71,6 +72,37 @@ class _AiSettingsState extends State { String get _platform => Platform.isAndroid ? 'android' : 'windows'; + /// 176: 해상도 올리기 메모리 (적게 · 보통 · 많이) - 이 기기에서의 타일 · 예상 메모리 + Widget _upMemoryTile() { + final mem = deviceMemTotalMb(); + String level(String id) { + final t = androidUpscaleTile(memTotalMb: mem, share: upscaleMemoryShare(id)); + return trf('타일 {0} · 약 {1}GB', [t, (upscaleTileMemoryMb(t) / 1024).toStringAsFixed(1)]); + } + + return SettingTile( + leading: const Icon(Icons.memory), + title: Text(tr('해상도 올리기 메모리')), + subtitle: Text([ + if (mem != null) trf('이 기기 메모리 {0}GB 기준:', [(mem / 1024).toStringAsFixed(0)]), + trf('적게 (느림): {0}', [level('low')]), + trf('보통: {0}', [level('normal')]), + trf('많이 (빠름): {0} - 다른 앱이 많이 켜져 있으면 Android 가 이 앱을 끌 수 있습니다', [level('high')]), + tr('타일이 작을수록 느립니다 (예: 16GB 폰에서 1024×768 을 2배로 - 512 약 4분 · 320 약 9분 30초).'), + ].join('\n')), + isThreeLine: true, + trailing: DropdownButton( + value: c.settings.aiUpMemory, + items: [ + DropdownMenuItem(value: 'low', child: Text(tr('적게 (느림)'))), + DropdownMenuItem(value: 'normal', child: Text(tr('보통'))), + DropdownMenuItem(value: 'high', child: Text(tr('많이 (빠름)'))), + ], + onChanged: (v) => c.updateSettings((x) => x.aiUpMemory = v ?? 'normal'), + ), + ); + } + List get _files => [ for (final f in aiCatalog) if ((f.platforms.isEmpty || f.platforms.contains(_platform)) && (f.needs != 'nvidia' || _nvidia)) f, @@ -229,6 +261,8 @@ class _AiSettingsState extends State { onChanged: (v) => c.updateSettings((x) => x.aiUpModel = v ?? 'auto'), ), ), + // 176: Android CPU - 메모리를 많이 쓸수록 빠르다 (그래픽카드 · Windows 는 엔진이 정함) + if (Platform.isAndroid) _upMemoryTile(), SettingTile( leading: const Icon(Icons.zoom_out_map), title: Text(tr('배율')), diff --git a/lib/ui/ai_upscale_ui.dart b/lib/ui/ai_upscale_ui.dart index 66ca13b..1f9fbb4 100644 --- a/lib/ui/ai_upscale_ui.dart +++ b/lib/ui/ai_upscale_ui.dart @@ -62,7 +62,8 @@ Future _prepare(BuildContext context, AppController c) async { if (debugUpscalerForTest case final f?) return f(); final store = AiStore.instance ??= AiStore(Directory.systemTemp.path); Future ready() => - prepareUpscaler(store, modelSetting: c.settings.aiUpModel, device: c.settings.aiDevice, autoDevice: c.settings.aiAutoDevice); + prepareUpscaler(store, + modelSetting: c.settings.aiUpModel, device: c.settings.aiDevice, autoDevice: c.settings.aiAutoDevice, memory: c.settings.aiUpMemory); final up = await ready(); if (up != null || !context.mounted) return up; // 엔진 (Windows 는 받아야 함) · 모델 중 없는 것 diff --git a/test/upscale_job_test.dart b/test/upscale_job_test.dart index cc07328..23f7ac1 100644 --- a/test/upscale_job_test.dart +++ b/test/upscale_job_test.dart @@ -7,6 +7,7 @@ import 'package:image/image.dart' as img; import 'package:jj_mkvmaker/app/ai_local.dart'; import 'package:jj_mkvmaker/app/ai_upscale.dart'; import 'package:jj_mkvmaker/app/app_controller.dart'; +import 'package:jj_mkvmaker/app/settings.dart'; import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart'; import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart'; import 'package:jj_mkvmaker/services/platform_services.dart'; @@ -40,10 +41,22 @@ void main() { tmp.deleteSync(recursive: true); }); + test('176: 해상도 올리기 메모리 설정 - 적게 20% · 보통 30% (처음 값) · 많이 45%, 저장', () { + expect(AppSettings().aiUpMemory, 'normal'); + expect(AppSettings.fromJson((AppSettings()..aiUpMemory = 'high').toJson()).aiUpMemory, 'high'); + expect(AppSettings.fromJson({'aiUpMemory': 'x'}).aiUpMemory, 'normal'); + // S10 (약 15GB): 적게 320 · 보통 384 · 많이 512 + expect([for (final m in ['low', 'normal', 'high']) androidUpscaleTile(memTotalMb: 15000, share: upscaleMemoryShare(m))], [320, 384, 512]); + expect(upscaleTileMemoryMb(512), 6600); + // 빠르기 기록은 메모리 설정마다 따로 (Android CPU 만) + final a = AiUpscaler(device: const SdDevice('x', 'cpu', 'CPU'), modelPath: 'm', modelId: 'esrgan-x4plus', memory: 'low'); + expect(upscaleSpeedKey(a), Platform.isAndroid ? 'cpu|esrgan-x4plus|low' : 'cpu|esrgan-x4plus'); + }); + test('타일 크기: 기기 메모리의 20% 안 (S10 16GB → 320), 메모리를 모르면 큰 그림만 256', () { - expect(androidUpscaleTile(memTotalMb: 15000), 320); - expect(androidUpscaleTile(memTotalMb: 40000), 512); - expect(androidUpscaleTile(memTotalMb: 6000), 192); + expect(androidUpscaleTile(memTotalMb: 15000, share: 0.20), 320); + expect(androidUpscaleTile(memTotalMb: 40000, share: 0.20), 512); + expect(androidUpscaleTile(memTotalMb: 6000, share: 0.20), 192); expect(androidUpscaleTile(longSide: 1024), 256); expect(androidUpscaleTile(longSide: 800), 512); });