Merge pull request #4291 from diversao/fix/agc-release-parked-imports
fix(agc): release parked host imports a pinned guest range waits for
This commit is contained in:
commit
090e26aac1
|
|
@ -811,6 +811,8 @@ if(BUILD_TESTING)
|
|||
endif()
|
||||
add_test(NAME agc_host_import_unmap COMMAND agc_driver_recorder_tests --host-import-unmap-only)
|
||||
set_tests_properties(agc_host_import_unmap PROPERTIES SKIP_RETURN_CODE 77)
|
||||
add_test(NAME agc_parked_import_unmap COMMAND agc_driver_recorder_tests --parked-import-unmap-only)
|
||||
set_tests_properties(agc_parked_import_unmap PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 30 ENVIRONMENT "APS5_PIN_WAIT_MS=3000")
|
||||
add_test(NAME agc_unit_shadow COMMAND agc_driver_recorder_tests --unit-shadow-only)
|
||||
set_tests_properties(agc_unit_shadow PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 30 ENVIRONMENT "APS5_PIN_WAIT_MS=3000")
|
||||
add_test(NAME agc_descriptor_pool_recycling COMMAND agc_driver_recorder_tests --descriptor-pool-only)
|
||||
|
|
@ -822,7 +824,7 @@ if(BUILD_TESTING)
|
|||
add_test(NAME agc_draw_inputs_in_place COMMAND agc_driver_recorder_tests --draw-inputs-in-place-only)
|
||||
set_tests_properties(agc_draw_inputs_in_place PROPERTIES SKIP_RETURN_CODE 77)
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_host_import_unmap agc_unit_shadow agc_descriptor_pool_recycling agc_draw_snapshot_cap agc_multisample_guest_access agc_draw_inputs_in_place PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
set_tests_properties(agc_host_import_unmap agc_parked_import_unmap agc_unit_shadow agc_descriptor_pool_recycling agc_draw_snapshot_cap agc_multisample_guest_access agc_draw_inputs_in_place PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -219,6 +219,26 @@ void retireImport(VkDevice device, HostImports& state, std::map<std::uint64_t, H
|
|||
state.imports.erase(it);
|
||||
}
|
||||
|
||||
bool releaseParkedImports(HostImports& state, std::uint64_t begin, std::uint64_t end) {
|
||||
std::vector<std::shared_ptr<RetiredImport>> released;
|
||||
{
|
||||
std::lock_guard lock(state.mutex);
|
||||
for (auto device = state.parked.begin(); device != state.parked.end();) {
|
||||
auto& list = device->second;
|
||||
for (auto it = list.begin(); it != list.end();) {
|
||||
if ((*it)->entry.base < end && begin < (*it)->entry.base + (*it)->entry.bytes) {
|
||||
released.push_back(std::move(*it));
|
||||
it = list.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
device = list.empty() ? state.parked.erase(device) : std::next(device);
|
||||
}
|
||||
}
|
||||
return !released.empty();
|
||||
}
|
||||
|
||||
const char* bindImport(const Context& context, HostImport& entry, VkExternalMemoryHandleTypeFlagBits handleType, const void* import, std::uint32_t importTypes, bool& allocated, VkResult& failure) {
|
||||
const auto failed = [&](const char* step, VkResult result) -> const char* {
|
||||
if (entry.buffer) context.Function<PFN_vkDestroyBuffer>("vkDestroyBuffer")(context.device, entry.buffer, nullptr);
|
||||
|
|
@ -1534,6 +1554,7 @@ bool WaitForLeasesAndImports(std::uintptr_t address, std::size_t bytes) noexcept
|
|||
if (recorder != nullptr) recorder->FlushDeferredReleases();
|
||||
const auto end = static_cast<std::uint64_t>(address) + bytes;
|
||||
auto& imports = Imports();
|
||||
if (releaseParkedImports(imports, address, end)) retiredImport = true;
|
||||
const auto lease = GuestAllocations::GuestAllocationsAcquire_nid_postfix();
|
||||
{
|
||||
std::lock_guard importsLock(imports.mutex);
|
||||
|
|
@ -1585,6 +1606,7 @@ bool WaitForLeasesAndImports(std::uintptr_t address, std::size_t bytes) noexcept
|
|||
|
||||
const auto end = static_cast<std::uint64_t>(address) + bytes;
|
||||
auto& imports = Imports();
|
||||
if (releaseParkedImports(imports, address, end)) retiredImport = true;
|
||||
bool overlapsImport = false;
|
||||
{
|
||||
std::lock_guard importsLock(imports.mutex);
|
||||
|
|
|
|||
|
|
@ -2567,6 +2567,71 @@ void hostImportUnmapTests(const Device& device, Recorder& recorder) {
|
|||
std::cout << "host import unmap lifetime: ok\n";
|
||||
}
|
||||
|
||||
void parkedImportUnmapTests(const Device& device) {
|
||||
const auto& context = device.GetContext();
|
||||
if (context.hostImportAlignment == 0) {
|
||||
std::cout << "host imports unavailable: parked import unmap not tested\n";
|
||||
return;
|
||||
}
|
||||
const auto alignment = static_cast<std::size_t>(std::max<VkDeviceSize>(65536u, context.hostImportAlignment));
|
||||
const auto bytes = alignment * 4u;
|
||||
#ifdef _WIN32
|
||||
void* block = VirtualAlloc(nullptr, bytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
#else
|
||||
void* block = std::aligned_alloc(alignment, bytes);
|
||||
#endif
|
||||
Require(block != nullptr, "cannot allocate the parked import unmap block");
|
||||
const auto release = [&] {
|
||||
#ifdef _WIN32
|
||||
VirtualFree(block, 0, MEM_RELEASE);
|
||||
#else
|
||||
std::free(block);
|
||||
#endif
|
||||
};
|
||||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
std::unique_ptr<Device> replacement;
|
||||
bool imported = false;
|
||||
{
|
||||
std::lock_guard gpu(GpuMutex());
|
||||
imported = HostImportFor(context, address, bytes) != nullptr;
|
||||
}
|
||||
if (imported) {
|
||||
replacement = std::make_unique<Device>();
|
||||
std::lock_guard gpu(GpuMutex());
|
||||
imported = HostImportFor(replacement->GetContext(), address, bytes) != nullptr;
|
||||
}
|
||||
if (!imported) {
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Remove(block);
|
||||
if (replacement) ClearHostImports(replacement->GetContext().device);
|
||||
release();
|
||||
std::cout << "host import refused: parked import unmap not tested\n";
|
||||
return;
|
||||
}
|
||||
bool unmapped = false;
|
||||
try {
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Unmap(block, bytes, [&](const void*, std::size_t, const void*, bool) { unmapped = true; });
|
||||
} catch (const std::exception& error) {
|
||||
ClearHostImports(replacement->GetContext().device);
|
||||
ClearHostImports(context.device);
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Remove(block);
|
||||
release();
|
||||
throw std::runtime_error(std::string("guest unmap after a device replacement: ") + error.what());
|
||||
}
|
||||
ClearHostImports(replacement->GetContext().device);
|
||||
ClearImageMirrors(replacement->GetContext().device);
|
||||
replacement.reset();
|
||||
release();
|
||||
Require(unmapped, "guest unmap of a range a replaced device imported did not run");
|
||||
std::cout << "parked import unmap: ok\n";
|
||||
}
|
||||
|
||||
void importWatchTests(const Device& device) {
|
||||
using namespace AgcDriver::GuestMemory;
|
||||
const auto& context = device.GetContext();
|
||||
|
|
@ -5431,6 +5496,11 @@ int main(int argc, char** argv) {
|
|||
hostImportUnmapTests(device, recorder);
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::string_view(argv[1]) == "--parked-import-unmap-only") {
|
||||
gpu.unlock();
|
||||
parkedImportUnmapTests(device);
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::string_view(argv[1]) == "--unit-shadow-only") {
|
||||
if (!AgcDriver::Graphics::UnitShadowEnabled() || device.GetContext().hostImportAlignment == 0) {
|
||||
std::cout << "skipped, unit shadows or host imports are unavailable\n";
|
||||
|
|
|
|||
Loading…
Reference in New Issue