blob: 2794d8f296f6fcfbb46f832fc3574a15518d7eb7 [file] [log] [blame]
//
// Copyright 2024 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// FramebufferWgpu.cpp:
// Implements the class methods for FramebufferWgpu.
//
#include "libANGLE/renderer/wgpu/FramebufferWgpu.h"
#include <__config>
#include "common/debug.h"
#include "libANGLE/Context.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/wgpu/BufferWgpu.h"
#include "libANGLE/renderer/wgpu/ContextWgpu.h"
#include "libANGLE/renderer/wgpu/RenderTargetWgpu.h"
#include "libANGLE/renderer/wgpu/wgpu_utils.h"
namespace rx
{
namespace
{
bool CompareColorRenderPassAttachments(const wgpu::RenderPassColorAttachment &attachment1,
const wgpu::RenderPassColorAttachment &attachment2)
{
if (attachment1.nextInChain != nullptr || attachment2.nextInChain != nullptr)
{
return false;
}
return attachment1.view.Get() == attachment2.view.Get() &&
attachment1.depthSlice == attachment2.depthSlice &&
attachment1.resolveTarget.Get() == attachment2.resolveTarget.Get() &&
attachment1.loadOp == attachment2.loadOp && attachment1.storeOp == attachment2.storeOp &&
attachment1.clearValue.r == attachment2.clearValue.r &&
attachment1.clearValue.g == attachment2.clearValue.g &&
attachment1.clearValue.b == attachment2.clearValue.b &&
attachment1.clearValue.a == attachment2.clearValue.a;
}
bool CompareColorRenderPassAttachmentVectors(
const std::vector<wgpu::RenderPassColorAttachment> &attachments1,
const std::vector<wgpu::RenderPassColorAttachment> &attachments2)
{
if (attachments1.size() != attachments2.size())
{
return false;
}
for (uint32_t i = 0; i < attachments1.size(); ++i)
{
if (!CompareColorRenderPassAttachments(attachments1[i], attachments2[i]))
{
return false;
}
}
return true;
}
bool CompareDepthStencilRenderPassAttachments(
const wgpu::RenderPassDepthStencilAttachment &attachment1,
const wgpu::RenderPassDepthStencilAttachment &attachment2)
{
return attachment1.view.Get() == attachment2.view.Get() &&
attachment1.depthLoadOp == attachment2.depthLoadOp &&
attachment1.depthStoreOp == attachment2.depthStoreOp &&
attachment1.depthClearValue == attachment2.depthClearValue &&
attachment1.stencilLoadOp == attachment2.stencilLoadOp &&
attachment1.stencilStoreOp == attachment2.stencilStoreOp &&
attachment1.stencilClearValue == attachment2.stencilClearValue &&
attachment1.stencilReadOnly == attachment2.stencilReadOnly;
}
} // namespace
FramebufferWgpu::FramebufferWgpu(const gl::FramebufferState &state) : FramebufferImpl(state)
{
mCurrentColorAttachmentFormats.fill(wgpu::TextureFormat::Undefined);
}
FramebufferWgpu::~FramebufferWgpu() {}
angle::Result FramebufferWgpu::discard(const gl::Context *context,
size_t count,
const GLenum *attachments)
{
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::invalidate(const gl::Context *context,
size_t count,
const GLenum *attachments)
{
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::invalidateSub(const gl::Context *context,
size_t count,
const GLenum *attachments,
const gl::Rectangle &area)
{
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::clear(const gl::Context *context, GLbitfield mask)
{
bool clearColor = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_COLOR_BUFFER_BIT));
bool clearDepth = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT));
bool clearStencil = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_STENCIL_BUFFER_BIT));
ASSERT(clearDepth || clearStencil || clearColor);
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;
wgpu::RenderPassDepthStencilAttachment depthStencilAttachment;
float depthValue = 1;
uint32_t stencilValue = 0;
for (size_t enabledDrawBuffer : clearColorBuffers)
{
colorAttachments.push_back(webgpu::CreateNewClearColorAttachment(
clearValue, wgpu::kDepthSliceUndefined,
mRenderTargetCache.getColorDraw(mState, enabledDrawBuffer)->getTextureView()));
}
// Attempt to end a render pass if one has already been started.
bool isActiveRenderPass =
!CompareColorRenderPassAttachmentVectors(mCurrentColorAttachments, colorAttachments) ||
contextWgpu->hasActiveRenderPass();
if (clearDepth || clearStencil)
{
depthValue = context->getState().getDepthClearValue();
stencilValue = static_cast<uint32_t>(context->getState().getStencilClearValue());
depthStencilAttachment = webgpu::CreateNewDepthStencilAttachment(
depthValue, stencilValue, mRenderTargetCache.getDepthStencil()->getTextureView(),
clearDepth, clearStencil);
isActiveRenderPass =
isActiveRenderPass || !CompareDepthStencilRenderPassAttachments(
depthStencilAttachment, mCurrentDepthStencilAttachment);
}
if (mDeferredClears.any())
{
// Merge the current clear command with any deferred clears. This is to keep the clear paths
// simpler so they only need to consider the current or the deferred clears.
mergeClearWithDeferredClears(clearValue, clearColorBuffers, depthValue, stencilValue,
clearColor, clearDepth, clearStencil);
if (isActiveRenderPass)
{
ANGLE_TRY(flushDeferredClears(contextWgpu));
}
else
{
for (size_t colorIndexGL : mDeferredClears.getColorMask())
{
RenderTargetWgpu *renderTarget =
mRenderTargetCache.getColorDraw(mState, colorIndexGL);
webgpu::ClearValues deferredClearValue;
deferredClearValue = mDeferredClears[colorIndexGL];
if (mDeferredClears.hasDepth())
{
deferredClearValue.depthValue = mDeferredClears.getDepthValue();
}
if (mDeferredClears.hasStencil())
{
deferredClearValue.stencilValue = mDeferredClears.getStencilValue();
}
renderTarget->getImage()->stageClear(
renderTarget->getImage()->toGlLevel(renderTarget->getLevelIndex()),
deferredClearValue, false, false);
}
if (mDeferredClears.hasDepth() || mDeferredClears.hasStencil())
{
webgpu::ClearValues dsClearValue = {};
dsClearValue.depthValue = mDeferredClears.getDepthValue();
dsClearValue.stencilValue = mDeferredClears.getStencilValue();
RenderTargetWgpu *renderTarget = mRenderTargetCache.getDepthStencil();
renderTarget->getImage()->stageClear(
renderTarget->getImage()->toGlLevel(renderTarget->getLevelIndex()),
dsClearValue, mDeferredClears.hasDepth(), mDeferredClears.hasStencil());
}
mDeferredClears.reset();
}
return angle::Result::Continue;
}
if (isActiveRenderPass)
{
ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
}
setUpForRenderPass(contextWgpu, (clearDepth || clearStencil), std::move(colorAttachments),
depthStencilAttachment);
ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc));
ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::clearBufferfv(const gl::Context *context,
GLenum buffer,
GLint drawbuffer,
const GLfloat *values)
{
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::clearBufferuiv(const gl::Context *context,
GLenum buffer,
GLint drawbuffer,
const GLuint *values)
{
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::clearBufferiv(const gl::Context *context,
GLenum buffer,
GLint drawbuffer,
const GLint *values)
{
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::clearBufferfi(const gl::Context *context,
GLenum buffer,
GLint drawbuffer,
GLfloat depth,
GLint stencil)
{
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::readPixels(const gl::Context *context,
const gl::Rectangle &origArea,
GLenum format,
GLenum type,
const gl::PixelPackState &pack,
gl::Buffer *packBuffer,
void *ptrOrOffset)
{
// Get the pointer to write to from the argument or the pack buffer
GLubyte *pixels = nullptr;
if (packBuffer != nullptr)
{
UNREACHABLE();
}
else
{
pixels = reinterpret_cast<GLubyte *>(ptrOrOffset);
}
// Clip read area to framebuffer.
const gl::Extents fbSize = getState().getReadPixelsAttachment(format)->getSize();
const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
gl::Rectangle clippedArea;
if (!ClipRectangle(origArea, fbRect, &clippedArea))
{
// nothing to read
return angle::Result::Continue;
}
ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context);
ANGLE_TRY(flushDeferredClears(contextWgpu));
ANGLE_TRY(contextWgpu->flush(webgpu::RenderPassClosureReason::GLReadPixels));
GLuint outputSkipBytes = 0;
PackPixelsParams params;
ANGLE_TRY(webgpu::ImageHelper::getReadPixelsParams(contextWgpu, pack, packBuffer, format, type,
origArea, clippedArea, &params,
&outputSkipBytes));
params.reverseRowOrder = !params.reverseRowOrder;
webgpu::ImageHelper *sourceImageHelper = getReadPixelsRenderTarget()->getImage();
ANGLE_TRY(sourceImageHelper->readPixels(contextWgpu, params.area, params,
static_cast<uint8_t *>(pixels) + outputSkipBytes));
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::blit(const gl::Context *context,
const gl::Rectangle &sourceArea,
const gl::Rectangle &destArea,
GLbitfield mask,
GLenum filter)
{
return angle::Result::Continue;
}
gl::FramebufferStatus FramebufferWgpu::checkStatus(const gl::Context *context) const
{
return gl::FramebufferStatus::Complete();
}
angle::Result FramebufferWgpu::syncState(const gl::Context *context,
GLenum binding,
const gl::Framebuffer::DirtyBits &dirtyBits,
gl::Command command)
{
ContextWgpu *contextWgpu = webgpu::GetImpl(context);
bool dirtyDepthStencilAttachment = false;
ASSERT(dirtyBits.any());
gl::DrawBufferMask dirtyColorAttachments;
for (size_t dirtyBit : dirtyBits)
{
switch (dirtyBit)
{
case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
case gl::Framebuffer::DIRTY_BIT_DEPTH_BUFFER_CONTENTS:
case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
case gl::Framebuffer::DIRTY_BIT_STENCIL_BUFFER_CONTENTS:
{
ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState));
dirtyDepthStencilAttachment = true;
// Update the current depth stencil texture format let the context know if this
// framebuffer is bound for draw
RenderTargetWgpu *rt = mRenderTargetCache.getDepthStencil();
mCurrentDepthStencilFormat = (rt && rt->getImage())
? rt->getImage()->toWgpuTextureFormat()
: wgpu::TextureFormat::Undefined;
if (binding == GL_DRAW_FRAMEBUFFER)
{
contextWgpu->setDepthStencilFormat(mCurrentDepthStencilFormat);
}
break;
}
case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
break;
case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
case gl::Framebuffer::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_LAYERS:
case gl::Framebuffer::DIRTY_BIT_FOVEATION:
break;
default:
{
static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
uint32_t colorIndexGL;
if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
{
colorIndexGL = static_cast<uint32_t>(
dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
}
else
{
ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 &&
dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX);
colorIndexGL = static_cast<uint32_t>(
dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
}
ANGLE_TRY(
mRenderTargetCache.updateColorRenderTarget(context, mState, colorIndexGL));
// Update the current color texture formats let the context know if this framebuffer
// is bound for draw
RenderTargetWgpu *rt = mRenderTargetCache.getColorDraw(mState, colorIndexGL);
mCurrentColorAttachmentFormats[colorIndexGL] =
(rt && rt->getImage()) ? rt->getImage()->toWgpuTextureFormat()
: wgpu::TextureFormat::Undefined;
if (binding == GL_DRAW_FRAMEBUFFER)
{
contextWgpu->setColorAttachmentFormat(
colorIndexGL, mCurrentColorAttachmentFormats[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;
bool deferDepthStencilClears = 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;
}
if ((blitMask & (gl::CommandBlitBufferDepth | gl::CommandBlitBufferStencil)) == 0)
{
deferDepthStencilClears = true;
}
}
ANGLE_TRY(flushAttachmentUpdates(context, dirtyColorAttachments, dirtyDepthStencilAttachment,
deferColorClears, deferDepthStencilClears));
// Notify the ContextWgpu to update the pipeline desc or restart the renderpass
ANGLE_TRY(contextWgpu->onFramebufferChange(this, command));
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::getSamplePosition(const gl::Context *context,
size_t index,
GLfloat *xy) const
{
return angle::Result::Continue;
}
RenderTargetWgpu *FramebufferWgpu::getReadPixelsRenderTarget() const
{
return mRenderTargetCache.getColorRead(mState);
}
void FramebufferWgpu::addNewColorAttachments(
std::vector<wgpu::RenderPassColorAttachment> newColorAttachments)
{
mNewColorAttachments.insert(mCurrentColorAttachments.end(), newColorAttachments.begin(),
newColorAttachments.end());
}
void FramebufferWgpu::updateDepthStencilAttachment(
wgpu::RenderPassDepthStencilAttachment newRenderPassDepthStencilAttachment)
{
mNewDepthStencilAttachment = std::move(newRenderPassDepthStencilAttachment);
mAddedNewDepthStencilAttachment = true;
}
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->flushImageStagedUpdates(contextWgpu, &mDeferredClears,
colorIndexGL));
}
else
{
ANGLE_TRY(drawRenderTarget->flushImageStagedUpdates(contextWgpu, nullptr, 0));
}
}
if (mState.getReadBufferState() != GL_NONE && mState.getReadIndex() == colorIndexGL)
{
readRenderTarget = mRenderTargetCache.getColorRead(mState);
if (readRenderTarget && readRenderTarget != drawRenderTarget)
{
ANGLE_TRY(readRenderTarget->flushImageStagedUpdates(contextWgpu, nullptr, 0));
}
}
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::flushAttachmentUpdates(const gl::Context *context,
gl::DrawBufferMask dirtyColorAttachments,
bool dirtyDepthStencilAttachment,
bool deferColorClears,
bool deferDepthStencilClears)
{
for (size_t colorIndexGL : dirtyColorAttachments)
{
ANGLE_TRY(flushOneColorAttachmentUpdate(context, deferColorClears,
static_cast<uint32_t>(colorIndexGL)));
}
ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context);
RenderTargetWgpu *depthStencilRt = mRenderTargetCache.getDepthStencil();
if (depthStencilRt && dirtyDepthStencilAttachment)
{
if (deferDepthStencilClears)
{
// The underlying ImageHelper will check if a clear has a stencil value and store the
// deferred clear in the correct index.
ANGLE_TRY(depthStencilRt->flushImageStagedUpdates(contextWgpu, &mDeferredClears,
webgpu::kUnpackedDepthIndex));
}
else
{
ANGLE_TRY(depthStencilRt->flushImageStagedUpdates(contextWgpu, nullptr, 0));
}
}
// If we added any new attachments, we start a render pass to fully flush the updates.
if ((!mNewColorAttachments.empty() &&
mNewColorAttachments.size() != mCurrentColorAttachments.size()) ||
mAddedNewDepthStencilAttachment)
{
ANGLE_TRY(startRenderPassNewAttachments(contextWgpu));
}
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)->getTextureView()));
}
if (mRenderTargetCache.getDepthStencil() &&
(mDeferredClears.hasDepth() || mDeferredClears.hasStencil()))
{
mCurrentDepthStencilAttachment = webgpu::CreateNewDepthStencilAttachment(
mDeferredClears.getDepthValue(), mDeferredClears.getStencilValue(),
mRenderTargetCache.getDepthStencil()->getTextureView(), !mDeferredClears.hasDepth(),
!mDeferredClears.hasStencil());
mCurrentRenderPassDesc.depthStencilAttachment = &mCurrentDepthStencilAttachment;
}
else
{
mCurrentRenderPassDesc.depthStencilAttachment = nullptr;
}
mCurrentRenderPassDesc.colorAttachmentCount = mCurrentColorAttachments.size();
mCurrentRenderPassDesc.colorAttachments = mCurrentColorAttachments.data();
ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc));
ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::startRenderPassNewAttachments(ContextWgpu *contextWgpu)
{
// Flush out a render pass if there is an active one.
ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
setUpForRenderPass(contextWgpu, mAddedNewDepthStencilAttachment, mNewColorAttachments,
mNewDepthStencilAttachment);
mNewColorAttachments.clear();
mAddedNewDepthStencilAttachment = false;
ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc));
return angle::Result::Continue;
}
angle::Result FramebufferWgpu::startNewRenderPass(ContextWgpu *contextWgpu)
{
ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
mCurrentColorAttachments.clear();
for (size_t colorIndexGL : mState.getColorAttachmentsMask())
{
wgpu::RenderPassColorAttachment colorAttachment;
colorAttachment.view =
mRenderTargetCache.getColorDraw(mState, colorIndexGL)->getTextureView();
colorAttachment.depthSlice = wgpu::kDepthSliceUndefined;
colorAttachment.loadOp = wgpu::LoadOp::Load;
colorAttachment.storeOp = wgpu::StoreOp::Store;
mCurrentColorAttachments.push_back(colorAttachment);
}
if (mRenderTargetCache.getDepthStencil())
{
mCurrentDepthStencilAttachment = webgpu::CreateNewDepthStencilAttachment(
contextWgpu->getState().getDepthClearValue(),
static_cast<uint32_t>(contextWgpu->getState().getStencilClearValue()),
mRenderTargetCache.getDepthStencil()->getTextureView(), mState.hasDepth(),
mState.hasStencil());
mCurrentRenderPassDesc.depthStencilAttachment = &mCurrentDepthStencilAttachment;
}
else
{
mCurrentRenderPassDesc.depthStencilAttachment = nullptr;
}
mCurrentRenderPassDesc.colorAttachmentCount = mCurrentColorAttachments.size();
mCurrentRenderPassDesc.colorAttachments = mCurrentColorAttachments.data();
ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc));
return angle::Result::Continue;
}
void FramebufferWgpu::setUpForRenderPass(
ContextWgpu *contextWgpu,
bool depthOrStencil,
std::vector<wgpu::RenderPassColorAttachment> colorAttachments,
wgpu::RenderPassDepthStencilAttachment depthStencilAttachment)
{
if (depthOrStencil)
{
mCurrentDepthStencilAttachment = std::move(depthStencilAttachment);
mCurrentRenderPassDesc.depthStencilAttachment = &mCurrentDepthStencilAttachment;
}
else
{
mCurrentRenderPassDesc.depthStencilAttachment = nullptr;
}
mCurrentColorAttachments = std::move(colorAttachments);
mCurrentRenderPassDesc.colorAttachmentCount = mCurrentColorAttachments.size();
mCurrentRenderPassDesc.colorAttachments = mCurrentColorAttachments.data();
}
void FramebufferWgpu::mergeClearWithDeferredClears(wgpu::Color clearValue,
gl::DrawBufferMask clearColorBuffers,
float depthValue,
uint32_t stencilValue,
bool clearColor,
bool clearDepth,
bool clearStencil)
{
for (size_t enabledDrawBuffer : clearColorBuffers)
{
mDeferredClears.store(static_cast<uint32_t>(enabledDrawBuffer),
{clearValue, wgpu::kDepthSliceUndefined, 0, 0});
}
if (clearDepth)
{
mDeferredClears.store(webgpu::kUnpackedDepthIndex,
{clearValue, wgpu::kDepthSliceUndefined, depthValue, 0});
}
if (clearStencil)
{
mDeferredClears.store(webgpu::kUnpackedStencilIndex,
{clearValue, wgpu::kDepthSliceUndefined, 0, stencilValue});
}
}
} // namespace rx