forked from suyu/suyu
vk_texture_cache: Use 3D to scale images when blit is unsupported
This commit is contained in:
parent
4de584005f
commit
ebf36f23dd
4 changed files with 87 additions and 29 deletions
|
@ -363,7 +363,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
|
||||||
|
|
||||||
BlitImageHelper::~BlitImageHelper() = default;
|
BlitImageHelper::~BlitImageHelper() = default;
|
||||||
|
|
||||||
void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_view,
|
||||||
const Region2D& dst_region, const Region2D& src_region,
|
const Region2D& dst_region, const Region2D& src_region,
|
||||||
Tegra::Engines::Fermi2D::Filter filter,
|
Tegra::Engines::Fermi2D::Filter filter,
|
||||||
Tegra::Engines::Fermi2D::Operation operation) {
|
Tegra::Engines::Fermi2D::Operation operation) {
|
||||||
|
@ -373,7 +373,6 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
|
||||||
.operation = operation,
|
.operation = operation,
|
||||||
};
|
};
|
||||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||||
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
|
|
||||||
const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
|
const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
|
||||||
const VkPipeline pipeline = FindOrEmplacePipeline(key);
|
const VkPipeline pipeline = FindOrEmplacePipeline(key);
|
||||||
scheduler.RequestRenderpass(dst_framebuffer);
|
scheduler.RequestRenderpass(dst_framebuffer);
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
StateTracker& state_tracker, DescriptorPool& descriptor_pool);
|
StateTracker& state_tracker, DescriptorPool& descriptor_pool);
|
||||||
~BlitImageHelper();
|
~BlitImageHelper();
|
||||||
|
|
||||||
void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
void BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
|
||||||
const Region2D& dst_region, const Region2D& src_region,
|
const Region2D& dst_region, const Region2D& src_region,
|
||||||
Tegra::Engines::Fermi2D::Filter filter,
|
Tegra::Engines::Fermi2D::Filter filter,
|
||||||
Tegra::Engines::Fermi2D::Operation operation);
|
Tegra::Engines::Fermi2D::Operation operation);
|
||||||
|
|
|
@ -762,8 +762,8 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT && !is_src_msaa && !is_dst_msaa) {
|
if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT && !is_src_msaa && !is_dst_msaa) {
|
||||||
blit_image_helper.BlitColor(dst_framebuffer, src, dst_region, src_region, filter,
|
blit_image_helper.BlitColor(dst_framebuffer, src.Handle(Shader::TextureType::Color2D),
|
||||||
operation);
|
dst_region, src_region, filter, operation);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||||
|
@ -1131,18 +1131,10 @@ bool Image::ScaleUp() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto& device = runtime->device;
|
const auto& device = runtime->device;
|
||||||
const PixelFormat format = StorageFormat(info.format);
|
const bool is_2d = info.type == ImageType::e2D;
|
||||||
const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, format);
|
const u32 scaled_width = resolution.ScaleUp(info.size.width);
|
||||||
const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
|
const u32 scaled_height = is_2d ? resolution.ScaleUp(info.size.height) : info.size.height;
|
||||||
if (!device.IsFormatSupported(format_info.format, blit_usage, FormatType::Optimal)) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Device does not support scaling format {}", format);
|
|
||||||
// TODO: Use helper blits where applicable
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!scaled_image) {
|
if (!scaled_image) {
|
||||||
const bool is_2d = info.type == ImageType::e2D;
|
|
||||||
const u32 scaled_width = resolution.ScaleUp(info.size.width);
|
|
||||||
const u32 scaled_height = is_2d ? resolution.ScaleUp(info.size.height) : info.size.height;
|
|
||||||
auto scaled_info = info;
|
auto scaled_info = info;
|
||||||
scaled_info.size.width = scaled_width;
|
scaled_info.size.width = scaled_width;
|
||||||
scaled_info.size.height = scaled_height;
|
scaled_info.size.height = scaled_height;
|
||||||
|
@ -1150,11 +1142,56 @@ bool Image::ScaleUp() {
|
||||||
auto& allocator = runtime->memory_allocator;
|
auto& allocator = runtime->memory_allocator;
|
||||||
scaled_commit = MemoryCommit(allocator.Commit(scaled_image, MemoryUsage::DeviceLocal));
|
scaled_commit = MemoryCommit(allocator.Commit(scaled_image, MemoryUsage::DeviceLocal));
|
||||||
}
|
}
|
||||||
|
current_image = *scaled_image;
|
||||||
|
|
||||||
if (aspect_mask == 0) {
|
if (aspect_mask == 0) {
|
||||||
aspect_mask = ImageAspectMask(info.format);
|
aspect_mask = ImageAspectMask(info.format);
|
||||||
}
|
}
|
||||||
BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution);
|
static constexpr auto OPTIMAL_FORMAT = FormatType::Optimal;
|
||||||
current_image = *scaled_image;
|
const PixelFormat format = StorageFormat(info.format);
|
||||||
|
const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format;
|
||||||
|
const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
|
||||||
|
if (device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT)) {
|
||||||
|
BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution);
|
||||||
|
} else {
|
||||||
|
using namespace VideoCommon;
|
||||||
|
static constexpr auto BLIT_OPERATION = Tegra::Engines::Fermi2D::Operation::SrcCopy;
|
||||||
|
|
||||||
|
const auto view_info = ImageViewInfo(ImageViewType::e2D, info.format);
|
||||||
|
scale_view = std::make_unique<ImageView>(*runtime, view_info, NULL_IMAGE_ID, *this);
|
||||||
|
auto* view_ptr = scale_view.get();
|
||||||
|
|
||||||
|
const Region2D src_region{
|
||||||
|
.start = {0, 0},
|
||||||
|
.end = {static_cast<s32>(info.size.width), static_cast<s32>(info.size.height)},
|
||||||
|
};
|
||||||
|
const Region2D dst_region{
|
||||||
|
.start = {0, 0},
|
||||||
|
.end = {static_cast<s32>(scaled_width), static_cast<s32>(scaled_height)},
|
||||||
|
};
|
||||||
|
const VkExtent2D extent{
|
||||||
|
.width = scaled_width,
|
||||||
|
.height = scaled_height,
|
||||||
|
};
|
||||||
|
if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||||
|
scale_framebuffer = std::make_unique<Framebuffer>(*runtime, view_ptr, nullptr, extent);
|
||||||
|
const auto color_view = scale_view->Handle(Shader::TextureType::Color2D);
|
||||||
|
|
||||||
|
runtime->blit_image_helper.BlitColor(
|
||||||
|
scale_framebuffer.get(), color_view, dst_region, src_region,
|
||||||
|
Tegra::Engines::Fermi2D::Filter::Bilinear, BLIT_OPERATION);
|
||||||
|
} else if (!runtime->device.IsBlitDepthStencilSupported() &&
|
||||||
|
aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||||
|
scale_framebuffer = std::make_unique<Framebuffer>(*runtime, nullptr, view_ptr, extent);
|
||||||
|
runtime->blit_image_helper.BlitDepthStencil(
|
||||||
|
scale_framebuffer.get(), scale_view->DepthView(), scale_view->StencilView(),
|
||||||
|
dst_region, src_region, Tegra::Engines::Fermi2D::Filter::Point, BLIT_OPERATION);
|
||||||
|
} else {
|
||||||
|
// TODO: Use helper blits where applicable
|
||||||
|
LOG_ERROR(Render_Vulkan, "Device does not support scaling format {}", format);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
flags |= ImageFlagBits::Rescaled;
|
flags |= ImageFlagBits::Rescaled;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1370,7 +1407,27 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
|
||||||
}
|
}
|
||||||
|
|
||||||
Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers,
|
Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers,
|
||||||
ImageView* depth_buffer, const VideoCommon::RenderTargets& key) {
|
ImageView* depth_buffer, const VideoCommon::RenderTargets& key)
|
||||||
|
: render_area{VkExtent2D{
|
||||||
|
.width = key.size.width,
|
||||||
|
.height = key.size.height,
|
||||||
|
}} {
|
||||||
|
CreateFramebuffer(runtime, color_buffers, depth_buffer);
|
||||||
|
if (runtime.device.HasDebuggingToolAttached()) {
|
||||||
|
framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Framebuffer::Framebuffer(TextureCacheRuntime& runtime, ImageView* color_buffer,
|
||||||
|
ImageView* depth_buffer, VkExtent2D extent)
|
||||||
|
: render_area{extent} {
|
||||||
|
std::array<ImageView*, NUM_RT> color_buffers{color_buffer};
|
||||||
|
CreateFramebuffer(runtime, color_buffers, depth_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||||
|
std::span<ImageView*, NUM_RT> color_buffers,
|
||||||
|
ImageView* depth_buffer) {
|
||||||
std::vector<VkImageView> attachments;
|
std::vector<VkImageView> attachments;
|
||||||
RenderPassKey renderpass_key{};
|
RenderPassKey renderpass_key{};
|
||||||
s32 num_layers = 1;
|
s32 num_layers = 1;
|
||||||
|
@ -1408,10 +1465,6 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
|
||||||
|
|
||||||
renderpass = runtime.render_pass_cache.Get(renderpass_key);
|
renderpass = runtime.render_pass_cache.Get(renderpass_key);
|
||||||
|
|
||||||
render_area = VkExtent2D{
|
|
||||||
.width = key.size.width,
|
|
||||||
.height = key.size.height,
|
|
||||||
};
|
|
||||||
num_color_buffers = static_cast<u32>(num_colors);
|
num_color_buffers = static_cast<u32>(num_colors);
|
||||||
framebuffer = runtime.device.GetLogical().CreateFramebuffer({
|
framebuffer = runtime.device.GetLogical().CreateFramebuffer({
|
||||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||||
|
@ -1420,13 +1473,10 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
|
||||||
.renderPass = renderpass,
|
.renderPass = renderpass,
|
||||||
.attachmentCount = static_cast<u32>(attachments.size()),
|
.attachmentCount = static_cast<u32>(attachments.size()),
|
||||||
.pAttachments = attachments.data(),
|
.pAttachments = attachments.data(),
|
||||||
.width = key.size.width,
|
.width = render_area.width,
|
||||||
.height = key.size.height,
|
.height = render_area.height,
|
||||||
.layers = static_cast<u32>(std::max(num_layers, 1)),
|
.layers = static_cast<u32>(std::max(num_layers, 1)),
|
||||||
});
|
});
|
||||||
if (runtime.device.HasDebuggingToolAttached()) {
|
|
||||||
framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureCacheRuntime::AccelerateImageUpload(
|
void TextureCacheRuntime::AccelerateImageUpload(
|
||||||
|
|
|
@ -145,6 +145,9 @@ private:
|
||||||
vk::Image scaled_image{};
|
vk::Image scaled_image{};
|
||||||
MemoryCommit scaled_commit{};
|
MemoryCommit scaled_commit{};
|
||||||
VkImage current_image{};
|
VkImage current_image{};
|
||||||
|
|
||||||
|
std::unique_ptr<Framebuffer> scale_framebuffer;
|
||||||
|
std::unique_ptr<ImageView> scale_view;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ImageView : public VideoCommon::ImageViewBase {
|
class ImageView : public VideoCommon::ImageViewBase {
|
||||||
|
@ -221,9 +224,15 @@ private:
|
||||||
|
|
||||||
class Framebuffer {
|
class Framebuffer {
|
||||||
public:
|
public:
|
||||||
explicit Framebuffer(TextureCacheRuntime&, std::span<ImageView*, NUM_RT> color_buffers,
|
explicit Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers,
|
||||||
ImageView* depth_buffer, const VideoCommon::RenderTargets& key);
|
ImageView* depth_buffer, const VideoCommon::RenderTargets& key);
|
||||||
|
|
||||||
|
explicit Framebuffer(TextureCacheRuntime& runtime, ImageView* color_buffer,
|
||||||
|
ImageView* depth_buffer, VkExtent2D extent);
|
||||||
|
|
||||||
|
void CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||||
|
std::span<ImageView*, NUM_RT> color_buffers, ImageView* depth_buffer);
|
||||||
|
|
||||||
[[nodiscard]] VkFramebuffer Handle() const noexcept {
|
[[nodiscard]] VkFramebuffer Handle() const noexcept {
|
||||||
return *framebuffer;
|
return *framebuffer;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue