Compare commits

...

9 commits

Author SHA1 Message Date
f50488b1a6 [frontend] add sample shading slider
Signed-off-by: crueter <crueter@eden-emu.dev>
2025-08-14 14:45:15 +02:00
39d1c16bc8 [vk] Fix Sample Shading to ensure it is properly enabled
Even when sample shading was enabled via settings, the pipeline was
configured with minSampleShading = 0.0f, effectively disabling the
feature.

This patch sets minSampleShading = 1.0f when sample shading is enabled,
ensuring that per-sample shading is actually used as intended.
2025-08-14 14:45:15 +02:00
c36cc0d3ee
[core/nvdrv] Fix Random Unmap Memory Clearing (#176)
Now memory should only be unmapped after it was mapped.
Could eventually fix some graphical errors, and improve performance.

Reviewed-on: eden-emu/eden#176
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-authored-by: SDK-Chan <sdkchan@eden-emu.dev>
Co-committed-by: SDK-Chan <sdkchan@eden-emu.dev>
2025-08-14 14:30:09 +02:00
444b9f361e
[VK] PR 180 extension (#257)
fyi there is nothing called VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL

Co-authored-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-on: eden-emu/eden#257
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-authored-by: wildcard <nubieluv@gmail.com>
Co-committed-by: wildcard <nubieluv@gmail.com>
2025-08-14 01:39:18 +02:00
bd944b71d5
[cmake] fix vcpkg and zy* install (#247)
vcpkg wouldn't clone before, but now it actually does and seems to work in my testing

also doesn't install zycore and zydis (thanks aur testers)

Reviewed-on: eden-emu/eden#247
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
2025-08-14 00:00:35 +02:00
1465757ded
[VK] Only enable executable properties when debugging is enabled, extension of pr 243 (#256)
Reviewed-on: eden-emu/eden#256
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-authored-by: wildcard <nubieluv@gmail.com>
Co-committed-by: wildcard <nubieluv@gmail.com>
2025-08-13 19:49:45 +02:00
fc88638693
[vk] only enable statistics bit if graphics debugging is enabled (#243)
seems to improve perf, this bit is basically useless outside of debugging

credit: wildcard
Signed-off-by: crueter <crueter@eden-emu.dev>

Co-authored-by: Shinmegumi <shinmegumi@eden-emu.dev>
Reviewed-on: eden-emu/eden#243
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2025-08-13 19:25:52 +02:00
2b62a41942
[vk] fix line_topologies check (#248)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: eden-emu/eden#248
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-08-13 19:25:05 +02:00
c8d6f23129
[vk] Bring Vulkan closer to Spec (#180)
The changes noted below bring Vulkan closer to 1.3 spec and get rid of validation errors and enable us to properly use one or two more functions.

Reviewed-on: eden-emu/eden#180
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-committed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2025-08-13 18:02:05 +02:00
24 changed files with 261 additions and 154 deletions

View file

@ -218,13 +218,7 @@ if (YUZU_USE_BUNDLED_VCPKG)
include(CPMUtil)
AddPackage(
NAME vcpkg
DOWNLOAD_ONLY YES
URL "https://github.com/microsoft/vcpkg.git"
GIT_TAG "ea2a964f93"
SHA "ea2a964f93"
)
CPMAddPackage("gh:microsoft/vcpkg#10d3b37514")
include(${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake)
elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "")

View file

@ -30,7 +30,7 @@ function(AddPackage)
cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
if (NOT DEFINED PKG_ARGS_NAME)
message(FATAL_ERROR "CPMUtil: No package name defined")
message(FATAL_ERROR "[CPMUtil] ${PKG_ARGS_NAME}: No package name defined")
endif()
if (NOT DEFINED PKG_ARGS_URL)
@ -38,21 +38,21 @@ function(AddPackage)
set(PKG_GIT_URL https://github.com/${PKG_ARGS_REPO})
set(PKG_URL "${PKG_GIT_URL}/archive/${PKG_ARGS_SHA}.zip")
else()
message(FATAL_ERROR "CPMUtil: No custom URL and no repository + sha defined")
message(FATAL_ERROR "[CPMUtil] ${PKG_ARGS_NAME}: No custom URL and no repository + sha defined")
endif()
else()
set(PKG_URL ${PKG_ARGS_URL})
set(PKG_GIT_URL ${PKG_URL})
endif()
message(STATUS "CPMUtil: Downloading package ${PKG_ARGS_NAME} from ${PKG_URL}")
message(STATUS "[CPMUtil] ${PKG_ARGS_NAME}: Downloading package from ${PKG_URL}")
if (NOT DEFINED PKG_ARGS_KEY)
if (DEFINED PKG_ARGS_SHA)
string(SUBSTRING ${PKG_ARGS_SHA} 0 4 PKG_KEY)
message(STATUS "CPMUtil: No custom key defined, using ${PKG_KEY} from sha")
message(STATUS "[CPMUtil] ${PKG_ARGS_NAME}: No custom key defined, using ${PKG_KEY} from sha")
else()
message(FATAL_ERROR "CPMUtil: No custom key and no commit sha defined")
message(FATAL_ERROR "[CPMUtil] ${PKG_ARGS_NAME}: No custom key and no commit sha defined")
endif()
else()
set(PKG_KEY ${PKG_ARGS_KEY})
@ -99,7 +99,7 @@ function(AddPackage)
elseif(DEFINED PKG_ARGS_VERSION)
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS ${PKG_ARGS_VERSION})
else()
message(WARNING "CPMUtil: Package ${PKG_ARGS_NAME} has no specified sha or version")
message(WARNING "[CPMUtil] Package ${PKG_ARGS_NAME} has no specified sha or version")
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS "unknown")
endif()
else()

View file

@ -39,6 +39,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
SOC_OVERLAY_POSITION("soc_overlay_position"),
MEMORY_LAYOUT("memory_layout_mode"),
FSR_SHARPENING_SLIDER("fsr_sharpening_slider"),
RENDERER_SAMPLE_SHADING_FRACTION("sample_shading_fraction"),
FAST_CPU_TIME("fast_cpu_time"),
CPU_TICKS("cpu_ticks"),
FAST_GPU_TIME("fast_gpu_time"),
@ -57,7 +58,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
OFFLINE_WEB_APPLET("offline_web_applet_mode"),
LOGIN_SHARE_APPLET("login_share_applet_mode"),
WIFI_WEB_AUTH_APPLET("wifi_web_auth_applet_mode"),
MY_PAGE_APPLET("my_page_applet_mode")
MY_PAGE_APPLET("my_page_applet_mode"),
;
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)

View file

@ -159,6 +159,14 @@ abstract class SettingsItem(
descriptionId = R.string.sample_shading_description
)
)
put(
SliderSetting(
IntSetting.RENDERER_SAMPLE_SHADING_FRACTION,
titleId = R.string.sample_shading_fraction,
descriptionId = R.string.sample_shading_fraction_description,
units = "%"
)
)
put(
SliderSetting(
ShortSetting.RENDERER_SPEED_LIMIT,

View file

@ -443,6 +443,7 @@ class SettingsFragmentPresenter(
add(BooleanSetting.RENDERER_PROVOKING_VERTEX.key)
add(BooleanSetting.RENDERER_DESCRIPTOR_INDEXING.key)
add(BooleanSetting.RENDERER_SAMPLE_SHADING.key)
add(IntSetting.RENDERER_SAMPLE_SHADING_FRACTION.key)
add(HeaderSetting(R.string.veil_renderer))
add(BooleanSetting.ENABLE_RAII.key)

View file

@ -82,6 +82,8 @@
<string name="descriptor_indexing_description">Improves texture and buffer handling, as well as the Maxwell translation layer. Supported by some Vulkan 1.1 GPUs and all Vulkan 1.2+ GPUs.</string>
<string name="sample_shading">Sample Shading</string>
<string name="sample_shading_description">Allows the fragment shader to execute per sample in a multi-sampled fragment instead once per fragment. Improves graphics quality at the cost of some performance. Only Vulkan 1.1+ devices support this extension.</string>
<string name="sample_shading_fraction">Sample Shading Fraction</string>
<string name="sample_shading_fraction_description">The intensity of the sample shading pass. Higher values improve quality more but also reduce performance to a greater extent.</string>
<string name="veil_renderer">Renderer</string>
<string name="enable_raii">RAII</string>

View file

@ -527,7 +527,17 @@ struct Values {
SwitchableSetting<bool> provoking_vertex{linkage, false, "provoking_vertex", Category::RendererExtensions};
SwitchableSetting<bool> descriptor_indexing{linkage, false, "descriptor_indexing", Category::RendererExtensions};
SwitchableSetting<bool> sample_shading{linkage, false, "sample_shading", Category::RendererExtensions};
SwitchableSetting<bool> sample_shading{linkage, false, "sample_shading", Category::RendererExtensions, Specialization::Paired};
SwitchableSetting<u32, true> sample_shading_fraction{linkage,
50,
0,
100,
"sample_shading_fraction",
Category::RendererExtensions,
Specialization::Scalar,
true,
false,
&sample_shading};
Setting<bool> renderer_debug{linkage, false, "debug", Category::RendererDebug};
Setting<bool> renderer_shader_feedback{linkage, false, "shader_feedback",

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors
// SPDX-License-Identifier: GPL-3.0-or-later
@ -312,7 +315,7 @@ NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) {
NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
LOG_DEBUG(Service_NVDRV,
"called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}"
", offset={}",
", offset=0x{:X}",
params.flags, params.handle, params.buffer_offset, params.mapping_size,
params.offset);
@ -406,19 +409,21 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
mapping_map[params.offset] = mapping;
}
map_buffer_offsets.insert(params.offset);
return NvResult::Success;
}
NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) {
LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
if (map_buffer_offsets.find(params.offset) != map_buffer_offsets.end()) {
LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
std::scoped_lock lock(mutex);
std::scoped_lock lock(mutex);
if (!vm.initialised) {
return NvResult::BadValue;
}
if (!vm.initialised) {
return NvResult::BadValue;
}
try {
auto mapping{mapping_map.at(params.offset)};
if (!mapping->fixed) {
@ -440,10 +445,8 @@ NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) {
nvmap.UnpinHandle(mapping->handle);
mapping_map.erase(params.offset);
} catch (const std::out_of_range&) {
LOG_WARNING(Service_NVDRV, "Couldn't find region to unmap at 0x{:X}", params.offset);
map_buffer_offsets.erase(params.offset);
}
return NvResult::Success;
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors
// SPDX-License-Identifier: GPL-3.0-or-later
@ -10,6 +13,7 @@
#include <memory>
#include <mutex>
#include <optional>
#include <unordered_set>
#include <vector>
#include "common/address_space.h"
@ -109,6 +113,8 @@ private:
};
static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
std::unordered_set<s64_le> map_buffer_offsets{};
struct IoctlMapBufferEx {
MappingFlags flags{}; // bit0: fixed_offset, bit2: cacheable
u32_le kind{}; // -1 is default

View file

@ -138,7 +138,6 @@ endif()
if (DYNARMIC_USE_BUNDLED_EXTERNALS)
set(CMAKE_DISABLE_FIND_PACKAGE_biscuit ON)
set(CMAKE_DISABLE_FIND_PACKAGE_Catch2 ON)
set(CMAKE_DISABLE_FIND_PACKAGE_fmt ON)
set(CMAKE_DISABLE_FIND_PACKAGE_mcl ON)
set(CMAKE_DISABLE_FIND_PACKAGE_oaknut ON)

View file

@ -28,6 +28,7 @@ if ("riscv" IN_LIST ARCHITECTURE)
REPO "lioncash/biscuit"
SHA 76b0be8dae
HASH 47d55ed02d032d6cf3dc107c6c0a9aea686d5f25aefb81d1af91db027b6815bd5add1755505e19d76625feeb17aa2db6cd1668fe0dad2e6a411519bde6ca4489
BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS}
)
endif()
@ -92,12 +93,17 @@ AddPackage(
# zydis
# TODO(crueter): maybe it's just Gentoo but zydis system package really sucks
if ("x86_64" IN_LIST ARCHITECTURE)
AddPackage(
NAME Zycore
REPO "zyantific/zycore-c"
SHA 75a36c45ae
HASH 15aa399f39713e042c4345bc3175c82f14dca849fde2a21d4f591f62c43e227b70d868d8bb86beb5f4eb68b1d6bd3792cdd638acf89009e787e3d10ee7401924
OPTIONS
"CMAKE_DISABLE_FIND_PACKAGE_Doxygen ON"
# BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS}
EXCLUDE_FROM_ALL ON
)
AddPackage(
@ -112,5 +118,7 @@ if ("x86_64" IN_LIST ARCHITECTURE)
"ZYDIS_BUILD_DOXYGEN OFF"
"ZYAN_ZYCORE_PATH ${Zycore_SOURCE_DIR}"
"CMAKE_DISABLE_FIND_PACKAGE_Doxygen ON"
# BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS}
EXCLUDE_FROM_ALL ON
)
endif()

View file

@ -1,4 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
@ -518,7 +521,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region,
src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) {
TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL);
TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
BeginRenderPass(cmdbuf, dst_framebuffer);
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
UpdateOneTextureDescriptorSet(device, descriptor_set, src_sampler, src_image_view);

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -55,7 +58,7 @@ ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipel
.requiredSubgroupSize = GuestWarpSize,
};
VkPipelineCreateFlags flags{};
if (device.IsKhrPipelineExecutablePropertiesEnabled()) {
if (device.IsKhrPipelineExecutablePropertiesEnabled() && Settings::values.renderer_debug.GetValue()) {
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
}
pipeline = device.GetLogical().CreateComputePipeline(

View file

@ -94,7 +94,7 @@ bool IsLine(VkPrimitiveTopology topology) {
VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
// VK_PRIMITIVE_TOPOLOGY_LINE_LOOP_EXT,
};
return std::ranges::find(line_topologies, topology) == line_topologies.end();
return std::ranges::find(line_topologies, topology) != line_topologies.end();
}
VkViewportSwizzleNV UnpackViewportSwizzle(u16 swizzle) {
@ -502,7 +502,6 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
const RenderAreaPushConstant& render_area) {
scheduler.RequestRenderpass(texture_cache.GetFramebuffer());
if (!is_built.load(std::memory_order::relaxed)) {
// Wait for the pipeline to be built
scheduler.Record([this](vk::CommandBuffer) {
@ -744,7 +743,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.flags = 0,
.rasterizationSamples = MaxwellToVK::MsaaMode(key.state.msaa_mode),
.sampleShadingEnable = Settings::values.sample_shading.GetValue() ? VK_TRUE : VK_FALSE,
.minSampleShading = 0.0f,
.minSampleShading = static_cast<float>(Settings::values.sample_shading_fraction.GetValue()) / 100.0f,
.pSampleMask = nullptr,
.alphaToCoverageEnable = key.state.alpha_to_coverage_enabled != 0 ? VK_TRUE : VK_FALSE,
.alphaToOneEnable = key.state.alpha_to_one_enabled != 0 ? VK_TRUE : VK_FALSE,
@ -902,7 +901,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
*/
}
VkPipelineCreateFlags flags{};
if (device.IsKhrPipelineExecutablePropertiesEnabled()) {
if (device.IsKhrPipelineExecutablePropertiesEnabled() && Settings::values.renderer_debug.GetValue()) {
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
}

View file

@ -13,7 +13,7 @@
#include <unordered_map>
#include <utility>
#include <vector>
#include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "common/bit_util.h"
#include "common/common_types.h"
#include "video_core/engines/draw_manager.h"
@ -116,11 +116,11 @@ struct HostSyncValues {
class SamplesStreamer : public BaseStreamer {
public:
explicit SamplesStreamer(size_t id_, QueryCacheRuntime& runtime_,
VideoCore::RasterizerInterface* rasterizer_, const Device& device_,
VideoCore::RasterizerInterface* rasterizer_, TextureCache& texture_cache_, const Device& device_,
Scheduler& scheduler_, const MemoryAllocator& memory_allocator_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue,
DescriptorPool& descriptor_pool)
: BaseStreamer(id_), runtime{runtime_}, rasterizer{rasterizer_}, device{device_},
: BaseStreamer(id_), texture_cache{texture_cache_}, runtime{runtime_}, rasterizer{rasterizer_}, device{device_},
scheduler{scheduler_}, memory_allocator{memory_allocator_} {
current_bank = nullptr;
current_query = nullptr;
@ -153,16 +153,33 @@ public:
if (has_started) {
return;
}
ReserveHostQuery();
// Ensure outside render pass
scheduler.RequestOutsideRenderPassOperationContext();
// Reset query pool outside render pass
scheduler.Record([query_pool = current_query_pool,
query_index = current_bank_slot](vk::CommandBuffer cmdbuf) {
query_index = current_bank_slot](vk::CommandBuffer cmdbuf) {
cmdbuf.ResetQueryPool(query_pool, static_cast<u32>(query_index), 1);
});
// Manually restart the render pass (required for vkCmdClearAttachments, etc.)
scheduler.RequestRenderpass(texture_cache.GetFramebuffer());
// Begin query inside the newly started render pass
scheduler.Record([query_pool = current_query_pool,
query_index = current_bank_slot](vk::CommandBuffer cmdbuf) {
const bool use_precise = Settings::IsGPULevelHigh();
cmdbuf.BeginQuery(query_pool, static_cast<u32>(query_index),
use_precise ? VK_QUERY_CONTROL_PRECISE_BIT : 0);
});
has_started = true;
}
void PauseCounter() override {
if (!has_started) {
return;
@ -404,7 +421,7 @@ private:
size_slots -= amount;
}
}
TextureCache& texture_cache;
template <bool is_ordered, typename Func>
void ApplyBanksWideOp(std::vector<size_t>& queries, Func&& func) {
std::conditional_t<is_ordered, std::map<size_t, std::pair<size_t, size_t>>,
@ -1163,13 +1180,13 @@ struct QueryCacheRuntimeImpl {
const MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
StagingBufferPool& staging_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue,
DescriptorPool& descriptor_pool)
DescriptorPool& descriptor_pool, TextureCache& texture_cache_)
: rasterizer{rasterizer_}, device_memory{device_memory_}, buffer_cache{buffer_cache_},
device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
staging_pool{staging_pool_}, guest_streamer(0, runtime),
sample_streamer(static_cast<size_t>(QueryType::ZPassPixelCount64), runtime, rasterizer,
device, scheduler, memory_allocator, compute_pass_descriptor_queue,
descriptor_pool),
texture_cache_, device, scheduler, memory_allocator,
compute_pass_descriptor_queue, descriptor_pool),
tfb_streamer(static_cast<size_t>(QueryType::StreamingByteCount), runtime, device,
scheduler, memory_allocator, staging_pool),
primitives_succeeded_streamer(
@ -1240,10 +1257,10 @@ QueryCacheRuntime::QueryCacheRuntime(VideoCore::RasterizerInterface* rasterizer,
const MemoryAllocator& memory_allocator_,
Scheduler& scheduler_, StagingBufferPool& staging_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue,
DescriptorPool& descriptor_pool) {
DescriptorPool& descriptor_pool, TextureCache& texture_cache_) {
impl = std::make_unique<QueryCacheRuntimeImpl>(
*this, rasterizer, device_memory_, buffer_cache_, device_, memory_allocator_, scheduler_,
staging_pool_, compute_pass_descriptor_queue, descriptor_pool);
staging_pool_, compute_pass_descriptor_queue, descriptor_pool, texture_cache_);
}
void QueryCacheRuntime::Bind3DEngine(Maxwell3D* maxwell3d) {

View file

@ -7,7 +7,7 @@
#include "video_core/query_cache/query_cache_base.h"
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
#include "video_core/renderer_vulkan/vk_texture_cache.h"
namespace VideoCore {
class RasterizerInterface;
}
@ -17,7 +17,6 @@ class StreamerInterface;
}
namespace Vulkan {
class Device;
class Scheduler;
class StagingBufferPool;
@ -32,7 +31,7 @@ public:
const MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
StagingBufferPool& staging_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue,
DescriptorPool& descriptor_pool);
DescriptorPool& descriptor_pool, TextureCache& texture_cache_);
~QueryCacheRuntime();
template <typename SyncValuesType>

View file

@ -189,7 +189,7 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
guest_descriptor_queue, compute_pass_descriptor_queue, descriptor_pool),
buffer_cache(device_memory, buffer_cache_runtime),
query_cache_runtime(this, device_memory, buffer_cache, device, memory_allocator, scheduler,
staging_pool, compute_pass_descriptor_queue, descriptor_pool),
staging_pool, compute_pass_descriptor_queue, descriptor_pool, texture_cache),
query_cache(gpu, *this, device_memory, query_cache_runtime),
pipeline_cache(device_memory, device, scheduler, descriptor_pool, guest_descriptor_queue,
render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()),

View file

@ -136,7 +136,6 @@ public:
void BindChannel(Tegra::Control::ChannelState& channel) override;
void ReleaseChannel(s32 channel_id) override;
std::optional<FramebufferTextureInfo> AccelerateDisplay(const Tegra::FramebufferConfig& config,
VAddr framebuffer_addr,
u32 pixel_stride);
@ -147,7 +146,6 @@ private:
0x0100E95004038000ULL, // XC2
0x0100A6301214E000ULL, // FE:Engage
};
static constexpr size_t MAX_TEXTURES = 192;
static constexpr size_t MAX_IMAGES = 48;
static constexpr size_t MAX_IMAGE_VIEWS = MAX_TEXTURES + MAX_IMAGES;

View file

@ -270,46 +270,77 @@ void Scheduler::EndPendingOperations() {
EndRenderPass();
}
void Scheduler::EndRenderPass() {
if (!state.renderpass) {
return;
void Scheduler::EndRenderPass()
{
if (!state.renderpass) {
return;
}
query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false);
query_cache->NotifySegment(false);
Record([num_images = num_renderpass_images,
images = renderpass_images,
ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) {
std::array<VkImageMemoryBarrier, 9> barriers;
VkPipelineStageFlags src_stages = 0;
for (size_t i = 0; i < num_images; ++i) {
const VkImageSubresourceRange& range = ranges[i];
const bool is_color = range.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT;
const bool is_depth_stencil = range.aspectMask
& (VK_IMAGE_ASPECT_DEPTH_BIT
| VK_IMAGE_ASPECT_STENCIL_BIT);
VkAccessFlags src_access = 0;
VkPipelineStageFlags this_stage = 0;
if (is_color) {
src_access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
this_stage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
if (is_depth_stencil) {
src_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
this_stage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
}
src_stages |= this_stage;
barriers[i] = VkImageMemoryBarrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = src_access,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = images[i],
.subresourceRange = range,
};
}
cmdbuf.EndRenderPass();
cmdbuf.PipelineBarrier(src_stages,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0,
{},
{},
{barriers.data(), num_images} // Batched image barriers
);
});
state.renderpass = nullptr;
num_renderpass_images = 0;
}
query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false);
query_cache->NotifySegment(false);
Record([num_images = num_renderpass_images, images = renderpass_images,
ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) {
std::array<VkImageMemoryBarrier, 9> barriers;
for (size_t i = 0; i < num_images; ++i) {
barriers[i] = VkImageMemoryBarrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = images[i],
.subresourceRange = ranges[i],
};
}
cmdbuf.EndRenderPass();
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, nullptr, nullptr,
vk::Span(barriers.data(), num_images));
});
state.renderpass = nullptr;
num_renderpass_images = 0;
}
void Scheduler::AcquireNewChunk() {
std::scoped_lock rl{reserve_mutex};

View file

@ -508,58 +508,84 @@ TransformBufferCopies(std::span<const VideoCommon::BufferCopy> copies, size_t bu
return value;
}
}
struct RangedBarrierRange {
u32 min_mip = std::numeric_limits<u32>::max();
u32 max_mip = std::numeric_limits<u32>::min();
u32 min_layer = std::numeric_limits<u32>::max();
u32 max_layer = std::numeric_limits<u32>::min();
void AddLayers(const VkImageSubresourceLayers& layers) {
min_mip = std::min(min_mip, layers.mipLevel);
max_mip = std::max(max_mip, layers.mipLevel + 1);
min_layer = std::min(min_layer, layers.baseArrayLayer);
max_layer = std::max(max_layer, layers.baseArrayLayer + layers.layerCount);
}
VkImageSubresourceRange SubresourceRange(VkImageAspectFlags aspect_mask) const noexcept {
return VkImageSubresourceRange{
.aspectMask = aspect_mask,
.baseMipLevel = min_mip,
.levelCount = max_mip - min_mip,
.baseArrayLayer = min_layer,
.layerCount = max_layer - min_layer,
};
}
};
void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage image,
VkImageAspectFlags aspect_mask, bool is_initialized,
std::span<const VkBufferImageCopy> copies) {
static constexpr VkAccessFlags WRITE_ACCESS_FLAGS =
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
static constexpr VkAccessFlags READ_ACCESS_FLAGS = VK_ACCESS_SHADER_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
// Compute exact mip/layer range being written to
RangedBarrierRange range;
for (const auto& region : copies) {
range.AddLayers(region.imageSubresource);
}
const VkImageSubresourceRange subresource_range = range.SubresourceRange(aspect_mask);
const VkImageMemoryBarrier read_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = WRITE_ACCESS_FLAGS,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange{
.aspectMask = aspect_mask,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = WRITE_ACCESS_FLAGS,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange = subresource_range,
};
const VkImageMemoryBarrier write_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = WRITE_ACCESS_FLAGS | READ_ACCESS_FLAGS,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange{
.aspectMask = aspect_mask,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = WRITE_ACCESS_FLAGS | READ_ACCESS_FLAGS,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange = subresource_range,
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
read_barrier);
cmdbuf.CopyBufferToImage(src_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copies);
// TODO: Move this to another API
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
write_barrier);
cmdbuf.PipelineBarrier(
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
0, nullptr, nullptr, write_barrier);
}
[[nodiscard]] VkImageBlit MakeImageBlit(const Region2D& dst_region, const Region2D& src_region,
@ -652,29 +678,7 @@ void TryTransformSwizzleIfNeeded(PixelFormat format, std::array<SwizzleSource, 4
}
}
struct RangedBarrierRange {
u32 min_mip = std::numeric_limits<u32>::max();
u32 max_mip = std::numeric_limits<u32>::min();
u32 min_layer = std::numeric_limits<u32>::max();
u32 max_layer = std::numeric_limits<u32>::min();
void AddLayers(const VkImageSubresourceLayers& layers) {
min_mip = std::min(min_mip, layers.mipLevel);
max_mip = std::max(max_mip, layers.mipLevel + 1);
min_layer = std::min(min_layer, layers.baseArrayLayer);
max_layer = std::max(max_layer, layers.baseArrayLayer + layers.layerCount);
}
VkImageSubresourceRange SubresourceRange(VkImageAspectFlags aspect_mask) const noexcept {
return VkImageSubresourceRange{
.aspectMask = aspect_mask,
.baseMipLevel = min_mip,
.levelCount = max_mip - min_mip,
.baseArrayLayer = min_layer,
.layerCount = max_layer - min_layer,
};
}
};
[[nodiscard]] VkFormat Format(Shader::ImageFormat format) {
switch (format) {
@ -1458,12 +1462,18 @@ void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
.subresourceRange = dst_range.SubresourceRange(aspect_mask),
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, {}, {}, pre_barriers);
cmdbuf.PipelineBarrier(
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0, nullptr, nullptr, pre_barriers);
cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_copies);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, {}, {}, post_barriers);
cmdbuf.PipelineBarrier(
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
0, nullptr, nullptr, post_barriers);
});
}
@ -2377,7 +2387,7 @@ void TextureCacheRuntime::TransitionImageLayout(Image& image) {
};
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([barrier](vk::CommandBuffer cmdbuf) {
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, barrier);
});
}

View file

@ -120,6 +120,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkCmdEndConditionalRenderingEXT);
X(vkCmdEndQuery);
X(vkCmdEndRenderPass);
X(vkCmdResetQueryPool);
X(vkCmdEndTransformFeedbackEXT);
X(vkCmdEndDebugUtilsLabelEXT);
X(vkCmdFillBuffer);

View file

@ -219,6 +219,7 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT{};
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{};
PFN_vkCmdEndQuery vkCmdEndQuery{};
PFN_vkCmdResetQueryPool vkCmdResetQueryPool{};
PFN_vkCmdEndRenderPass vkCmdEndRenderPass{};
PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT{};
PFN_vkCmdFillBuffer vkCmdFillBuffer{};
@ -1137,7 +1138,9 @@ public:
VkCommandBuffer operator*() const noexcept {
return handle;
}
void ResetQueryPool(VkQueryPool query_pool, uint32_t first, uint32_t count) const noexcept {
dld->vkCmdResetQueryPool(handle, query_pool, first, count);
}
void Begin(const VkCommandBufferBeginInfo& begin_info) const {
Check(dld->vkBeginCommandBuffer(handle, &begin_info));
}

View file

@ -36,7 +36,16 @@ void ConfigureGraphicsExtensions::Setup(const ConfigurationShared::Builder& buil
for (auto setting :
Settings::values.linkage.by_category[Settings::Category::RendererExtensions]) {
ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs);
ConfigurationShared::Widget* widget = [&]() {
if (setting->Id() == Settings::values.sample_shading_fraction.Id()) {
// TODO(crueter): should support this natively perhaps?
return builder.BuildWidget(
setting, apply_funcs, ConfigurationShared::RequestType::Slider, true,
1.0f, nullptr, tr("%", "Sample Shading percentage (e.g. 50%)"));
} else {
return builder.BuildWidget(setting, apply_funcs);
}
}();
if (widget == nullptr) {
continue;

View file

@ -360,8 +360,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent)
tr("Improves texture & buffer handling and the Maxwell translation layer.\n"
"Some Vulkan 1.1+ and all 1.2+ devices support this extension."));
INSERT(Settings, sample_shading, QString(), QString());
INSERT(Settings,
sample_shading,
sample_shading_fraction,
tr("Sample Shading"),
tr("Allows the fragment shader to execute per sample in a multi-sampled fragment "
"instead once per fragment. Improves graphics quality at the cost of some performance.\n"