Skip to content

Commit

Permalink
Terminate process once all trim ranges have been captured
Browse files Browse the repository at this point in the history
Once all frame ranges specified by
GFXRECON_CAPTURE_FRAMES/debug.gfxrecon.capture_frames) have been
recorded, GFXR will call exit() forcing the whole process to terminate.

New control options (GFXRECON_QUIT_AFTER_CAPTURE_FRAMES for desktop and
debug_gfxrecon.quit_after_capture_frames for Android) can be used to
enable or disable this.
  • Loading branch information
panos-lunarg committed Jul 19, 2023
1 parent 1535711 commit a55e256
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 23 deletions.
1 change: 1 addition & 0 deletions USAGE_android.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ Option | Property | Type | Description
------| ------------- |------|-------------
Capture File Name | debug.gfxrecon.capture_file | STRING | Path to use when creating the capture file. Default is: `/sdcard/gfxrecon_capture.gfxr`
Capture Specific Frames | debug.gfxrecon.capture_frames | STRING | Specify one or more comma-separated frame ranges to capture. Each range will be written to its own file. A frame range can be specified as a single value, to specify a single frame to capture, or as two hyphenated values, to specify the first and last frame to capture. Frame ranges should be specified in ascending order and cannot overlap. Note that frame numbering is 1-based (i.e. the first frame is frame 1). Example: `200,301-305` will create two capture files, one containing a single frame and one containing five frames. Default is: Empty string (all frames are captured).
Quit after capturing frame ranges | debug_gfxrecon.quit_after_capture_frames | BOOL | Setting it to `true` will force the application to terminate once all frame ranges specified by `debug.gfxrecon.capture_frames` have been captured.
Capture trigger for Android | debug.gfxrecon.capture_android_trigger | BOOL | Set during runtime to `true` to start capturing and to `false` to stop. If not set at all then it is disabled (non-trimmed capture). Default is not set.
Capture File Compression Type | debug.gfxrecon.capture_compression_type | STRING | Compression format to use with the capture file. Valid values are: `LZ4`, `ZLIB`, `ZSTD`, and `NONE`. Default is: `LZ4`
Capture File Timestamp | debug.gfxrecon.capture_file_timestamp | BOOL | Add a timestamp to the capture file as described by [Timestamps](#timestamps). Default is: `true`
Expand Down
1 change: 1 addition & 0 deletions USAGE_desktop_D3D12.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ Option | Environment Variable | Type | Description
------| ------------- |------|-------------
Capture File Name | GFXRECON_CAPTURE_FILE | STRING | Path to use when creating the capture file. Default is: `gfxrecon_capture.gfxr`
Capture Specific Frames | GFXRECON_CAPTURE_FRAMES | STRING | Specify one or more comma-separated frame ranges to capture. Each range will be written to its own file. A frame range can be specified as a single value, to specify a single frame to capture, or as two hyphenated values, to specify the first and last frame to capture. Frame ranges should be specified in ascending order and cannot overlap. Note that frame numbering is 1-based (i.e. the first frame is frame 1). Example: `200,301-305` will create two capture files, one containing a single frame and one containing five frames. Default is: Empty string (all frames are captured).
Quit after capturing frame ranges | GFXRECON_QUIT_AFTER_CAPTURE_FRAMES | BOOL | Setting it to `true` will force the application to terminate once all frame ranges specified by `GFXRECON_CAPTURE_FRAMES` have been captured.
Hotkey Capture Trigger | GFXRECON_CAPTURE_TRIGGER | STRING | Specify a hotkey (any one of F1-F12, TAB, CONTROL) that will be used to start/stop capture. Example: `F3` will set the capture trigger to F3 hotkey. One capture file will be generated for each pair of start/stop hotkey presses. Default is: Empty string (hotkey capture trigger is disabled).
Hotkey Capture Trigger | GFXRECON_CAPTURE_TRIGGER_FRAMES | STRING | Specify a limit on the number of frames to be captured via hotkey. Example: `1` will capture exactly one frame when the trigger key is pressed. Default is: Empty string (no limit)
Capture File Compression Type | GFXRECON_CAPTURE_COMPRESSION_TYPE | STRING | Compression format to use with the capture file. Valid values are: `LZ4`, `ZLIB`, `ZSTD`, and `NONE`. Default is: `LZ4`
Expand Down
1 change: 1 addition & 0 deletions USAGE_desktop_Vulkan.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ Option | Environment Variable | Type | Description
------| ------------- |------|-------------
Capture File Name | GFXRECON_CAPTURE_FILE | STRING | Path to use when creating the capture file. Default is: `gfxrecon_capture.gfxr`
Capture Specific Frames | GFXRECON_CAPTURE_FRAMES | STRING | Specify one or more comma-separated frame ranges to capture. Each range will be written to its own file. A frame range can be specified as a single value, to specify a single frame to capture, or as two hyphenated values, to specify the first and last frame to capture. Frame ranges should be specified in ascending order and cannot overlap. Note that frame numbering is 1-based (i.e. the first frame is frame 1). Example: `200,301-305` will create two capture files, one containing a single frame and one containing five frames. Default is: Empty string (all frames are captured).
Quit after capturing frame ranges | GFXRECON_QUIT_AFTER_CAPTURE_FRAMES | BOOL | Setting it to `true` will force the application to terminate once all frame ranges specified by `GFXRECON_CAPTURE_FRAMES` have been captured.
Hotkey Capture Trigger | GFXRECON_CAPTURE_TRIGGER | STRING | Specify a hotkey (any one of F1-F12, TAB, CONTROL) that will be used to start/stop capture. Example: `F3` will set the capture trigger to F3 hotkey. One capture file will be generated for each pair of start/stop hotkey presses. Default is: Empty string (hotkey capture trigger is disabled).
Hotkey Capture Trigger | GFXRECON_CAPTURE_TRIGGER_FRAMES | STRING | Specify a limit on the number of frames to be captured via hotkey. Example: `1` will capture exactly one frame when the trigger key is pressed. Default is: Empty string (no limit)
Capture File Compression Type | GFXRECON_CAPTURE_COMPRESSION_TYPE | STRING | Compression format to use with the capture file. Valid values are: `LZ4`, `ZLIB`, `ZSTD`, and `NONE`. Default is: `LZ4`
Expand Down
34 changes: 26 additions & 8 deletions framework/encode/capture_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ uint32_t CaptureManager::instanc
std::mutex CaptureManager::instance_lock_;
thread_local std::unique_ptr<CaptureManager::ThreadData> CaptureManager::thread_data_;
CaptureManager::ApiCallMutexT CaptureManager::api_call_mutex_;
std::atomic<uint64_t> CaptureManager::block_index_ = 0;
std::atomic<uint64_t> CaptureManager::block_index_ = 0;
std::function<void()> CaptureManager::delete_instance_func_ = nullptr;

std::atomic<format::HandleId> CaptureManager::unique_id_counter_{ format::kNullHandleId };

Expand Down Expand Up @@ -97,7 +98,7 @@ CaptureManager::CaptureManager(format::ApiFamilyId api_family) :
previous_runtime_trigger_state_(CaptureSettings::RuntimeTriggerState::kNotUsed), debug_layer_(false),
debug_device_lost_(false), screenshot_prefix_(""), screenshots_enabled_(false), global_frame_count_(0),
disable_dxr_(false), accel_struct_padding_(0), iunknown_wrapping_(false), force_command_serialization_(false),
queue_zero_only_(false)
queue_zero_only_(false), quit_after_frame_ranges_(false)
{}

CaptureManager::~CaptureManager()
Expand All @@ -109,7 +110,8 @@ CaptureManager::~CaptureManager()
}

bool CaptureManager::CreateInstance(std::function<CaptureManager*()> GetInstanceFunc,
std::function<void()> NewInstanceFunc)
std::function<void()> NewInstanceFunc,
std::function<void()> DeleteInstanceFunc)
{
bool success = true;
std::lock_guard<std::mutex> instance_lock(instance_lock_);
Expand All @@ -121,6 +123,11 @@ bool CaptureManager::CreateInstance(std::function<CaptureManager*()> GetInstance
// Create new instance of capture manager.
instance_count_ = 1;
NewInstanceFunc();
delete_instance_func_ = DeleteInstanceFunc;
if (std::atexit(CaptureManager::AtExit))
{
GFXRECON_LOG_WARNING("Failed registering atexit");
}

assert(GetInstanceFunc() != nullptr);

Expand Down Expand Up @@ -167,8 +174,7 @@ bool CaptureManager::CreateInstance(std::function<CaptureManager*()> GetInstance
return success;
}

void CaptureManager::DestroyInstance(std::function<const CaptureManager*()> GetInstanceFunc,
std::function<void()> DeleteInstanceFunc)
void CaptureManager::DestroyInstance(std::function<const CaptureManager*()> GetInstanceFunc)
{
std::lock_guard<std::mutex> instance_lock(instance_lock_);

Expand All @@ -180,7 +186,8 @@ void CaptureManager::DestroyInstance(std::function<const CaptureManager*()> GetI

if (instance_count_ == 0)
{
DeleteInstanceFunc();
assert(delete_instance_func_);
delete_instance_func_();
assert(GetInstanceFunc() == nullptr);

util::Log::Release();
Expand Down Expand Up @@ -321,8 +328,9 @@ bool CaptureManager::Initialize(std::string base_filename, const CaptureSettings
else
{
// Override default kModeWrite capture mode.
trim_enabled_ = true;
trim_ranges_ = trace_settings.trim_ranges;
trim_enabled_ = true;
trim_ranges_ = trace_settings.trim_ranges;
quit_after_frame_ranges_ = trace_settings.quit_after_frame_ranges;

// Determine if trim starts at the first frame
if (!trace_settings.trim_ranges.empty())
Expand Down Expand Up @@ -733,6 +741,13 @@ void CaptureManager::EndFrame()
{
file_stream_->Flush();
}

// Terminate process if this was the last trim range and the user has asked to do so
if (kModeDisabled == capture_mode_ && quit_after_frame_ranges_)
{
GFXRECON_LOG_INFO("All trim ranges have been captured. Quitting.");
exit(EXIT_SUCCESS);
}
}

std::string CaptureManager::CreateTrimFilename(const std::string& base_filename,
Expand Down Expand Up @@ -818,6 +833,9 @@ void CaptureManager::ActivateTrimming()
void CaptureManager::DeactivateTrimming()
{
capture_mode_ &= ~kModeWrite;

assert(file_stream_);
file_stream_->Flush();
file_stream_ = nullptr;
}

Expand Down
19 changes: 16 additions & 3 deletions framework/encode/capture_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,11 @@ class CaptureManager
};

protected:
static bool CreateInstance(std::function<CaptureManager*()> GetInstanceFunc, std::function<void()> NewInstanceFunc);
static bool CreateInstance(std::function<CaptureManager*()> GetInstanceFunc,
std::function<void()> NewInstanceFunc,
std::function<void()> DeleteInstanceFunc);

static void DestroyInstance(std::function<const CaptureManager*()> GetInstanceFunc,
std::function<void()> DeleteInstanceFunc);
static void DestroyInstance(std::function<const CaptureManager*()> GetInstanceFunc);

CaptureManager(format::ApiFamilyId api_family);

Expand Down Expand Up @@ -295,6 +296,16 @@ class CaptureManager
WriteToFile(scratch_buffer.data(), scratch_buffer.size());
}

private:
static void AtExit()
{
if (delete_instance_func_)
{
delete_instance_func_();
delete_instance_func_ = nullptr;
}
}

private:
static uint32_t instance_count_;
static std::mutex instance_lock_;
Expand Down Expand Up @@ -334,6 +345,8 @@ class CaptureManager
bool iunknown_wrapping_;
bool force_command_serialization_;
bool queue_zero_only_;
bool quit_after_frame_ranges_;
static std::function<void()> delete_instance_func_;

struct
{
Expand Down
9 changes: 9 additions & 0 deletions framework/encode/capture_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ GFXRECON_BEGIN_NAMESPACE(encode)
#define SCREENSHOT_FRAMES_UPPER "SCREENSHOT_FRAMES"
#define CAPTURE_FRAMES_LOWER "capture_frames"
#define CAPTURE_FRAMES_UPPER "CAPTURE_FRAMES"
#define QUIT_AFTER_CAPTURE_FRAMES_LOWER "quit_after_capture_frames"
#define QUIT_AFTER_CAPTURE_FRAMES_UPPER "QUIT_AFTER_CAPTURE_FRAMES"
#define CAPTURE_TRIGGER_LOWER "capture_trigger"
#define CAPTURE_TRIGGER_UPPER "CAPTURE_TRIGGER"
#define CAPTURE_TRIGGER_FRAMES_LOWER "capture_trigger_frames"
Expand Down Expand Up @@ -155,6 +157,7 @@ const char kScreenshotDirEnvVar[] = GFXRECON_ENV_VAR_
const char kScreenshotFormatEnvVar[] = GFXRECON_ENV_VAR_PREFIX SCREENSHOT_FORMAT_LOWER;
const char kScreenshotFramesEnvVar[] = GFXRECON_ENV_VAR_PREFIX SCREENSHOT_FRAMES_LOWER;
const char kCaptureFramesEnvVar[] = GFXRECON_ENV_VAR_PREFIX CAPTURE_FRAMES_LOWER;
const char kQuitAfterFramesEnvVar[] = GFXRECON_ENV_VAR_PREFIX QUIT_AFTER_CAPTURE_FRAMES_LOWER;
const char kCaptureTriggerEnvVar[] = GFXRECON_ENV_VAR_PREFIX CAPTURE_TRIGGER_LOWER;
const char kCaptureTriggerFramesEnvVar[] = GFXRECON_ENV_VAR_PREFIX CAPTURE_TRIGGER_FRAMES_LOWER;
const char kCaptureIUnknownWrappingEnvVar[] = GFXRECON_ENV_VAR_PREFIX CAPTURE_IUNKNOWN_WRAPPING_LOWER;
Expand Down Expand Up @@ -205,6 +208,7 @@ const char kScreenshotDirEnvVar[] = GFXRECON_ENV_VAR_
const char kScreenshotFormatEnvVar[] = GFXRECON_ENV_VAR_PREFIX SCREENSHOT_FORMAT_UPPER;
const char kScreenshotFramesEnvVar[] = GFXRECON_ENV_VAR_PREFIX SCREENSHOT_FRAMES_UPPER;
const char kCaptureFramesEnvVar[] = GFXRECON_ENV_VAR_PREFIX CAPTURE_FRAMES_UPPER;
const char kQuitAfterFramesEnvVar[] = GFXRECON_ENV_VAR_PREFIX QUIT_AFTER_CAPTURE_FRAMES_UPPER;
const char kPageGuardCopyOnMapEnvVar[] = GFXRECON_ENV_VAR_PREFIX PAGE_GUARD_COPY_ON_MAP_UPPER;
const char kPageGuardSeparateReadEnvVar[] = GFXRECON_ENV_VAR_PREFIX PAGE_GUARD_SEPARATE_READ_UPPER;
const char kPageGuardPersistentMemoryEnvVar[] = GFXRECON_ENV_VAR_PREFIX PAGE_GUARD_PERSISTENT_MEMORY_UPPER;
Expand Down Expand Up @@ -253,6 +257,7 @@ const std::string kOptionKeyScreenshotDir = std::stri
const std::string kOptionKeyScreenshotFormat = std::string(kSettingsFilter) + std::string(SCREENSHOT_FORMAT_LOWER);
const std::string kOptionKeyScreenshotFrames = std::string(kSettingsFilter) + std::string(SCREENSHOT_FRAMES_LOWER);
const std::string kOptionKeyCaptureFrames = std::string(kSettingsFilter) + std::string(CAPTURE_FRAMES_LOWER);
const std::string kOptionKeyQuitAfterCaptureFrames = std::string(kSettingsFilter) + std::string(QUIT_AFTER_CAPTURE_FRAMES_LOWER);
const std::string kOptionKeyCaptureTrigger = std::string(kSettingsFilter) + std::string(CAPTURE_TRIGGER_LOWER);
const std::string kOptionKeyCaptureTriggerFrames = std::string(kSettingsFilter) + std::string(CAPTURE_TRIGGER_FRAMES_LOWER);
const std::string kOptionKeyCaptureIUnknownWrapping = std::string(kSettingsFilter) + std::string(CAPTURE_IUNKNOWN_WRAPPING_LOWER);
Expand Down Expand Up @@ -384,6 +389,7 @@ void CaptureSettings::LoadOptionsEnvVar(OptionsMap* options)

// Trimming environment variables
LoadSingleOptionEnvVar(options, kCaptureFramesEnvVar, kOptionKeyCaptureFrames);
LoadSingleOptionEnvVar(options, kQuitAfterFramesEnvVar, kOptionKeyQuitAfterCaptureFrames);
LoadSingleOptionEnvVar(options, kCaptureTriggerEnvVar, kOptionKeyCaptureTrigger);
LoadSingleOptionEnvVar(options, kCaptureTriggerFramesEnvVar, kOptionKeyCaptureTriggerFrames);

Expand Down Expand Up @@ -489,6 +495,9 @@ void CaptureSettings::ProcessOptions(OptionsMap* options, CaptureSettings* setti
}
}

settings->trace_settings_.quit_after_frame_ranges = ParseBoolString(
FindOption(options, kOptionKeyQuitAfterCaptureFrames), settings->trace_settings_.quit_after_frame_ranges);

// Page guard environment variables
settings->trace_settings_.page_guard_copy_on_map = ParseBoolString(
FindOption(options, kOptionKeyPageGuardCopyOnMap), settings->trace_settings_.page_guard_copy_on_map);
Expand Down
1 change: 1 addition & 0 deletions framework/encode/capture_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class CaptureSettings
uint32_t accel_struct_padding{ 0 };
bool force_command_serialization{ false };
bool queue_zero_only{ false };
bool quit_after_frame_ranges{ false };

// An optimization for the page_guard memory tracking mode that eliminates the need for shadow memory by
// overriding vkAllocateMemory so that all host visible allocations use the external memory extension with a
Expand Down
14 changes: 8 additions & 6 deletions framework/encode/d3d12_capture_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ bool D3D12CaptureManager::CreateInstance()
[]() {
assert(instance_ == nullptr);
instance_ = new D3D12CaptureManager();
},
[]() {
if (instance_)
{
delete instance_;
instance_ = nullptr;
}
});
if (instance_->IsAnnotated() == true && instance_->resource_value_annotator_ == nullptr)
{
Expand All @@ -60,12 +67,7 @@ bool D3D12CaptureManager::CreateInstance()

void D3D12CaptureManager::DestroyInstance()
{
CaptureManager::DestroyInstance([]() -> const CaptureManager* { return instance_; },
[]() {
assert(instance_ != nullptr);
delete instance_;
instance_ = nullptr;
});
CaptureManager::DestroyInstance([]() -> const CaptureManager* { return instance_; });
}

void D3D12CaptureManager::EndCreateApiCallCapture(HRESULT result, REFIID riid, void** handle)
Expand Down
14 changes: 8 additions & 6 deletions framework/encode/vulkan_capture_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ bool VulkanCaptureManager::CreateInstance()
[]() {
assert(instance_ == nullptr);
instance_ = new VulkanCaptureManager();
},
[]() {
if (instance_)
{
delete instance_;
instance_ = nullptr;
}
});

GFXRECON_LOG_INFO(" Vulkan Header Version %u.%u.%u",
Expand All @@ -73,12 +80,7 @@ bool VulkanCaptureManager::CreateInstance()

void VulkanCaptureManager::DestroyInstance()
{
CaptureManager::DestroyInstance([]() -> const CaptureManager* { return instance_; },
[]() {
assert(instance_ != nullptr);
delete instance_;
instance_ = nullptr;
});
CaptureManager::DestroyInstance([]() -> const CaptureManager* { return instance_; });
}

void VulkanCaptureManager::WriteTrackedState(util::FileOutputStream* file_stream, format::ThreadId thread_id)
Expand Down

0 comments on commit a55e256

Please sign in to comment.