blob: ce8b892a65f3e6091d7eaafe773bd7dc377b26a9 [file] [log] [blame]
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/bug_1307307_tracker.h"
#include "base/check.h"
#include "base/debug/crash_logging.h"
#include "base/debug/leak_annotations.h"
#include "base/no_destructor.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_local.h"
namespace gpu {
namespace {
base::ThreadLocalPointer<Bug1307307Tracker::VideoAccessError>&
LastThreadLocalVideoAccessError() {
static base::NoDestructor<
base::ThreadLocalPointer<Bug1307307Tracker::VideoAccessError>>
last_video_access_error;
return *last_video_access_error;
}
} // namespace
Bug1307307Tracker::Bug1307307Tracker() = default;
Bug1307307Tracker::~Bug1307307Tracker() = default;
void Bug1307307Tracker::BeforeAccess() {
ClearLastAccessError();
}
void Bug1307307Tracker::CopySubTextureFinished(const gpu::Mailbox& source,
const gpu::Mailbox& destination,
bool failed) {
auto error = GetLastAccessError();
DCHECK(error == VideoAccessError::kNoError || failed);
auto it = copy_sub_texture_results_.Get(destination);
if (it == copy_sub_texture_results_.end()) {
it = copy_sub_texture_results_.Put(destination, CopySubTextureResult());
it->second.ever_succeeded = !failed;
}
it->second.source = source;
it->second.failed = failed;
it->second.video_error = error;
it->second.ever_succeeded |= !failed;
}
void Bug1307307Tracker::GenerateCrashKey(int hops,
VideoAccessError video_error,
bool cleared) {
static auto* const cleared_crash_key = base::debug::AllocateCrashKeyString(
"si-error-cleared", base::debug::CrashKeySize::Size32);
static auto* const video_error_crash_key =
base::debug::AllocateCrashKeyString("si-error-video",
base::debug::CrashKeySize::Size32);
base::debug::SetCrashKeyString(
video_error_crash_key,
base::StringPrintf("%d:%d", static_cast<int>(video_error), hops));
base::debug::SetCrashKeyString(cleared_crash_key, cleared ? "1" : "0");
}
void Bug1307307Tracker::AccessFailed(const gpu::Mailbox& mailbox,
bool cleared) {
// Check if this mailbox had video access error.
auto error = GetLastAccessError();
if (error != VideoAccessError::kNoError) {
GenerateCrashKey(0, error, cleared);
return;
}
// There could be intermediate copies on the path from video decoder to the
// canvas. If there is chain of copies: "video => image1 => image2 => canvas"
// and the first one will fail in CopySubTexture call, the remaining will also
// fail because intermediate images won't be marked as Cleared.
// Traverse the CopySubTexture chain to find first CopySubTexture operation
// that failed with VideoAccessError if any.
auto it = copy_sub_texture_results_.Peek(mailbox);
int hops = 1;
while (it != copy_sub_texture_results_.end()) {
if (it->second.video_error != VideoAccessError::kNoError) {
GenerateCrashKey(hops, it->second.video_error, cleared);
return;
}
it = copy_sub_texture_results_.Peek(it->second.source);
hops++;
// There is no guarantee that there is no loop, so bail out after
// reasonable amount of iterations.
if (hops > 10)
break;
}
GenerateCrashKey(-1, VideoAccessError::kNoError, cleared);
}
void Bug1307307Tracker::SetLastAccessError(VideoAccessError error) {
auto& last_error = LastThreadLocalVideoAccessError();
if (!last_error.Get()) {
auto* value = new VideoAccessError;
// We never delete this pointer, but we should have only two threads (Gpu
// Main and DrDc) that can call this function, so amount of memory is
// capped.
ANNOTATE_LEAKING_OBJECT_PTR(value);
last_error.Set(value);
}
*last_error.Get() = error;
}
void Bug1307307Tracker::ClearLastAccessError() {
SetLastAccessError(VideoAccessError::kNoError);
}
Bug1307307Tracker::VideoAccessError Bug1307307Tracker::GetLastAccessError() {
if (auto* error = LastThreadLocalVideoAccessError().Get())
return *error;
return VideoAccessError::kNoError;
}
bool Bug1307307Tracker::HadNoTextureOwnerError() {
auto error = GetLastAccessError();
return error == VideoAccessError::kSurfaceTexture_NoTextureOwner ||
error == VideoAccessError::kImageReader_NoTextureOwner;
}
} // namespace gpu