Commit 9d5ebe42 authored by Jiawei Shao's avatar Jiawei Shao Committed by Commit Bot

Reland "WebGPU: Add early-returns in the request of adapter and device when context is lost"

Reland with the fixes on the missing check in the test bodies so that they can early
return when the platform does not support WebGPU.

Original change's description:
WebGPU: Add early-returns in the request of adapter and device when context is lost

This patch adds early-returns in the request of GPUAdapter and GPUDevice
when the WebGPU context is lost.

In the following patches we will implement more clean-ups when the
WebGPU context is lost.

TBR=kbr@chromium.org

Change-Id: I64f6b4c88d868f0e83c131875bfacd465279948a
Bug: chromium:996713
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2119350
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: default avatarCorentin Wallez <cwallez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#753173}
parent 65aa6aa2
......@@ -51,8 +51,6 @@ WebGPUCommandSerializer::~WebGPUCommandSerializer() {}
// This function can only be called once for each WebGPUCommandSerializer
// object (before any call of GetCmdSpace()).
// TODO(jiawei.shao@intel.com): early return and directly call the callback
// function when the connection to the GPU process has been lost.
void WebGPUCommandSerializer::RequestDeviceCreation(
uint32_t requested_adapter_id,
const WGPUDeviceProperties& requested_device_properties) {
......@@ -345,11 +343,19 @@ void WebGPUImplementation::SetGLError(GLenum error,
}
// GpuControlClient implementation.
// TODO(jiawei.shao@intel.com): do other clean-ups when the context is lost.
void WebGPUImplementation::OnGpuControlLostContext() {
NOTIMPLEMENTED();
OnGpuControlLostContextMaybeReentrant();
// This should never occur more than once.
DCHECK(!lost_context_callback_run_);
lost_context_callback_run_ = true;
if (!lost_context_callback_.is_null()) {
std::move(lost_context_callback_).Run();
}
}
void WebGPUImplementation::OnGpuControlLostContextMaybeReentrant() {
NOTIMPLEMENTED();
lost_ = true;
}
void WebGPUImplementation::OnGpuControlErrorMessage(const char* message,
int32_t id) {
......@@ -553,6 +559,10 @@ bool WebGPUImplementation::RequestAdapterAsync(
PowerPreference power_preference,
base::OnceCallback<void(uint32_t, const WGPUDeviceProperties&)>
request_adapter_callback) {
if (lost_) {
return false;
}
// Now that we declare request_adapter_serial as an uint64, it can't overflow
// because we just increment an uint64 by one.
DawnRequestAdapterSerial request_adapter_serial = NextRequestAdapterSerial();
......@@ -579,6 +589,10 @@ bool WebGPUImplementation::RequestDeviceAsync(
base::OnceCallback<void(bool, DawnDeviceClientID)>
request_device_callback) {
#if BUILDFLAG(USE_DAWN)
if (lost_) {
return false;
}
// Now that we declare device_client_id as an uint64, it can't overflow
// because we just increment an uint64 by one.
DawnDeviceClientID device_client_id = NextDeviceClientID();
......
......@@ -193,6 +193,8 @@ class WEBGPU_EXPORT WebGPUImplementation final : public WebGPUInterface,
request_device_callback_map_;
DawnDeviceClientID device_client_id_ = 0;
std::atomic_bool lost_{false};
DISALLOW_COPY_AND_ASSIGN(WebGPUImplementation);
};
......
......@@ -25,6 +25,10 @@ namespace {
void OnRequestAdapterCallback(uint32_t adapter_service_id,
const WGPUDeviceProperties& properties) {}
void CountCallback(int* count) {
(*count)++;
}
} // anonymous namespace
WebGPUTest::Options::Options() = default;
......@@ -103,7 +107,7 @@ void WebGPUTest::Initialize(const Options& options) {
dawnProcSetProcs(&procs);
}
webgpu::WebGPUInterface* WebGPUTest::webgpu() const {
webgpu::WebGPUImplementation* WebGPUTest::webgpu() const {
return context_->GetImplementation();
}
......@@ -164,4 +168,73 @@ TEST_F(WebGPUTest, FlushNoCommands) {
webgpu()->FlushCommands();
}
// Referred from GLES2ImplementationTest/ReportLoss
TEST_F(WebGPUTest, ReportLoss) {
Initialize(WebGPUTest::Options());
if (!WebGPUSupported()) {
LOG(ERROR) << "Test skipped because WebGPU isn't supported";
return;
}
GpuControlClient* webgpu_as_client = webgpu();
int lost_count = 0;
webgpu()->SetLostContextCallback(base::BindOnce(&CountCallback, &lost_count));
EXPECT_EQ(0, lost_count);
webgpu_as_client->OnGpuControlLostContext();
// The lost context callback should be run when WebGPUImplementation is
// notified of the loss.
EXPECT_EQ(1, lost_count);
}
// Referred from GLES2ImplementationTest/ReportLossReentrant
TEST_F(WebGPUTest, ReportLossReentrant) {
Initialize(WebGPUTest::Options());
if (!WebGPUSupported()) {
LOG(ERROR) << "Test skipped because WebGPU isn't supported";
return;
}
GpuControlClient* webgpu_as_client = webgpu();
int lost_count = 0;
webgpu()->SetLostContextCallback(base::BindOnce(&CountCallback, &lost_count));
EXPECT_EQ(0, lost_count);
webgpu_as_client->OnGpuControlLostContextMaybeReentrant();
// The lost context callback should not be run yet to avoid calling back into
// clients re-entrantly, and having them re-enter WebGPUImplementation.
EXPECT_EQ(0, lost_count);
}
TEST_F(WebGPUTest, RequestAdapterAfterContextLost) {
Initialize(WebGPUTest::Options());
if (!WebGPUSupported()) {
LOG(ERROR) << "Test skipped because WebGPU isn't supported";
return;
}
webgpu()->OnGpuControlLostContext();
ASSERT_FALSE(
webgpu()->RequestAdapterAsync(webgpu::PowerPreference::kDefault,
base::BindOnce(&OnRequestAdapterCallback)));
}
TEST_F(WebGPUTest, RequestDeviceAfterContextLost) {
Initialize(WebGPUTest::Options());
if (!WebGPUSupported()) {
LOG(ERROR) << "Test skipped because WebGPU isn't supported";
return;
}
webgpu()->OnGpuControlLostContext();
ASSERT_FALSE(webgpu()->RequestDeviceAsync(
kAdapterServiceID, {},
base::BindOnce(
[](bool success, webgpu::DawnDeviceClientID assigned_client_id) {})));
}
} // namespace gpu
......@@ -27,7 +27,7 @@ void OnRequestDeviceCallback(bool is_request_device_success,
namespace webgpu {
class WebGPUInterface;
class WebGPUImplementation;
} // namespace webgpu
......@@ -51,7 +51,7 @@ class WebGPUTest : public testing::Test {
void Initialize(const Options& options);
webgpu::WebGPUInterface* webgpu() const;
webgpu::WebGPUImplementation* webgpu() const;
SharedImageInterface* GetSharedImageInterface() const;
void RunPendingTasks();
......@@ -63,13 +63,14 @@ class WebGPUTest : public testing::Test {
};
DeviceAndClientID GetNewDeviceAndClientID();
const uint32_t kAdapterServiceID = 0u;
private:
std::unique_ptr<viz::TestGpuServiceHolder> gpu_service_holder_;
std::unique_ptr<WebGPUInProcessContext> context_;
bool is_initialized_ = false;
webgpu::DawnDeviceClientID next_device_client_id_ = 1;
const uint32_t kAdapterServiceID = 0u;
};
} // namespace gpu
......
......@@ -95,7 +95,7 @@ const GpuFeatureInfo& WebGPUInProcessContext::GetGpuFeatureInfo() const {
return command_buffer_->GetGpuFeatureInfo();
}
webgpu::WebGPUInterface* WebGPUInProcessContext::GetImplementation() {
webgpu::WebGPUImplementation* WebGPUInProcessContext::GetImplementation() {
return webgpu_implementation_.get();
}
......
......@@ -25,7 +25,6 @@ struct GpuFeatureInfo;
struct SharedMemoryLimits;
namespace webgpu {
class WebGPUInterface;
class WebGPUImplementation;
} // namespace webgpu
......@@ -52,7 +51,7 @@ class WebGPUInProcessContext {
// Allows direct access to the WebGPUImplementation so a
// WebGPUInProcessContext can be used without making it current.
gpu::webgpu::WebGPUInterface* GetImplementation();
gpu::webgpu::WebGPUImplementation* GetImplementation();
base::TestSimpleTaskRunner* GetTaskRunner();
// Test only functions.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment