/*
** Copyright (c) 2019-2023 LunarG, Inc.
** Copyright (c) 2023-2025 Advanced Micro Devices, Inc. All rights reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and associated documentation files (the "Software"),
** to deal in the Software without restriction, including without limitation
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
** and/or sell copies of the Software, and to permit persons to whom the
** Software is furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in
** all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
*/

#include "tool_settings.h"
#include "tool_command_line.h"

#ifndef GFXRECON_REPLAY_SETTINGS_H
#define GFXRECON_REPLAY_SETTINGS_H

const char kOptions[] =
    "-h|--help,--version,--log-debugview,--no-debug-popup,--paused,--sync,--sfa|--skip-failed-allocations,--opcd|--"
    "omit-pipeline-cache-data,--remove-unsupported,--validate,--debug-device-lost,--create-dummy-allocations,--"
    "screenshot-all,--onhb|--omit-null-hardware-buffers,--qamr|--quit-after-measurement-range,--fmr|--flush-"
    "measurement-range,--flush-inside-measurement-range,--vssb|--virtual-swapchain-skip-blit,--use-captured-swapchain-"
    "indices,--dcp,--discard-cached-psos,--use-colorspace-fallback,--use-cached-psos,--dx12-override-object-names,--"
    "dx12-ags-inject-markers,--offscreen-swapchain-frame-boundary,--wait-before-present,--dump-resources-before-draw,"
    "--dump-resources-modifiable-state-only,--pbi-all,--preload-measurement-range,--add-new-pipeline-caches,--"
    "screenshot-ignore-FrameBoundaryANDROID,--deduplicate-device,--log-timestamps,--capture,--idle-before-submit,--"
    "serialize-render-passes,--serialize-queue-submissions,--async-processing,--isolate-render-passes,--serialize-"
    "compute-"
    "and-transfer";
const char kArguments[] =
    "--log-level,--log-file,--cpu-mask,--gpu,--gpu-group,--pause-frame,--wsi,--surface-index,-m|--memory-translation,"
    "--replace-shaders,--screenshots,--screenshot-interval,--denied-messages,--allowed-messages,--screenshot-format,--"
    "screenshot-dir,--screenshot-prefix,--screenshot-size,--screenshot-scale,--mfr|--measurement-frame-range,--fw|--"
    "force-windowed,--fwo|--force-windowed-origin,--batching-memory-usage,--measurement-file,--swapchain,--sgfs|--skip-"
    "get-fence-status,--sgfr|--skip-get-fence-ranges,--dump-resources,--dump-resources-dir,--dump-resources-image-"
    "format,pbis,--pcj|--pipeline-creation-jobs,--save-pipeline-cache,--load-pipeline-cache,--quit-after-frame,--"
    "present-mode,--wait-before-first-submit,--present-override,--frame-"
    "warm-up-spirv,--frame-warm-up-load,--wait-before-frame,--loop-frame,--loop-count,--"
    "replay-event-plugin-path,--replay-event-plugin-params";

static void PrintUsage(const char* exe_name)
{
    std::string app_name = std::filesystem::path(exe_name).stem().string();

    GFXRECON_WRITE_CONSOLE("\n%s - A tool to replay GFXReconstruct capture files.\n", app_name.c_str());
    GFXRECON_WRITE_CONSOLE("Usage:");
    GFXRECON_WRITE_CONSOLE("  %s\t[-h | --help] [--version]", app_name.c_str());
    GFXRECON_WRITE_CONSOLE("\t\t\t[--cpu-mask <binary-mask>] [--gpu <index>] [--gpu-group <index>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--pause-frame <N>] [--paused] [--sync] [--screenshot-all]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--screenshots <N1(-N2),...>] [--screenshot-format <format>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--screenshot-dir <dir>] [--screenshot-prefix <file-prefix>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--screenshot-size <width>x<height>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--screenshot-scale <scale>] [--screenshot-interval <N>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--capture]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--sfa | --skip-failed-allocations] [--replace-shaders <dir>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--opcd | --omit-pipeline-cache-data] [--wsi <platform>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--use-cached-psos] [--surface-index <N>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--remove-unsupported] [--validate]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--onhb | --omit-null-hardware-buffers]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[-m <mode> | --memory-translation <mode>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--swapchain <mode>] [--present-mode <mode>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--vssb | --virtual-swapchain-skip-blit]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--use-captured-swapchain-indices]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--use-colorspace-fallback]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--offscreen-swapchain-frame-boundary]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--mfr|--measurement-frame-range <start-frame>-<end-frame>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--measurement-file <file>] [--quit-after-measurement-range]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--flush-measurement-range]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--fw <width,height> | --force-windowed <width,height>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--sgfs <status> | --skip-get-fence-status <status>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--sgfr <frame-ranges> | --skip-get-fence-ranges <frame-ranges>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--wait-before-first-submit <milliseconds>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--frame-warm-up-spirv <spirv-file>] [--frame-warm-up-load <load>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--idle-before-submit] [--pbi-all] [--pbis <index1,index2>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--serialize-render-passes] [--wait-before-frame <milliseconds>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--serialize-queue-submissions]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--replay-event-plugin-path <path>] [--replay-event-plugin-params <params>]");
#if !defined(_WIN32)
    GFXRECON_WRITE_CONSOLE("\t\t\t[--dump-resources <filename>.json]");
#endif
    GFXRECON_WRITE_CONSOLE("\t\t\t[--dump-resources-dir <dir>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--debug-messenger-level <level>]");
#if defined(_WIN32)
    GFXRECON_WRITE_CONSOLE("\t\t\t[--dump-resources <submit-index,command-index,drawcall-index>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--dump-resources-modifiable-state-only]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--dump-resources-image-format <format>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--fwo <x,y> | --force-windowed-origin <x,y>]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--log-level <level>] [--log-file <file>] [--log-debugview]");
    GFXRECON_WRITE_CONSOLE("\t\t\t[--batching-memory-usage <pct>]");
#if defined(_DEBUG)
    GFXRECON_WRITE_CONSOLE("\t\t\t[--no-debug-popup]");
#endif
#else
    GFXRECON_WRITE_CONSOLE("\t\t\t[--log-level <level>] [--log-file <file>]");
#endif
    GFXRECON_WRITE_CONSOLE("\t\t\t<file>\n");

    GFXRECON_WRITE_CONSOLE("Required arguments:");
    GFXRECON_WRITE_CONSOLE("  <file>\t\tPath to the capture file to replay.");
    GFXRECON_WRITE_CONSOLE("\nOptional arguments:");
    GFXRECON_WRITE_CONSOLE("  -h\t\t\tPrint usage information and exit (same as --help).");
    GFXRECON_WRITE_CONSOLE("  --version\t\tPrint version information and exit.");
    GFXRECON_WRITE_CONSOLE("  --log-level <level>\tSpecify highest level message to log. Options are:");
    GFXRECON_WRITE_CONSOLE("          \t\tdebug, info, warning, error, and fatal. Default is info.");
    GFXRECON_WRITE_CONSOLE("  --log-timestamps\tOutput a timestamp in front of each log message.");
    GFXRECON_WRITE_CONSOLE("  --log-file <file>\tWrite log messages to a file at the specified path.")
    GFXRECON_WRITE_CONSOLE("          \t\tDefault is: Empty string (file logging disabled).");
#if defined(_WIN32)
    GFXRECON_WRITE_CONSOLE("  --log-debugview\tLog messages with OutputDebugStringA.");
#endif
    GFXRECON_WRITE_CONSOLE(
        "  --debug-messenger-level <level>\tSpecify highest debug messenger severity level. Options are:")
    GFXRECON_WRITE_CONSOLE("          \t\tdebug, info, warning, and error. Default is warning.");
    GFXRECON_WRITE_CONSOLE("  --pause-frame <N>\tPause after replaying frame number N.");
    GFXRECON_WRITE_CONSOLE("  --paused\t\tPause after replaying the first frame (same");
    GFXRECON_WRITE_CONSOLE("          \t\tas --pause-frame 1).");
    GFXRECON_WRITE_CONSOLE("  --loop-frame <N>\tEnable frame repeat (experimental).");
    GFXRECON_WRITE_CONSOLE("          \t\tN specifies the frame number to repeat; default is 0.");
    GFXRECON_WRITE_CONSOLE("  --loop-count <N>\tSpecify the number of times to repeat the frame when");
    GFXRECON_WRITE_CONSOLE("          \t\tloop frame is enabled. Default is 0: replay forever.");
    GFXRECON_WRITE_CONSOLE("  --screenshot-all");
    GFXRECON_WRITE_CONSOLE("          \t\tGenerate screenshots for all frames.  When this");
    GFXRECON_WRITE_CONSOLE("          \t\toption is specified, --screenshots is ignored.");
    GFXRECON_WRITE_CONSOLE("  --screenshots <N1[-N2][,...]>");
    GFXRECON_WRITE_CONSOLE("          \t\tGenerate screenshots for the specified frames.");
    GFXRECON_WRITE_CONSOLE("          \t\tTarget frames are specified as a comma separated");
    GFXRECON_WRITE_CONSOLE("          \t\tlist of frame ranges.  A frame range can be specified");
    GFXRECON_WRITE_CONSOLE("          \t\tas a single value, to specify a single frame, or as");
    GFXRECON_WRITE_CONSOLE("          \t\ttwo hyphenated values, to specify the first and last");
    GFXRECON_WRITE_CONSOLE("          \t\tframes to process.  Frame ranges should be specified in");
    GFXRECON_WRITE_CONSOLE("          \t\tascending order and cannot overlap.  Note that frame");
    GFXRECON_WRITE_CONSOLE("          \t\tnumbering is 1-based (i.e. the first frame is frame 1).");
    GFXRECON_WRITE_CONSOLE("          \t\tExample: 200,301-305 will generate six screenshots.");
    GFXRECON_WRITE_CONSOLE("  --screenshot-interval <N>");
    GFXRECON_WRITE_CONSOLE("          \t\tSpecifies the number of frames between two screenshots");
    GFXRECON_WRITE_CONSOLE("          \t\twithin a screenshot range.");
    GFXRECON_WRITE_CONSOLE("          \t\tExample: If screenshot range is 10-15 and interval is 2,");
    GFXRECON_WRITE_CONSOLE("          \t\tscreenshot will be generated for frames 10, 12 and 14.");
    GFXRECON_WRITE_CONSOLE("          \t\tDefault is 1.");
    GFXRECON_WRITE_CONSOLE("  --screenshot-format <format>");
    GFXRECON_WRITE_CONSOLE("          \t\tImage file format to use for screenshot generation.");
    GFXRECON_WRITE_CONSOLE("          \t\tAvailable formats are:");
    GFXRECON_WRITE_CONSOLE("          \t\t    %s\t\tBitmap file format.  This is the default format.",
                           gfxrecon::util::kScreenshotFormatBmp);
    GFXRECON_WRITE_CONSOLE("          \t\t    %s\t\tPortable Network Graphics file format.",
                           gfxrecon::util::kScreenshotFormatPng);
    GFXRECON_WRITE_CONSOLE("  --screenshot-dir <dir>");
    GFXRECON_WRITE_CONSOLE("          \t\tDirectory to write screenshots.  Default is the current");
    GFXRECON_WRITE_CONSOLE("          \t\tworking directory.");
    GFXRECON_WRITE_CONSOLE("  --screenshot-prefix <file-prefix>");
    GFXRECON_WRITE_CONSOLE("          \t\tPrefix to apply to the screenshot file name.  Default is ");
    GFXRECON_WRITE_CONSOLE("          \t\t\"screenshot\", producing file names similar to");
    GFXRECON_WRITE_CONSOLE("          \t\t\"screenshot_frame_8049.bmp\".");
    GFXRECON_WRITE_CONSOLE("  --screenshot-scale <factor>[,<factor_y>]");
    GFXRECON_WRITE_CONSOLE("          \t\tSpecify one or two float scale factors to resize screenshot output.");
    GFXRECON_WRITE_CONSOLE("          \t\tUse --screenshot-scale <factor_x>,<factor_y> for non-uniform scaling.");
    GFXRECON_WRITE_CONSOLE("          \t\tA negative scale factor flips the output on that axis.");
    GFXRECON_WRITE_CONSOLE("          \t\te.g. --screenshot-scale 0.5, --screenshot-scale 1.0,-1.0 (flip Y).");
    GFXRECON_WRITE_CONSOLE("          \t\tDefault: 1.0 (original size).");
    GFXRECON_WRITE_CONSOLE("  --screenshot-size <width>x<height>");
    GFXRECON_WRITE_CONSOLE("          \t\tSpecify desired screenshot dimensions. Leaving this unspecified");
    GFXRECON_WRITE_CONSOLE("          \t\tscreenshots will use the swapchain images dimensions. If ");
    GFXRECON_WRITE_CONSOLE("          \t\t--screenshot-scale is also specified then this option is ignored.");
    GFXRECON_WRITE_CONSOLE("  --validate\t\tEnable the Khronos Vulkan validation layer when replaying a");
    GFXRECON_WRITE_CONSOLE("            \t\tVulkan capture or the Direct3D debug layer when replaying a");
    GFXRECON_WRITE_CONSOLE("            \t\tDirect3D 12 capture.");
    GFXRECON_WRITE_CONSOLE("  --cpu-mask <binary-mask>");
    GFXRECON_WRITE_CONSOLE("          \t\tSet of CPU cores used by the replayer.");
    GFXRECON_WRITE_CONSOLE("          \t\t`binary-mask` is a succession of '0' and '1' read from left to right");
    GFXRECON_WRITE_CONSOLE("          \t\tthat specifies used/unused cores.");
    GFXRECON_WRITE_CONSOLE("          \t\tFor example '10010' activates the first and");
    GFXRECON_WRITE_CONSOLE("          \t\tfourth cores and deactivate all other cores.");
    GFXRECON_WRITE_CONSOLE("          \t\tIf the option is not set, all cores can be used. If the option");
    GFXRECON_WRITE_CONSOLE("          \t\tis set only for some cores, the other cores are not used.");
    GFXRECON_WRITE_CONSOLE("  --gpu <index>\t\tUse the specified device for replay, where index");
    GFXRECON_WRITE_CONSOLE("          \t\tis the zero-based index to the array of physical devices");
    GFXRECON_WRITE_CONSOLE("          \t\treturned by vkEnumeratePhysicalDevices or IDXGIFactory1::EnumAdapters1.");
    GFXRECON_WRITE_CONSOLE("          \t\tReplay may fail if the specified device is not compatible with the");
    GFXRECON_WRITE_CONSOLE("          \t\toriginal capture devices.");
    GFXRECON_WRITE_CONSOLE("  --pbi-all\t\tPrint all block information.");
    GFXRECON_WRITE_CONSOLE(
        "  --pbis <index1,index2>\t\tPrint block information between block index1 and block index2.");
#if defined(_WIN32)
    GFXRECON_WRITE_CONSOLE("")
    GFXRECON_WRITE_CONSOLE("Windows only:")
    GFXRECON_WRITE_CONSOLE("  --dump-resources <submit-index,command-index,drawcall-index>");
    GFXRECON_WRITE_CONSOLE("          \t\tDump resources for a specific drawcall.");
    GFXRECON_WRITE_CONSOLE(
        "          \t\tThis can include vertex, index, const buffer, shader resource, render target,");
    GFXRECON_WRITE_CONSOLE("          \t\tand depth stencil resources. Resources are dumped after the drawcall.");
    GFXRECON_WRITE_CONSOLE(
        "  --fwo <x,y>\t\tForce windowed mode if not already, and allow setting of a custom window location.");
    GFXRECON_WRITE_CONSOLE("          \t\t(Same as --force-windowed-origin)");
#if defined(_DEBUG)
    GFXRECON_WRITE_CONSOLE("  --no-debug-popup\tDisable the 'Abort, Retry, Ignore' message box");
    GFXRECON_WRITE_CONSOLE("       \t\t\tdisplayed when abort() is called (Windows debug only).");
#endif
#endif
    GFXRECON_WRITE_CONSOLE("")
    GFXRECON_WRITE_CONSOLE("Vulkan only:")
    GFXRECON_WRITE_CONSOLE("  --capture\t\tCapture the replaying GFXR file. Capture uses the same log");
    GFXRECON_WRITE_CONSOLE("       \t\t\toptions as replay. All other capture option behavior and");
    GFXRECON_WRITE_CONSOLE("       \t\t\tusage is the same as when capturing with the GFXR layer. The");
    GFXRECON_WRITE_CONSOLE("       \t\t\tcapture functionality is included in the `gfxrecon-replay`");
    GFXRECON_WRITE_CONSOLE("       \t\t\texecutable--no GFXR capture layer is added to the Vulkan layer");
    GFXRECON_WRITE_CONSOLE("       \t\t\tchain.");
    GFXRECON_WRITE_CONSOLE("  --sfa\t\t\tSkip vkAllocateMemory, vkAllocateCommandBuffers, and");
    GFXRECON_WRITE_CONSOLE("       \t\t\tvkAllocateDescriptorSets calls that failed during");
    GFXRECON_WRITE_CONSOLE("       \t\t\tcapture (same as --skip-failed-allocations).");
    GFXRECON_WRITE_CONSOLE("  --replace-shaders <dir>");
    GFXRECON_WRITE_CONSOLE("       \t\t\tReplace the shader code in each CreateShaderModule");
    GFXRECON_WRITE_CONSOLE("       \t\t\twith the contents of the file <dir>/sh<handle_id> if found, where");
    GFXRECON_WRITE_CONSOLE("       \t\t\t<handle_id> is the handle id of the CreateShaderModule call.");
    GFXRECON_WRITE_CONSOLE("       \t\t\tSee gfxrecon-extract.");
    GFXRECON_WRITE_CONSOLE("  --opcd\t\tOmit pipeline cache data from calls to");
    GFXRECON_WRITE_CONSOLE("        \t\tvkCreatePipelineCache and skip calls to");
    GFXRECON_WRITE_CONSOLE("        \t\tvkGetPipelineCacheData (same as");
    GFXRECON_WRITE_CONSOLE("        \t\t--omit-pipeline-cache-data).");
    GFXRECON_WRITE_CONSOLE("  --wsi <platform>\tForce replay to use the specified wsi platform. If no surface");
    GFXRECON_WRITE_CONSOLE("                  \twas available at capture time the option is ignored and no");
    GFXRECON_WRITE_CONSOLE("                  \tsurface is chosen.");
    GFXRECON_WRITE_CONSOLE("                  \tAvailable platforms are: %s", GetWsiArgString().c_str());
    GFXRECON_WRITE_CONSOLE("                  \tauto (default): Picks the same surface as at capture time if");
    GFXRECON_WRITE_CONSOLE("                  \t                possible, otherwise picks a surface available");
    GFXRECON_WRITE_CONSOLE("                  \t                on the replay device");
    GFXRECON_WRITE_CONSOLE("  --surface-index <N>\tRestrict rendering to the Nth surface object created.");
    GFXRECON_WRITE_CONSOLE("                  \tUsed with captures that include multiple surfaces.  Default");
    GFXRECON_WRITE_CONSOLE("                  \tis -1 (render to all surfaces).");
    GFXRECON_WRITE_CONSOLE("  --sync\t\tSynchronize after each queue submission with vkQueueWaitIdle.");
    GFXRECON_WRITE_CONSOLE("  --remove-unsupported\tRemove unsupported extensions and features from instance");
    GFXRECON_WRITE_CONSOLE("                      \tand device creation parameters.");
    GFXRECON_WRITE_CONSOLE("  -m <mode>\t\tEnable memory translation for replay on GPUs with memory");
    GFXRECON_WRITE_CONSOLE("          \t\ttypes that are not compatible with the capture GPU's");
    GFXRECON_WRITE_CONSOLE("          \t\tmemory types.  Available modes are:");
    GFXRECON_WRITE_CONSOLE("          \t\t    %s\tNo memory translation is performed.  This", kMemoryTranslationNone);
    GFXRECON_WRITE_CONSOLE("          \t\t         \tis the default behavior.");
    GFXRECON_WRITE_CONSOLE("          \t\t    %s\tAttempt to map capture memory types to", kMemoryTranslationRemap);
    GFXRECON_WRITE_CONSOLE("          \t\t         \tcompatible replay memory types, without");
    GFXRECON_WRITE_CONSOLE("          \t\t         \taltering memory allocation behavior.");
    GFXRECON_WRITE_CONSOLE("          \t\t    %s\tAdjust memory allocation sizes and", kMemoryTranslationRealign);
    GFXRECON_WRITE_CONSOLE("          \t\t         \tresource binding offsets based on");
    GFXRECON_WRITE_CONSOLE("          \t\t         \treplay memory properties.");
    GFXRECON_WRITE_CONSOLE("          \t\t    %s\tChange memory allocation behavior based", kMemoryTranslationRebind);
    GFXRECON_WRITE_CONSOLE("          \t\t         \ton resource usage and replay memory");
    GFXRECON_WRITE_CONSOLE("          \t\t         \tproperties.  Resources may be bound");
    GFXRECON_WRITE_CONSOLE("          \t\t         \tto different allocations with different");
    GFXRECON_WRITE_CONSOLE("          \t\t         \toffsets.  Uses VMA to manage allocations");
    GFXRECON_WRITE_CONSOLE("          \t\t         \tand suballocations.");
    GFXRECON_WRITE_CONSOLE("  --swapchain <mode>\tChoose a swapchain mode to replay.");
    GFXRECON_WRITE_CONSOLE("          \t\tAvailable modes are:");
    GFXRECON_WRITE_CONSOLE("          \t\t    %s\tVirtual Swapchain of images which match", kSwapchainVirtual);
    GFXRECON_WRITE_CONSOLE("          \t\t         \tthe swapchain in effect at capture time and");
    GFXRECON_WRITE_CONSOLE("          \t\t         \twhich are copied to the underlying swapchain of the");
    GFXRECON_WRITE_CONSOLE("          \t\t         \timplementation being replayed on. Also displays");
    GFXRECON_WRITE_CONSOLE("          \t\t         \toffscreen frame boundaries to an additional window.");
    GFXRECON_WRITE_CONSOLE("          \t\t         \tThis is only available and default for Vulkan.");
    GFXRECON_WRITE_CONSOLE("          \t\t    %s\tUse the swapchain indices stored in the ", kSwapchainCaptured);
    GFXRECON_WRITE_CONSOLE("          \t\t         \tcapture directly on the swapchain setup for replay.");
    GFXRECON_WRITE_CONSOLE("          \t\t    %s\tDisable creating swapchains, surfaces", kSwapchainOffscreen);
    GFXRECON_WRITE_CONSOLE("          \t\t         \tand windows. To see rendering, add the --screenshots option.");
    GFXRECON_WRITE_CONSOLE("  --present-mode <mode>\tSet swapchain's VkPresentModeKHR.");
    GFXRECON_WRITE_CONSOLE("          \t\tAvailable modes are:");
    GFXRECON_WRITE_CONSOLE("          \t\t\t%s: Present mode used at capture time.", kPresentModeCapture);
    GFXRECON_WRITE_CONSOLE("          \t\t\t%s: VK_PRESENT_MODE_IMMEDIATE_KHR", kPresentModeImmediate);
    GFXRECON_WRITE_CONSOLE("          \t\t\t%s: VK_PRESENT_MODE_MAILBOX_KHR", kPresentModeMailbox);
    GFXRECON_WRITE_CONSOLE("          \t\t\t%s: VK_PRESENT_MODE_FIFO_KHR", kPresentModeFifo);
    GFXRECON_WRITE_CONSOLE("          \t\t\t%s: VK_PRESENT_MODE_FIFO_RELAXED_KHR", kPresentModeFifoRelaxed);
    GFXRECON_WRITE_CONSOLE("  --present-override <debug-name>");
    GFXRECON_WRITE_CONSOLE("       \t\t\tAdditionally present an image identified by a substring match against its");
    GFXRECON_WRITE_CONSOLE("       \t\t\tVK_EXT_debug_utils object name (depth/stencil images are ignored). The");
    GFXRECON_WRITE_CONSOLE("       \t\t\tmatched image is presented in a dedicated swapchain on every present and");
    GFXRECON_WRITE_CONSOLE("       \t\t\tused for screenshot operations. Multi-layer images are presented in a");
    GFXRECON_WRITE_CONSOLE("       \t\t\tseparate window per array layer. If multiple images match, the most");
    GFXRECON_WRITE_CONSOLE("       \t\t\trecently named one is used.");
    GFXRECON_WRITE_CONSOLE("  --vssb");
    GFXRECON_WRITE_CONSOLE("          \t\tSkip blit to real swapchain to gain performance during replay.");
    GFXRECON_WRITE_CONSOLE("  --use-captured-swapchain-indices");
    GFXRECON_WRITE_CONSOLE("          \t\tSame as \"--swapchain captured\".");
    GFXRECON_WRITE_CONSOLE("          \t\tIgnored if the \"--swapchain\" option is used.");
    GFXRECON_WRITE_CONSOLE("  --offscreen-swapchain-frame-boundary");
    GFXRECON_WRITE_CONSOLE("          \t\tShould only be used with offscreen swapchain.");
    GFXRECON_WRITE_CONSOLE("          \t\tActivates the extension VK_EXT_frame_boundary (always supported if");
    GFXRECON_WRITE_CONSOLE("          \t\ttrimming, checks for driver support otherwise) and inserts command");
    GFXRECON_WRITE_CONSOLE("          \t\tbuffer submission with VkFrameBoundaryEXT where vkQueuePresentKHR");
    GFXRECON_WRITE_CONSOLE("          \t\twas called in the original capture.");
    GFXRECON_WRITE_CONSOLE("          \t\tThis allows preserving frames when capturing a replay that uses.");
    GFXRECON_WRITE_CONSOLE("          \t\toffscreen swapchain.");
    GFXRECON_WRITE_CONSOLE("  --measurement-frame-range <start_frame>-<end_frame>");
    GFXRECON_WRITE_CONSOLE("          \t\tCustom framerange to measure FPS for.");
    GFXRECON_WRITE_CONSOLE("          \t\tThis range will include the start frame but not the end frame.");
    GFXRECON_WRITE_CONSOLE("          \t\tThe measurement frame range defaults to all frames except the loading");
    GFXRECON_WRITE_CONSOLE("          \t\tframe but can be configured for any range. If the end frame is past the");
    GFXRECON_WRITE_CONSOLE("          \t\tlast frame in the trace it will be clamped to the frame after the last");
    GFXRECON_WRITE_CONSOLE("          \t\t(so in that case the results would include the last frame).");
    GFXRECON_WRITE_CONSOLE("  --use-colorspace-fallback");
    GFXRECON_WRITE_CONSOLE("          \t\tSwap the swapchain color space if unsupported by replay device.");
    GFXRECON_WRITE_CONSOLE("          \t\tCheck if color space is not supported by replay device and fallback to "
                           "VK_COLOR_SPACE_SRGB_NONLINEAR_KHR.");
    GFXRECON_WRITE_CONSOLE("  --measurement-file <file>");
    GFXRECON_WRITE_CONSOLE("          \t\tWrite measurements to a file at the specified path.");
    GFXRECON_WRITE_CONSOLE("          \t\tDefault is: '/sdcard/gfxrecon-measurements.json' on android and");
    GFXRECON_WRITE_CONSOLE("          \t\t'./gfxrecon-measurements.json' on desktop.");
    GFXRECON_WRITE_CONSOLE("  --quit-after-measurement-range");
    GFXRECON_WRITE_CONSOLE("          \t\tIf this is specified the replayer will abort");
    GFXRECON_WRITE_CONSOLE("          \t\twhen it reaches the <end_frame> specified in");
    GFXRECON_WRITE_CONSOLE("          \t\tthe --measurement-frame-range argument.");
    GFXRECON_WRITE_CONSOLE("  --flush-measurement-range");
    GFXRECON_WRITE_CONSOLE("          \t\tIf this is specified the replayer will flush")
    GFXRECON_WRITE_CONSOLE("          \t\tand wait for all current GPU work to finish at the");
    GFXRECON_WRITE_CONSOLE("          \t\tstart and end of the measurement range.");
    GFXRECON_WRITE_CONSOLE("  --flush-inside-measurement-range");
    GFXRECON_WRITE_CONSOLE("          \t\tIf this is specified the replayer will flush")
    GFXRECON_WRITE_CONSOLE("          \t\tand wait for all current GPU work to finish at the");
    GFXRECON_WRITE_CONSOLE("          \t\tend of each frame inside the measurement range.");
    GFXRECON_WRITE_CONSOLE("  --gpu-group <index>\tUse the specified device group for replay, where index");
    GFXRECON_WRITE_CONSOLE("          \t\tis the zero-based index to the array of physical device group");
    GFXRECON_WRITE_CONSOLE("          \t\treturned by vkEnumeratePhysicalDeviceGroups.  Replay may fail");
    GFXRECON_WRITE_CONSOLE("          \t\tif the specified device group is not compatible with the");
    GFXRECON_WRITE_CONSOLE("          \t\toriginal capture device group.");
    GFXRECON_WRITE_CONSOLE("  --sgfs <status>");
    GFXRECON_WRITE_CONSOLE("          \t\tSpecify behavior to skip calls to vkWaitForFences and vkGetFenceStatus:");
    GFXRECON_WRITE_CONSOLE("          \t\t\tstatus=0 : Don't skip");
    GFXRECON_WRITE_CONSOLE("          \t\t\tstatus=1 : Skip unsuccessful calls");
    GFXRECON_WRITE_CONSOLE("          \t\t\tstatus=2 : Always skip");
    GFXRECON_WRITE_CONSOLE("          \t\tIf no skip frame range is specified (--sgfr), the status applies to all");
    GFXRECON_WRITE_CONSOLE("          \t\tframes.");
    GFXRECON_WRITE_CONSOLE("  --sgfr <frame-ranges>");
    GFXRECON_WRITE_CONSOLE("          \t\tFrame ranges where --sgfs applies. The format is:");
    GFXRECON_WRITE_CONSOLE("          \t\t\t<frame-start-1>-<frame-end-1>[,<frame-start-1>-<frame-end-1>]*");
    GFXRECON_WRITE_CONSOLE("  --wait-before-present");
    GFXRECON_WRITE_CONSOLE("          \t\tForce wait on completion of queue operations for all queues");
    GFXRECON_WRITE_CONSOLE("          \t\tbefore calling Present. This is needed for accurate acquisition");
    GFXRECON_WRITE_CONSOLE("          \t\tof instrumentation data on some platforms.");
#if !defined(_WIN32)
    GFXRECON_WRITE_CONSOLE("  --dump-resources <filename>.json");
    GFXRECON_WRITE_CONSOLE("          \t\tExtract dump resources block indices and options from the");
    GFXRECON_WRITE_CONSOLE("          \t\tspecified json file. The format for the json file is");
    GFXRECON_WRITE_CONSOLE("          \t\tdocumented in detail in vulkan_dump_resources.md.");
#endif
    GFXRECON_WRITE_CONSOLE("  --pipeline-creation-jobs <num_jobs>");
    GFXRECON_WRITE_CONSOLE("          \t\tSpecify the number of asynchronous pipeline-creation jobs as integer.");
    GFXRECON_WRITE_CONSOLE("          \t\tIf <num_jobs> is negative it will be added to the number of cpu-cores");
    GFXRECON_WRITE_CONSOLE("          \t\tDefault: 0 (do not use asynchronous operations).");
    GFXRECON_WRITE_CONSOLE("          \t\tSame as --pcj <num_jobs>");
    GFXRECON_WRITE_CONSOLE("  --save-pipeline-cache <cache-file>");
    GFXRECON_WRITE_CONSOLE("          \t\tIf set, produces pipeline caches at replay time instead of using");
    GFXRECON_WRITE_CONSOLE("          \t\tthe one saved at capture time and save those caches in <cache-file>.");
    GFXRECON_WRITE_CONSOLE("  --load-pipeline-cache <cache-file>");
    GFXRECON_WRITE_CONSOLE("          \t\tIf set, loads data created by the `--save-pipeline-cache`");
    GFXRECON_WRITE_CONSOLE("          \t\toption in <cache-file> and uses it to create the pipelines instead");
    GFXRECON_WRITE_CONSOLE("          \t\tof the pipeline caches saved at capture time.");
    GFXRECON_WRITE_CONSOLE("  --add-new-pipeline-caches");
    GFXRECON_WRITE_CONSOLE("          \t\tIf set, allows gfxreconstruct to create new vkPipelineCache objects");
    GFXRECON_WRITE_CONSOLE("          \t\twhen it encounters a pipeline created without cache. This option can");
    GFXRECON_WRITE_CONSOLE("          \t\tbe used in coordination with `--save-pipeline-cache` and");
    GFXRECON_WRITE_CONSOLE("          \t\t`--load-pipeline-cache`.");
    GFXRECON_WRITE_CONSOLE("  --screenshot-ignore-FrameBoundaryANDROID");
    GFXRECON_WRITE_CONSOLE("          \t\tIf set, frames switced with vkFrameBoundANDROID will be ignored from");
    GFXRECON_WRITE_CONSOLE("          \t\tthe screenshot handler.");
    GFXRECON_WRITE_CONSOLE("  --deduplicate-device");
    GFXRECON_WRITE_CONSOLE("          \t\tIf set, at most one VkDevice will be created for each VkPhysicalDevice for "
                           "RenderDoc and DXVK case.");
    GFXRECON_WRITE_CONSOLE("  --wait-before-first-submit <milliseconds>");
    GFXRECON_WRITE_CONSOLE("          \t\tWait specified milliseconds before submitting the first command buffer.");
    GFXRECON_WRITE_CONSOLE("  --idle-before-submit");
    GFXRECON_WRITE_CONSOLE("          \t\tWait for the GPU to become idle before each submit.");
    GFXRECON_WRITE_CONSOLE("  --serialize-render-passes");
    GFXRECON_WRITE_CONSOLE("          \t\tSerialize render passes by injecting execution barriers before render pass");
    GFXRECON_WRITE_CONSOLE("          \t\tbegin during replay.");
    GFXRECON_WRITE_CONSOLE("  --frame-warm-up-spirv <spirv-file>");
    GFXRECON_WRITE_CONSOLE("          \t\tSpecify a user-provided SPIR-V compute shader for the warm-up pass.");
    GFXRECON_WRITE_CONSOLE("          \t\tThe shader must use entry point `main` and set 0, binding 0 as a");
    GFXRECON_WRITE_CONSOLE("          \t\tstorage buffer. Warm-up runs before the first submit of each replayed");
    GFXRECON_WRITE_CONSOLE("          \t\tframe only when this option and a non-zero `--frame-warm-up-load`");
    GFXRECON_WRITE_CONSOLE("          \t\tare both provided.");
    GFXRECON_WRITE_CONSOLE("  --frame-warm-up-load <load>");
    GFXRECON_WRITE_CONSOLE("          \t\tSpecify workload scale factor for a compute dispatch warm-up pass");
    GFXRECON_WRITE_CONSOLE("          \t\trun before each frame replay. Default is 0 (disabled).");
    GFXRECON_WRITE_CONSOLE("  --wait-before-frame <milliseconds>");
    GFXRECON_WRITE_CONSOLE("          \t\tWait for the specified amount of milliseconds before starting to replay");
    GFXRECON_WRITE_CONSOLE("          \t\teach frame. Default is 0 (no wait).");
    GFXRECON_WRITE_CONSOLE("  --serialize-queue-submissions");
    GFXRECON_WRITE_CONSOLE("          \t\tSerialize submit entries within one vkQueueSubmit/vkQueueSubmit2");
    GFXRECON_WRITE_CONSOLE("          \t\tcall by adding semaphores between consecutive submits.");
    GFXRECON_WRITE_CONSOLE("  --replay-event-plugin-path <path>");
    GFXRECON_WRITE_CONSOLE("          \t\tPath to a replay event plugin library. If specified, the");
    GFXRECON_WRITE_CONSOLE("          \t\tplugin will be loaded and used to process replay events.");
    GFXRECON_WRITE_CONSOLE("          \t\t(forwarded to replay tool)");
    GFXRECON_WRITE_CONSOLE("  --replay-event-plugin-params <params>");
    GFXRECON_WRITE_CONSOLE("          \t\tParameters to forward to the replay event plugin. The format");
    GFXRECON_WRITE_CONSOLE("          \t\tof the parameters is determined by the plugin and is not");
    GFXRECON_WRITE_CONSOLE("          \t\tinterpreted by the replay tool. (forwarded to replay tool)");
    GFXRECON_WRITE_CONSOLE("  --isolate-render-passes");
    GFXRECON_WRITE_CONSOLE(
        "          \t\tIsolate render passes by splitting the command buffer into multiple submits.");

#if defined(_WIN32)
    GFXRECON_WRITE_CONSOLE("")
    GFXRECON_WRITE_CONSOLE("D3D12 only:")
    GFXRECON_WRITE_CONSOLE(
        "  --use-cached-psos  \tPermit using cached PSOs when creating graphics or compute pipelines.");
    GFXRECON_WRITE_CONSOLE(
        "       \t\t\tUsing cached PSOs may reduce PSO creation time but may result in replay errors.");
    GFXRECON_WRITE_CONSOLE("  --debug-device-lost\tEnable automatic injection of breadcrumbs into command buffers");
    GFXRECON_WRITE_CONSOLE("            \t\tand page fault reporting.");
    GFXRECON_WRITE_CONSOLE("            \t\tUsed to debug Direct3D 12 device removed problems.");
    GFXRECON_WRITE_CONSOLE("  --fw <width,height>\tSetup windowed and override resolution.");
    GFXRECON_WRITE_CONSOLE("                     \t(Same as --force-windowed)");
    GFXRECON_WRITE_CONSOLE("  --create-dummy-allocations");
    GFXRECON_WRITE_CONSOLE("          \t\tEnable creation of dummy heaps and resources for replay validation.");
    GFXRECON_WRITE_CONSOLE("  --dx12-override-object-names");
    GFXRECON_WRITE_CONSOLE("          \t\tGenerate unique names for all ID3D12Objects and");
    GFXRECON_WRITE_CONSOLE("          \t\tassign each object the generated name.");
    GFXRECON_WRITE_CONSOLE("          \t\tThis is intended to assist in replay debugging.");
    GFXRECON_WRITE_CONSOLE("  --dx12-ags-inject-markers");
    GFXRECON_WRITE_CONSOLE("          \t\tLabel each API calls as block index of the trace");
    GFXRECON_WRITE_CONSOLE("          \t\tRadeon GPU Detective could dump the label for debugging.");
    GFXRECON_WRITE_CONSOLE("  --batching-memory-usage <pct>");
    GFXRECON_WRITE_CONSOLE("          \t\tMax amount of memory consumption while loading a trimmed capture file.");
    GFXRECON_WRITE_CONSOLE("          \t\tAcceptable values range from 0 to 100 (default: 80)");
    GFXRECON_WRITE_CONSOLE("          \t\t0 means no batching at all");
    GFXRECON_WRITE_CONSOLE("          \t\t100 means use all available system and GPU memory");
    GFXRECON_WRITE_CONSOLE("  --dump-resources-modifiable-state-only");
    GFXRECON_WRITE_CONSOLE(
        "          \t\tOnly dump resources that are in a modifiable state set by D3D12 ResourceBarrier")
    GFXRECON_WRITE_CONSOLE("  --dump-resources-image-format <format>");
    GFXRECON_WRITE_CONSOLE("          \t\tImage file format to use when dumping image resources.");
    GFXRECON_WRITE_CONSOLE("          \t\tAvailable formats are: bmp, png");

#endif
}

#endif // GFXRECON_REPLAY_SETTINGS_H
