Skip to content
Open
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
1 change: 1 addition & 0 deletions src/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ add_executable(tests
core/priority_queue.cpp
core/internal_network/network.cpp
video_core/frame_dump_schedule.cpp
video_core/framebuffer_limits.cpp
video_core/memory_tracker.cpp
video_core/spirv_storage_alignment.cpp
video_core/pipeline_optimization.cpp
Expand Down
39 changes: 39 additions & 0 deletions src/tests/video_core/framebuffer_limits.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-3.0-or-later

#include <catch2/catch_test_macros.hpp>

#include "video_core/renderer_vulkan/framebuffer_limits.h"

namespace {
constexpr Vulkan::FramebufferSize APPLE_LIMITS{16384, 16384, 2048};
} // Anonymous namespace

TEST_CASE("Attachment-less framebuffers stay within the device limits",
"[video_core][framebuffer_limits]") {
const auto size = Vulkan::ClampFramebufferSize({32768, 32768, 1}, APPLE_LIMITS);
REQUIRE(size.width == 16384);
REQUIRE(size.height == 16384);
REQUIRE(size.layers == 1);
}

TEST_CASE("Framebuffer sizes within the device limits are unchanged",
"[video_core][framebuffer_limits]") {
const auto size = Vulkan::ClampFramebufferSize({1920, 1080, 6}, APPLE_LIMITS);
REQUIRE(size.width == 1920);
REQUIRE(size.height == 1080);
REQUIRE(size.layers == 6);
}

TEST_CASE("Framebuffer layers are clamped to the device limit",
"[video_core][framebuffer_limits]") {
const auto size = Vulkan::ClampFramebufferSize({64, 64, 4096}, APPLE_LIMITS);
REQUIRE(size.layers == 2048);
}

TEST_CASE("Framebuffers keep at least one pixel and one layer",
"[video_core][framebuffer_limits]") {
const auto size = Vulkan::ClampFramebufferSize({0, 0, 0}, APPLE_LIMITS);
REQUIRE(size.width == 1);
REQUIRE(size.height == 1);
REQUIRE(size.layers == 1);
}
1 change: 1 addition & 0 deletions src/video_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ add_library(video_core STATIC
renderer_vulkan/blit_image.h
renderer_vulkan/fixed_pipeline_state.cpp
renderer_vulkan/fixed_pipeline_state.h
renderer_vulkan/framebuffer_limits.h
renderer_vulkan/maxwell_to_vk.cpp
renderer_vulkan/maxwell_to_vk.h
renderer_vulkan/pipeline_helper.h
Expand Down
27 changes: 27 additions & 0 deletions src/video_core/renderer_vulkan/framebuffer_limits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <algorithm>

#include "common/common_types.h"

namespace Vulkan {

struct FramebufferSize {
u32 width;
u32 height;
u32 layers;
};

// Draws without attachments take their size from the surface clip, which games leave at
// 32768x32768. Apple GPUs allow 16384, and Metal loses the device on a larger framebuffer.
constexpr FramebufferSize ClampFramebufferSize(FramebufferSize size, FramebufferSize max) {
return {
(std::max)(1U, (std::min)(size.width, max.width)),
(std::max)(1U, (std::min)(size.height, max.height)),
(std::max)(1U, (std::min)(size.layers, max.layers)),
};
}

} // namespace Vulkan
8 changes: 7 additions & 1 deletion src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 128_MiB;
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 128_MiB;
#endif

// Unused space after the end of the stream buffer. Constant buffers are bound from it and the
// shaders declare each one at its full 64 KiB, so Metal checks 64 KiB from the binding offset
// against the end of the buffer ("argument c3[0] ... has space for 26624 bytes, but argument has a
// length(65536)"). The tail is never handed out, so every binding has the full 64 KiB behind it.
constexpr VkDeviceSize STREAM_BUFFER_TAIL = 64_KiB;

size_t GetStreamBufferSize(const Device& device) {
if (!device.HasDebuggingToolAttached()) {
if (device.IsIntegrated()) {
Expand Down Expand Up @@ -88,7 +94,7 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = stream_buffer_size,
.size = stream_buffer_size + STREAM_BUFFER_TAIL,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
Expand Down
8 changes: 8 additions & 0 deletions src/video_core/renderer_vulkan/vk_texture_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "video_core/engines/fermi_2d.h"
#include "video_core/renderer_vulkan/blit_image.h"
#include "video_core/renderer_vulkan/framebuffer_limits.h"
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
#include "video_core/renderer_vulkan/vk_compute_pass.h"
#include "video_core/renderer_vulkan/vk_render_pass_cache.h"
Expand Down Expand Up @@ -4501,6 +4502,13 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
runtime_ptr = &runtime;
render_area.width = (std::min)(render_area.width, width);
render_area.height = (std::min)(render_area.height, height);
const FramebufferSize size = ClampFramebufferSize(
{render_area.width, render_area.height,
static_cast<u32>((std::max)(num_layers, 1))},
{runtime.device.GetMaxFramebufferWidth(), runtime.device.GetMaxFramebufferHeight(),
runtime.device.GetMaxFramebufferLayers()});
render_area = VkExtent2D{.width = size.width, .height = size.height};
num_layers = static_cast<s32>(size.layers);

if (do_resolve_color) {
const u32 layers = static_cast<u32>((std::max)(num_layers, 1));
Expand Down
5 changes: 4 additions & 1 deletion src/video_core/vulkan_common/vulkan_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,10 @@ class Device {
FN_MAX_LIMIT_ELEM(DescriptorSetStorageBuffersDynamic) \
FN_MAX_LIMIT_ELEM(DescriptorSetSampledImages) \
FN_MAX_LIMIT_ELEM(DescriptorSetStorageImages) \
FN_MAX_LIMIT_ELEM(DescriptorSetInputAttachments)
FN_MAX_LIMIT_ELEM(DescriptorSetInputAttachments) \
FN_MAX_LIMIT_ELEM(FramebufferWidth) \
FN_MAX_LIMIT_ELEM(FramebufferHeight) \
FN_MAX_LIMIT_ELEM(FramebufferLayers)
#define FN_MAX_LIMIT_ELEM(name) \
u32 GetMax##name() const { return properties.properties.limits.max##name; }
FN_MAX_LIMIT_LIST
Expand Down
Loading