diff --git a/gpu/command_buffer/service/shared_image/dawn_copy_strategy.cc b/gpu/command_buffer/service/shared_image/dawn_copy_strategy.cc index e56810f86a9b3..da672accdf720 100644 --- a/gpu/command_buffer/service/shared_image/dawn_copy_strategy.cc +++ b/gpu/command_buffer/service/shared_image/dawn_copy_strategy.cc @@ -334,14 +334,19 @@ bool DawnCopyStrategy::CopyFromTextureToBacking(wgpu::Texture src_texture, plane_index < static_cast(staging_buffers.size()); ++plane_index) { const auto& staging_buffer_entry = staging_buffers[plane_index]; - bool success = false; + // The MapAsync callback is WaitAnyOnly: if WaitAny returns non-Success + // (e.g. TimedOut on device loss), Dawn retains the callback until + // ~EventManager and fires it then. Heap-allocate the result so the + // callback never writes to a dead stack slot. The capturing-lambda + // overload of MapAsync heap-allocates the closure and frees it when the + // callback fires. + auto success = std::make_shared(false); wgpu::FutureWaitInfo wait_info = {staging_buffer_entry.buffer.MapAsync( wgpu::MapMode::Read, 0, wgpu::kWholeMapSize, wgpu::CallbackMode::WaitAnyOnly, - [](wgpu::MapAsyncStatus status, wgpu::StringView, bool* success) { + [success](wgpu::MapAsyncStatus status, wgpu::StringView) { *success = status == wgpu::MapAsyncStatus::Success; - }, - &success)}; + })}; if (device.GetAdapter().GetInstance().WaitAny(1, &wait_info, UINT64_MAX) != wgpu::WaitStatus::Success) { @@ -349,7 +354,7 @@ bool DawnCopyStrategy::CopyFromTextureToBacking(wgpu::Texture src_texture, return false; } - if (!wait_info.completed || !success) { + if (!wait_info.completed || !*success) { LOG(ERROR) << "MapAsync did not yield a readable mapping."; return false; }