diff --git a/filament/backend/src/webgpu/WebGPUDriver.cpp b/filament/backend/src/webgpu/WebGPUDriver.cpp index 2db037c3bf..e2563588df 100644 --- a/filament/backend/src/webgpu/WebGPUDriver.cpp +++ b/filament/backend/src/webgpu/WebGPUDriver.cpp @@ -354,6 +354,17 @@ void WebGPUDriver::destroyProgram(Handle ph) { } void WebGPUDriver::destroyRenderTarget(Handle rth) { + if (rth) { + WGPURenderTarget* rt = handleCast(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(rth); + } } void WebGPUDriver::destroySwapChain(Handle sch) { @@ -580,7 +591,21 @@ void WebGPUDriver::createDefaultRenderTargetR(Handle rth, int) { void WebGPUDriver::createRenderTargetR(Handle 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(rth, width, height, samples, color, depth, stencil); +} void WebGPUDriver::createFenceR(Handle fh, int) {} @@ -845,35 +870,74 @@ void WebGPUDriver::compilePrograms(CompilerPriorityQueue priority, void WebGPUDriver::beginRenderPass(Handle rth, RenderPassParams const& params) { assert_invariant(mCommandEncoder); - auto* renderTarget = handleCast(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(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 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(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(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(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(params.viewport.left), + static_cast(params.viewport.bottom), + static_cast(viewportWidth), + static_cast(viewportHeight), + params.depthRange.near, + params.depthRange.far); } void WebGPUDriver::endRenderPass(int /* dummy */) { diff --git a/filament/backend/src/webgpu/WebGPUHandles.cpp b/filament/backend/src/webgpu/WebGPUHandles.cpp index 04ce8d5861..8213d09edf 100644 --- a/filament/backend/src/webgpu/WebGPUHandles.cpp +++ b/filament/backend/src/webgpu/WebGPUHandles.cpp @@ -923,58 +923,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( + static_cast(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 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(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(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 diff --git a/filament/backend/src/webgpu/WebGPUHandles.h b/filament/backend/src/webgpu/WebGPUHandles.h index cd0e6bf5e5..a33bc4362a 100644 --- a/filament/backend/src/webgpu/WebGPUHandles.h +++ b/filament/backend/src/webgpu/WebGPUHandles.h @@ -197,57 +197,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 colorAttachments{}; -}; + MRT mColorAttachments{}; + Attachment mDepthAttachment{}; + Attachment mStencilAttachment{}; + // Cached descriptors for the render pass + std::vector mColorAttachmentDescriptors; + wgpu::RenderPassDepthStencilAttachment mDepthStencilAttachmentDescriptor{}; + bool mHasDepthStencilAttachment = false; +}; }// namespace filament::backend #endif// TNT_FILAMENT_BACKEND_WEBGPUHANDLES_H