aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libANGLE/renderer/wgpu/ContextWgpu.h2
-rw-r--r--src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp186
-rw-r--r--src/libANGLE/renderer/wgpu/FramebufferWgpu.h17
-rw-r--r--src/libANGLE/renderer/wgpu/RenderTargetWgpu.h1
-rw-r--r--src/libANGLE/renderer/wgpu/TextureWgpu.cpp52
-rw-r--r--src/libANGLE/renderer/wgpu/TextureWgpu.h8
-rw-r--r--src/libANGLE/renderer/wgpu/wgpu_helpers.cpp106
-rw-r--r--src/libANGLE/renderer/wgpu/wgpu_helpers.h46
-rw-r--r--src/libANGLE/renderer/wgpu/wgpu_utils.cpp31
-rw-r--r--src/libANGLE/renderer/wgpu/wgpu_utils.h46
-rw-r--r--src/tests/angle_end2end_tests_expectations.txt6
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