[UI] Image post-processing and full presentation/window rework
[GPU] Add FXAA post-processing [UI] Add FidelityFX FSR and CAS post-processing [UI] Add blue noise dithering from 10bpc to 8bpc [GPU] Apply the DC PWL gamma ramp closer to the spec, supporting fully white color [UI] Allow the GPU CP thread to present on the host directly, bypassing the UI thread OS paint event [UI] Allow variable refresh rate (or tearing) [UI] Present the newest frame (restart) on DXGI [UI] Replace GraphicsContext with a far more advanced Presenter with more coherent surface connection and UI overlay state management [UI] Connect presentation to windows via the Surface class, not native window handles [Vulkan] Switch to simpler Vulkan setup with no instance/device separation due to interdependencies and to pass fewer objects around [Vulkan] Lower the minimum required Vulkan version to 1.0 [UI/GPU] Various cleanup, mainly ComPtr usage [UI] Support per-monitor DPI awareness v2 on Windows [UI] DPI-scale Dear ImGui [UI] Replace the remaining non-detachable window delegates with unified window event and input listeners [UI] Allow listeners to safely destroy or close the window, and to register/unregister listeners without use-after-free and the ABA problem [UI] Explicit Z ordering of input listeners and UI overlays, top-down for input, bottom-up for drawing [UI] Add explicit window lifecycle phases [UI] Replace Window virtual functions with explicit desired state, its application, actual state, its feedback [UI] GTK: Apply the initial size to the drawing area [UI] Limit internal UI frame rate to that of the monitor [UI] Hide the cursor using a timer instead of polling due to no repeated UI thread paints with GPU CP thread presentation, and only within the window
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -10,66 +10,166 @@
|
||||
#ifndef XENIA_UI_VULKAN_VULKAN_IMMEDIATE_DRAWER_H_
|
||||
#define XENIA_UI_VULKAN_VULKAN_IMMEDIATE_DRAWER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/ui/immediate_drawer.h"
|
||||
#include "xenia/ui/vulkan/vulkan.h"
|
||||
#include "xenia/ui/vulkan/vulkan_upload_buffer_pool.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace vulkan {
|
||||
|
||||
class LightweightCircularBuffer;
|
||||
class VulkanContext;
|
||||
|
||||
class VulkanImmediateDrawer : public ImmediateDrawer {
|
||||
public:
|
||||
VulkanImmediateDrawer(VulkanContext* graphics_context);
|
||||
~VulkanImmediateDrawer() override;
|
||||
static std::unique_ptr<VulkanImmediateDrawer> Create(
|
||||
const VulkanProvider& provider) {
|
||||
auto immediate_drawer = std::unique_ptr<VulkanImmediateDrawer>(
|
||||
new VulkanImmediateDrawer(provider));
|
||||
if (!immediate_drawer->Initialize()) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::move(immediate_drawer);
|
||||
}
|
||||
|
||||
VkResult Initialize();
|
||||
void Shutdown();
|
||||
~VulkanImmediateDrawer();
|
||||
|
||||
std::unique_ptr<ImmediateTexture> CreateTexture(uint32_t width,
|
||||
uint32_t height,
|
||||
ImmediateTextureFilter filter,
|
||||
bool repeat,
|
||||
bool is_repeated,
|
||||
const uint8_t* data) override;
|
||||
std::unique_ptr<ImmediateTexture> WrapTexture(VkImageView image_view,
|
||||
VkSampler sampler,
|
||||
uint32_t width,
|
||||
uint32_t height);
|
||||
|
||||
void Begin(int render_target_width, int render_target_height) override;
|
||||
void Begin(UIDrawContext& ui_draw_context, float coordinate_space_width,
|
||||
float coordinate_space_height) override;
|
||||
void BeginDrawBatch(const ImmediateDrawBatch& batch) override;
|
||||
void Draw(const ImmediateDraw& draw) override;
|
||||
void EndDrawBatch() override;
|
||||
void End() override;
|
||||
|
||||
VkSampler GetSampler(ImmediateTextureFilter filter, bool repeat);
|
||||
protected:
|
||||
void OnLeavePresenter() override;
|
||||
|
||||
private:
|
||||
VulkanContext* context_ = nullptr;
|
||||
struct PushConstants {
|
||||
struct Vertex {
|
||||
float coordinate_space_size_inv[2];
|
||||
} vertex;
|
||||
};
|
||||
|
||||
struct {
|
||||
VkSampler nearest_clamp = nullptr;
|
||||
VkSampler nearest_repeat = nullptr;
|
||||
VkSampler linear_clamp = nullptr;
|
||||
VkSampler linear_repeat = nullptr;
|
||||
} samplers_;
|
||||
class VulkanImmediateTexture : public ImmediateTexture {
|
||||
public:
|
||||
struct Resource {
|
||||
VkImage image;
|
||||
VkDeviceMemory memory;
|
||||
VkImageView image_view;
|
||||
uint32_t descriptor_index;
|
||||
};
|
||||
|
||||
VkDescriptorSetLayout texture_set_layout_ = nullptr;
|
||||
VkDescriptorPool descriptor_pool_ = nullptr;
|
||||
VkPipelineLayout pipeline_layout_ = nullptr;
|
||||
VkPipeline triangle_pipeline_ = nullptr;
|
||||
VkPipeline line_pipeline_ = nullptr;
|
||||
VulkanImmediateTexture(uint32_t width, uint32_t height)
|
||||
: ImmediateTexture(width, height), immediate_drawer_(nullptr) {}
|
||||
~VulkanImmediateTexture() override;
|
||||
|
||||
std::unique_ptr<LightweightCircularBuffer> circular_buffer_;
|
||||
// If null, this is either a blank texture, or the immediate drawer has been
|
||||
// destroyed.
|
||||
VulkanImmediateDrawer* immediate_drawer_;
|
||||
size_t immediate_drawer_index_;
|
||||
// Invalid if immediate_drawer_ is null, since it's managed by the immediate
|
||||
// drawer.
|
||||
Resource resource_;
|
||||
size_t pending_upload_index_;
|
||||
uint64_t last_usage_submission_ = 0;
|
||||
};
|
||||
|
||||
bool batch_has_index_buffer_ = false;
|
||||
VkCommandBuffer current_cmd_buffer_ = nullptr;
|
||||
int current_render_target_width_ = 0;
|
||||
int current_render_target_height_ = 0;
|
||||
struct TextureDescriptorPool {
|
||||
// Using uint64_t for recycled bits.
|
||||
static constexpr uint32_t kDescriptorCount = 64;
|
||||
VkDescriptorPool pool;
|
||||
VkDescriptorSet sets[kDescriptorCount];
|
||||
uint32_t index;
|
||||
uint32_t unallocated_count;
|
||||
uint64_t recycled_bits;
|
||||
TextureDescriptorPool* unallocated_next;
|
||||
TextureDescriptorPool* recycled_next;
|
||||
};
|
||||
|
||||
VulkanImmediateDrawer(const VulkanProvider& provider) : provider_(provider) {}
|
||||
bool Initialize();
|
||||
|
||||
bool EnsurePipelinesCreatedForCurrentRenderPass();
|
||||
|
||||
// Allocates a combined image sampler in a pool and returns its index, or
|
||||
// UINT32_MAX in case of failure.
|
||||
uint32_t AllocateTextureDescriptor();
|
||||
VkDescriptorSet GetTextureDescriptor(uint32_t descriptor_index) const;
|
||||
void FreeTextureDescriptor(uint32_t descriptor_index);
|
||||
|
||||
// If data is null, a (1, 1, 1, 1) image will be created, which can be used as
|
||||
// a replacement when drawing without a real texture.
|
||||
bool CreateTextureResource(uint32_t width, uint32_t height,
|
||||
ImmediateTextureFilter filter, bool is_repeated,
|
||||
const uint8_t* data,
|
||||
VulkanImmediateTexture::Resource& resource_out,
|
||||
size_t& pending_upload_index_out);
|
||||
void DestroyTextureResource(VulkanImmediateTexture::Resource& resource);
|
||||
void OnImmediateTextureDestroyed(VulkanImmediateTexture& texture);
|
||||
|
||||
const VulkanProvider& provider_;
|
||||
|
||||
// Combined image sampler pools for textures.
|
||||
VkDescriptorSetLayout texture_descriptor_set_layout_;
|
||||
std::vector<TextureDescriptorPool*> texture_descriptor_pools_;
|
||||
TextureDescriptorPool* texture_descriptor_pool_unallocated_first_ = nullptr;
|
||||
TextureDescriptorPool* texture_descriptor_pool_recycled_first_ = nullptr;
|
||||
|
||||
VulkanImmediateTexture::Resource white_texture_ = {};
|
||||
std::vector<VulkanImmediateTexture*> textures_;
|
||||
struct PendingTextureUpload {
|
||||
// Null for internal resources such as the white texture.
|
||||
VulkanImmediateTexture* texture;
|
||||
// VK_NULL_HANDLE if need to clear rather than to copy.
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory buffer_memory;
|
||||
VkImage image;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
std::vector<PendingTextureUpload> texture_uploads_pending_;
|
||||
struct SubmittedTextureUploadBuffer {
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory buffer_memory;
|
||||
uint64_t submission_index;
|
||||
};
|
||||
std::deque<SubmittedTextureUploadBuffer> texture_upload_buffers_submitted_;
|
||||
// Resource and last usage submission pairs.
|
||||
std::vector<std::pair<VulkanImmediateTexture::Resource, uint64_t>>
|
||||
textures_deleted_;
|
||||
|
||||
std::unique_ptr<VulkanUploadBufferPool> vertex_buffer_pool_;
|
||||
|
||||
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
|
||||
|
||||
VkFormat pipeline_framebuffer_format_ = VK_FORMAT_UNDEFINED;
|
||||
VkPipeline pipeline_triangle_ = VK_NULL_HANDLE;
|
||||
VkPipeline pipeline_line_ = VK_NULL_HANDLE;
|
||||
|
||||
// The submission index within the current Begin (or the last, if outside
|
||||
// one).
|
||||
uint64_t last_paint_submission_index_ = 0;
|
||||
// Completed submission index as of the latest Begin, to coarsely skip delayed
|
||||
// texture deletion.
|
||||
uint64_t last_completed_submission_index_ = 0;
|
||||
|
||||
VkCommandBuffer current_command_buffer_ = VK_NULL_HANDLE;
|
||||
VkExtent2D current_render_target_extent_;
|
||||
VkRect2D current_scissor_;
|
||||
VkPipeline current_pipeline_;
|
||||
uint32_t current_texture_descriptor_index_;
|
||||
bool batch_open_ = false;
|
||||
bool batch_has_index_buffer_;
|
||||
};
|
||||
|
||||
} // namespace vulkan
|
||||
|
||||
Reference in New Issue
Block a user