-
Notifications
You must be signed in to change notification settings - Fork 127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support multiple simultaneous API capture managers #1536
Support multiple simultaneous API capture managers #1536
Conversation
CI gfxreconstruct build queued with queue ID 179237. |
CI gfxreconstruct build # 4103 running. |
CI gfxreconstruct build # 4103 failed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some comment for reviewers.
framework/encode/capture_manager.cpp
Outdated
@@ -51,12 +51,11 @@ std::mutex CaptureManager::ThreadData::count | |||
format::ThreadId CaptureManager::ThreadData::thread_count_ = 0; | |||
std::unordered_map<uint64_t, format::ThreadId> CaptureManager::ThreadData::id_map_; | |||
|
|||
uint32_t CaptureManager::instance_count_ = 0; | |||
CaptureManager* CaptureManager::singleton_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note the change of terminology from "instance" to "singleton" throughout the PR. The singleton pattern implemented maps many API instances to the same CaptureManager singletons, thus calling the "singletons" "instances" seems quite confusing, given that a CreateInstance call may correlate to 0 or 1 CaptureManager creations, and DestroyInstance may correlate to 0 or 1 CaptureManager destructions.
framework/encode/capture_manager.cpp
Outdated
@@ -89,8 +88,8 @@ format::ThreadId CaptureManager::ThreadData::GetThreadId() | |||
return id; | |||
} | |||
|
|||
CaptureManager::CaptureManager(format::ApiFamilyId api_family) : | |||
api_family_(api_family), force_file_flush_(false), timestamp_filename_(true), | |||
CaptureManager::CaptureManager() : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CaptureManager changes from being a base class to a referenced common class. All API specific capture managers access the common functionality through a referenced instance of the common class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add this comment to the source itself.
framework/encode/capture_manager.cpp
Outdated
// Initialize logging to report only errors (to stderr). | ||
util::Log::Settings stderr_only_log_settings; | ||
stderr_only_log_settings.min_severity = util::Log::kErrorSeverity; | ||
stderr_only_log_settings.output_errors_to_stderr = true; | ||
util::Log::Init(stderr_only_log_settings); | ||
|
||
// WIP WIP -- FIRST WINS for settings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the current implementation doesn't support multiple disparate API's being captured, the "first wins" settings limitation doesn't impact current functionality, but needs to be resolved for actual multi API support (which is need for specific future use cases).
WIP comment is to attract reviewers attention, to be changed to NOTE or TODO prior to commit.
framework/encode/capture_manager.cpp
Outdated
GFXRECON_ASSERT(inserted.second); | ||
manager_it = inserted.first; | ||
|
||
// WIP NOTE moved here from CaptureTracker::Initialize... DRY'r than putting it into the API specific |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Folks with a better understand of why StateTracker objects are lazily created please comment. Would it be reasonable to always create an empty state tracker, even if unused, s.t. eventual interactions between multiple capture managers settings don't lead to some inconsistent state?
framework/encode/capture_manager.cpp
Outdated
GFXRECON_LOG_DEBUG("CaptureManager::CreateInstance(): Current instance count is %u", instance_count_); | ||
|
||
return success; | ||
} | ||
|
||
void CaptureManager::DestroyInstance(std::function<const CaptureManager*()> GetInstanceFunc) | ||
void CaptureManager::DestroyInstance(ApiCaptureManagerBase* api_capture_manager) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The destruction function is now captured at CreateInstance time. The "delete on last" logic is implemented here in the common class.
@@ -1093,7 +1168,7 @@ void CaptureManager::WriteFillMemoryCmd(format::HandleId memory_id, uint64_t off | |||
|
|||
void CaptureManager::WriteCreateHeapAllocationCmd(uint64_t allocation_id, uint64_t allocation_size) | |||
{ | |||
if ((GetCaptureMode() & kModeWrite) == kModeWrite) | |||
if (IsCaptureModeWrite()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Class segregation moved the definition such that it would need qualification, and since the expression needed rewrite, seemed DRY'r to encapsulate.
void CaptureManager::WriteCaptureOptions(std::string& operation_annotation) | ||
{ | ||
CaptureSettings::TraceSettings default_settings = GetDefaultTraceSettings(); | ||
CaptureSettings::TraceSettings default_settings = default_settings_.GetTraceSettings(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The common capture manager sets this up, getting information from the capture manager associated with the first CreateInstance... seemed simplest to cache that data away, rather than track who's on first.
framework/encode/capture_manager.h
Outdated
@@ -374,6 +388,178 @@ class CaptureManager | |||
} rv_annotation_info_; | |||
}; | |||
|
|||
class ApiCaptureManagerBase |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My biggest concerns here are maintainability and performance (with the additional indirection). Not sure of a different approach that would require a lookup of CaptureManager::singleton_ everywhere one of these methods is invoked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another possible idea for breaking apart these classes: Have the common capture manager and each API capture manager be singletons and require the calling code (e.g., in the API-specific capture manager classes, or in the generated encoder files) to know which class to call into. Then the API manager classes don't need to pass-through all the common class methods and might help promote a division of responsibilities between the common and API-specific capture managers.
The API capture managers could still store a pointer to the common capture manager for cases when they need to call into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The goal of the ApiCaptureManagerBase passthrough calls was to minimize the code change impact of call into the common CaptureManager. Without this, every common call would need to be changed to be prefixed by common_manager_-> which seemed needlessly noisy (diff-wise) and verbose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another thought on this: forcing the users of capture managers to be explicit about calling into the API capture manager or the common capture manager may help code clarity. For example, the calls to AcquireSharedApiCallLock
are currently made on the API-specific capture manager classes D3D12CaptureManager
or VulkanCaptureManager
. This could make it not obvious that D3D12CaptureManager::AcquireSharedApiCallLock
acquires a lock across all capture managers. Making the choice of capture manager explicit could help solidify the concept of global vs API-specific capture functions and promote correct usage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this makes things more complicated. Especially because we're still sharing the file write locks. So now we'd be blocking on API calls and file write locks while the file write itself would be the mitigating restriction. So just having the file lock would be sufficient.
if (instance_->IsAnnotated() == true && instance_->resource_value_annotator_ == nullptr) | ||
{ | ||
instance_->resource_value_annotator_ = std::make_unique<Dx12ResourceValueAnnotator>(); | ||
bool ret = CaptureManager::CreateInstance<D3D12CaptureManager>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The templated overload associates the calling classes constructor/destructor functions automagically.
@bradgrantham @davidd-lunarg -- I've added some explanatory comments. Please review so I can revise and complete to unblock the multi-api "work on a branch" there stuff that needs to be resolved after this to do multi-API correctly, but this will all forward progress, and should be functionally equivalent for the currently supported operating modes. (i.e. single API at a time) |
f94320a
to
2c5123c
Compare
CI gfxreconstruct build queued with queue ID 180502. |
CI gfxreconstruct build # 4106 running. |
CI gfxreconstruct build # 4106 failed. |
2c5123c
to
7ecaee7
Compare
CI gfxreconstruct build queued with queue ID 180524. |
CI gfxreconstruct build # 4107 running. |
CI gfxreconstruct build # 4107 failed. |
CI gfxreconstruct build queued with queue ID 180726. |
CI gfxreconstruct build # 4114 running. |
CI gfxreconstruct build # 4114 failed. |
7ecaee7
to
48cb40c
Compare
CI gfxreconstruct build queued with queue ID 181045. |
CI gfxreconstruct build # 4115 running. |
CI gfxreconstruct build # 4115 failed. |
48cb40c
to
04c935d
Compare
CI gfxreconstruct build queued with queue ID 181105. |
CI gfxreconstruct build # 4149 failed. |
24bc60b
to
b52fbf7
Compare
CI gfxreconstruct build queued with queue ID 185214. |
b52fbf7
to
a385ea6
Compare
CI gfxreconstruct build queued with queue ID 185233. |
CI gfxreconstruct build # 4154 running. |
CI gfxreconstruct build # 4154 passed. |
@davidd-lunarg @bradgrantham -- ready for review |
framework/encode/capture_manager.h
Outdated
using ApiCaptureManagerMap = std::unordered_map<ApiCaptureManager*, ApiInstanceRecord>; | ||
ApiCaptureManagerMap api_capture_managers_; | ||
|
||
CaptureSettings default_settings_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should clarify the difference here between default_settings_
and capture_settings_
in a comment.
a385ea6
to
0d0cc69
Compare
CI gfxreconstruct build queued with queue ID 185371. |
CI gfxreconstruct build # 185371 cancelled. |
0d0cc69
to
f1369cb
Compare
CI gfxreconstruct build queued with queue ID 185440. |
CI gfxreconstruct build # 4159 running. |
CI gfxreconstruct build # 4159 passed. |
framework/format/api_call_id.h
Outdated
@@ -54,7 +54,7 @@ enum ApiFamilyId : uint16_t | |||
ApiFamily_Vulkan = 1, | |||
ApiFamily_Dxgi = 2, | |||
ApiFamily_D3D12 = 3, | |||
ApiFamily_AGS = 4, | |||
ApiFamily_AGS = 4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this file doesn't need to be modified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, okay to leave trailing comma (unless clang-format complained?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Request to wrap loop in braces, echoed small nit on comma, otherwise looks great
{ | ||
capture_mode_ |= kModeWrite; | ||
|
||
auto thread_data = GetThreadData(); | ||
assert(thread_data != nullptr); | ||
|
||
WriteTrackedState(file_stream_.get(), thread_data->thread_id_); | ||
for (auto& manager : api_capture_managers_) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please wrap block in braces. Thank you!
framework/format/api_call_id.h
Outdated
@@ -54,7 +54,7 @@ enum ApiFamilyId : uint16_t | |||
ApiFamily_Vulkan = 1, | |||
ApiFamily_Dxgi = 2, | |||
ApiFamily_D3D12 = 3, | |||
ApiFamily_AGS = 4, | |||
ApiFamily_AGS = 4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, okay to leave trailing comma (unless clang-format complained?)
f1369cb
to
4e6ee08
Compare
CI gfxreconstruct build queued with queue ID 185949. |
Split common and api specific options from isA to refsA relationship. Rename CaptureManager to CommonCaptureManager API specific capture managers inherit from ApiCaptureManager base, class. For single API sessions should be exactly equivalent.
4e6ee08
to
8b1bae3
Compare
CI gfxreconstruct build queued with queue ID 185950. |
CI gfxreconstruct build # 4167 running. |
CI gfxreconstruct build # 4167 passed. |
Split common and api specific options from isA to refsA relationship.
For single API sessions should be exactly equivalent.
This is a first piece of multiple API support needed for pending feature development.
Issues to be resolved:
Settings Arbitration: different API invocations of the layer may have different settings. Determining where are complete set of options are (without having to repeat them in every JSON) is one challenge. Resolving which setting "wins" (first, last, some priority heuristic). Settings side effects (like whether an StateTracker is create) need to be address if later invocations can change settings.
A number of interfaces became "public" to support this. The other choice is friendship between the various CaptureManagers, thoughts?
Also, concerns about performance or maintainability.