diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index 6669898637c3..06bfa8e4d43d 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -264,6 +264,7 @@ if (FILAMENT_SUPPORTS_WEBGPU) src/webgpu/WebGPUSwapChain.cpp src/webgpu/WebGPUSwapChain.h src/webgpu/WGPUProgram.cpp + src/webgpu/WGPUTimerQuery.cpp ) if (WIN32) list(APPEND SRCS src/webgpu/platform/WebGPUPlatformWindows.cpp) diff --git a/filament/backend/src/webgpu/WGPUTimerQuery.cpp b/filament/backend/src/webgpu/WGPUTimerQuery.cpp new file mode 100644 index 000000000000..0bfd318ef316 --- /dev/null +++ b/filament/backend/src/webgpu/WGPUTimerQuery.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "WebGPUHandles.h" + +#include +#include +#include + +namespace filament::backend { + +void WGPUTimerQuery::beginTimeElapsedQuery() { + std::cout << " WGPUTimerQuery::beginTimeElapsedQuery()" <elapsedNanoseconds = 0; + // Capture the timer query status via a weak_ptr because the WGPUTimerQuery could be destroyed + // before the block executes. + std::weak_ptr statusPtr = status; + + if (auto s = statusPtr.lock()) { + s->elapsedNanoseconds = std::chrono::steady_clock::now().time_since_epoch().count(); + } +} + +void WGPUTimerQuery::endTimeElapsedQuery() { + std::cout << " WGPUTimerQuery::endTimeElapsedQuery()" <elapsedNanoseconds == 0) + { + std::cout << " %%%%%%%%WGPUTimerQuery::endTimeElapsedQuery()" < statusPtr = status; + if (auto s = statusPtr.lock()) { + s->previousElapsed = s->elapsedNanoseconds = + std::chrono::steady_clock::now().time_since_epoch().count() - + s->elapsedNanoseconds; + } + } +} + +bool WGPUTimerQuery::getQueryResult(uint64_t* outElapsedTime) { + std::cout << " WGPUTimerQuery::getQueryResult: " << std::endl; + if (status->previousElapsed == 0) { + return false; + } + if (outElapsedTime) { + *outElapsedTime = status->previousElapsed; + std::cout << " TimeResult: " << status->previousElapsed << std::endl; + status->previousElapsed = 0; + } + return true; +} + +}// namespace filament::backend diff --git a/filament/backend/src/webgpu/WebGPUDriver.cpp b/filament/backend/src/webgpu/WebGPUDriver.cpp index 56b4bc114c1d..36e643990df6 100644 --- a/filament/backend/src/webgpu/WebGPUDriver.cpp +++ b/filament/backend/src/webgpu/WebGPUDriver.cpp @@ -14,7 +14,9 @@ * limitations under the License. */ #include +#include "webgpu/WebGPUConstants.h" #include "webgpu/WebGPUDriver.h" +#include "WebGPUHandles.h" #include "WebGPUPipelineCreation.h" #include "WebGPUSwapChain.h" @@ -43,7 +45,7 @@ #include #include #include - +#include namespace filament::backend { namespace { @@ -311,13 +313,13 @@ void WebGPUDriver::finish(int /* dummy */) { } void WebGPUDriver::destroyRenderPrimitive(Handle rph) { - if (rph) { + if (rph) { destructHandle(rph); } } void WebGPUDriver::destroyVertexBufferInfo(Handle vbih) { - if (vbih) { + if (vbih) { destructHandle(vbih); } } @@ -359,11 +361,7 @@ void WebGPUDriver::destroySwapChain(Handle sch) { mSwapChain = nullptr; } -void WebGPUDriver::destroyStream(Handle sh) { -} - -void WebGPUDriver::destroyTimerQuery(Handle tqh) { -} +void WebGPUDriver::destroyStream(Handle sh) {} void WebGPUDriver::destroyDescriptorSetLayout(Handle tqh) { if (tqh) { @@ -400,7 +398,36 @@ Handle WebGPUDriver::createFenceS() noexcept { } Handle WebGPUDriver::createTimerQueryS() noexcept { - return Handle((Handle::HandleId) mNextFakeHandle++); + // The handle must be constructed here, as a synchronous call to getTimerQueryValue might happen + // before createTimerQueryR is executed. + return allocAndConstructHandle(); +} + +void WebGPUDriver::createTimerQueryR(Handle tqh, int /* dummy */) { + // nothing to do, timer query was constructed in createTimerQueryS +} + +void WebGPUDriver::destroyTimerQuery(Handle tqh) { + if (tqh) { + destructHandle(tqh); + } +} + +void WebGPUDriver::beginTimerQuery(Handle tqh) { + std::cout << "WebGPUDriver::beginTimerQuery" <(tqh); +} + +void WebGPUDriver::endTimerQuery(Handle tqh) { + std::cout << "WebGPUDriver::endTimerQuery" <(tqh); +} + +TimerQueryResult WebGPUDriver::getTimerQueryValue(Handle tqh, uint64_t* elapsedTime) { + std::cout << "WebGPUDriver::getTimerQueryValue" <(tqh); + return tq->getQueryResult(elapsedTime) ? TimerQueryResult::AVAILABLE + : TimerQueryResult::NOT_READY; } Handle WebGPUDriver::createIndexBufferS() noexcept { @@ -581,7 +608,6 @@ void WebGPUDriver::createRenderTargetR(Handle rth, TargetBufferF void WebGPUDriver::createFenceR(Handle fh, int) {} -void WebGPUDriver::createTimerQueryR(Handle tqh, int) {} void WebGPUDriver::createDescriptorSetLayoutR(Handle dslh, backend::DescriptorSetLayout&& info) { @@ -757,17 +783,14 @@ void WebGPUDriver::update3DImage(Handle th, void WebGPUDriver::setupExternalImage(void* image) { } -TimerQueryResult WebGPUDriver::getTimerQueryValue(Handle tqh, uint64_t* elapsedTime) { - return TimerQueryResult::ERROR; -} - void WebGPUDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) { } void WebGPUDriver::setExternalStream(Handle th, Handle sh) { } -void WebGPUDriver::generateMipmaps(Handle th) { } +void WebGPUDriver::generateMipmaps(Handle th) { +} void WebGPUDriver::compilePrograms(CompilerPriorityQueue priority, CallbackHandler* handler, CallbackHandler::Callback callback, void* user) { @@ -809,6 +832,7 @@ void WebGPUDriver::beginRenderPass(Handle rth, RenderPassParams red = 1.0f; } assert_invariant(mTextureView); + wgpu::RenderPassColorAttachment renderPassColorAttachment = { .view = mTextureView, // TODO: remove this code once WebGPU Pipeline is implemented with render targets, pipeline and buffers. @@ -855,12 +879,29 @@ void WebGPUDriver::makeCurrent(Handle drawSch, Handle } void WebGPUDriver::commit(Handle sch) { +// mTimerQuery->beginTimeElapsedQuery(); wgpu::CommandBufferDescriptor commandBufferDescriptor{ .label = "command_buffer", }; mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor); assert_invariant(mCommandBuffer); mCommandEncoder = nullptr; + assert_invariant(mCommandBuffer); + mQueue.OnSubmittedWorkDone(wgpu::CallbackMode::AllowSpontaneous, + [this](auto const& status) { + std::cout << "OnSubmittedWorkDone called " << std::endl; + if (status == wgpu::QueueWorkDoneStatus::Success) { + if (mTimerQuery) { + mTimerQuery->endTimeElapsedQuery(); + } + } + else + { + std::cout << "NOT SUCCESS" << std::endl; + } + }); + + mTimerQuery->beginTimeElapsedQuery(); mQueue.Submit(1, &mCommandBuffer); mCommandBuffer = nullptr; mTextureView = nullptr; @@ -1002,14 +1043,8 @@ void WebGPUDriver::scissor( Viewport scissor) { } -void WebGPUDriver::beginTimerQuery(Handle tqh) { -} - -void WebGPUDriver::endTimerQuery(Handle tqh) { -} -void WebGPUDriver::resetState(int) { -} +void WebGPUDriver::resetState(int) {} void WebGPUDriver::updateDescriptorSetBuffer(Handle dsh, backend::descriptor_binding_t binding, Handle boh, uint32_t offset, @@ -1179,5 +1214,4 @@ wgpu::AddressMode WebGPUDriver::fWrapModeToWAddressMode(const SamplerWrapMode& f return wgpu::AddressMode::Undefined; } - } // namespace filament diff --git a/filament/backend/src/webgpu/WebGPUDriver.h b/filament/backend/src/webgpu/WebGPUDriver.h index c6a2d99d23a1..038cee211e3f 100644 --- a/filament/backend/src/webgpu/WebGPUDriver.h +++ b/filament/backend/src/webgpu/WebGPUDriver.h @@ -17,8 +17,6 @@ #ifndef TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H #define TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H -#include "WebGPUHandles.h" -#include "webgpu/WebGPUConstants.h" #include #include "DriverBase.h" @@ -41,6 +39,8 @@ namespace filament::backend { class WebGPUSwapChain; +class WGPURenderTarget; +class WGPUTimerQuery; /** * WebGPU backend (driver) implementation @@ -93,6 +93,7 @@ class WebGPUDriver final : public DriverBase { wgpu::RenderPassEncoder mRenderPassEncoder = nullptr; wgpu::CommandBuffer mCommandBuffer = nullptr; WGPURenderTarget* mDefaultRenderTarget = nullptr; + WGPUTimerQuery* mTimerQuery = nullptr; tsl::robin_map mPipelineMap; /* @@ -129,6 +130,11 @@ class WebGPUDriver final : public DriverBase { return mHandleAllocator.construct(handle, std::forward(args)...); } + template + Handle allocAndConstructHandle(ARGS&&... args) { + return mHandleAllocator.allocateAndConstruct(std::forward(args)...); + } + template D* handleCast(Handle handle) noexcept { return mHandleAllocator.handle_cast(handle); diff --git a/filament/backend/src/webgpu/WebGPUHandles.h b/filament/backend/src/webgpu/WebGPUHandles.h index 96578df42ac3..41a3397c7bc1 100644 --- a/filament/backend/src/webgpu/WebGPUHandles.h +++ b/filament/backend/src/webgpu/WebGPUHandles.h @@ -259,5 +259,23 @@ class WGPURenderTarget : public HwRenderTarget { std::vector colorAttachments{}; }; +class WGPUTimerQuery : public HwTimerQuery { +public: + WGPUTimerQuery() + : status(std::make_shared()) {} + + void beginTimeElapsedQuery(); + void endTimeElapsedQuery(); + bool getQueryResult(uint64_t* outElapsedTimeNanoseconds); + +private: + struct Status { + std::atomic elapsedNanoseconds{ 0 }; + std::atomic previousElapsed{ 0 }; + }; + + std::shared_ptr status; +}; + }// namespace filament::backend #endif// TNT_FILAMENT_BACKEND_WEBGPUHANDLES_H