Compare commits

..

2 Commits

Author SHA1 Message Date
Juan Caldas
c7da1c0ad5 Update timer Query call back 2025-06-17 12:02:26 -04:00
Juan Caldas
04ff88fab2 Implement TimerQueries 2025-06-17 11:42:18 -04:00
7 changed files with 170 additions and 43 deletions

View File

@@ -283,6 +283,8 @@ if (FILAMENT_SUPPORTS_WEBGPU)
src/webgpu/WebGPUSwapChain.h
src/webgpu/WebGPUTexture.cpp
src/webgpu/WebGPUTexture.h
src/webgpu/WebGPUTimerQuery.cpp
src/webgpu/WebGPUTimerQuery.h
src/webgpu/WebGPUVertexBuffer.cpp
src/webgpu/WebGPUVertexBuffer.h
src/webgpu/WebGPUVertexBufferInfo.cpp

View File

@@ -172,15 +172,11 @@ SPDPipeline& MipmapGenerator::GetOrCreatePipeline(const PipelineCacheKey& key) {
entry.binding = i;
entry.visibility = wgpu::ShaderStage::Compute;
if (i == 0) {
if (key.scalarType == SPDScalarType::I32) {
entry.texture.sampleType = wgpu::TextureSampleType::Sint;
} else if (key.scalarType == SPDScalarType::U32) {
entry.texture.sampleType = wgpu::TextureSampleType::Uint;
} else if (key.scalarType == SPDScalarType::F32 || key.scalarType == SPDScalarType::F16) {
entry.texture.sampleType = wgpu::TextureSampleType::Float;
} else {
entry.texture.sampleType = wgpu::TextureSampleType::UnfilterableFloat;
}
entry.texture.sampleType = (key.scalarType == SPDScalarType::I32)
? wgpu::TextureSampleType::Sint
: (key.scalarType == SPDScalarType::U32)
? wgpu::TextureSampleType::Uint
: wgpu::TextureSampleType::UnfilterableFloat;
entry.texture.viewDimension = wgpu::TextureViewDimension::e2DArray;
} else {
entry.storageTexture.access = wgpu::StorageTextureAccess::WriteOnly;

View File

@@ -25,6 +25,7 @@
#include "WebGPURenderTarget.h"
#include "WebGPUSwapChain.h"
#include "WebGPUTexture.h"
#include "WebGPUTimerQuery.h"
#include "WebGPUVertexBuffer.h"
#include "WebGPUVertexBufferInfo.h"
#include <backend/platforms/WebGPUPlatform.h>
@@ -101,8 +102,9 @@ template class ConcreteDispatcher<WebGPUDriver>;
void WebGPUDriver::terminate() {
}
void WebGPUDriver::tick(int) {
void WebGPUDriver::tick(int /*dummy*/) {
mDevice.Tick();
mAdapter.GetInstance().ProcessEvents();
}
void WebGPUDriver::beginFrame(int64_t monotonic_clock_ns,
@@ -216,9 +218,6 @@ void WebGPUDriver::destroyStream(Handle<HwStream> sh) {
//TODO
}
void WebGPUDriver::destroyTimerQuery(Handle<HwTimerQuery> tqh) {
}
void WebGPUDriver::destroyDescriptorSetLayout(
Handle<HwDescriptorSetLayout> descriptorSetLayoutHandle) {
if (descriptorSetLayoutHandle) {
@@ -268,7 +267,31 @@ Handle<HwFence> WebGPUDriver::createFenceS() noexcept {
}
Handle<HwTimerQuery> WebGPUDriver::createTimerQueryS() noexcept {
return Handle<HwTimerQuery>((Handle<HwTimerQuery>::HandleId) mNextFakeHandle++);
return allocAndConstructHandle<WebGPUTimerQuery, HwTimerQuery>();
}
void WebGPUDriver::createTimerQueryR(Handle<HwTimerQuery> timerQueryHandle, int /*dummy*/) {
// nothing to do, timer query was constructed in createTimerQueryS
}
void WebGPUDriver::destroyTimerQuery(Handle<HwTimerQuery> timerQueryHandle) {
if (timerQueryHandle) {
destructHandle<WebGPUTimerQuery>(timerQueryHandle);
}
}
TimerQueryResult WebGPUDriver::getTimerQueryValue(Handle<HwTimerQuery> timerQueryHandle, uint64_t* elapsedTime) {
auto* timerQuery = handleCast<WebGPUTimerQuery>(timerQueryHandle);
return timerQuery->getQueryResult(elapsedTime) ? TimerQueryResult::AVAILABLE
: TimerQueryResult::NOT_READY;
}
void WebGPUDriver::beginTimerQuery(Handle<HwTimerQuery> timerQueryHandle) {
mTimerQuery = handleCast<WebGPUTimerQuery>(timerQueryHandle);
}
void WebGPUDriver::endTimerQuery(Handle<HwTimerQuery> timerQueryHandle) {
mTimerQuery = handleCast<WebGPUTimerQuery>(timerQueryHandle);
}
Handle<HwIndexBuffer> WebGPUDriver::createIndexBufferS() noexcept {
@@ -337,6 +360,9 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
mDevice, flags);
assert_invariant(mSwapChain);
FWGPU_LOGW << "WebGPU support is highly experimental, in development, and tested for only a "
"small set of simple samples (e.g. hellotriangle and texturedquad), thus issues "
"are likely to be encountered at this stage.";
#if !FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) && !defined(NDEBUG)
char printSystemHex[16];
snprintf(printSystemHex, sizeof(printSystemHex), "%#x", FWGPU_PRINT_SYSTEM);
@@ -459,8 +485,6 @@ void WebGPUDriver::createFenceR(Handle<HwFence> fh, int) {
//todo
}
void WebGPUDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {}
void WebGPUDriver::createDescriptorSetLayoutR(
Handle<HwDescriptorSetLayout> descriptorSetLayoutHandle,
backend::DescriptorSetLayout&& info) {
@@ -609,24 +633,11 @@ size_t WebGPUDriver::getMaxUniformBufferSize() {
}
size_t WebGPUDriver::getMaxTextureSize(const SamplerType target) {
size_t result = 2048u;
switch (target) {
case SamplerType::SAMPLER_2D:
case SamplerType::SAMPLER_2D_ARRAY:
case SamplerType::SAMPLER_EXTERNAL:
case SamplerType::SAMPLER_CUBEMAP:
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
result = mDeviceLimits.maxTextureDimension2D;
break;
case SamplerType::SAMPLER_3D:
result = mDeviceLimits.maxTextureDimension3D;
break;
}
return result;
return 2048u;
}
size_t WebGPUDriver::getMaxArrayTextureLayers() {
return mDeviceLimits.maxTextureArrayLayers;
return 256u;
}
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> indexBufferHandle,
@@ -737,10 +748,6 @@ void WebGPUDriver::setupExternalImage(void* image) {
//todo
}
TimerQueryResult WebGPUDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint64_t* elapsedTime) {
return TimerQueryResult::ERROR;
}
void WebGPUDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) {
//todo
}
@@ -934,8 +941,10 @@ void WebGPUDriver::commit(Handle<HwSwapChain> sch) {
mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor);
assert_invariant(mCommandBuffer);
mCommandEncoder = nullptr;
if (mTimerQuery) {
mTimerQuery->beginTimeElapsedQuery();
}
mQueue.Submit(1, &mCommandBuffer);
static bool firstRender = true;
// For the first frame rendered, we need to make sure the work is done before presenting or we
// get a purple flash
@@ -950,6 +959,15 @@ void WebGPUDriver::commit(Handle<HwSwapChain> sch) {
<< static_cast<uint32_t>(wStatus);
}
firstRender = false;
} else {
mQueue.OnSubmittedWorkDone(wgpu::CallbackMode::AllowSpontaneous,
[=](wgpu::QueueWorkDoneStatus status) {
if (status == wgpu::QueueWorkDoneStatus::Success) {
if (mTimerQuery) {
mTimerQuery->endTimeElapsedQuery();
}
}
});
}
mCommandBuffer = nullptr;
mTextureView = nullptr;
@@ -1161,12 +1179,6 @@ void WebGPUDriver::scissor(
//todo
}
void WebGPUDriver::beginTimerQuery(Handle<HwTimerQuery> tqh) {
}
void WebGPUDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
}
void WebGPUDriver::resetState(int) {
//todo
}

View File

@@ -43,6 +43,7 @@
namespace filament::backend {
class WebGPUSwapChain;
class WebGPUTimerQuery;
/**
* WebGPU backend (driver) implementation
@@ -78,6 +79,7 @@ private:
WebGPURenderTarget* mDefaultRenderTarget = nullptr;
WebGPURenderTarget* mCurrentRenderTarget = nullptr;
spd::MipmapGenerator mMipMapGenerator;
WebGPUTimerQuery* mTimerQuery = nullptr;
tsl::robin_map<uint32_t, wgpu::RenderPipeline> mPipelineMap;
@@ -116,6 +118,11 @@ private:
return mHandleAllocator.allocate<D>();
}
template<typename D, typename B, typename... ARGS>
Handle<B> allocAndConstructHandle(ARGS&&... args) {
return mHandleAllocator.allocateAndConstruct<D>(std::forward<ARGS>(args)...);
}
template<typename D, typename B, typename... ARGS>
D* constructHandle(Handle<B>& handle, ARGS&&... args) noexcept {
return mHandleAllocator.construct<D>(handle, std::forward<ARGS>(args)...);

View File

@@ -101,7 +101,7 @@ template<typename WebGPUPrintable>
return out.str();
}
[[nodiscard]] inline std::string adapterInfoToString(wgpu::AdapterInfo const& info) {
[[nodiscard]] std::string adapterInfoToString(wgpu::AdapterInfo const& info) {
std::stringstream out;
out << "vendor (" << info.vendorID << ") '" << info.vendor
<< "' device (" << info.deviceID << ") '" << info.device

View File

@@ -0,0 +1,60 @@
/*
* 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 "WebGPUTimerQuery.h"
#include <chrono>
#include <cstdint>
#include <memory>
namespace filament::backend {
void WebGPUTimerQuery::beginTimeElapsedQuery() {
mStatus->elapsedNanoseconds = 0;
// Capture the timer query status via a weak_ptr because the WGPUTimerQuery could be destroyed
// before the block executes.
std::weak_ptr<WebGPUTimerQuery::Status> statusPtr = mStatus;
if (auto s = statusPtr.lock()) {
s->elapsedNanoseconds = std::chrono::steady_clock::now().time_since_epoch().count();
}
}
void WebGPUTimerQuery::endTimeElapsedQuery() {
// Capture the timer query status via a weak_ptr because the WGPUTimerQuery could be destroyed
// before the block executes.
if (mStatus->elapsedNanoseconds != 0) {
std::weak_ptr<WebGPUTimerQuery::Status> statusPtr = mStatus;
if (auto s = statusPtr.lock()) {
s->previousElapsed = s->elapsedNanoseconds =
std::chrono::steady_clock::now().time_since_epoch().count() -
s->elapsedNanoseconds;
}
}
}
bool WebGPUTimerQuery::getQueryResult(uint64_t* outElapsedTime) {
if (mStatus->previousElapsed == 0) {
return false;
}
if (outElapsedTime) {
*outElapsedTime = mStatus->previousElapsed;
mStatus->previousElapsed = 0;
}
return true;
}
}// namespace filament::backend

View File

@@ -0,0 +1,50 @@
/*
* 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.
*/
#ifndef TNT_FILAMENT_BACKEND_WEBGPUTIMERQUERY_H
#define TNT_FILAMENT_BACKEND_WEBGPUTIMERQUERY_H
#include "DriverBase.h"
#include <webgpu/webgpu_cpp.h>
#include <atomic>
#include <cstdint>
#include <memory>
namespace filament::backend {
class WebGPUTimerQuery : public HwTimerQuery {
public:
WebGPUTimerQuery()
: mStatus(std::make_shared<Status>()) {}
void beginTimeElapsedQuery();
void endTimeElapsedQuery();
bool getQueryResult(uint64_t* outElapsedTimeNanoseconds);
private:
struct Status {
std::atomic<uint64_t> elapsedNanoseconds{ 0 };
std::atomic<uint64_t> previousElapsed{ 0 };
};
std::shared_ptr<Status> mStatus;
};
} // namespace filament::backend
#endif //TNT_FILAMENT_BACKEND_WEBGPUTIMERQUERY_H