citra/src/video_core/renderer_vulkan/vk_texture_runtime.h
GPUCode dfa2fd0e0d
Add vulkan backend (#6512)
* code: Prepare frontend for vulkan support

* citra_qt: Add vulkan options to the GUI

* vk_instance: Collect tooling info

* renderer_vulkan: Add vulkan backend

* qt: Fix fullscreen and resize issues on macOS. (#47)

* qt: Fix bugged macOS full screen transition.

* renderer/vulkan: Fix swapchain recreation destroying in-use semaphore.

* renderer/vulkan: Make gl_Position invariant. (#48)

This fixes an issue with black artifacts in Pokemon games on Apple GPUs.
If the vertex calculations differ slightly between render passes, it can
cause parts of model faces to fail depth test.

* vk_renderpass_cache: Bump pixel format count

* android: Custom driver code

* vk_instance: Set moltenvk configuration

* rasterizer_cache: Proper surface unregister

* citra_qt: Fix invalid characters

* vk_rasterizer: Correct special unbind

* android: Allow async presentation toggle

* vk_graphics_pipeline: Fix async shader compilation

* We were actually waiting for the pipelines regardless of the setting, oops

* vk_rasterizer: More robust attribute loading

* android: Move PollEvents to OpenGL window

* Vulkan does not need this and it causes problems

* vk_instance: Enable robust buffer access

* Improves stability on mali devices

* vk_renderpass_cache: Bring back renderpass flushing

* externals: Update vulkan-headers

* gl_rasterizer: Separable shaders for everyone

* vk_blit_helper: Corect depth to color convertion

* renderer_vulkan: Implement reinterpretation with copy

* Allows reinterpreteration with simply copy on AMD

* vk_graphics_pipeline: Only fast compile if no shaders are pending

* With this shaders weren't being compiled in parallel

* vk_swapchain: Ensure vsync doesn't lock framerate

* vk_present_window: Match guest swapchain size to vulkan image count

* Less latency and fixes crashes that were caused by images being deleted before free

* vk_instance: Blacklist VK_EXT_pipeline_creation_cache_control with nvidia gpus

* Resolves crashes when async shader compilation is enabled

* vk_rasterizer: Bump async threshold to 6

* Many games have fullscreen quads with 6 vertices. Fixes pokemon textures missing with async shaders

* android: More robust surface recreation

* renderer_vulkan: Fix dynamic state being lost

* vk_pipeline_cache: Skip cache save when no pipeline cache exists

* This is the cache when loading a save state

* sdl: Fix surface initialization on macOS. (#49)

* sdl: Fix surface initialization on macOS.

* sdl: Fix render window events not being handled under Vulkan.

* renderer/vulkan: Fix binding/unbinding of shadow rendering buffer.

* vk_stream_buffer: Respect non coherent access alignment

* Required by nvidia GPUs on MacOS

* renderer/vulkan: Support VK_EXT_fragment_shader_interlock for shadow rendering. (#51)

* renderer_vulkan: Port some recent shader fixes

* vk_pipeline_cache: Improve shadow detection

* vk_swapchain: Add missing check

* renderer_vulkan: Fix hybrid screen

* Revert "gl_rasterizer: Separable shaders for everyone"

Causes crashes on mali GPUs, will need separate PR

This reverts commit d22d556d30.

* renderer_vulkan: Fix flipped screenshot

---------

Co-authored-by: Steveice10 <1269164+Steveice10@users.noreply.github.com>
2023-09-13 01:28:50 +03:00

299 lines
9.3 KiB
C++

// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <deque>
#include <span>
#include "video_core/rasterizer_cache/framebuffer_base.h"
#include "video_core/rasterizer_cache/rasterizer_cache_base.h"
#include "video_core/rasterizer_cache/surface_base.h"
#include "video_core/renderer_vulkan/vk_blit_helper.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
VK_DEFINE_HANDLE(VmaAllocation)
namespace VideoCore {
struct Material;
}
namespace Vulkan {
class Instance;
class RenderpassCache;
class DescriptorPool;
class DescriptorSetProvider;
class Surface;
struct Handle {
VmaAllocation alloc;
vk::Image image;
vk::UniqueImageView image_view;
};
/**
* Provides texture manipulation functions to the rasterizer cache
* Separating this into a class makes it easier to abstract graphics API code
*/
class TextureRuntime {
friend class Surface;
public:
explicit TextureRuntime(const Instance& instance, Scheduler& scheduler,
RenderpassCache& renderpass_cache, DescriptorPool& pool,
DescriptorSetProvider& texture_provider, u32 num_swapchain_images);
~TextureRuntime();
const Instance& GetInstance() const {
return instance;
}
Scheduler& GetScheduler() const {
return scheduler;
}
RenderpassCache& GetRenderpassCache() {
return renderpass_cache;
}
/// Returns the removal threshold ticks for the garbage collector
u32 RemoveThreshold();
/// Submits and waits for current GPU work.
void Finish();
/// Maps an internal staging buffer of the provided size for pixel uploads/downloads
VideoCore::StagingData FindStaging(u32 size, bool upload);
/// Attempts to reinterpret a rectangle of source to another rectangle of dest
bool Reinterpret(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy);
/// Fills the rectangle of the texture with the clear value provided
bool ClearTexture(Surface& surface, const VideoCore::TextureClear& clear);
/// Copies a rectangle of src_tex to another rectange of dst_rect
bool CopyTextures(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy);
/// Blits a rectangle of src_tex to another rectange of dst_rect
bool BlitTextures(Surface& surface, Surface& dest, const VideoCore::TextureBlit& blit);
/// Generates mipmaps for all the available levels of the texture
void GenerateMipmaps(Surface& surface);
/// Returns true if the provided pixel format needs convertion
bool NeedsConversion(VideoCore::PixelFormat format) const;
/// Removes any descriptor sets that contain the provided image view.
void FreeDescriptorSetsWithImage(vk::ImageView image_view);
private:
/// Clears a partial texture rect using a clear rectangle
void ClearTextureWithRenderpass(Surface& surface, const VideoCore::TextureClear& clear);
private:
const Instance& instance;
Scheduler& scheduler;
RenderpassCache& renderpass_cache;
DescriptorSetProvider& texture_provider;
BlitHelper blit_helper;
StreamBuffer upload_buffer;
StreamBuffer download_buffer;
u32 num_swapchain_images;
};
class Surface : public VideoCore::SurfaceBase {
friend class TextureRuntime;
public:
explicit Surface(TextureRuntime& runtime, const VideoCore::SurfaceParams& params);
explicit Surface(TextureRuntime& runtime, const VideoCore::SurfaceBase& surface,
const VideoCore::Material* materal);
~Surface();
Surface(const Surface&) = delete;
Surface& operator=(const Surface&) = delete;
Surface(Surface&& o) noexcept = default;
Surface& operator=(Surface&& o) noexcept = default;
vk::ImageAspectFlags Aspect() const noexcept {
return traits.aspect;
}
/// Returns the image at index, otherwise the base image
vk::Image Image(u32 index = 1) const noexcept;
/// Returns the image view at index, otherwise the base view
vk::ImageView ImageView(u32 index = 1) const noexcept;
/// Returns a copy of the upscaled image handle, used for feedback loops.
vk::ImageView CopyImageView() noexcept;
/// Returns the framebuffer view of the surface image
vk::ImageView FramebufferView() noexcept;
/// Returns the depth view of the surface image
vk::ImageView DepthView() noexcept;
/// Returns the stencil view of the surface image
vk::ImageView StencilView() noexcept;
/// Returns the R32 image view used for atomic load/store
vk::ImageView StorageView() noexcept;
/// Returns a framebuffer handle for rendering to this surface
vk::Framebuffer Framebuffer() noexcept;
/// Uploads pixel data in staging to a rectangle region of the surface texture
void Upload(const VideoCore::BufferTextureCopy& upload, const VideoCore::StagingData& staging);
/// Uploads the custom material to the surface allocation.
void UploadCustom(const VideoCore::Material* material, u32 level);
/// Downloads pixel data to staging from a rectangle region of the surface texture
void Download(const VideoCore::BufferTextureCopy& download,
const VideoCore::StagingData& staging);
/// Scales up the surface to match the new resolution scale.
void ScaleUp(u32 new_scale);
/// Returns the bpp of the internal surface format
u32 GetInternalBytesPerPixel() const;
/// Returns the access flags indicative of the surface
vk::AccessFlags AccessFlags() const noexcept;
/// Returns the pipeline stage flags indicative of the surface
vk::PipelineStageFlags PipelineStageFlags() const noexcept;
private:
/// Performs blit between the scaled/unscaled images
void BlitScale(const VideoCore::TextureBlit& blit, bool up_scale);
/// Downloads scaled depth stencil data
void DepthStencilDownload(const VideoCore::BufferTextureCopy& download,
const VideoCore::StagingData& staging);
public:
TextureRuntime* runtime;
const Instance* instance;
Scheduler* scheduler;
FormatTraits traits;
std::array<Handle, 3> handles{};
std::array<vk::UniqueFramebuffer, 2> framebuffers{};
Handle copy_handle;
vk::UniqueImageView depth_view;
vk::UniqueImageView stencil_view;
vk::UniqueImageView storage_view;
bool is_framebuffer{};
bool is_storage{};
};
class Framebuffer : public VideoCore::FramebufferParams {
public:
explicit Framebuffer(TextureRuntime& runtime, const VideoCore::FramebufferParams& params,
Surface* color, Surface* depth_stencil);
~Framebuffer();
Framebuffer(const Framebuffer&) = delete;
Framebuffer& operator=(const Framebuffer&) = delete;
Framebuffer(Framebuffer&& o) noexcept = default;
Framebuffer& operator=(Framebuffer&& o) noexcept = default;
VideoCore::PixelFormat Format(VideoCore::SurfaceType type) const noexcept {
return formats[Index(type)];
}
[[nodiscard]] vk::ImageView ImageView(VideoCore::SurfaceType type) const noexcept {
return image_views[Index(type)];
}
[[nodiscard]] vk::Framebuffer Handle() const noexcept {
return framebuffer.get();
}
[[nodiscard]] std::array<vk::Image, 2> Images() const noexcept {
return images;
}
[[nodiscard]] std::array<vk::ImageAspectFlags, 2> Aspects() const noexcept {
return aspects;
}
[[nodiscard]] vk::RenderPass RenderPass() const noexcept {
return render_pass;
}
u32 Scale() const noexcept {
return res_scale;
}
u32 Width() const noexcept {
return width;
}
u32 Height() const noexcept {
return height;
}
private:
std::array<vk::Image, 2> images{};
std::array<vk::ImageView, 2> image_views{};
vk::UniqueFramebuffer framebuffer;
vk::RenderPass render_pass;
std::array<vk::ImageAspectFlags, 2> aspects{};
std::array<VideoCore::PixelFormat, 2> formats{VideoCore::PixelFormat::Invalid,
VideoCore::PixelFormat::Invalid};
u32 width{};
u32 height{};
u32 res_scale{1};
};
class Sampler {
public:
Sampler(TextureRuntime& runtime, const VideoCore::SamplerParams& params);
~Sampler();
Sampler(const Sampler&) = delete;
Sampler& operator=(const Sampler&) = delete;
Sampler(Sampler&& o) noexcept = default;
Sampler& operator=(Sampler&& o) noexcept = default;
[[nodiscard]] vk::Sampler Handle() const noexcept {
return sampler.get();
}
private:
vk::UniqueSampler sampler;
};
class DebugScope {
public:
template <typename... T>
explicit DebugScope(TextureRuntime& runtime, Common::Vec4f color,
fmt::format_string<T...> format, T... args)
: DebugScope{runtime, color, fmt::format(format, std::forward<T>(args)...)} {}
explicit DebugScope(TextureRuntime& runtime, Common::Vec4f color, std::string_view label);
~DebugScope();
private:
Scheduler& scheduler;
bool has_debug_tool;
};
struct Traits {
using Runtime = Vulkan::TextureRuntime;
using Surface = Vulkan::Surface;
using Sampler = Vulkan::Sampler;
using Framebuffer = Vulkan::Framebuffer;
using DebugScope = Vulkan::DebugScope;
};
using RasterizerCache = VideoCore::RasterizerCache<Traits>;
} // namespace Vulkan