early-access version 2790
This commit is contained in:
@@ -184,7 +184,7 @@ struct FormatTuple {
|
||||
{VK_FORMAT_BC3_SRGB_BLOCK}, // BC3_SRGB
|
||||
{VK_FORMAT_BC7_SRGB_BLOCK}, // BC7_SRGB
|
||||
{VK_FORMAT_R4G4B4A4_UNORM_PACK16, Attachable}, // A4B4G4R4_UNORM
|
||||
{VK_FORMAT_R4G4_UNORM_PACK8}, // R4G4_UNORM
|
||||
{VK_FORMAT_R4G4_UNORM_PACK8}, // G4R4_UNORM
|
||||
{VK_FORMAT_ASTC_4x4_SRGB_BLOCK}, // ASTC_2D_4X4_SRGB
|
||||
{VK_FORMAT_ASTC_8x8_SRGB_BLOCK}, // ASTC_2D_8X8_SRGB
|
||||
{VK_FORMAT_ASTC_8x5_SRGB_BLOCK}, // ASTC_2D_8X5_SRGB
|
||||
|
@@ -102,13 +102,13 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
|
||||
debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
|
||||
surface(CreateSurface(instance, render_window)),
|
||||
device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false),
|
||||
state_tracker(gpu), scheduler(device, state_tracker),
|
||||
state_tracker(), scheduler(device, state_tracker),
|
||||
swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
|
||||
render_window.GetFramebufferLayout().height, false),
|
||||
blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler,
|
||||
screen_info),
|
||||
rasterizer(render_window, gpu, gpu.MemoryManager(), cpu_memory, screen_info, device,
|
||||
memory_allocator, state_tracker, scheduler) {
|
||||
rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator,
|
||||
state_tracker, scheduler) {
|
||||
Report();
|
||||
} catch (const vk::Exception& exception) {
|
||||
LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what());
|
||||
@@ -142,7 +142,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
|
||||
const auto recreate_swapchain = [&] {
|
||||
if (!has_been_recreated) {
|
||||
has_been_recreated = true;
|
||||
scheduler.WaitWorker();
|
||||
scheduler.Finish();
|
||||
}
|
||||
const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout();
|
||||
swapchain.Create(layout.width, layout.height, is_srgb);
|
||||
|
@@ -126,8 +126,8 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
|
||||
const u32 secondary_offset{desc.secondary_cbuf_offset + index_offset};
|
||||
const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].Address() +
|
||||
secondary_offset};
|
||||
const u32 lhs_raw{gpu_memory.Read<u32>(addr)};
|
||||
const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)};
|
||||
const u32 lhs_raw{gpu_memory.Read<u32>(addr) << desc.shift_left};
|
||||
const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr) << desc.secondary_shift_left};
|
||||
return TexturePair(lhs_raw | rhs_raw, via_header_index);
|
||||
}
|
||||
}
|
||||
|
@@ -11,11 +11,8 @@
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
InnerFence::InnerFence(VKScheduler& scheduler_, u32 payload_, bool is_stubbed_)
|
||||
: FenceBase{payload_, is_stubbed_}, scheduler{scheduler_} {}
|
||||
|
||||
InnerFence::InnerFence(VKScheduler& scheduler_, GPUVAddr address_, u32 payload_, bool is_stubbed_)
|
||||
: FenceBase{address_, payload_, is_stubbed_}, scheduler{scheduler_} {}
|
||||
InnerFence::InnerFence(VKScheduler& scheduler_, bool is_stubbed_)
|
||||
: FenceBase{is_stubbed_}, scheduler{scheduler_} {}
|
||||
|
||||
InnerFence::~InnerFence() = default;
|
||||
|
||||
@@ -49,12 +46,8 @@ VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegr
|
||||
: GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_},
|
||||
scheduler{scheduler_} {}
|
||||
|
||||
Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) {
|
||||
return std::make_shared<InnerFence>(scheduler, value, is_stubbed);
|
||||
}
|
||||
|
||||
Fence VKFenceManager::CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) {
|
||||
return std::make_shared<InnerFence>(scheduler, addr, value, is_stubbed);
|
||||
Fence VKFenceManager::CreateFence(bool is_stubbed) {
|
||||
return std::make_shared<InnerFence>(scheduler, is_stubbed);
|
||||
}
|
||||
|
||||
void VKFenceManager::QueueFence(Fence& fence) {
|
||||
|
@@ -25,8 +25,7 @@ class VKScheduler;
|
||||
|
||||
class InnerFence : public VideoCommon::FenceBase {
|
||||
public:
|
||||
explicit InnerFence(VKScheduler& scheduler_, u32 payload_, bool is_stubbed_);
|
||||
explicit InnerFence(VKScheduler& scheduler_, GPUVAddr address_, u32 payload_, bool is_stubbed_);
|
||||
explicit InnerFence(VKScheduler& scheduler_, bool is_stubbed_);
|
||||
~InnerFence();
|
||||
|
||||
void Queue();
|
||||
@@ -52,8 +51,7 @@ public:
|
||||
VKScheduler& scheduler);
|
||||
|
||||
protected:
|
||||
Fence CreateFence(u32 value, bool is_stubbed) override;
|
||||
Fence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) override;
|
||||
Fence CreateFence(bool is_stubbed) override;
|
||||
void QueueFence(Fence& fence) override;
|
||||
bool IsFenceSignaled(Fence& fence) const override;
|
||||
void WaitFence(Fence& fence) override;
|
||||
|
@@ -215,15 +215,14 @@ ConfigureFuncPtr ConfigureFunc(const std::array<vk::ShaderModule, NUM_STAGES>& m
|
||||
} // Anonymous namespace
|
||||
|
||||
GraphicsPipeline::GraphicsPipeline(
|
||||
Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_,
|
||||
VKScheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_,
|
||||
VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool,
|
||||
VKUpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread,
|
||||
PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
|
||||
const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages,
|
||||
const std::array<const Shader::Info*, NUM_STAGES>& infos)
|
||||
: key{key_}, maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, device{device_},
|
||||
texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, scheduler{scheduler_},
|
||||
: key{key_}, device{device_}, texture_cache{texture_cache_},
|
||||
buffer_cache{buffer_cache_}, scheduler{scheduler_},
|
||||
update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} {
|
||||
if (shader_notify) {
|
||||
shader_notify->MarkShaderBuilding();
|
||||
@@ -288,7 +287,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
|
||||
buffer_cache.SetUniformBuffersState(enabled_uniform_buffer_masks, &uniform_buffer_sizes);
|
||||
|
||||
const auto& regs{maxwell3d.regs};
|
||||
const auto& regs{maxwell3d->regs};
|
||||
const bool via_header_index{regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex};
|
||||
const auto config_stage{[&](size_t stage) LAMBDA_FORCEINLINE {
|
||||
const Shader::Info& info{stage_infos[stage]};
|
||||
@@ -302,7 +301,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
++ssbo_index;
|
||||
}
|
||||
}
|
||||
const auto& cbufs{maxwell3d.state.shader_stages[stage].const_buffers};
|
||||
const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers};
|
||||
const auto read_handle{[&](const auto& desc, u32 index) {
|
||||
ASSERT(cbufs[desc.cbuf_index].enabled);
|
||||
const u32 index_offset{index << desc.size_shift};
|
||||
@@ -315,13 +314,14 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
const u32 second_offset{desc.secondary_cbuf_offset + index_offset};
|
||||
const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].address +
|
||||
second_offset};
|
||||
const u32 lhs_raw{gpu_memory.Read<u32>(addr)};
|
||||
const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)};
|
||||
const u32 lhs_raw{gpu_memory->Read<u32>(addr) << desc.shift_left};
|
||||
const u32 rhs_raw{gpu_memory->Read<u32>(separate_addr)
|
||||
<< desc.secondary_shift_left};
|
||||
const u32 raw{lhs_raw | rhs_raw};
|
||||
return TexturePair(raw, via_header_index);
|
||||
}
|
||||
}
|
||||
return TexturePair(gpu_memory.Read<u32>(addr), via_header_index);
|
||||
return TexturePair(gpu_memory->Read<u32>(addr), via_header_index);
|
||||
}};
|
||||
const auto add_image{[&](const auto& desc, bool blacklist) LAMBDA_FORCEINLINE {
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
|
@@ -69,15 +69,16 @@ class GraphicsPipeline {
|
||||
static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
|
||||
|
||||
public:
|
||||
explicit GraphicsPipeline(
|
||||
Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory,
|
||||
VKScheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache,
|
||||
VideoCore::ShaderNotify* shader_notify, const Device& device,
|
||||
DescriptorPool& descriptor_pool, VKUpdateDescriptorQueue& update_descriptor_queue,
|
||||
Common::ThreadWorker* worker_thread, PipelineStatistics* pipeline_statistics,
|
||||
RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key,
|
||||
std::array<vk::ShaderModule, NUM_STAGES> stages,
|
||||
const std::array<const Shader::Info*, NUM_STAGES>& infos);
|
||||
explicit GraphicsPipeline(VKScheduler& scheduler, BufferCache& buffer_cache,
|
||||
TextureCache& texture_cache, VideoCore::ShaderNotify* shader_notify,
|
||||
const Device& device, DescriptorPool& descriptor_pool,
|
||||
VKUpdateDescriptorQueue& update_descriptor_queue,
|
||||
Common::ThreadWorker* worker_thread,
|
||||
PipelineStatistics* pipeline_statistics,
|
||||
RenderPassCache& render_pass_cache,
|
||||
const GraphicsPipelineCacheKey& key,
|
||||
std::array<vk::ShaderModule, NUM_STAGES> stages,
|
||||
const std::array<const Shader::Info*, NUM_STAGES>& infos);
|
||||
|
||||
GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete;
|
||||
GraphicsPipeline(GraphicsPipeline&&) noexcept = delete;
|
||||
@@ -109,6 +110,11 @@ public:
|
||||
return [](GraphicsPipeline* pl, bool is_indexed) { pl->ConfigureImpl<Spec>(is_indexed); };
|
||||
}
|
||||
|
||||
void SetEngine(Tegra::Engines::Maxwell3D* maxwell3d_, Tegra::MemoryManager* gpu_memory_) {
|
||||
maxwell3d = maxwell3d_;
|
||||
gpu_memory = gpu_memory_;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Spec>
|
||||
void ConfigureImpl(bool is_indexed);
|
||||
@@ -120,8 +126,8 @@ private:
|
||||
void Validate();
|
||||
|
||||
const GraphicsPipelineCacheKey key;
|
||||
Tegra::Engines::Maxwell3D& maxwell3d;
|
||||
Tegra::MemoryManager& gpu_memory;
|
||||
Tegra::Engines::Maxwell3D* maxwell3d;
|
||||
Tegra::MemoryManager* gpu_memory;
|
||||
const Device& device;
|
||||
TextureCache& texture_cache;
|
||||
BufferCache& buffer_cache;
|
||||
|
@@ -259,17 +259,15 @@ bool GraphicsPipelineCacheKey::operator==(const GraphicsPipelineCacheKey& rhs) c
|
||||
return std::memcmp(&rhs, this, Size()) == 0;
|
||||
}
|
||||
|
||||
PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::Engines::Maxwell3D& maxwell3d_,
|
||||
Tegra::Engines::KeplerCompute& kepler_compute_,
|
||||
Tegra::MemoryManager& gpu_memory_, const Device& device_,
|
||||
PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device_,
|
||||
VKScheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||
VKUpdateDescriptorQueue& update_descriptor_queue_,
|
||||
RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_,
|
||||
TextureCache& texture_cache_, VideoCore::ShaderNotify& shader_notify_)
|
||||
: VideoCommon::ShaderCache{rasterizer_, gpu_memory_, maxwell3d_, kepler_compute_},
|
||||
device{device_}, scheduler{scheduler_}, descriptor_pool{descriptor_pool_},
|
||||
update_descriptor_queue{update_descriptor_queue_}, render_pass_cache{render_pass_cache_},
|
||||
buffer_cache{buffer_cache_}, texture_cache{texture_cache_}, shader_notify{shader_notify_},
|
||||
: VideoCommon::ShaderCache{rasterizer_}, device{device_}, scheduler{scheduler_},
|
||||
descriptor_pool{descriptor_pool_}, update_descriptor_queue{update_descriptor_queue_},
|
||||
render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_},
|
||||
texture_cache{texture_cache_}, shader_notify{shader_notify_},
|
||||
use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
|
||||
workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "yuzu:PipelineBuilder"),
|
||||
serialization_thread(1, "yuzu:PipelineSerialization") {
|
||||
@@ -337,7 +335,7 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() {
|
||||
current_pipeline = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
graphics_key.state.Refresh(maxwell3d, device.IsExtExtendedDynamicStateSupported(),
|
||||
graphics_key.state.Refresh(*maxwell3d, device.IsExtExtendedDynamicStateSupported(),
|
||||
device.IsExtVertexInputDynamicStateSupported());
|
||||
|
||||
if (current_pipeline) {
|
||||
@@ -357,7 +355,7 @@ ComputePipeline* PipelineCache::CurrentComputePipeline() {
|
||||
if (!shader) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto& qmd{kepler_compute.launch_description};
|
||||
const auto& qmd{kepler_compute->launch_description};
|
||||
const ComputePipelineCacheKey key{
|
||||
.unique_hash = shader->unique_hash,
|
||||
.shared_memory_size = qmd.shared_alloc,
|
||||
@@ -484,13 +482,13 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const
|
||||
}
|
||||
// If something is using depth, we can assume that games are not rendering anything which
|
||||
// will be used one time.
|
||||
if (maxwell3d.regs.zeta_enable) {
|
||||
if (maxwell3d->regs.zeta_enable) {
|
||||
return nullptr;
|
||||
}
|
||||
// If games are using a small index count, we can assume these are full screen quads.
|
||||
// Usually these shaders are only used once for building textures so we can assume they
|
||||
// can't be built async
|
||||
if (maxwell3d.regs.index_array.count <= 6 || maxwell3d.regs.vertex_buffer.count <= 6) {
|
||||
if (maxwell3d->regs.index_array.count <= 6 || maxwell3d->regs.vertex_buffer.count <= 6) {
|
||||
return pipeline;
|
||||
}
|
||||
return nullptr;
|
||||
@@ -555,10 +553,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
previous_stage = &program;
|
||||
}
|
||||
Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
|
||||
return std::make_unique<GraphicsPipeline>(
|
||||
maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, &shader_notify, device,
|
||||
descriptor_pool, update_descriptor_queue, thread_worker, statistics, render_pass_cache, key,
|
||||
std::move(modules), infos);
|
||||
return std::make_unique<GraphicsPipeline>(scheduler, buffer_cache, texture_cache,
|
||||
&shader_notify, device, descriptor_pool,
|
||||
update_descriptor_queue, thread_worker, statistics,
|
||||
render_pass_cache, key, std::move(modules), infos);
|
||||
|
||||
} catch (const Shader::Exception& exception) {
|
||||
LOG_ERROR(Render_Vulkan, "{}", exception.what());
|
||||
@@ -590,9 +588,9 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() {
|
||||
|
||||
std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
const ComputePipelineCacheKey& key, const ShaderInfo* shader) {
|
||||
const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()};
|
||||
const auto& qmd{kepler_compute.launch_description};
|
||||
ComputeEnvironment env{kepler_compute, gpu_memory, program_base, qmd.program_start};
|
||||
const GPUVAddr program_base{kepler_compute->regs.code_loc.Address()};
|
||||
const auto& qmd{kepler_compute->launch_description};
|
||||
ComputeEnvironment env{*kepler_compute, *gpu_memory, program_base, qmd.program_start};
|
||||
env.SetCachedSize(shader->size_bytes);
|
||||
|
||||
main_pools.ReleaseContents();
|
||||
|
@@ -100,9 +100,7 @@ struct ShaderPools {
|
||||
|
||||
class PipelineCache : public VideoCommon::ShaderCache {
|
||||
public:
|
||||
explicit PipelineCache(RasterizerVulkan& rasterizer, Tegra::Engines::Maxwell3D& maxwell3d,
|
||||
Tegra::Engines::KeplerCompute& kepler_compute,
|
||||
Tegra::MemoryManager& gpu_memory, const Device& device,
|
||||
explicit PipelineCache(RasterizerVulkan& rasterizer, const Device& device,
|
||||
VKScheduler& scheduler, DescriptorPool& descriptor_pool,
|
||||
VKUpdateDescriptorQueue& update_descriptor_queue,
|
||||
RenderPassCache& render_pass_cache, BufferCache& buffer_cache,
|
||||
|
@@ -65,10 +65,9 @@ void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) {
|
||||
usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false;
|
||||
}
|
||||
|
||||
VKQueryCache::VKQueryCache(VideoCore::RasterizerInterface& rasterizer_,
|
||||
Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_,
|
||||
const Device& device_, VKScheduler& scheduler_)
|
||||
: QueryCacheBase{rasterizer_, maxwell3d_, gpu_memory_}, device{device_}, scheduler{scheduler_},
|
||||
VKQueryCache::VKQueryCache(VideoCore::RasterizerInterface& rasterizer_, const Device& device_,
|
||||
VKScheduler& scheduler_)
|
||||
: QueryCacheBase{rasterizer_}, device{device_}, scheduler{scheduler_},
|
||||
query_pools{
|
||||
QueryPool{device_, scheduler_, QueryType::SamplesPassed},
|
||||
} {}
|
||||
|
@@ -52,9 +52,8 @@ private:
|
||||
class VKQueryCache final
|
||||
: public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter> {
|
||||
public:
|
||||
explicit VKQueryCache(VideoCore::RasterizerInterface& rasterizer_,
|
||||
Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_,
|
||||
const Device& device_, VKScheduler& scheduler_);
|
||||
explicit VKQueryCache(VideoCore::RasterizerInterface& rasterizer_, const Device& device_,
|
||||
VKScheduler& scheduler_);
|
||||
~VKQueryCache();
|
||||
|
||||
std::pair<VkQueryPool, u32> AllocateQuery(VideoCore::QueryType type);
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include "common/microprofile.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
#include "video_core/control/channel_state.h"
|
||||
#include "video_core/engines/kepler_compute.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/renderer_vulkan/blit_image.h"
|
||||
@@ -141,14 +142,11 @@ DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_instan
|
||||
} // Anonymous namespace
|
||||
|
||||
RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
|
||||
Tegra::MemoryManager& gpu_memory_,
|
||||
Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_,
|
||||
const Device& device_, MemoryAllocator& memory_allocator_,
|
||||
StateTracker& state_tracker_, VKScheduler& scheduler_)
|
||||
: RasterizerAccelerated{cpu_memory_}, gpu{gpu_},
|
||||
gpu_memory{gpu_memory_}, maxwell3d{gpu.Maxwell3D()}, kepler_compute{gpu.KeplerCompute()},
|
||||
screen_info{screen_info_}, device{device_}, memory_allocator{memory_allocator_},
|
||||
state_tracker{state_tracker_}, scheduler{scheduler_},
|
||||
: RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, screen_info{screen_info_}, device{device_},
|
||||
memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_},
|
||||
staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler),
|
||||
update_descriptor_queue(device, scheduler),
|
||||
blit_image(device, scheduler, state_tracker, descriptor_pool),
|
||||
@@ -158,14 +156,13 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
|
||||
memory_allocator, staging_pool,
|
||||
blit_image, astc_decoder_pass,
|
||||
render_pass_cache},
|
||||
texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory),
|
||||
texture_cache(texture_cache_runtime, *this),
|
||||
buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool,
|
||||
update_descriptor_queue, descriptor_pool),
|
||||
buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime),
|
||||
pipeline_cache(*this, maxwell3d, kepler_compute, gpu_memory, device, scheduler,
|
||||
descriptor_pool, update_descriptor_queue, render_pass_cache, buffer_cache,
|
||||
texture_cache, gpu.ShaderNotify()),
|
||||
query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, accelerate_dma{buffer_cache},
|
||||
buffer_cache(*this, cpu_memory_, buffer_cache_runtime),
|
||||
pipeline_cache(*this, device, scheduler, descriptor_pool, update_descriptor_queue,
|
||||
render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()),
|
||||
query_cache{*this, device, scheduler}, accelerate_dma{buffer_cache},
|
||||
fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
|
||||
wfi_event(device.GetLogical().CreateEvent()) {
|
||||
scheduler.SetQueryCache(query_cache);
|
||||
@@ -186,14 +183,16 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
|
||||
return;
|
||||
}
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
// update engine as channel may be different.
|
||||
pipeline->SetEngine(maxwell3d, gpu_memory);
|
||||
pipeline->Configure(is_indexed);
|
||||
|
||||
BeginTransformFeedback();
|
||||
|
||||
UpdateDynamicStates();
|
||||
|
||||
const auto& regs{maxwell3d.regs};
|
||||
const u32 num_instances{maxwell3d.mme_draw.instance_count};
|
||||
const auto& regs{maxwell3d->regs};
|
||||
const u32 num_instances{maxwell3d->mme_draw.instance_count};
|
||||
const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_instanced, is_indexed)};
|
||||
scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
|
||||
if (draw_params.is_indexed) {
|
||||
@@ -211,14 +210,14 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
|
||||
void RasterizerVulkan::Clear() {
|
||||
MICROPROFILE_SCOPE(Vulkan_Clearing);
|
||||
|
||||
if (!maxwell3d.ShouldExecute()) {
|
||||
if (!maxwell3d->ShouldExecute()) {
|
||||
return;
|
||||
}
|
||||
FlushWork();
|
||||
|
||||
query_cache.UpdateCounters();
|
||||
|
||||
auto& regs = maxwell3d.regs;
|
||||
auto& regs = maxwell3d->regs;
|
||||
const bool use_color = regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
|
||||
regs.clear_buffers.A;
|
||||
const bool use_depth = regs.clear_buffers.Z;
|
||||
@@ -241,8 +240,15 @@ void RasterizerVulkan::Clear() {
|
||||
}
|
||||
UpdateViewportsState(regs);
|
||||
|
||||
VkRect2D default_scissor;
|
||||
default_scissor.offset.x = 0;
|
||||
default_scissor.offset.y = 0;
|
||||
default_scissor.extent.width = std::numeric_limits<s32>::max();
|
||||
default_scissor.extent.height = std::numeric_limits<s32>::max();
|
||||
|
||||
VkClearRect clear_rect{
|
||||
.rect = GetScissorState(regs, 0, up_scale, down_shift),
|
||||
.rect = regs.clear_flags.scissor ? GetScissorState(regs, 0, up_scale, down_shift)
|
||||
: default_scissor,
|
||||
.baseArrayLayer = regs.clear_buffers.layer,
|
||||
.layerCount = 1,
|
||||
};
|
||||
@@ -332,9 +338,9 @@ void RasterizerVulkan::DispatchCompute() {
|
||||
return;
|
||||
}
|
||||
std::scoped_lock lock{texture_cache.mutex, buffer_cache.mutex};
|
||||
pipeline->Configure(kepler_compute, gpu_memory, scheduler, buffer_cache, texture_cache);
|
||||
pipeline->Configure(*kepler_compute, *gpu_memory, scheduler, buffer_cache, texture_cache);
|
||||
|
||||
const auto& qmd{kepler_compute.launch_description};
|
||||
const auto& qmd{kepler_compute->launch_description};
|
||||
const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([dim](vk::CommandBuffer cmdbuf) { cmdbuf.Dispatch(dim[0], dim[1], dim[2]); });
|
||||
@@ -415,7 +421,7 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) {
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SyncGuestHost() {
|
||||
void RasterizerVulkan::InvalidateGPUCache() {
|
||||
pipeline_cache.SyncGuestHost();
|
||||
{
|
||||
std::scoped_lock lock{buffer_cache.mutex};
|
||||
@@ -435,40 +441,30 @@ void RasterizerVulkan::UnmapMemory(VAddr addr, u64 size) {
|
||||
pipeline_cache.OnCPUWrite(addr, size);
|
||||
}
|
||||
|
||||
void RasterizerVulkan::ModifyGPUMemory(GPUVAddr addr, u64 size) {
|
||||
void RasterizerVulkan::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {
|
||||
{
|
||||
std::scoped_lock lock{texture_cache.mutex};
|
||||
texture_cache.UnmapGPUMemory(addr, size);
|
||||
texture_cache.UnmapGPUMemory(as_id, addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) {
|
||||
if (!gpu.IsAsync()) {
|
||||
gpu_memory.Write<u32>(addr, value);
|
||||
return;
|
||||
}
|
||||
fence_manager.SignalSemaphore(addr, value);
|
||||
void RasterizerVulkan::SignalFence(std::function<void()>&& func) {
|
||||
fence_manager.SignalFence(std::move(func));
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SyncOperation(std::function<void()>&& func) {
|
||||
fence_manager.SyncOperation(std::move(func));
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SignalSyncPoint(u32 value) {
|
||||
if (!gpu.IsAsync()) {
|
||||
gpu.IncrementSyncPoint(value);
|
||||
return;
|
||||
}
|
||||
fence_manager.SignalSyncPoint(value);
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SignalReference() {
|
||||
if (!gpu.IsAsync()) {
|
||||
return;
|
||||
}
|
||||
fence_manager.SignalOrdering();
|
||||
}
|
||||
|
||||
void RasterizerVulkan::ReleaseFences() {
|
||||
if (!gpu.IsAsync()) {
|
||||
return;
|
||||
}
|
||||
fence_manager.WaitPendingFences();
|
||||
}
|
||||
|
||||
@@ -545,13 +541,13 @@ Tegra::Engines::AccelerateDMAInterface& RasterizerVulkan::AccessAccelerateDMA()
|
||||
}
|
||||
|
||||
void RasterizerVulkan::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size,
|
||||
std::span<u8> memory) {
|
||||
auto cpu_addr = gpu_memory.GpuToCpuAddress(address);
|
||||
std::span<const u8> memory) {
|
||||
auto cpu_addr = gpu_memory->GpuToCpuAddress(address);
|
||||
if (!cpu_addr) [[unlikely]] {
|
||||
gpu_memory.WriteBlock(address, memory.data(), copy_size);
|
||||
gpu_memory->WriteBlock(address, memory.data(), copy_size);
|
||||
return;
|
||||
}
|
||||
gpu_memory.WriteBlockUnsafe(address, memory.data(), copy_size);
|
||||
gpu_memory->WriteBlockUnsafe(address, memory.data(), copy_size);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{buffer_cache.mutex};
|
||||
if (!buffer_cache.InlineMemory(*cpu_addr, copy_size, memory)) {
|
||||
@@ -620,7 +616,7 @@ bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateDynamicStates() {
|
||||
auto& regs = maxwell3d.regs;
|
||||
auto& regs = maxwell3d->regs;
|
||||
UpdateViewportsState(regs);
|
||||
UpdateScissorsState(regs);
|
||||
UpdateDepthBias(regs);
|
||||
@@ -644,7 +640,7 @@ void RasterizerVulkan::UpdateDynamicStates() {
|
||||
}
|
||||
|
||||
void RasterizerVulkan::BeginTransformFeedback() {
|
||||
const auto& regs = maxwell3d.regs;
|
||||
const auto& regs = maxwell3d->regs;
|
||||
if (regs.tfb_enabled == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -660,7 +656,7 @@ void RasterizerVulkan::BeginTransformFeedback() {
|
||||
}
|
||||
|
||||
void RasterizerVulkan::EndTransformFeedback() {
|
||||
const auto& regs = maxwell3d.regs;
|
||||
const auto& regs = maxwell3d->regs;
|
||||
if (regs.tfb_enabled == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -910,7 +906,7 @@ void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs&
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
auto& dirty{maxwell3d.dirty.flags};
|
||||
auto& dirty{maxwell3d->dirty.flags};
|
||||
if (!dirty[Dirty::VertexInput]) {
|
||||
return;
|
||||
}
|
||||
@@ -967,4 +963,41 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) {
|
||||
CreateChannel(channel);
|
||||
{
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
texture_cache.CreateChannel(channel);
|
||||
buffer_cache.CreateChannel(channel);
|
||||
}
|
||||
pipeline_cache.CreateChannel(channel);
|
||||
query_cache.CreateChannel(channel);
|
||||
state_tracker.SetupTables(channel);
|
||||
}
|
||||
|
||||
void RasterizerVulkan::BindChannel(Tegra::Control::ChannelState& channel) {
|
||||
const s32 channel_id = channel.bind_id;
|
||||
BindToChannel(channel_id);
|
||||
{
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
texture_cache.BindToChannel(channel_id);
|
||||
buffer_cache.BindToChannel(channel_id);
|
||||
}
|
||||
pipeline_cache.BindToChannel(channel_id);
|
||||
query_cache.BindToChannel(channel_id);
|
||||
state_tracker.ChangeChannel(channel);
|
||||
state_tracker.InvalidateState();
|
||||
}
|
||||
|
||||
void RasterizerVulkan::ReleaseChannel(s32 channel_id) {
|
||||
EraseChannel(channel_id);
|
||||
{
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
texture_cache.EraseChannel(channel_id);
|
||||
buffer_cache.EraseChannel(channel_id);
|
||||
}
|
||||
pipeline_cache.EraseChannel(channel_id);
|
||||
query_cache.EraseChannel(channel_id);
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/control/channel_state_cache.h"
|
||||
#include "video_core/engines/maxwell_dma.h"
|
||||
#include "video_core/rasterizer_accelerated.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
@@ -54,13 +55,13 @@ private:
|
||||
BufferCache& buffer_cache;
|
||||
};
|
||||
|
||||
class RasterizerVulkan final : public VideoCore::RasterizerAccelerated {
|
||||
class RasterizerVulkan final : public VideoCore::RasterizerAccelerated,
|
||||
protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
|
||||
public:
|
||||
explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
|
||||
Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_,
|
||||
VKScreenInfo& screen_info_, const Device& device_,
|
||||
MemoryAllocator& memory_allocator_, StateTracker& state_tracker_,
|
||||
VKScheduler& scheduler_);
|
||||
Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_,
|
||||
const Device& device_, MemoryAllocator& memory_allocator_,
|
||||
StateTracker& state_tracker_, VKScheduler& scheduler_);
|
||||
~RasterizerVulkan() override;
|
||||
|
||||
void Draw(bool is_indexed, bool is_instanced) override;
|
||||
@@ -75,10 +76,11 @@ public:
|
||||
bool MustFlushRegion(VAddr addr, u64 size) override;
|
||||
void InvalidateRegion(VAddr addr, u64 size) override;
|
||||
void OnCPUWrite(VAddr addr, u64 size) override;
|
||||
void SyncGuestHost() override;
|
||||
void InvalidateGPUCache() override;
|
||||
void UnmapMemory(VAddr addr, u64 size) override;
|
||||
void ModifyGPUMemory(GPUVAddr addr, u64 size) override;
|
||||
void SignalSemaphore(GPUVAddr addr, u32 value) override;
|
||||
void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
|
||||
void SignalFence(std::function<void()>&& func) override;
|
||||
void SyncOperation(std::function<void()>&& func) override;
|
||||
void SignalSyncPoint(u32 value) override;
|
||||
void SignalReference() override;
|
||||
void ReleaseFences() override;
|
||||
@@ -93,12 +95,18 @@ public:
|
||||
const Tegra::Engines::Fermi2D::Config& copy_config) override;
|
||||
Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override;
|
||||
void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size,
|
||||
std::span<u8> memory) override;
|
||||
std::span<const u8> memory) override;
|
||||
bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
|
||||
u32 pixel_stride) override;
|
||||
void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) override;
|
||||
|
||||
void InitializeChannel(Tegra::Control::ChannelState& channel) override;
|
||||
|
||||
void BindChannel(Tegra::Control::ChannelState& channel) override;
|
||||
|
||||
void ReleaseChannel(s32 channel_id) override;
|
||||
|
||||
private:
|
||||
static constexpr size_t MAX_TEXTURES = 192;
|
||||
static constexpr size_t MAX_IMAGES = 48;
|
||||
@@ -134,9 +142,6 @@ private:
|
||||
void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
|
||||
Tegra::GPU& gpu;
|
||||
Tegra::MemoryManager& gpu_memory;
|
||||
Tegra::Engines::Maxwell3D& maxwell3d;
|
||||
Tegra::Engines::KeplerCompute& kepler_compute;
|
||||
|
||||
VKScreenInfo& screen_info;
|
||||
const Device& device;
|
||||
|
@@ -7,9 +7,9 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "video_core/control/channel_state.h"
|
||||
#include "video_core/dirty_flags.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
||||
|
||||
#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name)
|
||||
@@ -174,9 +174,8 @@ void SetupDirtyVertexBindings(Tables& tables) {
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
StateTracker::StateTracker(Tegra::GPU& gpu)
|
||||
: flags{gpu.Maxwell3D().dirty.flags}, invalidation_flags{MakeInvalidationFlags()} {
|
||||
auto& tables{gpu.Maxwell3D().dirty.tables};
|
||||
void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) {
|
||||
auto& tables{channel_state.maxwell_3d->dirty.tables};
|
||||
SetupDirtyFlags(tables);
|
||||
SetupDirtyViewports(tables);
|
||||
SetupDirtyScissors(tables);
|
||||
@@ -199,4 +198,14 @@ StateTracker::StateTracker(Tegra::GPU& gpu)
|
||||
SetupDirtyVertexBindings(tables);
|
||||
}
|
||||
|
||||
void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) {
|
||||
flags = &channel_state.maxwell_3d->dirty.flags;
|
||||
}
|
||||
|
||||
void StateTracker::InvalidateState() {
|
||||
flags->set();
|
||||
}
|
||||
|
||||
StateTracker::StateTracker() : flags{}, invalidation_flags{MakeInvalidationFlags()} {}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@@ -10,6 +10,12 @@
|
||||
#include "video_core/dirty_flags.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
|
||||
namespace Tegra {
|
||||
namespace Control {
|
||||
struct ChannelState;
|
||||
}
|
||||
} // namespace Tegra
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
namespace Dirty {
|
||||
@@ -53,19 +59,19 @@ class StateTracker {
|
||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||
|
||||
public:
|
||||
explicit StateTracker(Tegra::GPU& gpu);
|
||||
explicit StateTracker();
|
||||
|
||||
void InvalidateCommandBufferState() {
|
||||
flags |= invalidation_flags;
|
||||
(*flags) |= invalidation_flags;
|
||||
current_topology = INVALID_TOPOLOGY;
|
||||
}
|
||||
|
||||
void InvalidateViewports() {
|
||||
flags[Dirty::Viewports] = true;
|
||||
(*flags)[Dirty::Viewports] = true;
|
||||
}
|
||||
|
||||
void InvalidateScissors() {
|
||||
flags[Dirty::Scissors] = true;
|
||||
(*flags)[Dirty::Scissors] = true;
|
||||
}
|
||||
|
||||
bool TouchViewports() {
|
||||
@@ -139,16 +145,22 @@ public:
|
||||
return has_changed;
|
||||
}
|
||||
|
||||
void SetupTables(Tegra::Control::ChannelState& channel_state);
|
||||
|
||||
void ChangeChannel(Tegra::Control::ChannelState& channel_state);
|
||||
|
||||
void InvalidateState();
|
||||
|
||||
private:
|
||||
static constexpr auto INVALID_TOPOLOGY = static_cast<Maxwell::PrimitiveTopology>(~0u);
|
||||
|
||||
bool Exchange(std::size_t id, bool new_value) const noexcept {
|
||||
const bool is_dirty = flags[id];
|
||||
flags[id] = new_value;
|
||||
const bool is_dirty = (*flags)[id];
|
||||
(*flags)[id] = new_value;
|
||||
return is_dirty;
|
||||
}
|
||||
|
||||
Tegra::Engines::Maxwell3D::DirtyState::Flags& flags;
|
||||
Tegra::Engines::Maxwell3D::DirtyState::Flags* flags;
|
||||
Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags;
|
||||
Maxwell::PrimitiveTopology current_topology = INVALID_TOPOLOGY;
|
||||
};
|
||||
|
@@ -35,7 +35,8 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats)
|
||||
VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) {
|
||||
// Mailbox doesn't lock the application like fifo (vsync), prefer it
|
||||
const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR);
|
||||
if (found_mailbox != modes.end()) {
|
||||
if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Borderless &&
|
||||
found_mailbox != modes.end()) {
|
||||
return VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
}
|
||||
if (Settings::values.disable_fps_limit.GetValue()) {
|
||||
@@ -155,8 +156,16 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities,
|
||||
present_mode = ChooseSwapPresentMode(present_modes);
|
||||
|
||||
u32 requested_image_count{capabilities.minImageCount + 1};
|
||||
if (capabilities.maxImageCount > 0 && requested_image_count > capabilities.maxImageCount) {
|
||||
requested_image_count = capabilities.maxImageCount;
|
||||
// Ensure Tripple buffering if possible.
|
||||
if (capabilities.maxImageCount > 0) {
|
||||
if (requested_image_count > capabilities.maxImageCount) {
|
||||
requested_image_count = capabilities.maxImageCount;
|
||||
} else {
|
||||
requested_image_count =
|
||||
std::max(requested_image_count, std::min(3U, capabilities.maxImageCount));
|
||||
}
|
||||
} else {
|
||||
requested_image_count = std::max(requested_image_count, 3U);
|
||||
}
|
||||
VkSwapchainCreateInfoKHR swapchain_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||
|
@@ -593,7 +593,7 @@ void TryTransformSwizzleIfNeeded(PixelFormat format, std::array<SwizzleSource, 4
|
||||
case PixelFormat::A5B5G5R1_UNORM:
|
||||
std::ranges::transform(swizzle, swizzle.begin(), SwapSpecial);
|
||||
break;
|
||||
case PixelFormat::R4G4_UNORM:
|
||||
case PixelFormat::G4R4_UNORM:
|
||||
std::ranges::transform(swizzle, swizzle.begin(), SwapGreenRed);
|
||||
break;
|
||||
default:
|
||||
@@ -1481,7 +1481,8 @@ bool Image::BlitScaleHelper(bool scale_up) {
|
||||
auto* view_ptr = blit_view.get();
|
||||
if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
if (!blit_framebuffer) {
|
||||
blit_framebuffer = std::make_unique<Framebuffer>(*runtime, view_ptr, nullptr, extent);
|
||||
blit_framebuffer =
|
||||
std::make_unique<Framebuffer>(*runtime, view_ptr, nullptr, extent, scale_up);
|
||||
}
|
||||
const auto color_view = blit_view->Handle(Shader::TextureType::Color2D);
|
||||
|
||||
@@ -1489,7 +1490,8 @@ bool Image::BlitScaleHelper(bool scale_up) {
|
||||
src_region, operation, BLIT_OPERATION);
|
||||
} else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
if (!blit_framebuffer) {
|
||||
blit_framebuffer = std::make_unique<Framebuffer>(*runtime, nullptr, view_ptr, extent);
|
||||
blit_framebuffer =
|
||||
std::make_unique<Framebuffer>(*runtime, nullptr, view_ptr, extent, scale_up);
|
||||
}
|
||||
runtime->blit_image_helper.BlitDepthStencil(blit_framebuffer.get(), blit_view->DepthView(),
|
||||
blit_view->StencilView(), dst_region,
|
||||
@@ -1747,34 +1749,43 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
|
||||
.width = key.size.width,
|
||||
.height = key.size.height,
|
||||
}} {
|
||||
CreateFramebuffer(runtime, color_buffers, depth_buffer);
|
||||
CreateFramebuffer(runtime, color_buffers, depth_buffer, key.is_rescaled);
|
||||
if (runtime.device.HasDebuggingToolAttached()) {
|
||||
framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Framebuffer::Framebuffer(TextureCacheRuntime& runtime, ImageView* color_buffer,
|
||||
ImageView* depth_buffer, VkExtent2D extent)
|
||||
ImageView* depth_buffer, VkExtent2D extent, bool is_rescaled)
|
||||
: render_area{extent} {
|
||||
std::array<ImageView*, NUM_RT> color_buffers{color_buffer};
|
||||
CreateFramebuffer(runtime, color_buffers, depth_buffer);
|
||||
CreateFramebuffer(runtime, color_buffers, depth_buffer, is_rescaled);
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer() = default;
|
||||
|
||||
void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||
std::span<ImageView*, NUM_RT> color_buffers,
|
||||
ImageView* depth_buffer) {
|
||||
ImageView* depth_buffer, bool is_rescaled) {
|
||||
std::vector<VkImageView> attachments;
|
||||
RenderPassKey renderpass_key{};
|
||||
s32 num_layers = 1;
|
||||
|
||||
const auto& resolution = runtime.resolution;
|
||||
is_rescaled |= resolution.active;
|
||||
|
||||
u32 width = 0;
|
||||
u32 height = 0;
|
||||
for (size_t index = 0; index < NUM_RT; ++index) {
|
||||
const ImageView* const color_buffer = color_buffers[index];
|
||||
if (!color_buffer) {
|
||||
renderpass_key.color_formats[index] = PixelFormat::Invalid;
|
||||
continue;
|
||||
}
|
||||
width = std::max(width, is_rescaled ? resolution.ScaleUp(color_buffer->size.width)
|
||||
: color_buffer->size.width);
|
||||
height = std::max(height, is_rescaled ? resolution.ScaleUp(color_buffer->size.height)
|
||||
: color_buffer->size.height);
|
||||
attachments.push_back(color_buffer->RenderTarget());
|
||||
renderpass_key.color_formats[index] = color_buffer->format;
|
||||
num_layers = std::max(num_layers, color_buffer->range.extent.layers);
|
||||
@@ -1785,6 +1796,10 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||
}
|
||||
const size_t num_colors = attachments.size();
|
||||
if (depth_buffer) {
|
||||
width = std::max(width, is_rescaled ? resolution.ScaleUp(depth_buffer->size.width)
|
||||
: depth_buffer->size.width);
|
||||
height = std::max(height, is_rescaled ? resolution.ScaleUp(depth_buffer->size.height)
|
||||
: depth_buffer->size.height);
|
||||
attachments.push_back(depth_buffer->RenderTarget());
|
||||
renderpass_key.depth_format = depth_buffer->format;
|
||||
num_layers = std::max(num_layers, depth_buffer->range.extent.layers);
|
||||
@@ -1801,6 +1816,8 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||
renderpass_key.samples = samples;
|
||||
|
||||
renderpass = runtime.render_pass_cache.Get(renderpass_key);
|
||||
render_area.width = std::min(render_area.width, width);
|
||||
render_area.height = std::min(render_area.height, height);
|
||||
|
||||
num_color_buffers = static_cast<u32>(num_colors);
|
||||
framebuffer = runtime.device.GetLogical().CreateFramebuffer({
|
||||
|
@@ -268,7 +268,7 @@ public:
|
||||
ImageView* depth_buffer, const VideoCommon::RenderTargets& key);
|
||||
|
||||
explicit Framebuffer(TextureCacheRuntime& runtime, ImageView* color_buffer,
|
||||
ImageView* depth_buffer, VkExtent2D extent);
|
||||
ImageView* depth_buffer, VkExtent2D extent, bool is_rescaled);
|
||||
|
||||
~Framebuffer();
|
||||
|
||||
@@ -279,7 +279,8 @@ public:
|
||||
Framebuffer& operator=(Framebuffer&&) = default;
|
||||
|
||||
void CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||
std::span<ImageView*, NUM_RT> color_buffers, ImageView* depth_buffer);
|
||||
std::span<ImageView*, NUM_RT> color_buffers, ImageView* depth_buffer,
|
||||
bool is_rescaled = false);
|
||||
|
||||
[[nodiscard]] VkFramebuffer Handle() const noexcept {
|
||||
return *framebuffer;
|
||||
|
Reference in New Issue
Block a user