Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2011 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | #include "RenderThread.h" |
| 17 | |
| 18 | #include "ChannelStream.h" |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 19 | #include "FrameBuffer.h" |
Kaiyi Li | 1b6feaa | 2022-03-25 10:12:38 -0700 | [diff] [blame] | 20 | #include "ReadBuffer.h" |
| 21 | #include "RenderChannelImpl.h" |
Kaiyi Li | 1b6feaa | 2022-03-25 10:12:38 -0700 | [diff] [blame] | 22 | #include "RenderThreadInfo.h" |
Kaiyi Li | 1b6feaa | 2022-03-25 10:12:38 -0700 | [diff] [blame] | 23 | #include "RingStream.h" |
Kaiyi Li | 74d3ef3 | 2022-09-21 12:47:43 -0700 | [diff] [blame] | 24 | #include "VkDecoderContext.h" |
Joshua Duong | ef2bbc2 | 2022-10-05 11:59:15 -0700 | [diff] [blame] | 25 | #include "aemu/base/HealthMonitor.h" |
Gurchetan Singh | 6ed12e9 | 2024-01-19 02:19:50 +0000 | [diff] [blame] | 26 | #include "aemu/base/Metrics.h" |
| 27 | #include "aemu/base/files/StreamSerializing.h" |
Gurchetan Singh | 95b30dc | 2024-01-18 18:31:15 -0800 | [diff] [blame] | 28 | #include "aemu/base/synchronization/Lock.h" |
| 29 | #include "aemu/base/synchronization/MessageChannel.h" |
Joshua Duong | ef2bbc2 | 2022-10-05 11:59:15 -0700 | [diff] [blame] | 30 | #include "aemu/base/system/System.h" |
Gurchetan Singh | 95b30dc | 2024-01-18 18:31:15 -0800 | [diff] [blame] | 31 | #include "apigen-codec-common/ChecksumCalculatorThreadInfo.h" |
Jason Macnak | e43e3a0 | 2021-10-14 10:35:33 -0700 | [diff] [blame] | 32 | #include "host-common/logging.h" |
Kaiyi Li | 1b6feaa | 2022-03-25 10:12:38 -0700 | [diff] [blame] | 33 | #include "vulkan/VkCommonOperations.h" |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 34 | |
Gurchetan Singh | 95b30dc | 2024-01-18 18:31:15 -0800 | [diff] [blame] | 35 | #if GFXSTREAM_ENABLE_HOST_GLES |
| 36 | #include "RenderControl.h" |
| 37 | #endif |
| 38 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 39 | #define EMUGL_DEBUG_LEVEL 0 |
Lingfeng Yang | bfe3c72 | 2020-10-29 10:33:18 -0700 | [diff] [blame] | 40 | #include "host-common/debug.h" |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 41 | |
Doug Horn | 370c07b | 2021-01-08 12:12:52 -0800 | [diff] [blame] | 42 | #ifndef _WIN32 |
| 43 | #include <unistd.h> |
| 44 | #endif |
| 45 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 46 | #include <assert.h> |
Lingfeng Yang | bfe3c72 | 2020-10-29 10:33:18 -0700 | [diff] [blame] | 47 | #include <string.h> |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 48 | |
Jason Macnak | 4949145 | 2022-07-20 14:57:37 -0700 | [diff] [blame] | 49 | #include <unordered_map> |
| 50 | |
Jason Macnak | ed0c9e6 | 2023-03-30 15:58:24 -0700 | [diff] [blame] | 51 | namespace gfxstream { |
| 52 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 53 | using android::base::AutoLock; |
William Ho | 9999989 | 2022-05-24 11:10:59 -0700 | [diff] [blame] | 54 | using android::base::EventHangMetadata; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 55 | using android::base::MessageChannel; |
Jason Macnak | ed0c9e6 | 2023-03-30 15:58:24 -0700 | [diff] [blame] | 56 | using emugl::GfxApiLogger; |
| 57 | using vk::VkDecoderContext; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 58 | |
| 59 | struct RenderThread::SnapshotObjects { |
| 60 | RenderThreadInfo* threadInfo; |
| 61 | ChecksumCalculator* checksumCalc; |
| 62 | ChannelStream* channelStream; |
| 63 | RingStream* ringStream; |
| 64 | ReadBuffer* readBuffer; |
| 65 | }; |
| 66 | |
| 67 | static bool getBenchmarkEnabledFromEnv() { |
Lingfeng Yang | bfe3c72 | 2020-10-29 10:33:18 -0700 | [diff] [blame] | 68 | auto threadEnabled = android::base::getEnvironmentVariable("ANDROID_EMUGL_RENDERTHREAD_STATS"); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 69 | if (threadEnabled == "1") return true; |
| 70 | return false; |
| 71 | } |
| 72 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 73 | // Start with a smaller buffer to not waste memory on a low-used render threads. |
| 74 | static constexpr int kStreamBufferSize = 128 * 1024; |
| 75 | |
Doug Horn | 370c07b | 2021-01-08 12:12:52 -0800 | [diff] [blame] | 76 | // Requires this many threads on the system available to run unlimited. |
| 77 | static constexpr int kMinThreadsToRunUnlimited = 5; |
| 78 | |
| 79 | // A thread run limiter that limits render threads to run one slice at a time. |
| 80 | static android::base::Lock sThreadRunLimiter; |
| 81 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 82 | RenderThread::RenderThread(RenderChannelImpl* channel, |
Jason Macnak | 1220d96 | 2023-11-21 16:53:21 -0800 | [diff] [blame] | 83 | android::base::Stream* loadStream, |
| 84 | uint32_t virtioGpuContextId) |
Lingfeng Yang | bfe3c72 | 2020-10-29 10:33:18 -0700 | [diff] [blame] | 85 | : android::base::Thread(android::base::ThreadFlags::MaskSignals, 2 * 1024 * 1024), |
Doug Horn | 370c07b | 2021-01-08 12:12:52 -0800 | [diff] [blame] | 86 | mChannel(channel), |
Jason Macnak | 1220d96 | 2023-11-21 16:53:21 -0800 | [diff] [blame] | 87 | mRunInLimitedMode(android::base::getCpuCoreCount() < kMinThreadsToRunUnlimited), |
| 88 | mContextId(virtioGpuContextId) |
Doug Horn | 370c07b | 2021-01-08 12:12:52 -0800 | [diff] [blame] | 89 | { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 90 | if (loadStream) { |
| 91 | const bool success = loadStream->getByte(); |
| 92 | if (success) { |
| 93 | mStream.emplace(0); |
| 94 | android::base::loadStream(loadStream, &*mStream); |
| 95 | mState = SnapshotState::StartLoading; |
| 96 | } else { |
| 97 | mFinished.store(true, std::memory_order_relaxed); |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | RenderThread::RenderThread( |
| 103 | struct asg_context context, |
Doug Horn | 05386c5 | 2021-01-08 13:51:36 -0800 | [diff] [blame] | 104 | android::base::Stream* loadStream, |
Gurchetan Singh | f60b2b7 | 2022-08-22 17:01:02 -0700 | [diff] [blame] | 105 | android::emulation::asg::ConsumerCallbacks callbacks, |
| 106 | uint32_t contextId, uint32_t capsetId, |
| 107 | std::optional<std::string> nameOpt) |
| 108 | : android::base::Thread(android::base::ThreadFlags::MaskSignals, 2 * 1024 * 1024, |
| 109 | std::move(nameOpt)), |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 110 | mRingStream( |
Gurchetan Singh | f60b2b7 | 2022-08-22 17:01:02 -0700 | [diff] [blame] | 111 | new RingStream(context, callbacks, kStreamBufferSize)), |
| 112 | mContextId(contextId), mCapsetId(capsetId) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 113 | if (loadStream) { |
| 114 | const bool success = loadStream->getByte(); |
| 115 | if (success) { |
| 116 | mStream.emplace(0); |
| 117 | android::base::loadStream(loadStream, &*mStream); |
| 118 | mState = SnapshotState::StartLoading; |
| 119 | } else { |
| 120 | mFinished.store(true, std::memory_order_relaxed); |
| 121 | } |
| 122 | } |
| 123 | } |
| 124 | |
Jason Macnak | 69698e3 | 2021-09-08 15:40:04 -0700 | [diff] [blame] | 125 | // Note: the RenderThread destructor might be called from a different thread |
| 126 | // than from RenderThread::main() so thread specific cleanup likely belongs at |
| 127 | // the end of RenderThread::main(). |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 128 | RenderThread::~RenderThread() = default; |
| 129 | |
| 130 | void RenderThread::pausePreSnapshot() { |
| 131 | AutoLock lock(mLock); |
| 132 | assert(mState == SnapshotState::Empty); |
| 133 | mStream.emplace(); |
| 134 | mState = SnapshotState::StartSaving; |
Doug Horn | 60cc9fb | 2021-01-08 14:13:38 -0800 | [diff] [blame] | 135 | if (mRingStream) { |
| 136 | mRingStream->pausePreSnapshot(); |
| 137 | // mCondVar.broadcastAndUnlock(&lock); |
| 138 | } |
| 139 | if (mChannel) { |
| 140 | mChannel->pausePreSnapshot(); |
| 141 | mCondVar.broadcastAndUnlock(&lock); |
| 142 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 143 | } |
| 144 | |
Yahan Zhou | d1c7e1e | 2023-11-09 14:59:26 -0800 | [diff] [blame] | 145 | void RenderThread::resume(bool waitForSave) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 146 | AutoLock lock(mLock); |
| 147 | // This function can be called for a thread from pre-snapshot loading |
| 148 | // state; it doesn't need to do anything. |
| 149 | if (mState == SnapshotState::Empty) { |
| 150 | return; |
| 151 | } |
Doug Horn | 60cc9fb | 2021-01-08 14:13:38 -0800 | [diff] [blame] | 152 | if (mRingStream) mRingStream->resume(); |
Yahan Zhou | d1c7e1e | 2023-11-09 14:59:26 -0800 | [diff] [blame] | 153 | if (waitForSave) { |
| 154 | waitForSnapshotCompletion(&lock); |
| 155 | } |
| 156 | mNeedReloadProcessResources = true; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 157 | mStream.clear(); |
| 158 | mState = SnapshotState::Empty; |
| 159 | if (mChannel) mChannel->resume(); |
Doug Horn | 60cc9fb | 2021-01-08 14:13:38 -0800 | [diff] [blame] | 160 | if (mRingStream) mRingStream->resume(); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 161 | mCondVar.broadcastAndUnlock(&lock); |
| 162 | } |
| 163 | |
| 164 | void RenderThread::save(android::base::Stream* stream) { |
| 165 | bool success; |
| 166 | { |
| 167 | AutoLock lock(mLock); |
| 168 | assert(mState == SnapshotState::StartSaving || |
| 169 | mState == SnapshotState::InProgress || |
| 170 | mState == SnapshotState::Finished); |
| 171 | waitForSnapshotCompletion(&lock); |
| 172 | success = mState == SnapshotState::Finished; |
| 173 | } |
| 174 | |
| 175 | if (success) { |
| 176 | assert(mStream); |
| 177 | stream->putByte(1); |
| 178 | android::base::saveStream(stream, *mStream); |
| 179 | } else { |
| 180 | stream->putByte(0); |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | void RenderThread::waitForSnapshotCompletion(AutoLock* lock) { |
| 185 | while (mState != SnapshotState::Finished && |
| 186 | !mFinished.load(std::memory_order_relaxed)) { |
| 187 | mCondVar.wait(lock); |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | template <class OpImpl> |
| 192 | void RenderThread::snapshotOperation(AutoLock* lock, OpImpl&& implFunc) { |
| 193 | assert(isPausedForSnapshotLocked()); |
| 194 | mState = SnapshotState::InProgress; |
| 195 | mCondVar.broadcastAndUnlock(lock); |
| 196 | |
| 197 | implFunc(); |
| 198 | |
| 199 | lock->lock(); |
| 200 | |
| 201 | mState = SnapshotState::Finished; |
| 202 | mCondVar.broadcast(); |
| 203 | |
| 204 | // Only return after we're allowed to proceed. |
| 205 | while (isPausedForSnapshotLocked()) { |
| 206 | mCondVar.wait(lock); |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | void RenderThread::loadImpl(AutoLock* lock, const SnapshotObjects& objects) { |
| 211 | snapshotOperation(lock, [this, &objects] { |
| 212 | objects.readBuffer->onLoad(&*mStream); |
| 213 | if (objects.channelStream) objects.channelStream->load(&*mStream); |
| 214 | if (objects.ringStream) objects.ringStream->load(&*mStream); |
| 215 | objects.checksumCalc->load(&*mStream); |
| 216 | objects.threadInfo->onLoad(&*mStream); |
| 217 | }); |
| 218 | } |
| 219 | |
| 220 | void RenderThread::saveImpl(AutoLock* lock, const SnapshotObjects& objects) { |
| 221 | snapshotOperation(lock, [this, &objects] { |
| 222 | objects.readBuffer->onSave(&*mStream); |
| 223 | if (objects.channelStream) objects.channelStream->save(&*mStream); |
| 224 | if (objects.ringStream) objects.ringStream->save(&*mStream); |
| 225 | objects.checksumCalc->save(&*mStream); |
| 226 | objects.threadInfo->onSave(&*mStream); |
| 227 | }); |
| 228 | } |
| 229 | |
| 230 | bool RenderThread::isPausedForSnapshotLocked() const { |
| 231 | return mState != SnapshotState::Empty; |
| 232 | } |
| 233 | |
| 234 | bool RenderThread::doSnapshotOperation(const SnapshotObjects& objects, |
| 235 | SnapshotState state) { |
| 236 | AutoLock lock(mLock); |
| 237 | if (mState == state) { |
| 238 | switch (state) { |
| 239 | case SnapshotState::StartLoading: |
| 240 | loadImpl(&lock, objects); |
| 241 | return true; |
| 242 | case SnapshotState::StartSaving: |
| 243 | saveImpl(&lock, objects); |
| 244 | return true; |
| 245 | default: |
| 246 | return false; |
| 247 | } |
| 248 | } |
| 249 | return false; |
| 250 | } |
| 251 | |
| 252 | void RenderThread::setFinished() { |
| 253 | // Make sure it never happens that we wait forever for the thread to |
| 254 | // save to snapshot while it was not even going to. |
| 255 | AutoLock lock(mLock); |
| 256 | mFinished.store(true, std::memory_order_relaxed); |
| 257 | if (mState != SnapshotState::Empty) { |
| 258 | mCondVar.broadcastAndUnlock(&lock); |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | intptr_t RenderThread::main() { |
| 263 | if (mFinished.load(std::memory_order_relaxed)) { |
Jason Macnak | e43e3a0 | 2021-10-14 10:35:33 -0700 | [diff] [blame] | 264 | ERR("Error: fail loading a RenderThread @%p", this); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 265 | return 0; |
| 266 | } |
| 267 | |
| 268 | RenderThreadInfo tInfo; |
| 269 | ChecksumCalculatorThreadInfo tChecksumInfo; |
| 270 | ChecksumCalculator& checksumCalc = tChecksumInfo.get(); |
| 271 | bool needRestoreFromSnapshot = false; |
| 272 | |
| 273 | // |
| 274 | // initialize decoders |
Gurchetan Singh | 95b30dc | 2024-01-18 18:31:15 -0800 | [diff] [blame] | 275 | #if GFXSTREAM_ENABLE_HOST_GLES |
Aaron Ruby | 52cef35 | 2024-07-02 13:31:23 -0400 | [diff] [blame] | 276 | if (!FrameBuffer::getFB()->getFeatures().GuestVulkanOnly.enabled) { |
Jason Macnak | 94fb5e0 | 2022-07-27 15:36:53 -0700 | [diff] [blame] | 277 | tInfo.initGl(); |
| 278 | } |
Jason Macnak | 09ec44f | 2022-07-27 15:02:27 -0700 | [diff] [blame] | 279 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 280 | initRenderControlContext(&tInfo.m_rcDec); |
Gurchetan Singh | 95b30dc | 2024-01-18 18:31:15 -0800 | [diff] [blame] | 281 | #endif |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 282 | |
| 283 | if (!mChannel && !mRingStream) { |
Jason Macnak | e43e3a0 | 2021-10-14 10:35:33 -0700 | [diff] [blame] | 284 | GL_LOG("Exited a loader RenderThread @%p", this); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 285 | mFinished.store(true, std::memory_order_relaxed); |
| 286 | return 0; |
| 287 | } |
| 288 | |
| 289 | ChannelStream stream(mChannel, RenderChannel::Buffer::kSmallSize); |
| 290 | IOStream* ioStream = |
| 291 | mChannel ? (IOStream*)&stream : (IOStream*)mRingStream.get(); |
| 292 | |
| 293 | ReadBuffer readBuf(kStreamBufferSize); |
| 294 | if (mRingStream) { |
| 295 | readBuf.setNeededFreeTailSize(0); |
| 296 | } |
| 297 | |
| 298 | const SnapshotObjects snapshotObjects = { |
| 299 | &tInfo, &checksumCalc, &stream, mRingStream.get(), &readBuf, |
| 300 | }; |
| 301 | |
| 302 | // Framebuffer initialization is asynchronous, so we need to make sure |
| 303 | // it's completely initialized before running any GL commands. |
| 304 | FrameBuffer::waitUntilInitialized(); |
Jason Macnak | ed0c9e6 | 2023-03-30 15:58:24 -0700 | [diff] [blame] | 305 | if (vk::getGlobalVkEmulation()) { |
Jason Macnak | 22efd87 | 2022-07-20 16:54:23 -0700 | [diff] [blame] | 306 | tInfo.m_vkInfo.emplace(); |
Kaiyi Li | 1b6feaa | 2022-03-25 10:12:38 -0700 | [diff] [blame] | 307 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 308 | |
Gurchetan Singh | fccd048 | 2024-01-17 18:04:19 -0800 | [diff] [blame] | 309 | #if GFXSTREAM_ENABLE_HOST_MAGMA |
Matt Sandy | 5fd27cf | 2023-05-12 10:13:18 -0700 | [diff] [blame] | 310 | tInfo.m_magmaInfo.emplace(mContextId); |
Gurchetan Singh | a8df2a3 | 2023-09-11 16:40:55 -0700 | [diff] [blame] | 311 | #endif |
Matt Sandy | e815f35 | 2023-03-10 18:28:35 +0000 | [diff] [blame] | 312 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 313 | // This is the only place where we try loading from snapshot. |
| 314 | // But the context bind / restoration will be delayed after receiving |
| 315 | // the first GL command. |
| 316 | if (doSnapshotOperation(snapshotObjects, SnapshotState::StartLoading)) { |
Jason Macnak | e43e3a0 | 2021-10-14 10:35:33 -0700 | [diff] [blame] | 317 | GL_LOG("Loaded RenderThread @%p from snapshot", this); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 318 | needRestoreFromSnapshot = true; |
| 319 | } else { |
| 320 | // Not loading from a snapshot: continue regular startup, read |
| 321 | // the |flags|. |
| 322 | uint32_t flags = 0; |
| 323 | while (ioStream->read(&flags, sizeof(flags)) != sizeof(flags)) { |
| 324 | // Stream read may fail because of a pending snapshot. |
| 325 | if (!doSnapshotOperation(snapshotObjects, SnapshotState::StartSaving)) { |
| 326 | setFinished(); |
Jason Macnak | e43e3a0 | 2021-10-14 10:35:33 -0700 | [diff] [blame] | 327 | GL_LOG("Exited a RenderThread @%p early", this); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 328 | return 0; |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | // |flags| used to mean something, now they're not used. |
| 333 | (void)flags; |
| 334 | } |
| 335 | |
| 336 | int stats_totalBytes = 0; |
| 337 | uint64_t stats_progressTimeUs = 0; |
Lingfeng Yang | bfe3c72 | 2020-10-29 10:33:18 -0700 | [diff] [blame] | 338 | auto stats_t0 = android::base::getHighResTimeUs() / 1000; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 339 | bool benchmarkEnabled = getBenchmarkEnabledFromEnv(); |
| 340 | |
| 341 | // |
| 342 | // open dump file if RENDER_DUMP_DIR is defined |
| 343 | // |
| 344 | const char* dump_dir = getenv("RENDERER_DUMP_DIR"); |
| 345 | FILE* dumpFP = nullptr; |
| 346 | if (dump_dir) { |
Lingfeng Yang | bfe3c72 | 2020-10-29 10:33:18 -0700 | [diff] [blame] | 347 | // size_t bsize = strlen(dump_dir) + 32; |
| 348 | // char* fname = new char[bsize]; |
| 349 | // snprintf(fname, bsize, "%s" PATH_SEP "stream_%p", dump_dir, this); |
| 350 | // dumpFP = android_fopen(fname, "wb"); |
| 351 | // if (!dumpFP) { |
| 352 | // fprintf(stderr, "Warning: stream dump failed to open file %s\n", |
| 353 | // fname); |
| 354 | // } |
| 355 | // delete[] fname; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 356 | } |
| 357 | |
Kaiyi Li | ccc93f3 | 2022-07-25 16:49:43 -0700 | [diff] [blame] | 358 | GfxApiLogger gfxLogger; |
William Ho | d5d4d19 | 2022-09-20 14:14:16 -0700 | [diff] [blame] | 359 | auto& metricsLogger = FrameBuffer::getFB()->getMetricsLogger(); |
Kaiyi Li | 816b8ca | 2022-07-22 11:31:52 -0700 | [diff] [blame] | 360 | |
Kaiyi Li | ae167ab | 2022-10-10 12:29:59 -0700 | [diff] [blame] | 361 | const ProcessResources* processResources = nullptr; |
Andrew Woloszyn | 1a5e397 | 2023-08-25 19:04:58 -0400 | [diff] [blame] | 362 | bool anyProgress = false; |
Greg Schlomoff | c947a35 | 2021-10-07 10:53:28 -0700 | [diff] [blame] | 363 | while (true) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 364 | // Let's make sure we read enough data for at least some processing. |
Greg Schlomoff | c947a35 | 2021-10-07 10:53:28 -0700 | [diff] [blame] | 365 | uint32_t packetSize; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 366 | if (readBuf.validData() >= 8) { |
| 367 | // We know that packet size is the second int32_t from the start. |
Greg Schlomoff | c947a35 | 2021-10-07 10:53:28 -0700 | [diff] [blame] | 368 | packetSize = *(uint32_t*)(readBuf.buf() + 4); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 369 | if (!packetSize) { |
| 370 | // Emulator will get live-stuck here if packet size is read to be zero; |
| 371 | // crash right away so we can see these events. |
Lingfeng Yang | bfe3c72 | 2020-10-29 10:33:18 -0700 | [diff] [blame] | 372 | // emugl::emugl_crash_reporter( |
| 373 | // "Guest should never send a size-0 GL packet\n"); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 374 | } |
| 375 | } else { |
| 376 | // Read enough data to at least be able to get the packet size next |
| 377 | // time. |
| 378 | packetSize = 8; |
| 379 | } |
Andrew Woloszyn | 1a5e397 | 2023-08-25 19:04:58 -0400 | [diff] [blame] | 380 | if (!anyProgress) { |
| 381 | // If we didn't make any progress last time, then make sure we read at least one |
| 382 | // extra byte. |
| 383 | packetSize = std::max(packetSize, static_cast<uint32_t>(readBuf.validData() + 1)); |
| 384 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 385 | int stat = 0; |
Greg Schlomoff | c947a35 | 2021-10-07 10:53:28 -0700 | [diff] [blame] | 386 | if (packetSize > readBuf.validData()) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 387 | stat = readBuf.getData(ioStream, packetSize); |
| 388 | if (stat <= 0) { |
| 389 | if (doSnapshotOperation(snapshotObjects, SnapshotState::StartSaving)) { |
| 390 | continue; |
| 391 | } else { |
| 392 | D("Warning: render thread could not read data from stream"); |
| 393 | break; |
| 394 | } |
| 395 | } else if (needRestoreFromSnapshot) { |
Doug Horn | 05386c5 | 2021-01-08 13:51:36 -0800 | [diff] [blame] | 396 | // If we're using RingStream that might load before FrameBuffer |
| 397 | // restores the contexts from the handles, so check again here. |
| 398 | |
| 399 | tInfo.postLoadRefreshCurrentContextSurfacePtrs(); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 400 | needRestoreFromSnapshot = false; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 401 | } |
Yahan Zhou | d1c7e1e | 2023-11-09 14:59:26 -0800 | [diff] [blame] | 402 | if (mNeedReloadProcessResources) { |
| 403 | processResources = nullptr; |
| 404 | mNeedReloadProcessResources = false; |
| 405 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 406 | } |
| 407 | |
Greg Schlomoff | c947a35 | 2021-10-07 10:53:28 -0700 | [diff] [blame] | 408 | DD("render thread read %i bytes, op %i, packet size %i", |
| 409 | readBuf.validData(), *(uint32_t*)readBuf.buf(), |
| 410 | *(uint32_t*)(readBuf.buf() + 4)); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 411 | |
| 412 | // |
| 413 | // log received bandwidth statistics |
| 414 | // |
| 415 | if (benchmarkEnabled) { |
| 416 | stats_totalBytes += readBuf.validData(); |
Lingfeng Yang | bfe3c72 | 2020-10-29 10:33:18 -0700 | [diff] [blame] | 417 | auto dt = android::base::getHighResTimeUs() / 1000 - stats_t0; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 418 | if (dt > 1000) { |
| 419 | float dts = (float)dt / 1000.0f; |
| 420 | printf("Used Bandwidth %5.3f MB/s, time in progress %f ms total %f ms\n", ((float)stats_totalBytes / dts) / (1024.0f*1024.0f), |
| 421 | stats_progressTimeUs / 1000.0f, |
| 422 | (float)dt); |
| 423 | readBuf.printStats(); |
Lingfeng Yang | bfe3c72 | 2020-10-29 10:33:18 -0700 | [diff] [blame] | 424 | stats_t0 = android::base::getHighResTimeUs() / 1000; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 425 | stats_progressTimeUs = 0; |
| 426 | stats_totalBytes = 0; |
| 427 | } |
| 428 | } |
| 429 | |
| 430 | // |
| 431 | // dump stream to file if needed |
| 432 | // |
| 433 | if (dumpFP) { |
| 434 | int skip = readBuf.validData() - stat; |
| 435 | fwrite(readBuf.buf() + skip, 1, readBuf.validData() - skip, dumpFP); |
| 436 | fflush(dumpFP); |
| 437 | } |
| 438 | |
Andrew Woloszyn | 1a5e397 | 2023-08-25 19:04:58 -0400 | [diff] [blame] | 439 | bool progress = false; |
| 440 | anyProgress = false; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 441 | do { |
Andrew Woloszyn | 1a5e397 | 2023-08-25 19:04:58 -0400 | [diff] [blame] | 442 | anyProgress |= progress; |
William Ho | 7e0e3a6 | 2022-12-02 15:48:10 -0800 | [diff] [blame] | 443 | std::unique_ptr<EventHangMetadata::HangAnnotations> renderThreadData = |
| 444 | std::make_unique<EventHangMetadata::HangAnnotations>(); |
Jason Macnak | fd014e2 | 2023-04-06 16:03:51 -0700 | [diff] [blame] | 445 | |
Gurchetan Singh | f870645 | 2023-09-06 17:22:35 -0700 | [diff] [blame] | 446 | const char* contextName = nullptr; |
| 447 | if (mNameOpt) { |
| 448 | contextName = (*mNameOpt).c_str(); |
Jason Macnak | fd014e2 | 2023-04-06 16:03:51 -0700 | [diff] [blame] | 449 | } |
| 450 | |
William Ho | 7e0e3a6 | 2022-12-02 15:48:10 -0800 | [diff] [blame] | 451 | auto* healthMonitor = FrameBuffer::getFB()->getHealthMonitor(); |
| 452 | if (healthMonitor) { |
Gurchetan Singh | f870645 | 2023-09-06 17:22:35 -0700 | [diff] [blame] | 453 | if (contextName) { |
William Ho | 7e0e3a6 | 2022-12-02 15:48:10 -0800 | [diff] [blame] | 454 | renderThreadData->insert( |
Gurchetan Singh | f870645 | 2023-09-06 17:22:35 -0700 | [diff] [blame] | 455 | {{"renderthread_guest_process", contextName}}); |
William Ho | 7e0e3a6 | 2022-12-02 15:48:10 -0800 | [diff] [blame] | 456 | } |
| 457 | if (readBuf.validData() >= 4) { |
| 458 | renderThreadData->insert( |
| 459 | {{"first_opcode", std::to_string(*(uint32_t*)readBuf.buf())}, |
| 460 | {"buffer_length", std::to_string(readBuf.validData())}}); |
| 461 | } |
Jason Macnak | 4949145 | 2022-07-20 14:57:37 -0700 | [diff] [blame] | 462 | } |
William Ho | 7e0e3a6 | 2022-12-02 15:48:10 -0800 | [diff] [blame] | 463 | auto watchdog = WATCHDOG_BUILDER(healthMonitor, "RenderThread decode operation") |
Kaiyi Li | b38fbb8 | 2022-09-15 08:45:28 -0700 | [diff] [blame] | 464 | .setHangType(EventHangMetadata::HangType::kRenderThread) |
| 465 | .setAnnotations(std::move(renderThreadData)) |
| 466 | .build(); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 467 | |
C Stout | d47e46e | 2023-08-23 13:06:49 -0700 | [diff] [blame] | 468 | if (!tInfo.m_puid) { |
| 469 | tInfo.m_puid = mContextId; |
C Stout | d47e46e | 2023-08-23 13:06:49 -0700 | [diff] [blame] | 470 | } |
| 471 | |
Joshua Duong | 6f6b803 | 2024-05-31 11:27:56 -0700 | [diff] [blame] | 472 | if (!processResources && tInfo.m_puid && tInfo.m_puid != INVALID_CONTEXT_ID) { |
Kaiyi Li | ae167ab | 2022-10-10 12:29:59 -0700 | [diff] [blame] | 473 | processResources = FrameBuffer::getFB()->getProcessResources(tInfo.m_puid); |
Lingfeng Yang | a558928 | 2021-01-22 20:49:26 -0800 | [diff] [blame] | 474 | } |
| 475 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 476 | progress = false; |
Lingfeng Yang | 6279649 | 2021-01-06 14:33:17 -0800 | [diff] [blame] | 477 | size_t last; |
| 478 | |
| 479 | // |
| 480 | // try to process some of the command buffer using the |
| 481 | // Vulkan decoder |
| 482 | // |
Lingfeng Yang | 73cdafe | 2021-01-22 20:51:03 -0800 | [diff] [blame] | 483 | // Note: It's risky to limit Vulkan decoding to one thread, |
| 484 | // so we do it outside the limiter |
Jason Macnak | 22efd87 | 2022-07-20 16:54:23 -0700 | [diff] [blame] | 485 | if (tInfo.m_vkInfo) { |
Gurchetan Singh | 633d05c | 2023-04-26 09:53:49 -0700 | [diff] [blame] | 486 | tInfo.m_vkInfo->ctx_id = mContextId; |
Kaiyi Li | 74d3ef3 | 2022-09-21 12:47:43 -0700 | [diff] [blame] | 487 | VkDecoderContext context = { |
Gurchetan Singh | f870645 | 2023-09-06 17:22:35 -0700 | [diff] [blame] | 488 | .processName = contextName, |
Kaiyi Li | 74d3ef3 | 2022-09-21 12:47:43 -0700 | [diff] [blame] | 489 | .gfxApiLogger = &gfxLogger, |
William Ho | 7e0e3a6 | 2022-12-02 15:48:10 -0800 | [diff] [blame] | 490 | .healthMonitor = FrameBuffer::getFB()->getHealthMonitor(), |
William Ho | d5d4d19 | 2022-09-20 14:14:16 -0700 | [diff] [blame] | 491 | .metricsLogger = &metricsLogger, |
Kaiyi Li | 74d3ef3 | 2022-09-21 12:47:43 -0700 | [diff] [blame] | 492 | }; |
Jason Macnak | 22efd87 | 2022-07-20 16:54:23 -0700 | [diff] [blame] | 493 | last = tInfo.m_vkInfo->m_vkDec.decode(readBuf.buf(), readBuf.validData(), ioStream, |
Yilong Li | c3cb381 | 2023-02-18 08:09:20 -0800 | [diff] [blame] | 494 | processResources, context); |
Lingfeng Yang | 6279649 | 2021-01-06 14:33:17 -0800 | [diff] [blame] | 495 | if (last > 0) { |
Kaiyi Li | 69ba5fb | 2022-10-20 17:05:23 -0700 | [diff] [blame] | 496 | if (!processResources) { |
| 497 | ERR("Processed some Vulkan packets without process resources created. " |
| 498 | "That's problematic."); |
| 499 | } |
Lingfeng Yang | 6279649 | 2021-01-06 14:33:17 -0800 | [diff] [blame] | 500 | readBuf.consume(last); |
| 501 | progress = true; |
| 502 | } |
| 503 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 504 | |
Doug Horn | 370c07b | 2021-01-08 12:12:52 -0800 | [diff] [blame] | 505 | if (mRunInLimitedMode) { |
Lingfeng Yang | 73cdafe | 2021-01-22 20:51:03 -0800 | [diff] [blame] | 506 | sThreadRunLimiter.lock(); |
Doug Horn | 370c07b | 2021-01-08 12:12:52 -0800 | [diff] [blame] | 507 | } |
| 508 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 509 | // try to process some of the command buffer using the GLESv1 |
| 510 | // decoder |
| 511 | // |
| 512 | // DRIVER WORKAROUND: |
| 513 | // On Linux with NVIDIA GPU's at least, we need to avoid performing |
| 514 | // GLES ops while someone else holds the FrameBuffer write lock. |
| 515 | // |
| 516 | // To be more specific, on Linux with NVIDIA Quadro K2200 v361.xx, |
| 517 | // we get a segfault in the NVIDIA driver when glTexSubImage2D |
| 518 | // is called at the same time as glXMake(Context)Current. |
| 519 | // |
| 520 | // To fix, this driver workaround avoids calling |
| 521 | // any sort of GLES call when we are creating/destroying EGL |
| 522 | // contexts. |
| 523 | { |
| 524 | FrameBuffer::getFB()->lockContextStructureRead(); |
| 525 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 526 | |
Gurchetan Singh | 95b30dc | 2024-01-18 18:31:15 -0800 | [diff] [blame] | 527 | #if GFXSTREAM_ENABLE_HOST_GLES |
Jason Macnak | 09ec44f | 2022-07-27 15:02:27 -0700 | [diff] [blame] | 528 | if (tInfo.m_glInfo) { |
| 529 | { |
| 530 | last = tInfo.m_glInfo->m_glDec.decode( |
| 531 | readBuf.buf(), readBuf.validData(), ioStream, &checksumCalc); |
| 532 | if (last > 0) { |
| 533 | progress = true; |
| 534 | readBuf.consume(last); |
| 535 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 536 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 537 | |
Jason Macnak | 09ec44f | 2022-07-27 15:02:27 -0700 | [diff] [blame] | 538 | // |
| 539 | // try to process some of the command buffer using the GLESv2 |
| 540 | // decoder |
| 541 | // |
| 542 | { |
| 543 | last = tInfo.m_glInfo->m_gl2Dec.decode(readBuf.buf(), readBuf.validData(), |
| 544 | ioStream, &checksumCalc); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 545 | |
Jason Macnak | 09ec44f | 2022-07-27 15:02:27 -0700 | [diff] [blame] | 546 | if (last > 0) { |
| 547 | progress = true; |
| 548 | readBuf.consume(last); |
| 549 | } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 550 | } |
| 551 | } |
Gurchetan Singh | 95b30dc | 2024-01-18 18:31:15 -0800 | [diff] [blame] | 552 | #endif |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 553 | |
| 554 | FrameBuffer::getFB()->unlockContextStructureRead(); |
| 555 | // |
| 556 | // try to process some of the command buffer using the |
| 557 | // renderControl decoder |
| 558 | // |
Gurchetan Singh | 95b30dc | 2024-01-18 18:31:15 -0800 | [diff] [blame] | 559 | #if GFXSTREAM_ENABLE_HOST_GLES |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 560 | { |
| 561 | last = tInfo.m_rcDec.decode(readBuf.buf(), readBuf.validData(), |
| 562 | ioStream, &checksumCalc); |
| 563 | if (last > 0) { |
| 564 | readBuf.consume(last); |
| 565 | progress = true; |
| 566 | } |
| 567 | } |
Gurchetan Singh | 95b30dc | 2024-01-18 18:31:15 -0800 | [diff] [blame] | 568 | #endif |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 569 | |
Matt Sandy | e815f35 | 2023-03-10 18:28:35 +0000 | [diff] [blame] | 570 | // |
| 571 | // try to process some of the command buffer using the Magma |
| 572 | // decoder |
| 573 | // |
Gurchetan Singh | fccd048 | 2024-01-17 18:04:19 -0800 | [diff] [blame] | 574 | #if GFXSTREAM_ENABLE_HOST_MAGMA |
Matt Sandy | df03981 | 2023-04-24 10:59:21 -0700 | [diff] [blame] | 575 | if (tInfo.m_magmaInfo && tInfo.m_magmaInfo->mMagmaDec) |
Matt Sandy | e815f35 | 2023-03-10 18:28:35 +0000 | [diff] [blame] | 576 | { |
Matt Sandy | df03981 | 2023-04-24 10:59:21 -0700 | [diff] [blame] | 577 | last = tInfo.m_magmaInfo->mMagmaDec->decode(readBuf.buf(), readBuf.validData(), |
| 578 | ioStream, &checksumCalc); |
Matt Sandy | e815f35 | 2023-03-10 18:28:35 +0000 | [diff] [blame] | 579 | if (last > 0) { |
| 580 | readBuf.consume(last); |
| 581 | progress = true; |
| 582 | } |
| 583 | } |
Gurchetan Singh | a8df2a3 | 2023-09-11 16:40:55 -0700 | [diff] [blame] | 584 | #endif |
Matt Sandy | e815f35 | 2023-03-10 18:28:35 +0000 | [diff] [blame] | 585 | |
Lingfeng Yang | 73cdafe | 2021-01-22 20:51:03 -0800 | [diff] [blame] | 586 | if (mRunInLimitedMode) { |
| 587 | sThreadRunLimiter.unlock(); |
| 588 | } |
| 589 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 590 | } while (progress); |
| 591 | } |
| 592 | |
| 593 | if (dumpFP) { |
| 594 | fclose(dumpFP); |
| 595 | } |
| 596 | |
Gurchetan Singh | 95b30dc | 2024-01-18 18:31:15 -0800 | [diff] [blame] | 597 | #if GFXSTREAM_ENABLE_HOST_GLES |
Jason Macnak | 94fb5e0 | 2022-07-27 15:36:53 -0700 | [diff] [blame] | 598 | if (tInfo.m_glInfo) { |
| 599 | FrameBuffer::getFB()->drainGlRenderThreadResources(); |
| 600 | } |
Gurchetan Singh | 95b30dc | 2024-01-18 18:31:15 -0800 | [diff] [blame] | 601 | #endif |
Jason Macnak | 69698e3 | 2021-09-08 15:40:04 -0700 | [diff] [blame] | 602 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 603 | setFinished(); |
| 604 | |
Jason Macnak | e43e3a0 | 2021-10-14 10:35:33 -0700 | [diff] [blame] | 605 | GL_LOG("Exited a RenderThread @%p", this); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 606 | return 0; |
| 607 | } |
| 608 | |
Jason Macnak | ed0c9e6 | 2023-03-30 15:58:24 -0700 | [diff] [blame] | 609 | } // namespace gfxstream |