Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always use homogeneous attachment sizes #5679

Merged
merged 2 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions filament/backend/src/metal/MetalHandles.mm
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include <utils/trap.h>
#include <utils/debug.h>

#include <math/vec2.h>
#include <math/scalar.h>

#include <math.h>

namespace filament {
Expand Down Expand Up @@ -806,6 +809,10 @@ BufferDescriptor b(nullptr, 0u, [](void* buffer, size_t size, void* user) {
MetalRenderTarget::MetalRenderTarget(MetalContext* context, uint32_t width, uint32_t height,
uint8_t samples, Attachment colorAttachments[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT], Attachment depthAttachment) :
HwRenderTarget(width, height), context(context), samples(samples) {
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmin = {std::numeric_limits<size_t>::max()};
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmax = {0};
UTILS_UNUSED_IN_RELEASE size_t attachmentCount = 0;

for (size_t i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
if (!colorAttachments[i]) {
continue;
Expand All @@ -816,6 +823,13 @@ BufferDescriptor b(nullptr, 0u, [](void* buffer, size_t size, void* user) {
"MetalRenderTarget was initialized with a MSAA COLOR%d texture, but sample count is %d.",
i, samples);

auto t = color[i].metalTexture;
const auto twidth = std::max(1u, t->width >> color[i].level);
const auto theight = std::max(1u, t->height >> color[i].level);
tmin = { std::min(tmin.x, twidth), std::min(tmin.y, theight) };
tmax = { std::max(tmax.x, twidth), std::max(tmax.y, theight) };
attachmentCount++;

bejado marked this conversation as resolved.
Show resolved Hide resolved
// If we were given a single-sampled texture but the samples parameter is > 1, we create
// a multisampled sidecar texture and do a resolve automatically.
if (samples > 1 && color[i].getSampleCount() == 1) {
Expand All @@ -834,6 +848,13 @@ BufferDescriptor b(nullptr, 0u, [](void* buffer, size_t size, void* user) {
"MetalRenderTarget was initialized with a MSAA DEPTH texture, but sample count is %d.",
samples);

auto t = depth.metalTexture;
const auto twidth = std::max(1u, t->width >> depth.level);
const auto theight = std::max(1u, t->height >> depth.level);
tmin = { math::min(tmin.x, twidth), math::min(tmin.y, theight) };
tmax = { math::max(tmax.x, twidth), math::max(tmax.y, theight) };
attachmentCount++;

// If we were given a single-sampled texture but the samples parameter is > 1, we create
// a multisampled sidecar texture and do a resolve automatically.
if (samples > 1 && depth.getSampleCount() == 1) {
Expand All @@ -844,6 +865,10 @@ BufferDescriptor b(nullptr, 0u, [](void* buffer, size_t size, void* user) {
}
}
}

// Verify that all attachments have the same dimensions.
assert_invariant(attachmentCount > 0);
assert_invariant(tmin == tmax);
}

void MetalRenderTarget::setUpRenderPassAttachments(MTLRenderPassDescriptor* descriptor,
Expand Down
23 changes: 19 additions & 4 deletions filament/backend/src/opengl/OpenGLDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,12 +1076,17 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
rt->gl.samples = samples;
rt->targets = targets;

UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmin = {std::numeric_limits<uint32_t>::max()};
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmax = {0};

if (any(targets & TargetBufferFlags::COLOR_ALL)) {
GLenum bufs[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = { GL_NONE };
const size_t maxDrawBuffers = getMaxDrawBuffers();
for (size_t i = 0; i < maxDrawBuffers; i++) {
if (any(targets & getTargetBufferFlagsAt(i))) {
rt->gl.color[i] = handle_cast<GLTexture*>(color[i].handle);
auto t = rt->gl.color[i] = handle_cast<GLTexture*>(color[i].handle);
tmin = { std::min(tmin.x, t->width), std::min(tmin.y, t->height) };
tmax = { std::max(tmax.x, t->width), std::max(tmax.y, t->height) };
framebufferTexture(color[i], rt, GL_COLOR_ATTACHMENT0 + i);
bufs[i] = GL_COLOR_ATTACHMENT0 + i;
}
Expand All @@ -1094,7 +1099,9 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
bool specialCased = false;
if ((targets & TargetBufferFlags::DEPTH_AND_STENCIL) == TargetBufferFlags::DEPTH_AND_STENCIL) {
assert_invariant(!stencil.handle || stencil.handle == depth.handle);
rt->gl.depth = handle_cast<GLTexture*>(depth.handle);
auto t = rt->gl.depth = handle_cast<GLTexture*>(depth.handle);
tmin = { std::min(tmin.x, t->width), std::min(tmin.y, t->height) };
tmax = { std::max(tmax.x, t->width), std::max(tmax.y, t->height) };
if (any(rt->gl.depth->usage & TextureUsage::SAMPLEABLE) ||
(!depth.handle && !stencil.handle)) {
// special case: depth & stencil requested, and both provided as the same texture
Expand All @@ -1106,15 +1113,23 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,

if (!specialCased) {
if (any(targets & TargetBufferFlags::DEPTH)) {
rt->gl.depth = handle_cast<GLTexture*>(depth.handle);
auto t = rt->gl.depth = handle_cast<GLTexture*>(depth.handle);
tmin = { std::min(tmin.x, t->width), std::min(tmin.y, t->height) };
tmax = { std::max(tmax.x, t->width), std::max(tmax.y, t->height) };
framebufferTexture(depth, rt, GL_DEPTH_ATTACHMENT);
}
if (any(targets & TargetBufferFlags::STENCIL)) {
rt->gl.stencil = handle_cast<GLTexture*>(stencil.handle);
auto t = rt->gl.stencil = handle_cast<GLTexture*>(stencil.handle);
tmin = { std::min(tmin.x, t->width), std::min(tmin.y, t->height) };
tmax = { std::max(tmax.x, t->width), std::max(tmax.y, t->height) };
framebufferTexture(stencil, rt, GL_STENCIL_ATTACHMENT);
}
}

// Verify that all attachments have the same dimensions.
assert_invariant(any(targets & TargetBufferFlags::ALL));
assert_invariant(tmin == tmax);

CHECK_GL_ERROR(utils::slog.e)
}

Expand Down
22 changes: 19 additions & 3 deletions filament/backend/src/vulkan/VulkanDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,10 @@ void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int) {
void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
TargetBufferFlags targets, uint32_t width, uint32_t height, uint8_t samples,
MRT color, TargetBufferInfo depth, TargetBufferInfo stencil) {
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmin = {std::numeric_limits<uint32_t>::max()};
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmax = {0};
UTILS_UNUSED_IN_RELEASE size_t attachmentCount = 0;

VulkanAttachment colorTargets[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
if (color[i].handle) {
Expand All @@ -548,7 +552,9 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
.layer = color[i].layer,
};
UTILS_UNUSED_IN_RELEASE VkExtent2D extent = colorTargets[i].getExtent2D();
assert_invariant(extent.width >= width && extent.height >= height);
tmin = { std::min(tmin.x, extent.width), std::min(tmin.y, extent.height) };
tmax = { std::max(tmax.x, extent.width), std::max(tmax.y, extent.height) };
attachmentCount++;
}
}

Expand All @@ -560,7 +566,9 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
.layer = depth.layer,
};
UTILS_UNUSED_IN_RELEASE VkExtent2D extent = depthStencil[0].getExtent2D();
assert_invariant(extent.width >= width && extent.height >= height);
tmin = { std::min(tmin.x, extent.width), std::min(tmin.y, extent.height) };
tmax = { std::max(tmax.x, extent.width), std::max(tmax.y, extent.height) };
attachmentCount++;
}

if (stencil.handle) {
Expand All @@ -570,9 +578,17 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
.layer = stencil.layer,
};
UTILS_UNUSED_IN_RELEASE VkExtent2D extent = depthStencil[1].getExtent2D();
assert_invariant(extent.width >= width && extent.height >= height);
tmin = { std::min(tmin.x, extent.width), std::min(tmin.y, extent.height) };
tmax = { std::max(tmax.x, extent.width), std::max(tmax.y, extent.height) };
attachmentCount++;
}

// All attachments must have the same dimensions, which must be greater than or equal to the
// render target dimensions.
assert_invariant(attachmentCount > 0);
assert_invariant(tmin == tmax);
assert_invariant(tmin.x >= width && tmin.y >= height);

auto renderTarget = construct<VulkanRenderTarget>(rth, mContext,
width, height, samples, colorTargets, depthStencil, mStagePool);
mDisposer.createDisposable(renderTarget, [this, rth] () {
Expand Down
13 changes: 0 additions & 13 deletions filament/src/ResourceAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,19 +129,6 @@ backend::TextureHandle ResourceAllocator::createTexture(const char* name,
uint32_t width, uint32_t height, uint32_t depth,
std::array<backend::TextureSwizzle, 4> swizzle,
backend::TextureUsage usage) noexcept {

// Some WebGL implementations complain about an incomplete framebuffer when the attachment sizes
// are heterogeneous. This merits further investigation.
#if !defined(__EMSCRIPTEN__)
if (!(usage & TextureUsage::SAMPLEABLE)) {
// If this texture is not going to be sampled, we can round its size up
// this helps prevent many reallocations for small size changes.
// We round to 16 pixels, which works for 720p btw.
width = (width + 15u) & ~15u;
height = (height + 15u) & ~15u;
}
#endif

// The frame graph descriptor uses "0" to mean "auto" but the sample count that is passed to the
// backend should always be 1 or greater.
samples = samples ? samples : uint8_t(1);
Expand Down
2 changes: 2 additions & 0 deletions filament/src/fg/PassNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ void RenderPassNode::resolve() noexcept {
rt.descriptor.clearFlags & rt.targetBufferFlags);
}

assert_invariant(minWidth == maxWidth);
assert_invariant(minHeight == maxHeight);
assert_invariant(any(rt.targetBufferFlags));

// of all attachments size matches there are no ambiguity about the RT size.
Expand Down