Skip to content

Commit 09bc7d2

Browse files
committed
fix(wgc): clear the breadcrumb by scope, not by remembering to
Two remaining review findings, both about the same thing: a diagnostic is only worth having if it cannot lie. encodeStage_ was cleared by hand on each return, and the paths that forgot -- GetBufferByIndex, buffer.As, GetResource in captureDxgiSample; the bridge-release-capture and output-view returns in convertBgraTextureToNv12 -- left it naming a call the writer had already left. The watchdog would then report a stage the process was not in, which is worse than reporting nothing, because the next #252 report would be read as evidence. A StageGuard clears it on scope exit instead, in both functions, and the six manual resets it subsumes are gone. submitVideoSample keeps its pair: after the lock there is no early return between setting the stage and clearing it. Also logs the HRESULT when MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS(TRUE) fails. Its two neighbours already log theirs, and this one sits on the path a machine takes when the GPU pipeline is being set up -- exactly the machines whose logs are currently all we have to go on. Not doing the other half of that finding: the stage it reports is ConfigureDxgiManager rather than a value naming hardware transforms. Nothing reads the enum except the CreateSinkWriter comparison at mf_encoder.cpp:550, so a new enumerator would be ceremony. The log line carries the attribute name and the HRESULT, which is what a reader actually needs.
1 parent 5af7d53 commit 09bc7d2

1 file changed

Lines changed: 18 additions & 6 deletions

File tree

electron/native/wgc-capture/src/mf_encoder.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ HRESULT createSinkWriterFromUrl(
234234
}
235235
hr = attributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);
236236
if (FAILED(hr)) {
237+
std::cerr << "ERROR: Set MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS(TRUE) failed (hr=0x"
238+
<< std::hex << hr << std::dec << ")" << std::endl;
237239
failedStage = SinkWriterCreateStage::ConfigureDxgiManager;
238240
return hr;
239241
}
@@ -348,6 +350,18 @@ void compositeWebcam(BYTE* destination, int width, int height, const BgraFrameVi
348350
}
349351
}
350352

353+
// Clears a breadcrumb on every exit from the scope it guards, which the manual
354+
// resets could not: each of these functions has a dozen failure returns, and
355+
// every one that forgot to clear left the watchdog naming a call the writer had
356+
// already left. Naming the wrong call is worse than naming none -- the whole
357+
// point of the breadcrumb is that the next #252 report does not have to guess.
358+
struct StageGuard {
359+
std::atomic<const char*>& stage;
360+
~StageGuard() {
361+
stage = "idle";
362+
}
363+
};
364+
351365
} // namespace
352366

353367
MFEncoder::~MFEncoder() {
@@ -1047,6 +1061,7 @@ MFEncoder::Nv12ConvertResult MFEncoder::convertBgraTextureToNv12(
10471061
// long enough for a busy GPU and short enough that a stuck bridge costs a
10481062
// dropped frame instead of the recording.
10491063
const DWORD acquireTimeoutMs = static_cast<DWORD>(std::max(50, 4000 / fps_));
1064+
const StageGuard stageGuard{encodeStage_};
10501065

10511066
// Key 0 is the capture side's, key 1 the encoder's. Timing out here leaves
10521067
// key 0 exactly where it was, so the next frame simply tries again; that
@@ -1063,11 +1078,9 @@ MFEncoder::Nv12ConvertResult MFEncoder::convertBgraTextureToNv12(
10631078
encodeStage_ = "bridge-acquire-capture";
10641079
const HRESULT captureAcquireHr = captureBridgeMutex_->AcquireSync(0, acquireTimeoutMs);
10651080
if (captureAcquireHr == static_cast<HRESULT>(WAIT_TIMEOUT)) {
1066-
encodeStage_ = "idle";
10671081
return Nv12ConvertResult::Contended;
10681082
}
10691083
if (!succeeded(captureAcquireHr, "Acquire capture bridge")) {
1070-
encodeStage_ = "idle";
10711084
return Nv12ConvertResult::Failed;
10721085
}
10731086
encodeStage_ = "bridge-copy";
@@ -1085,11 +1098,9 @@ MFEncoder::Nv12ConvertResult MFEncoder::convertBgraTextureToNv12(
10851098
const HRESULT encoderAcquireHr = encoderBridgeMutex_->AcquireSync(1, acquireTimeoutMs);
10861099
if (encoderAcquireHr == static_cast<HRESULT>(WAIT_TIMEOUT)) {
10871100
std::cerr << "ERROR: Acquire encoder bridge timed out" << std::endl;
1088-
encodeStage_ = "idle";
10891101
return Nv12ConvertResult::Failed;
10901102
}
10911103
if (!succeeded(encoderAcquireHr, "Acquire encoder bridge")) {
1092-
encodeStage_ = "idle";
10931104
return Nv12ConvertResult::Failed;
10941105
}
10951106
const auto releaseEncoderBridge = [&]() {
@@ -1135,7 +1146,6 @@ MFEncoder::Nv12ConvertResult MFEncoder::convertBgraTextureToNv12(
11351146
"VideoProcessorBlt");
11361147
encodeStage_ = "bridge-release-encoder";
11371148
const bool released = releaseEncoderBridge();
1138-
encodeStage_ = "idle";
11391149
return converted && released ? Nv12ConvertResult::Ok : Nv12ConvertResult::Failed;
11401150
}
11411151

@@ -1156,11 +1166,13 @@ bool MFEncoder::captureDxgiSample(
11561166
std::cerr << "ERROR: Unexpected WGC DXGI texture format or dimensions" << std::endl;
11571167
return false;
11581168
}
1169+
// Declared after the two early returns above, which run before any stage is
1170+
// set and so have nothing to clear.
1171+
const StageGuard stageGuard{encodeStage_};
11591172

11601173
Microsoft::WRL::ComPtr<IMFSample> sample;
11611174
encodeStage_ = "allocate-sample";
11621175
if (!succeeded(videoSampleAllocator_->AllocateSample(&sample), "Allocate DXGI video sample")) {
1163-
encodeStage_ = "idle";
11641176
return false;
11651177
}
11661178

0 commit comments

Comments
 (0)