Fix broken layerCount for some types of textures (#8151)

Currently mLayerCount for RenderTarget is always updated to the number
of depth for attachments, which incurs unintended behaviors for some
types of textures. i.e., 2d array, cubemap array, and 3d textures.

Fix this by updating mLayerCount only for multiview use case.

BUGS=[369165616]
This commit is contained in:
Sungun Park
2024-09-24 10:24:32 -07:00
committed by GitHub
parent fe15a3047e
commit 9d57ced452
9 changed files with 63 additions and 25 deletions

View File

@@ -30,10 +30,6 @@ namespace filament::backend {
struct TargetBufferInfo {
// note: the parameters of this constructor are not in the order of this structure's fields
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level, uint16_t layer, uint8_t baseViewIndex) noexcept
: handle(handle), baseViewIndex(baseViewIndex), level(level), layer(layer) {
}
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
: handle(handle), level(level), layer(layer) {
}
@@ -51,14 +47,15 @@ struct TargetBufferInfo {
// texture to be used as render target
Handle<HwTexture> handle;
// Starting layer index for multiview. This value is only used when the `layerCount` for the
// render target is greater than 1.
uint8_t baseViewIndex = 0;
// level to be used
uint8_t level = 0;
// For cubemaps and 3D textures. See TextureCubemapFace for the face->layer mapping
// - For cubemap textures, this indicates the face of the cubemap. See TextureCubemapFace for
// the face->layer mapping)
// - For 2d array, cubemap array, and 3d textures, this indicates an index of a single layer of
// them.
// - For multiview textures (i.e., layerCount for the RenderTarget is greater than 1), this
// indicates a starting layer index of the current 2d array texture for multiview.
uint16_t layer = 0;
};
@@ -103,7 +100,7 @@ public:
// this is here for backward compatibility
MRT(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
: mInfos{{ handle, level, layer, 0 }} {
: mInfos{{ handle, level, layer }} {
}
};

View File

@@ -1213,7 +1213,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
if (layerCount > 1) {
// if layerCount > 1, it means we use the multiview extension.
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, attachment,
t->gl.id, 0, binfo.baseViewIndex, layerCount);
t->gl.id, 0, binfo.layer, layerCount);
} else
#endif // !defined(__EMSCRIPTEN__) && !defined(IOS)
{

View File

@@ -410,7 +410,6 @@ io::ostream& operator<<(io::ostream& out, const RasterState& rs) {
io::ostream& operator<<(io::ostream& out, const TargetBufferInfo& tbi) {
return out << "TargetBufferInfo{"
<< "handle=" << tbi.handle
<< ", baseViewIndex=" << tbi.baseViewIndex
<< ", level=" << tbi.level
<< ", layer=" << tbi.layer << "}";
}

View File

@@ -43,7 +43,6 @@ struct VulkanCommandBuffer;
struct VulkanAttachment {
VulkanTexture* texture = nullptr;
uint8_t level = 0;
uint8_t baseViewIndex = 0;
uint8_t layerCount = 1;
uint16_t layer = 0;

View File

@@ -595,7 +595,6 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
colorTargets[i] = {
.texture = mResourceAllocator.handle_cast<VulkanTexture*>(color[i].handle),
.level = color[i].level,
.baseViewIndex = color[i].baseViewIndex,
.layerCount = layerCount,
.layer = color[i].layer,
};
@@ -611,7 +610,6 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
depthStencil[0] = {
.texture = mResourceAllocator.handle_cast<VulkanTexture*>(depth.handle),
.level = depth.level,
.baseViewIndex = depth.baseViewIndex,
.layerCount = layerCount,
.layer = depth.layer,
};
@@ -625,7 +623,6 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
depthStencil[1] = {
.texture = mResourceAllocator.handle_cast<VulkanTexture*>(stencil.handle),
.level = stencil.level,
.baseViewIndex = stencil.baseViewIndex,
.layerCount = layerCount,
.layer = stencil.layer,
};

View File

@@ -118,7 +118,7 @@ public:
Builder& mipLevel(AttachmentPoint attachment, uint8_t level) noexcept;
/**
* Sets the cubemap face for a given attachment point.
* Sets the face for cubemap textures at the given attachment point.
*
* @param attachment The attachment point.
* @param face The associated cubemap face.
@@ -127,7 +127,12 @@ public:
Builder& face(AttachmentPoint attachment, CubemapFace face) noexcept;
/**
* Sets the layer for a given attachment point (for 3D textures).
* Sets an index of a single layer for 2d array, cubemap array, and 3d textures at the given
* attachment point.
*
* For cubemap array textures, layer is translated into an array index and face according to
* - index: layer / 6
* - face: layer % 6
*
* @param attachment The attachment point.
* @param layer The associated cubemap layer.
@@ -135,6 +140,19 @@ public:
*/
Builder& layer(AttachmentPoint attachment, uint32_t layer) noexcept;
/**
* Sets the starting index of the 2d array textures for multiview at the given attachment
* point.
*
* This requires COLOR and DEPTH attachments (if set) to be of 2D array textures.
*
* @param attachment The attachment point.
* @param layerCount The number of layers used for multiview, starting from baseLayer.
* @param baseLayer The starting index of the 2d array texture.
* @return A reference to this Builder for chaining calls.
*/
Builder& multiview(AttachmentPoint attachment, uint8_t layerCount, uint8_t baseLayer = 0) noexcept;
/**
* Creates the RenderTarget object and returns a pointer to it.
*

View File

@@ -44,6 +44,9 @@ struct RenderTarget::BuilderDetails {
uint32_t mWidth{};
uint32_t mHeight{};
uint8_t mSamples = 1; // currently not settable in the public facing API
// The number of layers for the render target. The value should be 1 except for multiview.
// If multiview is enabled, this value is appropriately updated based on the layerCount value
// from each attachment. Hence, #>1 means using multiview
uint8_t mLayerCount = 1;
};
@@ -75,6 +78,14 @@ RenderTarget::Builder& RenderTarget::Builder::layer(AttachmentPoint pt, uint32_t
return *this;
}
RenderTarget::Builder& RenderTarget::Builder::multiview(AttachmentPoint pt, uint8_t layerCount,
uint8_t baseLayer/*= 0*/) noexcept {
mImpl->mAttachments[(size_t)pt].layer = baseLayer;
mImpl->mAttachments[(size_t)pt].layerCount = layerCount;
return *this;
}
RenderTarget* RenderTarget::Builder::build(Engine& engine) {
using backend::TextureUsage;
const FRenderTarget::Attachment& color = mImpl->mAttachments[(size_t)AttachmentPoint::COLOR0];
@@ -105,28 +116,40 @@ RenderTarget* RenderTarget::Builder::build(Engine& engine) {
uint32_t maxWidth = 0;
uint32_t minHeight = std::numeric_limits<uint32_t>::max();
uint32_t maxHeight = 0;
uint32_t minDepth = std::numeric_limits<uint32_t>::max();
uint32_t maxDepth = 0;
uint32_t minLayerCount = std::numeric_limits<uint32_t>::max();
uint32_t maxLayerCount = 0;
for (auto const& attachment : mImpl->mAttachments) {
if (attachment.texture) {
const uint32_t w = attachment.texture->getWidth(attachment.mipLevel);
const uint32_t h = attachment.texture->getHeight(attachment.mipLevel);
const uint32_t d = attachment.texture->getDepth(attachment.mipLevel);
const uint32_t l = attachment.layerCount;
if (l > 0) {
FILAMENT_CHECK_PRECONDITION(
attachment.texture->getTarget() == Texture::Sampler::SAMPLER_2D_ARRAY)
<< "Texture sampler must be of 2d array for multiview";
}
FILAMENT_CHECK_PRECONDITION(attachment.layer + l <= d)
<< "layer + layerCount cannot exceed the number of depth";
minWidth = std::min(minWidth, w);
minHeight = std::min(minHeight, h);
minDepth = std::min(minDepth, d);
minLayerCount = std::min(minLayerCount, l);
maxWidth = std::max(maxWidth, w);
maxHeight = std::max(maxHeight, h);
maxDepth = std::max(maxDepth, d);
maxLayerCount = std::max(maxLayerCount, l);
}
}
FILAMENT_CHECK_PRECONDITION(minWidth == maxWidth && minHeight == maxHeight
&& minDepth == maxDepth) << "All attachments dimensions must match";
&& minLayerCount == maxLayerCount) << "All attachments dimensions must match";
mImpl->mWidth = minWidth;
mImpl->mHeight = minHeight;
mImpl->mLayerCount = minDepth;
if (minLayerCount > 0) {
// mLayerCount should be 1 except for multiview use where we update this variable
// to the number of layerCount for multiview.
mImpl->mLayerCount = minLayerCount;
}
return downcast(engine).createRenderTarget(*this);
}
@@ -141,7 +164,7 @@ FRenderTarget::FRenderTarget(FEngine& engine, const RenderTarget::Builder& build
backend::MRT mrt{};
TargetBufferInfo dinfo{};
auto setAttachment = [this](TargetBufferInfo& info, AttachmentPoint attachmentPoint) {
auto setAttachment = [&](TargetBufferInfo& info, AttachmentPoint attachmentPoint) {
Attachment const& attachment = mAttachments[(size_t)attachmentPoint];
auto t = downcast(attachment.texture);
info.handle = t->getHwHandle();

View File

@@ -39,6 +39,9 @@ public:
uint8_t mipLevel = 0;
CubemapFace face = RenderTarget::CubemapFace::POSITIVE_X;
uint32_t layer = 0;
// Indicates the number of layers used for multiview, starting from the `layer` (baseIndex).
// This means `layer` + `layerCount` cannot exceed the number of depth for the attachment.
uint16_t layerCount = 0;
};
FRenderTarget(FEngine& engine, const Builder& builder);

View File

@@ -224,6 +224,8 @@ int main(int argc, char** argv) {
app.stereoRenderTarget = RenderTarget::Builder()
.texture(RenderTarget::AttachmentPoint::COLOR, app.stereoColorTexture)
.texture(RenderTarget::AttachmentPoint::DEPTH, app.stereoDepthTexture)
.multiview(RenderTarget::AttachmentPoint::COLOR, eyeCount, 0)
.multiview(RenderTarget::AttachmentPoint::DEPTH, eyeCount, 0)
.build(*engine);
app.stereoView->setRenderTarget(app.stereoRenderTarget);
app.stereoView->setViewport({0, 0, vp.width, vp.height});