diff options
-rw-r--r-- | src/libANGLE/renderer/wgpu/ContextWgpu.h | 2 | ||||
-rw-r--r-- | src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp | 186 | ||||
-rw-r--r-- | src/libANGLE/renderer/wgpu/FramebufferWgpu.h | 17 | ||||
-rw-r--r-- | src/libANGLE/renderer/wgpu/RenderTargetWgpu.h | 1 | ||||
-rw-r--r-- | src/libANGLE/renderer/wgpu/TextureWgpu.cpp | 52 | ||||
-rw-r--r-- | src/libANGLE/renderer/wgpu/TextureWgpu.h | 8 | ||||
-rw-r--r-- | src/libANGLE/renderer/wgpu/wgpu_helpers.cpp | 106 | ||||
-rw-r--r-- | src/libANGLE/renderer/wgpu/wgpu_helpers.h | 46 | ||||
-rw-r--r-- | src/libANGLE/renderer/wgpu/wgpu_utils.cpp | 31 | ||||
-rw-r--r-- | src/libANGLE/renderer/wgpu/wgpu_utils.h | 46 | ||||
-rw-r--r-- | src/tests/angle_end2end_tests_expectations.txt | 6 |
11 files changed, 421 insertions, 80 deletions
diff --git a/src/libANGLE/renderer/wgpu/ContextWgpu.h b/src/libANGLE/renderer/wgpu/ContextWgpu.h index 6470abe804..1ebb77e82d 100644 --- a/src/libANGLE/renderer/wgpu/ContextWgpu.h +++ b/src/libANGLE/renderer/wgpu/ContextWgpu.h @@ -265,6 +265,8 @@ class ContextWgpu : public ContextImpl angle::Result startRenderPass(const wgpu::RenderPassDescriptor &desc); angle::Result endRenderPass(webgpu::RenderPassClosureReason closure_reason); + bool hasActiveRenderPass() { return mCurrentRenderPass != nullptr; } + angle::Result flush(); private: diff --git a/src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp b/src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp index 957579abaf..390763320f 100644 --- a/src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp +++ b/src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp @@ -8,6 +8,7 @@ // #include "libANGLE/renderer/wgpu/FramebufferWgpu.h" +#include <__config> #include "common/debug.h" #include "libANGLE/Context.h" @@ -109,28 +110,63 @@ angle::Result FramebufferWgpu::clear(const gl::Context *context, GLbitfield mask // TODO(anglebug.com/8582): support clearing depth and stencil buffers. ASSERT(!clearDepth && !clearStencil && clearColor); - ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context); - gl::ColorF colorClearValue = context->getState().getColorClearValue(); - + ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context); + gl::ColorF colorClearValue = context->getState().getColorClearValue(); + gl::DrawBufferMask clearColorBuffers = mState.getEnabledDrawBuffers(); + wgpu::Color clearValue; + clearValue.r = colorClearValue.red; + clearValue.g = colorClearValue.green; + clearValue.b = colorClearValue.blue; + clearValue.a = colorClearValue.alpha; std::vector<wgpu::RenderPassColorAttachment> colorAttachments; - for (size_t enabledDrawBuffer : mState.getEnabledDrawBuffers()) + for (size_t enabledDrawBuffer : clearColorBuffers) { - wgpu::RenderPassColorAttachment colorAttachment; - colorAttachment.view = - mRenderTargetCache.getColorDraw(mState, enabledDrawBuffer)->getTexture(); - colorAttachment.depthSlice = wgpu::kDepthSliceUndefined; - colorAttachment.loadOp = wgpu::LoadOp::Clear; - colorAttachment.storeOp = wgpu::StoreOp::Store; - colorAttachment.clearValue.r = colorClearValue.red; - colorAttachment.clearValue.g = colorClearValue.green; - colorAttachment.clearValue.b = colorClearValue.blue; - colorAttachment.clearValue.a = colorClearValue.alpha; - colorAttachments.push_back(colorAttachment); + colorAttachments.push_back(webgpu::CreateNewClearColorAttachment( + clearValue, wgpu::kDepthSliceUndefined, + mRenderTargetCache.getColorDraw(mState, enabledDrawBuffer)->getTexture())); } // Attempt to end a render pass if one has already been started. ANGLE_UNUSED_VARIABLE(CompareDepthStencilRenderPassAttachments); - if (!CompareColorRenderPassAttachmentVectors(mCurrentColorAttachments, colorAttachments)) + + bool isActiveRenderPass = + !CompareColorRenderPassAttachmentVectors(mCurrentColorAttachments, colorAttachments) || + contextWgpu->hasActiveRenderPass(); + + // If there is not currently an active render pass, merge clears with the deferred clears. This + // is to keep the clear paths simpler so they only need to consider the current or the deferred + // clears. + if (!isActiveRenderPass) + { + for (size_t enabledDrawBuffer : clearColorBuffers) + { + mDeferredClears.store(static_cast<uint32_t>(enabledDrawBuffer), + {clearValue, wgpu::kDepthSliceUndefined}); + } + } + + if (mDeferredClears.any()) + { + if (isActiveRenderPass) + { + ANGLE_TRY(flushDeferredClears(contextWgpu)); + } + else + { + for (size_t colorIndexGL : mDeferredClears.getColorMask()) + { + RenderTargetWgpu *renderTarget = + mRenderTargetCache.getColorDraw(mState, colorIndexGL); + renderTarget->getImage()->stageClear( + renderTarget->getImage()->toGlLevel(renderTarget->getLevelIndex()), + mDeferredClears[colorIndexGL]); + } + mDeferredClears.reset(); + } + return angle::Result::Continue; + } + + if (isActiveRenderPass) { ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass)); @@ -139,7 +175,6 @@ angle::Result FramebufferWgpu::clear(const gl::Context *context, GLbitfield mask mCurrentRenderPassDesc.colorAttachments = mCurrentColorAttachments.data(); } - // TODO(anglebug.com/8582): optimize this implementation. ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc)); ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass)); ANGLE_TRY(contextWgpu->flush()); @@ -209,7 +244,10 @@ angle::Result FramebufferWgpu::readPixels(const gl::Context *context, } ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context); - GLuint outputSkipBytes = 0; + + ANGLE_TRY(flushDeferredClears(contextWgpu)); + + GLuint outputSkipBytes = 0; PackPixelsParams params; const angle::Format &angleFormat = GetFormatFromFormatType(format, type); ANGLE_TRY(webgpu::ImageHelper::getReadPixelsParams(contextWgpu, pack, packBuffer, format, type, @@ -244,6 +282,8 @@ angle::Result FramebufferWgpu::syncState(const gl::Context *context, gl::Command command) { ASSERT(dirtyBits.any()); + + gl::DrawBufferMask dirtyColorAttachments; for (size_t dirtyBit : dirtyBits) { switch (dirtyBit) @@ -286,11 +326,27 @@ angle::Result FramebufferWgpu::syncState(const gl::Context *context, ANGLE_TRY( mRenderTargetCache.updateColorRenderTarget(context, mState, colorIndexGL)); + dirtyColorAttachments.set(colorIndexGL); break; } } } + // Like in Vulkan, defer clears for draw framebuffer ops as well as clears to read framebuffer + // attachments that are not taking part in a blit operation. + const bool isBlitCommand = command >= gl::Command::Blit && command <= gl::Command::BlitAll; + bool deferColorClears = binding == GL_DRAW_FRAMEBUFFER; + if (binding == GL_READ_FRAMEBUFFER && isBlitCommand) + { + uint32_t blitMask = + static_cast<uint32_t>(command) - static_cast<uint32_t>(gl::Command::Blit); + if ((blitMask & gl::CommandBlitBufferColor) == 0) + { + deferColorClears = true; + } + } + + ANGLE_TRY(flushColorAttachmentUpdates(context, dirtyColorAttachments, deferColorClears)); return angle::Result::Continue; } @@ -310,4 +366,98 @@ RenderTargetWgpu *FramebufferWgpu::getReadPixelsRenderTarget(const angle::Format return mRenderTargetCache.getColorRead(mState); } +void FramebufferWgpu::addNewColorAttachments( + std::vector<wgpu::RenderPassColorAttachment> newColorAttachments) +{ + mNewColorAttachments.insert(mCurrentColorAttachments.end(), newColorAttachments.begin(), + newColorAttachments.end()); +} + +angle::Result FramebufferWgpu::flushOneColorAttachmentUpdate(const gl::Context *context, + bool deferClears, + uint32_t colorIndexGL) +{ + ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context); + RenderTargetWgpu *drawRenderTarget = nullptr; + RenderTargetWgpu *readRenderTarget = nullptr; + + drawRenderTarget = mRenderTargetCache.getColorDraw(mState, colorIndexGL); + if (drawRenderTarget) + { + if (deferClears) + { + ANGLE_TRY(drawRenderTarget->getImage()->flushStagedUpdates( + contextWgpu, &mDeferredClears, colorIndexGL)); + } + else + { + ANGLE_TRY(drawRenderTarget->getImage()->flushStagedUpdates(contextWgpu)); + } + } + + if (mState.getReadBufferState() != GL_NONE && mState.getReadIndex() == colorIndexGL) + { + readRenderTarget = mRenderTargetCache.getColorRead(mState); + if (readRenderTarget && readRenderTarget != drawRenderTarget) + { + ANGLE_TRY(readRenderTarget->getImage()->flushStagedUpdates(contextWgpu)); + } + } + + return angle::Result::Continue; +} + +angle::Result FramebufferWgpu::flushColorAttachmentUpdates(const gl::Context *context, + gl::DrawBufferMask dirtyColorAttachments, + bool deferClears) +{ + for (size_t colorIndexGL : dirtyColorAttachments) + { + ANGLE_TRY(flushOneColorAttachmentUpdate(context, deferClears, + static_cast<uint32_t>(colorIndexGL))); + } + + // If we added any new color attachments, we start a render pass to fully flush the updates. + if (!mNewColorAttachments.empty() != mCurrentColorAttachments.size()) + { + ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context); + // Flush out a render pass if there is an active one. + ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass)); + ANGLE_TRY(contextWgpu->flush()); + + mCurrentColorAttachments = mNewColorAttachments; + mNewColorAttachments.clear(); + mCurrentRenderPassDesc.colorAttachmentCount = mCurrentColorAttachments.size(); + mCurrentRenderPassDesc.colorAttachments = mCurrentColorAttachments.data(); + ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc)); + } + return angle::Result::Continue; +} + +angle::Result FramebufferWgpu::flushDeferredClears(ContextWgpu *contextWgpu) +{ + if (mDeferredClears.empty()) + { + return angle::Result::Continue; + } + ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass)); + mCurrentColorAttachments.clear(); + for (size_t colorIndexGL : mState.getColorAttachmentsMask()) + { + if (!mDeferredClears.test(colorIndexGL)) + { + continue; + } + mCurrentColorAttachments.push_back(webgpu::CreateNewClearColorAttachment( + mDeferredClears[colorIndexGL].clearColor, mDeferredClears[colorIndexGL].depthSlice, + mRenderTargetCache.getColorDraw(mState, colorIndexGL)->getTexture())); + } + mCurrentRenderPassDesc.colorAttachmentCount = mCurrentColorAttachments.size(); + mCurrentRenderPassDesc.colorAttachments = mCurrentColorAttachments.data(); + ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc)); + ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass)); + ANGLE_TRY(contextWgpu->flush()); + + return angle::Result::Continue; +} } // namespace rx diff --git a/src/libANGLE/renderer/wgpu/FramebufferWgpu.h b/src/libANGLE/renderer/wgpu/FramebufferWgpu.h index 5376da8bb5..2f8700b793 100644 --- a/src/libANGLE/renderer/wgpu/FramebufferWgpu.h +++ b/src/libANGLE/renderer/wgpu/FramebufferWgpu.h @@ -80,10 +80,27 @@ class FramebufferWgpu : public FramebufferImpl RenderTargetWgpu *getReadPixelsRenderTarget(const angle::Format &format) const; + void addNewColorAttachments(std::vector<wgpu::RenderPassColorAttachment> newColorAttachments); + + angle::Result flushOneColorAttachmentUpdate(const gl::Context *context, + bool deferClears, + uint32_t colorIndexGL); + + angle::Result flushColorAttachmentUpdates(const gl::Context *context, + gl::DrawBufferMask dirtyColorAttachments, + bool deferClears); + + angle::Result flushDeferredClears(ContextWgpu *contextWgpu); + private: RenderTargetCache<RenderTargetWgpu> mRenderTargetCache; wgpu::RenderPassDescriptor mCurrentRenderPassDesc; std::vector<wgpu::RenderPassColorAttachment> mCurrentColorAttachments; + // Secondary vector to track new clears that are added and should be run in a new render pass + // during flushColorAttachmentUpdates. + std::vector<wgpu::RenderPassColorAttachment> mNewColorAttachments; + + webgpu::ClearValuesArray mDeferredClears; }; } // namespace rx diff --git a/src/libANGLE/renderer/wgpu/RenderTargetWgpu.h b/src/libANGLE/renderer/wgpu/RenderTargetWgpu.h index ef32caabd1..459b98d071 100644 --- a/src/libANGLE/renderer/wgpu/RenderTargetWgpu.h +++ b/src/libANGLE/renderer/wgpu/RenderTargetWgpu.h @@ -38,6 +38,7 @@ class RenderTargetWgpu final : public FramebufferAttachmentRenderTarget wgpu::TextureView getTexture() { return mTexture; } webgpu::ImageHelper *getImage() { return mImage; } + webgpu::LevelIndex getLevelIndex() const { return mLevelIndex; } private: webgpu::ImageHelper *mImage; diff --git a/src/libANGLE/renderer/wgpu/TextureWgpu.cpp b/src/libANGLE/renderer/wgpu/TextureWgpu.cpp index 027c3a8053..03517eb7b3 100644 --- a/src/libANGLE/renderer/wgpu/TextureWgpu.cpp +++ b/src/libANGLE/renderer/wgpu/TextureWgpu.cpp @@ -283,7 +283,7 @@ angle::Result TextureWgpu::syncState(const gl::Context *context, ANGLE_TRY(initializeImage(contextWgpu, isGenerateMipmap ? ImageMipLevels::FullMipChainForGenerateMipmap : ImageMipLevels::EnabledLevels)); - mImage->flushStagedUpdates(contextWgpu); + ANGLE_TRY(mImage->flushStagedUpdates(contextWgpu)); return angle::Result::Continue; } @@ -316,8 +316,6 @@ angle::Result TextureWgpu::getAttachmentRenderTarget(const gl::Context *context, { ANGLE_TRY(initializeImage(contextWgpu, ImageMipLevels::EnabledLevels)); } - // Note: Flushing updates will be moved to FramebufferWgpu when deferring clears is supported. - mImage->flushStagedUpdates(contextWgpu); GLuint layerIndex = 0, layerCount = 0, imageLayerCount = 0; GetRenderTargetLayerCountAndIndex(mImage, imageIndex, &layerIndex, &layerCount, @@ -330,9 +328,9 @@ angle::Result TextureWgpu::getAttachmentRenderTarget(const gl::Context *context, if (layerCount == 1) { - initSingleLayerRenderTargets(contextWgpu, imageLayerCount, - gl::LevelIndex(imageIndex.getLevelIndex()), - renderToTextureIndex); + ANGLE_TRY(initSingleLayerRenderTargets(contextWgpu, imageLayerCount, + gl::LevelIndex(imageIndex.getLevelIndex()), + renderToTextureIndex)); std::vector<std::vector<RenderTargetWgpu>> &levelRenderTargets = mSingleLayerRenderTargets[renderToTextureIndex]; @@ -516,7 +514,7 @@ angle::Result TextureWgpu::respecifyImageStorageIfNecessary(ContextWgpu *context mImage->getLevelCount() != getMipLevelCount(ImageMipLevels::FullMipChainForGenerateMipmap))) { - mImage->flushStagedUpdates(contextWgpu); + ANGLE_TRY(mImage->flushStagedUpdates(contextWgpu)); mImage->resetImage(); } @@ -527,7 +525,7 @@ angle::Result TextureWgpu::respecifyImageStorageIfNecessary(ContextWgpu *context // TODO(liza): Respecify the image once copying images is supported. if (TextureHasAnyRedefinedLevels(mRedefinedLevels) || isMipmapEnabledByMinFilter) { - mImage->flushStagedUpdates(contextWgpu); + ANGLE_TRY(mImage->flushStagedUpdates(contextWgpu)); mImage->resetImage(); } @@ -606,10 +604,11 @@ angle::Result TextureWgpu::maybeUpdateBaseMaxLevels(ContextWgpu *contextWgpu) return angle::Result::Continue; } -void TextureWgpu::initSingleLayerRenderTargets(ContextWgpu *contextWgpu, - GLuint layerCount, - gl::LevelIndex levelIndex, - gl::RenderToTextureImageIndex renderToTextureIndex) +angle::Result TextureWgpu::initSingleLayerRenderTargets( + ContextWgpu *contextWgpu, + GLuint layerCount, + gl::LevelIndex levelIndex, + gl::RenderToTextureImageIndex renderToTextureIndex) { std::vector<std::vector<RenderTargetWgpu>> &allLevelsRenderTargets = mSingleLayerRenderTargets[renderToTextureIndex]; @@ -624,7 +623,7 @@ void TextureWgpu::initSingleLayerRenderTargets(ContextWgpu *contextWgpu, // Lazy init. Check if already initialized. if (!renderTargets.empty()) { - return; + return angle::Result::Continue; } // There are |layerCount| render targets, one for each layer @@ -632,33 +631,14 @@ void TextureWgpu::initSingleLayerRenderTargets(ContextWgpu *contextWgpu, for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) { - wgpu::TextureViewDescriptor textureViewDesc; - textureViewDesc.aspect = wgpu::TextureAspect::All; - textureViewDesc.baseArrayLayer = layerIndex; - textureViewDesc.arrayLayerCount = 1; - textureViewDesc.baseMipLevel = mImage->toWgpuLevel(levelIndex).get(); - textureViewDesc.mipLevelCount = 1; - switch (mImage->getTextureDescriptor().dimension) - { - case wgpu::TextureDimension::Undefined: - textureViewDesc.dimension = wgpu::TextureViewDimension::Undefined; - break; - case wgpu::TextureDimension::e1D: - textureViewDesc.dimension = wgpu::TextureViewDimension::e1D; - break; - case wgpu::TextureDimension::e2D: - textureViewDesc.dimension = wgpu::TextureViewDimension::e2D; - break; - case wgpu::TextureDimension::e3D: - textureViewDesc.dimension = wgpu::TextureViewDimension::e3D; - break; - } - textureViewDesc.format = mImage->getTextureDescriptor().format; - wgpu::TextureView textureView = mImage->getTexture().CreateView(&textureViewDesc); + wgpu::TextureView textureView; + ANGLE_TRY(mImage->createTextureView(levelIndex, layerIndex, textureView)); renderTargets[layerIndex].set(mImage, textureView, mImage->toWgpuLevel(levelIndex), layerIndex, mImage->toWgpuTextureFormat()); } + + return angle::Result::Continue; } } // namespace rx diff --git a/src/libANGLE/renderer/wgpu/TextureWgpu.h b/src/libANGLE/renderer/wgpu/TextureWgpu.h index da6a8fa3df..0e5057aa25 100644 --- a/src/libANGLE/renderer/wgpu/TextureWgpu.h +++ b/src/libANGLE/renderer/wgpu/TextureWgpu.h @@ -202,10 +202,10 @@ class TextureWgpu : public TextureImpl angle::Result respecifyImageStorageIfNecessary(ContextWgpu *contextWgpu, gl::Command source); void prepareForGenerateMipmap(ContextWgpu *contextWgpu); angle::Result maybeUpdateBaseMaxLevels(ContextWgpu *contextWgpu); - void initSingleLayerRenderTargets(ContextWgpu *contextWgpu, - GLuint layerCount, - gl::LevelIndex levelIndex, - gl::RenderToTextureImageIndex renderToTextureIndex); + angle::Result initSingleLayerRenderTargets(ContextWgpu *contextWgpu, + GLuint layerCount, + gl::LevelIndex levelIndex, + gl::RenderToTextureImageIndex renderToTextureIndex); webgpu::ImageHelper *mImage; gl::LevelIndex mCurrentBaseLevel; gl::LevelIndex mCurrentMaxLevel; diff --git a/src/libANGLE/renderer/wgpu/wgpu_helpers.cpp b/src/libANGLE/renderer/wgpu/wgpu_helpers.cpp index d679ecb664..422f86023a 100644 --- a/src/libANGLE/renderer/wgpu/wgpu_helpers.cpp +++ b/src/libANGLE/renderer/wgpu/wgpu_helpers.cpp @@ -9,6 +9,7 @@ #include "libANGLE/renderer/wgpu/ContextWgpu.h" #include "libANGLE/renderer/wgpu/DisplayWgpu.h" +#include "libANGLE/renderer/wgpu/FramebufferWgpu.h" #include "wgpu_helpers.h" namespace rx @@ -35,32 +36,63 @@ angle::Result ImageHelper::initImage(wgpu::Device &device, return angle::Result::Continue; } -void ImageHelper::flushStagedUpdates(ContextWgpu *contextWgpu) +angle::Result ImageHelper::flushStagedUpdates(ContextWgpu *contextWgpu, + ClearValuesArray *deferredClears, + uint32_t deferredClearIndex) { - if (mBufferQueue.empty()) + if (mSubresourceQueue.empty()) { - return; + return angle::Result::Continue; } wgpu::Device device = contextWgpu->getDevice(); wgpu::Queue queue = contextWgpu->getQueue(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::ImageCopyTexture dst; dst.texture = mTexture; - for (const QueuedDataUpload &src : mBufferQueue) + std::vector<wgpu::RenderPassColorAttachment> colorAttachments; + for (const SubresourceUpdate &srcUpdate : mSubresourceQueue) { - if (src.targetLevel < mFirstAllocatedLevel || - src.targetLevel >= (mFirstAllocatedLevel + mTextureDescriptor.mipLevelCount)) + if (!isTextureLevelInAllocatedImage(srcUpdate.targetLevel)) { continue; } - LevelIndex targetLevelWgpu = toWgpuLevel(src.targetLevel); - dst.mipLevel = targetLevelWgpu.get(); - encoder.CopyBufferToTexture(&src.buffer, &dst, &mTextureDescriptor.size); + switch (srcUpdate.updateSource) + { + case UpdateSource::Texture: + dst.mipLevel = toWgpuLevel(srcUpdate.targetLevel).get(); + encoder.CopyBufferToTexture(&srcUpdate.textureData, &dst, &mTextureDescriptor.size); + break; + case UpdateSource::Clear: + if (deferredClears) + { + deferredClears->store(deferredClearIndex, srcUpdate.clearData); + } + else + { + + wgpu::TextureView textureView; + ANGLE_TRY(createTextureView(srcUpdate.targetLevel, 0, textureView)); + + colorAttachments.push_back( + CreateNewClearColorAttachment(srcUpdate.clearData.clearColor, + srcUpdate.clearData.depthSlice, textureView)); + } + break; + } + } + + if (!colorAttachments.empty()) + { + FramebufferWgpu *frameBuffer = + GetImplAs<FramebufferWgpu>(contextWgpu->getState().getDrawFramebuffer()); + frameBuffer->addNewColorAttachments(colorAttachments); } wgpu::CommandBuffer commandBuffer = encoder.Finish(); queue.Submit(1, &commandBuffer); encoder = nullptr; - mBufferQueue.clear(); + mSubresourceQueue.clear(); + + return angle::Result::Continue; } wgpu::TextureDescriptor ImageHelper::createTextureDescriptor(wgpu::TextureUsage usage, @@ -113,20 +145,26 @@ angle::Result ImageHelper::stageTextureUpload(ContextWgpu *contextWgpu, textureDataLayout.bytesPerRow = outputRowPitch; textureDataLayout.rowsPerImage = outputDepthPitch; wgpu::ImageCopyBuffer imageCopyBuffer; - imageCopyBuffer.layout = textureDataLayout; - imageCopyBuffer.buffer = bufferHelper.getBuffer(); - QueuedDataUpload dataUpload = {imageCopyBuffer, levelGL}; - mBufferQueue.push_back(dataUpload); + imageCopyBuffer.layout = textureDataLayout; + imageCopyBuffer.buffer = bufferHelper.getBuffer(); + SubresourceUpdate subresourceUpdate(UpdateSource::Texture, levelGL, imageCopyBuffer); + mSubresourceQueue.push_back(subresourceUpdate); return angle::Result::Continue; } +void ImageHelper::stageClear(gl::LevelIndex targetLevel, ClearValues clearValues) +{ + SubresourceUpdate subresourceUpdate(UpdateSource::Clear, targetLevel, clearValues); + mSubresourceQueue.push_back(subresourceUpdate); +} + void ImageHelper::removeStagedUpdates(gl::LevelIndex levelToRemove) { - for (auto it = mBufferQueue.begin(); it != mBufferQueue.end(); it++) + for (auto it = mSubresourceQueue.begin(); it != mSubresourceQueue.end(); it++) { - if (it->targetLevel == levelToRemove) + if (it->updateSource == UpdateSource::Texture && it->targetLevel == levelToRemove) { - mBufferQueue.erase(it); + mSubresourceQueue.erase(it); } } } @@ -212,6 +250,40 @@ angle::Result ImageHelper::readPixels(rx::ContextWgpu *contextWgpu, return angle::Result::Continue; } +angle::Result ImageHelper::createTextureView(gl::LevelIndex targetLevel, + uint32_t layerIndex, + wgpu::TextureView &textureViewOut) +{ + if (!isTextureLevelInAllocatedImage(targetLevel)) + { + return angle::Result::Stop; + } + wgpu::TextureViewDescriptor textureViewDesc; + textureViewDesc.aspect = wgpu::TextureAspect::All; + textureViewDesc.baseArrayLayer = layerIndex; + textureViewDesc.arrayLayerCount = 1; + textureViewDesc.baseMipLevel = toWgpuLevel(targetLevel).get(); + textureViewDesc.mipLevelCount = 1; + switch (mTextureDescriptor.dimension) + { + case wgpu::TextureDimension::Undefined: + textureViewDesc.dimension = wgpu::TextureViewDimension::Undefined; + break; + case wgpu::TextureDimension::e1D: + textureViewDesc.dimension = wgpu::TextureViewDimension::e1D; + break; + case wgpu::TextureDimension::e2D: + textureViewDesc.dimension = wgpu::TextureViewDimension::e2D; + break; + case wgpu::TextureDimension::e3D: + textureViewDesc.dimension = wgpu::TextureViewDimension::e3D; + break; + } + textureViewDesc.format = mTextureDescriptor.format; + textureViewOut = mTexture.CreateView(&textureViewDesc); + return angle::Result::Continue; +} + gl::LevelIndex ImageHelper::getLastAllocatedLevel() { return mFirstAllocatedLevel + mTextureDescriptor.mipLevelCount - 1; diff --git a/src/libANGLE/renderer/wgpu/wgpu_helpers.h b/src/libANGLE/renderer/wgpu/wgpu_helpers.h index 8da3cec690..5a7f58dd24 100644 --- a/src/libANGLE/renderer/wgpu/wgpu_helpers.h +++ b/src/libANGLE/renderer/wgpu/wgpu_helpers.h @@ -28,9 +28,39 @@ namespace webgpu // https://www.w3.org/TR/webgpu/#abstract-opdef-validating-gpuimagecopybuffer static const GLuint kCopyBufferAlignment = 256; -struct QueuedDataUpload +enum class UpdateSource { - wgpu::ImageCopyBuffer buffer; + Clear, + Texture, +}; + +struct SubresourceUpdate +{ + SubresourceUpdate() {} + ~SubresourceUpdate() {} + + SubresourceUpdate(UpdateSource targetUpdateSource, + gl::LevelIndex newTargetLevel, + wgpu::ImageCopyBuffer targetBuffer) + { + updateSource = targetUpdateSource; + textureData = targetBuffer; + targetLevel = newTargetLevel; + } + + SubresourceUpdate(UpdateSource targetUpdateSource, + gl::LevelIndex newTargetLevel, + ClearValues clearUpdate) + { + updateSource = targetUpdateSource; + targetLevel = newTargetLevel; + clearData = clearUpdate; + } + + UpdateSource updateSource; + ClearValues clearData; + wgpu::ImageCopyBuffer textureData; + gl::LevelIndex targetLevel; }; @@ -46,7 +76,9 @@ class ImageHelper gl::LevelIndex firstAllocatedLevel, wgpu::TextureDescriptor textureDescriptor); - void flushStagedUpdates(ContextWgpu *contextWgpu); + angle::Result flushStagedUpdates(ContextWgpu *contextWgpu, + ClearValuesArray *deferredClears = nullptr, + uint32_t deferredClearIndex = 0); wgpu::TextureDescriptor createTextureDescriptor(wgpu::TextureUsage usage, wgpu::TextureDimension dimension, @@ -65,6 +97,8 @@ class ImageHelper const gl::ImageIndex &index, const uint8_t *pixels); + void stageClear(gl::LevelIndex targetLevel, ClearValues clearValues); + void removeStagedUpdates(gl::LevelIndex levelToRemove); void resetImage(); @@ -84,6 +118,10 @@ class ImageHelper const rx::PackPixelsParams &packPixelsParams, const angle::Format &aspectFormat, void *pixels); + + angle::Result createTextureView(gl::LevelIndex targetLevel, + uint32_t layerIndex, + wgpu::TextureView &textureViewOut); LevelIndex toWgpuLevel(gl::LevelIndex levelIndexGl) const; gl::LevelIndex toGlLevel(LevelIndex levelIndexWgpu) const; bool isTextureLevelInAllocatedImage(gl::LevelIndex textureLevel); @@ -104,7 +142,7 @@ class ImageHelper gl::LevelIndex mFirstAllocatedLevel = gl::LevelIndex(0); - std::vector<QueuedDataUpload> mBufferQueue; + std::vector<SubresourceUpdate> mSubresourceQueue; }; struct BufferMapState { diff --git a/src/libANGLE/renderer/wgpu/wgpu_utils.cpp b/src/libANGLE/renderer/wgpu/wgpu_utils.cpp index e43c826d03..95b2085644 100644 --- a/src/libANGLE/renderer/wgpu/wgpu_utils.cpp +++ b/src/libANGLE/renderer/wgpu/wgpu_utils.cpp @@ -39,6 +39,20 @@ wgpu::Instance GetInstance(const gl::Context *context) return display->getInstance(); } +wgpu::RenderPassColorAttachment CreateNewClearColorAttachment(wgpu::Color clearValue, + uint32_t depthSlice, + wgpu::TextureView textureView) +{ + wgpu::RenderPassColorAttachment colorAttachment; + colorAttachment.view = textureView; + colorAttachment.depthSlice = depthSlice; + colorAttachment.loadOp = wgpu::LoadOp::Clear; + colorAttachment.storeOp = wgpu::StoreOp::Store; + colorAttachment.clearValue = clearValue; + + return colorAttachment; +} + bool IsWgpuError(wgpu::WaitStatus waitStatus) { return waitStatus != wgpu::WaitStatus::Success; @@ -49,6 +63,23 @@ bool IsWgpuError(WGPUBufferMapAsyncStatus mapBufferStatus) return mapBufferStatus != WGPUBufferMapAsyncStatus_Success; } +ClearValuesArray::ClearValuesArray() : mValues{}, mEnabled{} {} +ClearValuesArray::~ClearValuesArray() = default; + +ClearValuesArray::ClearValuesArray(const ClearValuesArray &other) = default; +ClearValuesArray &ClearValuesArray::operator=(const ClearValuesArray &rhs) = default; + +void ClearValuesArray::store(uint32_t index, ClearValues clearValues) +{ + mValues[index] = clearValues; + mEnabled.set(index); +} + +gl::DrawBufferMask ClearValuesArray::getColorMask() const +{ + return gl::DrawBufferMask(mEnabled.bits() & kUnpackedColorBuffersMask); +} + void EnsureCapsInitialized(const wgpu::Device &device, gl::Caps *nativeCaps) { wgpu::SupportedLimits limitsWgpu = {}; diff --git a/src/libANGLE/renderer/wgpu/wgpu_utils.h b/src/libANGLE/renderer/wgpu/wgpu_utils.h index 45f7c69ed6..6d209ed849 100644 --- a/src/libANGLE/renderer/wgpu/wgpu_utils.h +++ b/src/libANGLE/renderer/wgpu/wgpu_utils.h @@ -34,6 +34,10 @@ class DisplayWgpu; namespace webgpu { +constexpr size_t kUnpackedDepthIndex = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; +constexpr size_t kUnpackedStencilIndex = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1; +constexpr uint32_t kUnpackedColorBuffersMask = + angle::BitMask<uint32_t>(gl::IMPLEMENTATION_MAX_DRAW_BUFFERS); // WebGPU image level index. using LevelIndex = gl::LevelIndexWrapper<uint32_t>; @@ -45,12 +49,54 @@ enum class RenderPassClosureReason EnumCount = InvalidEnum, }; +struct ClearValues +{ + wgpu::Color clearColor; + uint32_t depthSlice; +}; + +class ClearValuesArray final +{ + public: + ClearValuesArray(); + ~ClearValuesArray(); + + ClearValuesArray(const ClearValuesArray &other); + ClearValuesArray &operator=(const ClearValuesArray &rhs); + + void store(uint32_t index, ClearValues clearValues); + gl::DrawBufferMask getColorMask() const; + void reset() + { + mValues.fill({}); + mEnabled.reset(); + } + void reset(size_t index) + { + mValues[index] = {}; + mEnabled.reset(index); + } + const ClearValues &operator[](size_t index) const { return mValues[index]; } + + bool empty() const { return mEnabled.none(); } + bool any() const { return mEnabled.any(); } + + bool test(size_t index) const { return mEnabled.test(index); } + + private: + gl::AttachmentArray<ClearValues> mValues; + gl::AttachmentsMask mEnabled; +}; + void EnsureCapsInitialized(const wgpu::Device &device, gl::Caps *nativeCaps); ContextWgpu *GetImpl(const gl::Context *context); DisplayWgpu *GetDisplay(const gl::Context *context); wgpu::Device GetDevice(const gl::Context *context); wgpu::Instance GetInstance(const gl::Context *context); +wgpu::RenderPassColorAttachment CreateNewClearColorAttachment(wgpu::Color clearValue, + uint32_t depthSlice, + wgpu::TextureView textureView); bool IsWgpuError(wgpu::WaitStatus waitStatus); bool IsWgpuError(WGPUBufferMapAsyncStatus mapBufferStatus); diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt index fc9abc334c..452f71024a 100644 --- a/src/tests/angle_end2end_tests_expectations.txt +++ b/src/tests/angle_end2end_tests_expectations.txt @@ -1415,7 +1415,11 @@ b/292285899 PIXEL4ORXL GLES : EGLSurfaceTest.DestroyAndRecreateWhileCurrent/* = // WebGPU failures 8485 WGPU : RendererTest.SimpleOperation/* = SKIP -8582 WGPU : ClearTest.* = SKIP +8582 WGPU : ClearTest.*Scissor* = SKIP +8582 WGPU : ClearTest.*Mask* = SKIP +8582 WGPU : ClearTest.DefaultFramebuffer* = SKIP +8582 WGPU : ClearTest.ChangeFramebufferAttachmentFromRGBAtoRGB* = SKIP +8582 WGPU : ClearTest.ClearIssue* = SKIP 8547 WGPU : Texture2DTest.Tex* = SKIP 8547 WGPU : Texture2DTest.Upload* = SKIP 8547 WGPU : Texture2DTest.*Superseding* = SKIP |