Compare commits

..

4 Commits

Author SHA1 Message Date
bridgewaterrobbie
8e2798f861 Needs cleaning: Move descriptor set binding to bind pipeline, caching them if a render pass is not begun 2025-05-23 15:56:33 -04:00
bridgewaterrobbie
f9842fd40b Hack: Use regex to remove tint annotations 2025-05-23 15:55:22 -04:00
bridgewaterrobbie
109908c460 Gemini tinkering 3 2025-05-21 18:02:26 -04:00
bridgewaterrobbie
3a1987406b More gemini tinkering 2025-05-21 15:11:10 -04:00
8 changed files with 128 additions and 52 deletions

View File

@@ -582,7 +582,6 @@ void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<
void WebGPUDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
constructHandle<WGPUProgram>(ph, mDevice, program);
}
void WebGPUDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int) {
assert_invariant(!mDefaultRenderTarget);
mDefaultRenderTarget = constructHandle<WGPURenderTarget>(rth);
@@ -1030,10 +1029,20 @@ void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
// VulkanPipelineCache to handle this, may be missing nuance
static auto pipleineStateHasher = utils::hash::MurmurHashFn<filament::backend::PipelineState>();
auto hash = pipleineStateHasher(pipelineState);
if(mPipelineMap.find(hash) != mPipelineMap.end()){
if(mPipelineMap.find(hash) != mPipelineMap.end()) {
mRenderPassEncoder.SetPipeline(mPipelineMap[hash]);
return;
}
for (size_t index = 0; index < MAX_DESCRIPTOR_SET_COUNT; ++index) {
auto& entry = currentDescriptorSets[index];
if (entry.bg != nullptr) {
mRenderPassEncoder.SetBindGroup(index, entry.bg, entry.dynamicOffsetCount,
entry.offsets.data());
entry.bg = nullptr;
entry.dynamicOffsetCount = 0;
entry.offsets.clear();
}
}
const auto* program = handleCast<WGPUProgram>(pipelineState.program);
assert_invariant(program);
assert_invariant(program->computeShaderModule == nullptr &&
@@ -1076,14 +1085,20 @@ void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
auto* renderPrimitive = handleCast<WGPURenderPrimitive>(rph);
auto* vbi = handleCast<WGPUVertexBufferInfo>(renderPrimitive->vertexBuffer->vbih);
// This *must* match the WGPUVertexBufferInfo that was bound in bindPipeline(). But we want
// to allow to call this before bindPipeline(), so the validation can only happen in draw()
auto vbi = handleCast<WGPUVertexBufferInfo>(renderPrimitive->vertexBuffer->vbih);
assert_invariant(
vbi->getVertexBufferLayoutSize() == renderPrimitive->vertexBuffer->buffers.size());
for (uint32_t i = 0; i < vbi->getVertexBufferLayoutSize(); i++) {
mRenderPassEncoder.SetVertexBuffer(i, renderPrimitive->vertexBuffer->buffers[i]);
// Loop over the WebGPU vertex buffer slots defined by the VertexBufferInfo.
// For each WebGPU slot, find the corresponding Filament buffer that supplies the data.
for (uint32_t webGPUSlot = 0; webGPUSlot < vbi->getWebGPULayoutCount(); ++webGPUSlot) {
uint8_t filamentBufferIndex = vbi->getFilamentBufferIndexForSlot(webGPUSlot);
// Ensure the Filament buffer index is valid for the vertexBuffer's internal storage.
// This check assumes renderPrimitive->vertexBuffer->buffers is sized by the
// original Filament buffer count.
assert_invariant(filamentBufferIndex < renderPrimitive->vertexBuffer->buffers.size());
mRenderPassEncoder.SetVertexBuffer(webGPUSlot,
renderPrimitive->vertexBuffer->buffers[filamentBufferIndex]);
}
mRenderPassEncoder.SetIndexBuffer(renderPrimitive->indexBuffer->getBuffer(),
@@ -1157,9 +1172,12 @@ void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> dsh,
backend::descriptor_set_t setIndex, backend::DescriptorSetOffsetArray&& offsets) {
const auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
const auto wbg = bindGroup->lockAndReturn(mDevice);
assert_invariant(mRenderPassEncoder);
const size_t dynamicOffsetCount = bindGroup->countEntitiesWithDynamicOffsets();
mRenderPassEncoder.SetBindGroup(setIndex, wbg, dynamicOffsetCount, offsets.data());
if(mRenderPassEncoder){
mRenderPassEncoder.SetBindGroup(setIndex, wbg, dynamicOffsetCount, offsets.data());
}
currentDescriptorSets[setIndex] = {wbg, dynamicOffsetCount, std::move(offsets)};
}
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {

View File

@@ -72,6 +72,12 @@ private:
wgpu::CommandEncoder mCommandEncoder = nullptr;
wgpu::TextureView mTextureView = nullptr;
wgpu::RenderPassEncoder mRenderPassEncoder = nullptr;
struct bgInfo{
wgpu::BindGroup bg;
size_t dynamicOffsetCount;
backend::DescriptorSetOffsetArray offsets;
};
std::array<bgInfo, MAX_DESCRIPTOR_SET_COUNT> currentDescriptorSets = {};
wgpu::CommandBuffer mCommandBuffer = nullptr;
WGPURenderTarget* mDefaultRenderTarget = nullptr;

View File

@@ -25,6 +25,7 @@
#include <algorithm>
#include <cstdint>
#include <map>
#include <utility>
#include <vector>
@@ -196,43 +197,77 @@ void WGPUBufferBase::updateGPUBuffer(BufferDescriptor& bufferDescriptor, uint32_
queue.WriteBuffer(buffer, byteOffset + legalSize, &mRemainderChunk, 4);
}
}
WGPUVertexBufferInfo::WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount,
AttributeArray const& attributes)
: HwVertexBufferInfo(bufferCount, attributeCount),
mVertexBufferLayout(bufferCount),
mAttributes(bufferCount) {
: HwVertexBufferInfo(bufferCount, attributeCount) { // Base class constructor
assert_invariant(attributeCount > 0);
assert_invariant(bufferCount > 0);
// bufferCount is Filament's buffer count. The number of WebGPU slots might differ.
struct LayoutKey {
uint8_t filamentBufferIndex;
uint16_t stride;
bool operator<(const LayoutKey& other) const {
if (filamentBufferIndex != other.filamentBufferIndex) {
return filamentBufferIndex < other.filamentBufferIndex;
}
return stride < other.stride;
}
};
std::map<LayoutKey, uint32_t> layoutKeyToWebGPUSlot;
uint32_t nextWebGPUSlot = 0;
for (uint32_t attribIndex = 0; attribIndex < attributes.size(); attribIndex++) {
Attribute const& attrib = attributes[attribIndex];
// Ignore the attributes which are not bind to vertex buffers.
// Ignore attributes not bound to any vertex buffer.
if (attrib.buffer == Attribute::BUFFER_UNUSED) {
continue;
}
assert_invariant(attrib.buffer < bufferCount);
assert_invariant(attrib.buffer < bufferCount); // Ensure Filament buffer index is valid
LayoutKey key = {attrib.buffer, attrib.stride};
uint32_t currentWebGPUSlot;
auto it = layoutKeyToWebGPUSlot.find(key);
if (it == layoutKeyToWebGPUSlot.end()) {
currentWebGPUSlot = nextWebGPUSlot++;
layoutKeyToWebGPUSlot[key] = currentWebGPUSlot;
mActualWebGPULayouts.emplace_back();
mActualWebGPULayouts.back().arrayStride = attrib.stride;
mActualWebGPULayouts.back().stepMode = wgpu::VertexStepMode::Vertex;
// .attributes and .attributeCount will be set later
mSlotMappings.emplace_back(SlotMapping{attrib.buffer});
mActualWebGPUAttributes.emplace_back(); // Add a new vector for this slot's attributes
} else {
currentWebGPUSlot = it->second;
// Sanity check: if we found an existing slot for this key, its stride should match.
assert_invariant(mActualWebGPULayouts[currentWebGPUSlot].arrayStride == attrib.stride);
}
bool const isInteger = attrib.flags & Attribute::FLAG_INTEGER_TARGET;
bool const isNormalized = attrib.flags & Attribute::FLAG_NORMALIZED;
wgpu::VertexFormat vertexFormat = getVertexFormat(attrib.type, isNormalized, isInteger);
// Attributes are sequential per buffer
mAttributes[attrib.buffer].push_back({
mActualWebGPUAttributes[currentWebGPUSlot].push_back({
.format = vertexFormat,
.offset = attrib.offset,
.shaderLocation = attribIndex,
.shaderLocation = attribIndex, // Use original attribIndex as shaderLocation
});
mVertexBufferLayout[attrib.buffer].stepMode = wgpu::VertexStepMode::Vertex;
if (mVertexBufferLayout[attrib.buffer].arrayStride == 0) {
mVertexBufferLayout[attrib.buffer].arrayStride = attrib.stride;
} else {
assert_invariant(mVertexBufferLayout[attrib.buffer].arrayStride == attrib.stride);
}
}
for (uint32_t bufferIndex = 0; bufferIndex < bufferCount; bufferIndex++) {
mVertexBufferLayout[bufferIndex].attributeCount = mAttributes[bufferIndex].size();
mVertexBufferLayout[bufferIndex].attributes = mAttributes[bufferIndex].data();
// Finalize attribute pointers and counts in mActualWebGPULayouts
for (uint32_t slot = 0; slot < mActualWebGPULayouts.size(); ++slot) {
if (!mActualWebGPUAttributes[slot].empty()) {
mActualWebGPULayouts[slot].attributeCount = mActualWebGPUAttributes[slot].size();
mActualWebGPULayouts[slot].attributes = mActualWebGPUAttributes[slot].data();
} else {
mActualWebGPULayouts[slot].attributeCount = 0;
mActualWebGPULayouts[slot].attributes = nullptr;
}
}
}

View File

@@ -52,30 +52,40 @@ class WGPUVertexBufferInfo : public HwVertexBufferInfo {
public:
WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount,
AttributeArray const& attributes);
inline wgpu::VertexBufferLayout const* getVertexBufferLayout() const {
return mVertexBufferLayout.data();
// Returns the WebGPU native vertex buffer layouts
inline wgpu::VertexBufferLayout const* getWebGPULayouts() const {
return mActualWebGPULayouts.data();
}
inline uint32_t getVertexBufferLayoutSize() const {
return mVertexBufferLayout.size();
// Returns the count of WebGPU native vertex buffer layouts
inline uint32_t getWebGPULayoutCount() const {
return mActualWebGPULayouts.size();
}
inline wgpu::VertexAttribute const* getVertexAttributeForIndex(uint32_t index) const {
assert_invariant(index < mAttributes.size());
return mAttributes[index].data();
}
inline uint32_t getVertexAttributeSize(uint32_t index) const {
assert_invariant(index < mAttributes.size());
return mAttributes[index].size();
// Returns the Filament buffer index for a given WebGPU layout slot
inline uint8_t getFilamentBufferIndexForSlot(uint32_t webgpuSlotIndex) const {
assert_invariant(webgpuSlotIndex < mSlotMappings.size());
return mSlotMappings[webgpuSlotIndex].filamentBufferIndex;
}
private:
// TODO: can we do better in terms on heap management.
std::vector<wgpu::VertexBufferLayout> mVertexBufferLayout{};
std::vector<std::vector<wgpu::VertexAttribute>> mAttributes{};
};
// Stores the final WebGPU vertex buffer layouts
std::vector<wgpu::VertexBufferLayout> mActualWebGPULayouts;
// Stores attributes per WebGPU layout, parallel to mActualWebGPULayouts.
// Each wgpu::VertexBufferLayout in mActualWebGPULayouts will point to its attributes here.
std::vector<std::vector<wgpu::VertexAttribute>> mActualWebGPUAttributes;
struct SlotMapping {
uint8_t filamentBufferIndex; // Original Filament buffer index for this WebGPU slot
};
// Maps a WebGPU slot index to its original Filament buffer index
std::vector<SlotMapping> mSlotMappings;
// Remove or comment out old members if they were similarly named:
// std::vector<wgpu::VertexBufferLayout> mVertexBufferLayout {}; // OLD
// std::vector<std::vector<wgpu::VertexAttribute>> mAttributes {}; // OLD
};
struct WGPUVertexBuffer : public HwVertexBuffer {
WGPUVertexBuffer(wgpu::Device const &device, uint32_t vertexCount, uint32_t bufferCount,
Handle<HwVertexBufferInfo> vbih);

View File

@@ -191,8 +191,8 @@ wgpu::RenderPipeline createWebGPURenderPipeline(wgpu::Device const& device,
.entryPoint = "main",
.constantCount = program.constants.size(),
.constants = program.constants.data(),
.bufferCount = vertexBufferInfo.getVertexBufferLayoutSize(),
.buffers = vertexBufferInfo.getVertexBufferLayout()
.bufferCount = vertexBufferInfo.getWebGPULayoutCount(),
.buffers = vertexBufferInfo.getWebGPULayouts()
},
.primitive = {
.topology = toWebGPU(primitiveType),

View File

@@ -320,11 +320,14 @@ wgpu::TextureView WebGPUSwapChain::getCurrentSurfaceTextureView(
if (surfaceTexture.status != wgpu::SurfaceGetCurrentTextureStatus::SuccessOptimal) {
return nullptr;
}
mCurrentSurfaceTexture = nullptr;
mCurrentSurfaceTexture = surfaceTexture.texture;
// Create a view for this surface texture
// TODO: review these initiliazations as webgpu pipeline gets mature
wgpu::TextureViewDescriptor textureViewDescriptor = {
.label = "surface_texture_view",
.format = surfaceTexture.texture.GetFormat(),
.format = mCurrentSurfaceTexture.GetFormat(),
.dimension = wgpu::TextureViewDimension::e2D,
.baseMipLevel = 0,
.mipLevelCount = 1,
@@ -337,6 +340,7 @@ wgpu::TextureView WebGPUSwapChain::getCurrentSurfaceTextureView(
void WebGPUSwapChain::present() {
assert_invariant(mSurface);
mSurface.Present();
mCurrentSurfaceTexture = nullptr;
}
}// namespace filament::backend

View File

@@ -52,6 +52,8 @@ private:
wgpu::TextureFormat mDepthFormat = wgpu::TextureFormat::Undefined;
wgpu::Texture mDepthTexture = nullptr;
wgpu::TextureView mDepthTextureView = nullptr;
wgpu::Texture mCurrentSurfaceTexture = nullptr; // To hold the texture from getCurrentTexture()
};
} // namespace filament::backend

View File

@@ -48,7 +48,7 @@
#include <unordered_map>
#include <utility>
#include <vector>
#include "regex"
#include <stddef.h>
#include <stdint.h>
@@ -601,7 +601,6 @@ bool GLSLPostProcessor::spirvToWgsl(SpirvBlob *spirv, std::string *outWsl) {
return false;
#endif
}
tint::Result<tint::wgsl::writer::Output> wgslOut = tint::wgsl::writer::Generate(tintRead,writerOpts);
/// An instance of SuccessType that can be used to check a tint Result.
tint::SuccessType tintSuccess;
@@ -610,7 +609,9 @@ bool GLSLPostProcessor::spirvToWgsl(SpirvBlob *spirv, std::string *outWsl) {
slog.e << "Tint writer error: " << wgslOut.Failure().reason << io::endl;
return false;
}
*outWsl = wgslOut->wgsl;
//Tint adds some annotations that Dawn complains about and needs removal
std::regex stride_regex(R"(@stride\([0-9]+\)\s*@internal\(disable_validation__ignore_stride\))");
*outWsl = std::regex_replace(wgslOut->wgsl, stride_regex, "");
return true;
#else
slog.i << "Trying to emit WGSL without including WebGPU dependencies,"