Compare commits
4 Commits
ry/wgpuFix
...
moreGemini
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e2798f861 | ||
|
|
f9842fd40b | ||
|
|
109908c460 | ||
|
|
3a1987406b |
@@ -354,6 +354,17 @@ void WebGPUDriver::destroyProgram(Handle<HwProgram> ph) {
|
||||
}
|
||||
|
||||
void WebGPUDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
|
||||
if (rth) {
|
||||
WGPURenderTarget* rt = handleCast<WGPURenderTarget>(rth);
|
||||
if (rt == mDefaultRenderTarget) {
|
||||
mDefaultRenderTarget = nullptr;
|
||||
}
|
||||
// WGPURenderTarget destructor is trivial.
|
||||
// The HwTexture handles stored within WGPURenderTarget (via MRT, TargetBufferInfo)
|
||||
// are not owned by WGPURenderTarget, so they are not destroyed here.
|
||||
// They are destroyed via WebGPUDriver::destroyTexture.
|
||||
destructHandle<WGPURenderTarget>(rth);
|
||||
}
|
||||
}
|
||||
|
||||
void WebGPUDriver::destroySwapChain(Handle<HwSwapChain> sch) {
|
||||
@@ -571,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);
|
||||
@@ -580,7 +590,21 @@ void WebGPUDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int) {
|
||||
|
||||
void WebGPUDriver::createRenderTargetR(Handle<HwRenderTarget> rth, TargetBufferFlags targets,
|
||||
uint32_t width, uint32_t height, uint8_t samples, uint8_t layerCount, MRT color,
|
||||
TargetBufferInfo depth, TargetBufferInfo stencil) {}
|
||||
TargetBufferInfo depth, TargetBufferInfo stencil) {
|
||||
// The `targets` flags indicate which of the `color`, `depth`, `stencil` TargetBufferInfo
|
||||
// are actually active for this render target.
|
||||
// We'll pass all TargetBufferInfo to WGPURenderTarget; it will use them if their handles are valid.
|
||||
|
||||
// Ensure that textures intended for use as attachments were created with
|
||||
// wgpu::TextureUsage::RenderAttachment. This check should ideally be in createTextureR
|
||||
// or validated here if possible.
|
||||
|
||||
// The `layerCount` parameter might be for creating array textures that this RT targets.
|
||||
// Individual attachments (color[i].layer, depth.layer, stencil.layer) specify which layer
|
||||
// of an array texture to bind. For now, we assume textures are pre-configured.
|
||||
|
||||
constructHandle<WGPURenderTarget>(rth, width, height, samples, color, depth, stencil);
|
||||
}
|
||||
|
||||
void WebGPUDriver::createFenceR(Handle<HwFence> fh, int) {}
|
||||
|
||||
@@ -845,35 +869,74 @@ void WebGPUDriver::compilePrograms(CompilerPriorityQueue priority,
|
||||
|
||||
void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, RenderPassParams const& params) {
|
||||
assert_invariant(mCommandEncoder);
|
||||
|
||||
auto* renderTarget = handleCast<WGPURenderTarget>(rth);
|
||||
// if (renderTarget == mDefaultRenderTarget) {
|
||||
// FWGPU_LOGW << "Default render target"
|
||||
// << utils::io::endl;
|
||||
// } else {
|
||||
// FWGPU_LOGW << "Non Default render target"
|
||||
// << utils::io::endl;
|
||||
// }
|
||||
wgpu::RenderPassDescriptor renderPassDescriptor;
|
||||
wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{
|
||||
.view = mSwapChain->getDepthTextureView(),
|
||||
.depthLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::DEPTH),
|
||||
.depthStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::DEPTH),
|
||||
.depthClearValue = static_cast<float>(params.clearDepth),
|
||||
.depthReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) > 0,
|
||||
.stencilLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::STENCIL),
|
||||
.stencilStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::STENCIL),
|
||||
.stencilClearValue = params.clearStencil,
|
||||
.stencilReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_STENCIL) > 0
|
||||
};
|
||||
renderTarget->setUpRenderPassAttachments(renderPassDescriptor, mTextureView, params);
|
||||
renderPassDescriptor.depthStencilAttachment = &depthStencilAttachment;
|
||||
|
||||
assert_invariant(mTextureView);
|
||||
wgpu::RenderPassDescriptor renderPassDescriptor{};
|
||||
wgpu::TextureView defaultColorView = nullptr;
|
||||
wgpu::TextureView defaultDepthStencilView = nullptr;
|
||||
|
||||
std::array<wgpu::TextureView, MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT> customColorViews{};
|
||||
uint32_t customColorViewCount = 0;
|
||||
wgpu::TextureView customDepthView = nullptr;
|
||||
wgpu::TextureView customStencilView = nullptr;
|
||||
|
||||
if (renderTarget->isDefaultRenderTarget()) {
|
||||
assert_invariant(mSwapChain && mTextureView);
|
||||
defaultColorView = mTextureView;
|
||||
defaultDepthStencilView = mSwapChain->getDepthTextureView();
|
||||
} else {
|
||||
// Resolve views for custom render target
|
||||
const auto& colorInfos = renderTarget->getColorAttachmentInfos();
|
||||
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; ++i) {
|
||||
if (colorInfos[i].handle) {
|
||||
auto* hwTexture = handleCast<WGPUTexture>(colorInfos[i].handle);
|
||||
if (hwTexture) {
|
||||
// TODO: Consider colorInfos[i].level and colorInfos[i].layer for view creation
|
||||
// if WGPUTexture::getTexView() isn't sufficient or needs parameters.
|
||||
customColorViews[customColorViewCount++] = hwTexture->getTexView();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto& depthInfo = renderTarget->getDepthAttachmentInfo();
|
||||
if (depthInfo.handle) {
|
||||
auto* hwTexture = handleCast<WGPUTexture>(depthInfo.handle);
|
||||
if (hwTexture) {
|
||||
customDepthView = hwTexture->getTexView();
|
||||
}
|
||||
}
|
||||
|
||||
const auto& stencilInfo = renderTarget->getStencilAttachmentInfo();
|
||||
if (stencilInfo.handle) {
|
||||
// If depth and stencil use the same texture handle, this will re-cast but that's fine.
|
||||
auto* hwTexture = handleCast<WGPUTexture>(stencilInfo.handle);
|
||||
if (hwTexture) {
|
||||
customStencilView = hwTexture->getTexView();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderTarget->setUpRenderPassAttachments(renderPassDescriptor,
|
||||
params,
|
||||
defaultColorView,
|
||||
defaultDepthStencilView,
|
||||
customColorViews.data(),
|
||||
customColorViewCount,
|
||||
customDepthView,
|
||||
customStencilView);
|
||||
|
||||
mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor);
|
||||
mRenderPassEncoder.SetViewport(params.viewport.left, params.viewport.bottom,
|
||||
params.viewport.width, params.viewport.height, params.depthRange.near, params.depthRange.far);
|
||||
// Ensure viewport dimensions are positive
|
||||
uint32_t viewportWidth = params.viewport.width > 0 ? params.viewport.width : 1;
|
||||
uint32_t viewportHeight = params.viewport.height > 0 ? params.viewport.height : 1;
|
||||
|
||||
mRenderPassEncoder.SetViewport(
|
||||
static_cast<float>(params.viewport.left),
|
||||
static_cast<float>(params.viewport.bottom),
|
||||
static_cast<float>(viewportWidth),
|
||||
static_cast<float>(viewportHeight),
|
||||
params.depthRange.near,
|
||||
params.depthRange.far);
|
||||
}
|
||||
|
||||
void WebGPUDriver::endRenderPass(int /* dummy */) {
|
||||
@@ -966,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 &&
|
||||
@@ -1012,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(),
|
||||
@@ -1093,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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -923,58 +958,147 @@ wgpu::TextureView WGPUTexture::makeTextureView(const uint8_t& baseLevel, const u
|
||||
return textureView;
|
||||
}
|
||||
|
||||
WGPURenderTarget::Attachment WGPURenderTarget::getDrawColorAttachment(size_t index) {
|
||||
assert_invariant( index < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
|
||||
auto result = color[index];
|
||||
if (index == 0 && defaultRenderTarget) {
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
WGPURenderTarget::WGPURenderTarget(uint32_t width, uint32_t height, uint8_t samples,
|
||||
const MRT& colorAttachmentsMRT,
|
||||
const Attachment& depthAttachmentInfo,
|
||||
const Attachment& stencilAttachmentInfo)
|
||||
: HwRenderTarget(width, height),
|
||||
defaultRenderTarget(false),
|
||||
samples(samples),
|
||||
mColorAttachments(colorAttachmentsMRT),
|
||||
mDepthAttachment(depthAttachmentInfo),
|
||||
mStencilAttachment(stencilAttachmentInfo) {
|
||||
mColorAttachmentDescriptors.reserve(MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
|
||||
}
|
||||
|
||||
// Static helper to map MRT index to TargetBufferFlags
|
||||
TargetBufferFlags WGPURenderTarget::getTargetBufferFlagsAt(int mrtIndex) {
|
||||
if (mrtIndex < 0 || mrtIndex >= MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT) {
|
||||
return TargetBufferFlags::NONE;
|
||||
}
|
||||
// This mapping assumes TargetBufferFlags::COLOR_0, COLOR_1 etc. are contiguous
|
||||
return static_cast<TargetBufferFlags>(
|
||||
static_cast<uint32_t>(TargetBufferFlags::COLOR0) << mrtIndex);
|
||||
}
|
||||
|
||||
// Corrected getLoadOperation
|
||||
wgpu::LoadOp WGPURenderTarget::getLoadOperation(RenderPassParams const& params,
|
||||
TargetBufferFlags buffer) {
|
||||
auto clearFlags = params.flags.clear;
|
||||
auto discardStartFlags = params.flags.discardStart;
|
||||
if (any(clearFlags & buffer)) {
|
||||
return wgpu::LoadOp::Clear;
|
||||
} else if (any(discardStartFlags & buffer)) {
|
||||
TargetBufferFlags bufferToOperateOn) {
|
||||
if (any(params.flags.clear & bufferToOperateOn)) {
|
||||
return wgpu::LoadOp::Clear;
|
||||
}
|
||||
if (any(params.flags.discardStart & bufferToOperateOn)) {
|
||||
return wgpu::LoadOp::Clear; // Or wgpu::LoadOp::Undefined if clear is not desired on discard
|
||||
}
|
||||
return wgpu::LoadOp::Load;
|
||||
}
|
||||
|
||||
// Corrected getStoreOperation
|
||||
wgpu::StoreOp WGPURenderTarget::getStoreOperation(RenderPassParams const& params,
|
||||
TargetBufferFlags buffer) {
|
||||
const auto discardEndFlags = params.flags.discardEnd;
|
||||
if (any(discardEndFlags & buffer)) {
|
||||
TargetBufferFlags bufferToOperateOn) {
|
||||
if (any(params.flags.discardEnd & bufferToOperateOn)) {
|
||||
return wgpu::StoreOp::Discard;
|
||||
}
|
||||
return wgpu::StoreOp::Store;
|
||||
}
|
||||
void WGPURenderTarget::setUpRenderPassAttachments(wgpu::RenderPassDescriptor& descriptor,
|
||||
wgpu::TextureView const& textureView, RenderPassParams const& params) {
|
||||
// auto discardFlags = params.flags.discardEnd;
|
||||
// (void) discardFlags;
|
||||
// std::vector<wgpu::RenderPassColorAttachment> colorAttachments;
|
||||
colorAttachments.clear();
|
||||
for (size_t i = 0; i < 1/*MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT*/; i++) {
|
||||
// auto attachment = getDrawColorAttachment(i);
|
||||
// if (attachment) {
|
||||
wgpu::RenderPassColorAttachment colorAttachment;
|
||||
colorAttachment.view = textureView;
|
||||
colorAttachment.loadOp = getLoadOperation(params, getTargetBufferFlagsAt(i));
|
||||
colorAttachment.storeOp = getStoreOperation(params, getTargetBufferFlagsAt(i));
|
||||
colorAttachment.clearValue = { params.clearColor.r, params.clearColor.g, params.clearColor.b, params.clearColor.a };
|
||||
colorAttachments.emplace_back(colorAttachment);
|
||||
// }
|
||||
|
||||
void WGPURenderTarget::setUpRenderPassAttachments(
|
||||
wgpu::RenderPassDescriptor& descriptor,
|
||||
RenderPassParams const& params,
|
||||
wgpu::TextureView const& defaultColorTextureView,
|
||||
wgpu::TextureView const& defaultDepthStencilTextureView,
|
||||
wgpu::TextureView const* customColorTextureViews,
|
||||
uint32_t customColorTextureViewCount,
|
||||
wgpu::TextureView const& customDepthTextureView,
|
||||
wgpu::TextureView const& customStencilTextureView) {
|
||||
mColorAttachmentDescriptors.clear();
|
||||
mHasDepthStencilAttachment = false;
|
||||
|
||||
if (defaultRenderTarget) {
|
||||
assert_invariant(defaultColorTextureView);
|
||||
wgpu::RenderPassColorAttachment colorAttDesc{};
|
||||
colorAttDesc.view = defaultColorTextureView;
|
||||
colorAttDesc.resolveTarget = nullptr;
|
||||
colorAttDesc.loadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::COLOR0);
|
||||
colorAttDesc.storeOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::COLOR0);
|
||||
colorAttDesc.clearValue = {params.clearColor.r, params.clearColor.g,
|
||||
params.clearColor.b, params.clearColor.a};
|
||||
mColorAttachmentDescriptors.push_back(colorAttDesc);
|
||||
|
||||
if (defaultDepthStencilTextureView) {
|
||||
mDepthStencilAttachmentDescriptor = {
|
||||
.view = defaultDepthStencilTextureView,
|
||||
.depthLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::DEPTH),
|
||||
.depthStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::DEPTH),
|
||||
.depthClearValue = static_cast<float>(params.clearDepth),
|
||||
.depthReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) > 0,
|
||||
.stencilLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::STENCIL),
|
||||
.stencilStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::STENCIL),
|
||||
.stencilClearValue = params.clearStencil,
|
||||
.stencilReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_STENCIL) > 0,
|
||||
};
|
||||
mHasDepthStencilAttachment = true;
|
||||
}
|
||||
} else { // Custom Render Target
|
||||
for (uint32_t i = 0; i < customColorTextureViewCount; ++i) {
|
||||
if (customColorTextureViews[i]) {
|
||||
wgpu::RenderPassColorAttachment colorAttDesc{};
|
||||
colorAttDesc.view = customColorTextureViews[i];
|
||||
colorAttDesc.resolveTarget = nullptr; // TODO: MSAA resolve for custom RT
|
||||
colorAttDesc.loadOp = WGPURenderTarget::getLoadOperation(params, getTargetBufferFlagsAt(i));
|
||||
colorAttDesc.storeOp = WGPURenderTarget::getStoreOperation(params, getTargetBufferFlagsAt(i));
|
||||
colorAttDesc.clearValue = {params.clearColor.r, params.clearColor.g,
|
||||
params.clearColor.b, params.clearColor.a};
|
||||
mColorAttachmentDescriptors.push_back(colorAttDesc);
|
||||
}
|
||||
}
|
||||
|
||||
wgpu::TextureView combinedDsView = customDepthTextureView ? customDepthTextureView : customStencilTextureView;
|
||||
|
||||
if (combinedDsView) {
|
||||
mDepthStencilAttachmentDescriptor = {};
|
||||
mDepthStencilAttachmentDescriptor.view = combinedDsView;
|
||||
|
||||
if (customDepthTextureView) {
|
||||
mDepthStencilAttachmentDescriptor.depthLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::DEPTH);
|
||||
mDepthStencilAttachmentDescriptor.depthStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::DEPTH);
|
||||
mDepthStencilAttachmentDescriptor.depthClearValue = static_cast<float>(params.clearDepth);
|
||||
mDepthStencilAttachmentDescriptor.depthReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) > 0;
|
||||
} else {
|
||||
mDepthStencilAttachmentDescriptor.depthLoadOp = wgpu::LoadOp::Undefined;
|
||||
mDepthStencilAttachmentDescriptor.depthStoreOp = wgpu::StoreOp::Undefined;
|
||||
mDepthStencilAttachmentDescriptor.depthReadOnly = true;
|
||||
}
|
||||
|
||||
if (customStencilTextureView) {
|
||||
mDepthStencilAttachmentDescriptor.stencilLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::STENCIL);
|
||||
mDepthStencilAttachmentDescriptor.stencilStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::STENCIL);
|
||||
mDepthStencilAttachmentDescriptor.stencilClearValue = params.clearStencil;
|
||||
mDepthStencilAttachmentDescriptor.stencilReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_STENCIL) > 0;
|
||||
} else {
|
||||
mDepthStencilAttachmentDescriptor.stencilLoadOp = wgpu::LoadOp::Undefined;
|
||||
mDepthStencilAttachmentDescriptor.stencilStoreOp = wgpu::StoreOp::Undefined;
|
||||
mDepthStencilAttachmentDescriptor.stencilReadOnly = true;
|
||||
}
|
||||
mHasDepthStencilAttachment = true;
|
||||
}
|
||||
}
|
||||
descriptor.colorAttachments = colorAttachments.data();
|
||||
descriptor.colorAttachmentCount = colorAttachments.size();
|
||||
descriptor.depthStencilAttachment = nullptr;
|
||||
descriptor.timestampWrites = nullptr;
|
||||
|
||||
descriptor.colorAttachmentCount = mColorAttachmentDescriptors.size();
|
||||
descriptor.colorAttachments = mColorAttachmentDescriptors.data();
|
||||
descriptor.depthStencilAttachment = mHasDepthStencilAttachment ? &mDepthStencilAttachmentDescriptor : nullptr;
|
||||
// descriptor.sampleCount was removed from the core spec. If your webgpu.h still has it,
|
||||
// and your Dawn version expects it, you might need to set it here based on this->samples.
|
||||
// e.g., descriptor.sampleCount = this->samples;
|
||||
}
|
||||
|
||||
math::uint2 WGPURenderTarget::getAttachmentSize() const noexcept {
|
||||
if (!defaultRenderTarget) {
|
||||
return {width, height};
|
||||
}
|
||||
// For default RT, size is dynamic and usually obtained from the swapchain.
|
||||
// The caller (WebGPUDriver::beginRenderPass) should know the current swapchain size.
|
||||
return {0,0};
|
||||
}
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
@@ -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);
|
||||
@@ -197,57 +207,66 @@ struct WGPURenderPrimitive : public HwRenderPrimitive {
|
||||
WGPUIndexBuffer* indexBuffer = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class WGPURenderTarget : public HwRenderTarget {
|
||||
public:
|
||||
class Attachment {
|
||||
public:
|
||||
friend class WGPURenderTarget;
|
||||
|
||||
Attachment() = default;
|
||||
Attachment(WGPUTexture* gpuTexture, uint8_t level = 0, uint16_t layer = 0)
|
||||
: level(level),
|
||||
layer(layer),
|
||||
texture(gpuTexture->getTexture()),
|
||||
mWGPUTexture(gpuTexture) {}
|
||||
operator bool() const {
|
||||
return mWGPUTexture != nullptr;
|
||||
}
|
||||
|
||||
uint8_t level = 0;
|
||||
uint16_t layer = 0;
|
||||
|
||||
private:
|
||||
wgpu::Texture texture = nullptr;
|
||||
WGPUTexture* mWGPUTexture = nullptr;
|
||||
};
|
||||
using Attachment = TargetBufferInfo; // Using TargetBufferInfo directly for attachments
|
||||
|
||||
WGPURenderTarget(uint32_t width, uint32_t height, uint8_t samples,
|
||||
Attachment colorAttachments[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT]);
|
||||
const MRT& colorAttachments,
|
||||
const Attachment& depthAttachment,
|
||||
const Attachment& stencilAttachment);
|
||||
|
||||
// Default constructor for the default render target
|
||||
WGPURenderTarget()
|
||||
: HwRenderTarget(0, 0),
|
||||
defaultRenderTarget(true) {}
|
||||
defaultRenderTarget(true),
|
||||
samples(1) {}
|
||||
|
||||
void setUpRenderPassAttachments(wgpu::RenderPassDescriptor& descriptor,
|
||||
wgpu::TextureView const& textureView, RenderPassParams const& params);
|
||||
// Updated signature: takes resolved views for custom RTs, and default views for default RT
|
||||
void setUpRenderPassAttachments(
|
||||
wgpu::RenderPassDescriptor& descriptor,
|
||||
RenderPassParams const& params,
|
||||
// For default render target:
|
||||
wgpu::TextureView const& defaultColorTextureView,
|
||||
wgpu::TextureView const& defaultDepthStencilTextureView,
|
||||
// For custom render targets:
|
||||
wgpu::TextureView const* customColorTextureViews, // Array of views
|
||||
uint32_t customColorTextureViewCount,
|
||||
wgpu::TextureView const& customDepthTextureView,
|
||||
wgpu::TextureView const& customStencilTextureView);
|
||||
|
||||
math::uint2 getAttachmentSize() noexcept;
|
||||
|
||||
math::uint2 getAttachmentSize() const noexcept;
|
||||
|
||||
bool isDefaultRenderTarget() const { return defaultRenderTarget; }
|
||||
uint8_t getSamples() const { return samples; }
|
||||
|
||||
Attachment getDrawColorAttachment(size_t index);
|
||||
Attachment getReadColorAttachment(size_t index);
|
||||
// Accessors for the driver to get stored attachment info
|
||||
const MRT& getColorAttachmentInfos() const { return mColorAttachments; }
|
||||
const Attachment& getDepthAttachmentInfo() const { return mDepthAttachment; }
|
||||
const Attachment& getStencilAttachmentInfo() const { return mStencilAttachment; }
|
||||
|
||||
// Static helpers for load/store operations
|
||||
static wgpu::LoadOp getLoadOperation(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||
static wgpu::StoreOp getStoreOperation(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||
|
||||
private:
|
||||
// Helper to map MRT index to TargetBufferFlags
|
||||
static TargetBufferFlags getTargetBufferFlagsAt(int mrtIndex);
|
||||
|
||||
bool defaultRenderTarget = false;
|
||||
uint8_t samples = 1;
|
||||
|
||||
Attachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
||||
math::uint2 attachmentSize = {};
|
||||
std::vector<wgpu::RenderPassColorAttachment> colorAttachments{};
|
||||
};
|
||||
MRT mColorAttachments{};
|
||||
Attachment mDepthAttachment{};
|
||||
Attachment mStencilAttachment{};
|
||||
|
||||
// Cached descriptors for the render pass
|
||||
std::vector<wgpu::RenderPassColorAttachment> mColorAttachmentDescriptors;
|
||||
wgpu::RenderPassDepthStencilAttachment mDepthStencilAttachmentDescriptor{};
|
||||
bool mHasDepthStencilAttachment = false;
|
||||
};
|
||||
}// namespace filament::backend
|
||||
#endif// TNT_FILAMENT_BACKEND_WEBGPUHANDLES_H
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,"
|
||||
|
||||
Reference in New Issue
Block a user