Compare commits

...

3 commits

Author SHA1 Message Date
yuzubot 4663c1de5c "Merge Tagged PR 12173" 2024-01-26 13:02:49 +00:00
yuzubot 15640423f5 "Merge Tagged PR 12749" 2024-01-26 13:02:48 +00:00
yuzubot 766d7961b4 "Merge Tagged PR 12769" 2024-01-26 13:02:48 +00:00
15 changed files with 164 additions and 75 deletions

View file

@ -106,6 +106,7 @@ add_library(common STATIC
precompiled_headers.h precompiled_headers.h
quaternion.h quaternion.h
range_map.h range_map.h
range_mutex.h
reader_writer_queue.h reader_writer_queue.h
ring_buffer.h ring_buffer.h
${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp

93
src/common/range_mutex.h Normal file
View file

@ -0,0 +1,93 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <condition_variable>
#include <mutex>
#include "common/intrusive_list.h"
namespace Common {
class ScopedRangeLock;
class RangeMutex {
public:
explicit RangeMutex() = default;
~RangeMutex() = default;
private:
friend class ScopedRangeLock;
void Lock(ScopedRangeLock& l);
void Unlock(ScopedRangeLock& l);
bool HasIntersectionLocked(ScopedRangeLock& l);
private:
std::mutex m_mutex;
std::condition_variable m_cv;
using LockList = Common::IntrusiveListBaseTraits<ScopedRangeLock>::ListType;
LockList m_list;
};
class ScopedRangeLock : public Common::IntrusiveListBaseNode<ScopedRangeLock> {
public:
explicit ScopedRangeLock(RangeMutex& mutex, u64 address, u64 size)
: m_mutex(mutex), m_address(address), m_size(size) {
if (m_size > 0) {
m_mutex.Lock(*this);
}
}
~ScopedRangeLock() {
if (m_size > 0) {
m_mutex.Unlock(*this);
}
}
u64 GetAddress() const {
return m_address;
}
u64 GetSize() const {
return m_size;
}
private:
RangeMutex& m_mutex;
const u64 m_address{};
const u64 m_size{};
};
inline void RangeMutex::Lock(ScopedRangeLock& l) {
std::unique_lock lk{m_mutex};
m_cv.wait(lk, [&] { return !HasIntersectionLocked(l); });
m_list.push_back(l);
}
inline void RangeMutex::Unlock(ScopedRangeLock& l) {
{
std::scoped_lock lk{m_mutex};
m_list.erase(m_list.iterator_to(l));
}
m_cv.notify_all();
}
inline bool RangeMutex::HasIntersectionLocked(ScopedRangeLock& l) {
const auto cur_begin = l.GetAddress();
const auto cur_last = l.GetAddress() + l.GetSize() - 1;
for (const auto& other : m_list) {
const auto other_begin = other.GetAddress();
const auto other_last = other.GetAddress() + other.GetSize() - 1;
if (cur_begin <= other_last && other_begin <= cur_last) {
return true;
}
}
return false;
}
} // namespace Common

View file

@ -10,6 +10,7 @@
#include <mutex> #include <mutex>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/range_mutex.h"
#include "common/scratch_buffer.h" #include "common/scratch_buffer.h"
#include "common/virtual_buffer.h" #include "common/virtual_buffer.h"
@ -204,7 +205,7 @@ private:
(1ULL << (device_virtual_bits - page_bits)) / subentries; (1ULL << (device_virtual_bits - page_bits)) / subentries;
using CachedPages = std::array<CounterEntry, num_counter_entries>; using CachedPages = std::array<CounterEntry, num_counter_entries>;
std::unique_ptr<CachedPages> cached_pages; std::unique_ptr<CachedPages> cached_pages;
std::mutex counter_guard; Common::RangeMutex counter_guard;
std::mutex mapping_guard; std::mutex mapping_guard;
}; };

View file

@ -508,12 +508,7 @@ void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) {
template <typename Traits> template <typename Traits>
void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) {
std::unique_lock<std::mutex> lk(counter_guard, std::defer_lock); Common::ScopedRangeLock lk(counter_guard, addr, size);
const auto Lock = [&] {
if (!lk) {
lk.lock();
}
};
u64 uncache_begin = 0; u64 uncache_begin = 0;
u64 cache_begin = 0; u64 cache_begin = 0;
u64 uncache_bytes = 0; u64 uncache_bytes = 0;
@ -548,7 +543,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
} }
uncache_bytes += Memory::YUZU_PAGESIZE; uncache_bytes += Memory::YUZU_PAGESIZE;
} else if (uncache_bytes > 0) { } else if (uncache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
uncache_bytes, false); uncache_bytes, false);
uncache_bytes = 0; uncache_bytes = 0;
@ -559,7 +553,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
} }
cache_bytes += Memory::YUZU_PAGESIZE; cache_bytes += Memory::YUZU_PAGESIZE;
} else if (cache_bytes > 0) { } else if (cache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
true); true);
cache_bytes = 0; cache_bytes = 0;
@ -567,12 +560,10 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
vpage++; vpage++;
} }
if (uncache_bytes > 0) { if (uncache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes,
false); false);
} }
if (cache_bytes > 0) { if (cache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
true); true);
} }

View file

@ -1093,6 +1093,20 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
[&] { rasterizer = true; }); [&] { rasterizer = true; });
if (rasterizer) { if (rasterizer) {
impl->InvalidateGPUMemory(ptr, size); impl->InvalidateGPUMemory(ptr, size);
const auto type = impl->current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Type();
if (type == Common::PageType::RasterizerCachedMemory) {
// Check if device mapped. If not, this bugged and we can unmark.
DAddr addr{};
Common::ScratchBuffer<u32> buffer;
impl->gpu_device_memory->ApplyOpOnPointer(ptr, buffer,
[&](DAddr address) { addr = address; });
if (addr == 0) {
LOG_ERROR(HW_Memory, "Fixing unmapped cached region {:#x}", GetInteger(vaddr));
impl->RasterizerMarkRegionCached(GetInteger(vaddr), size, false);
}
}
} }
#ifdef __linux__ #ifdef __linux__

View file

@ -110,7 +110,11 @@ void EmulatedController::ReloadFromSettings() {
original_npad_type = npad_type; original_npad_type = npad_type;
} }
SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::Active); // Disable special features before disconnecting
if (controller.right_polling_mode != Common::Input::PollingMode::Active) {
SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::Active);
}
Disconnect(); Disconnect();
if (player.connected) { if (player.connected) {
Connect(); Connect();
@ -1241,7 +1245,12 @@ bool EmulatedController::SetVibration(DeviceIndex device_index, const VibrationV
return false; return false;
} }
last_vibration_value = vibration; // Skip duplicated vibrations
if (last_vibration_value[index] == vibration) {
return Settings::values.vibration_enabled.GetValue();
}
last_vibration_value[index] = vibration;
if (!Settings::values.vibration_enabled) { if (!Settings::values.vibration_enabled) {
return false; return false;
@ -1272,7 +1281,10 @@ bool EmulatedController::SetVibration(DeviceIndex device_index, const VibrationV
} }
VibrationValue EmulatedController::GetActualVibrationValue(DeviceIndex device_index) const { VibrationValue EmulatedController::GetActualVibrationValue(DeviceIndex device_index) const {
return last_vibration_value; if (device_index >= DeviceIndex::MaxDeviceIndex) {
return Core::HID::DEFAULT_VIBRATION_VALUE;
}
return last_vibration_value[static_cast<std::size_t>(device_index)];
} }
bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {

View file

@ -581,7 +581,8 @@ private:
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
u32 turbo_button_state{0}; u32 turbo_button_state{0};
std::size_t nfc_handles{0}; std::size_t nfc_handles{0};
VibrationValue last_vibration_value{DEFAULT_VIBRATION_VALUE}; std::array<VibrationValue, 2> last_vibration_value{DEFAULT_VIBRATION_VALUE,
DEFAULT_VIBRATION_VALUE};
// Temporary values to avoid doing changes while the controller is in configuring mode // Temporary values to avoid doing changes while the controller is in configuring mode
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};

View file

@ -639,6 +639,15 @@ struct VibrationValue {
f32 low_frequency{}; f32 low_frequency{};
f32 high_amplitude{}; f32 high_amplitude{};
f32 high_frequency{}; f32 high_frequency{};
bool operator==(const VibrationValue& b) {
if (low_amplitude != b.low_amplitude || high_amplitude != b.high_amplitude) {
return false;
}
if (low_frequency != b.low_amplitude || high_frequency != b.high_frequency) {
return false;
}
return true;
}
}; };
static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size."); static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size.");

View file

@ -1546,7 +1546,10 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
std::span<const u8> upload_span; std::span<const u8> upload_span;
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset; const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
if (IsRangeGranular(device_addr, copy.size)) { if (IsRangeGranular(device_addr, copy.size)) {
upload_span = std::span(device_memory.GetPointer<u8>(device_addr), copy.size); auto* const ptr = device_memory.GetPointer<u8>(device_addr);
if (ptr != nullptr) {
upload_span = std::span(ptr, copy.size);
}
} else { } else {
if (immediate_buffer.empty()) { if (immediate_buffer.empty()) {
immediate_buffer = ImmediateBuffer(largest_copy); immediate_buffer = ImmediateBuffer(largest_copy);

View file

@ -243,10 +243,12 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
const u64 size_in_bytes{Tegra::Texture::CalculateSize( const u64 size_in_bytes{Tegra::Texture::CalculateSize(
true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)}; const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)};
const std::span<const u8> input_data(host_ptr, size_in_bytes); if (host_ptr != nullptr) {
Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, const std::span<const u8> input_data(host_ptr, size_in_bytes);
framebuffer.width, framebuffer.height, 1, block_height_log2, Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel,
0); framebuffer.width, framebuffer.height, 1,
block_height_log2, 0);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));

View file

@ -230,9 +230,11 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
const u64 tiled_size{Tegra::Texture::CalculateSize(true, bytes_per_pixel, const u64 tiled_size{Tegra::Texture::CalculateSize(true, bytes_per_pixel,
framebuffer.stride, framebuffer.height, framebuffer.stride, framebuffer.height,
1, block_height_log2, 0)}; 1, block_height_log2, 0)};
Tegra::Texture::UnswizzleTexture( if (host_ptr != nullptr) {
mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), Tegra::Texture::UnswizzleTexture(
bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size),
bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0);
}
const VkBufferImageCopy copy{ const VkBufferImageCopy copy{
.bufferOffset = image_offset, .bufferOffset = image_offset,

View file

@ -1064,8 +1064,6 @@ public:
} }
}); });
} }
auto* ptr = device_memory.GetPointer<u8>(new_query->dependant_address);
ASSERT(ptr != nullptr);
new_query->dependant_manage = must_manage_dependance; new_query->dependant_manage = must_manage_dependance;
pending_flush_queries.push_back(index); pending_flush_queries.push_back(index);
@ -1104,9 +1102,11 @@ public:
tfb_streamer.Free(query->dependant_index); tfb_streamer.Free(query->dependant_index);
} else { } else {
u8* pointer = device_memory.GetPointer<u8>(query->dependant_address); u8* pointer = device_memory.GetPointer<u8>(query->dependant_address);
u32 result; if (pointer != nullptr) {
std::memcpy(&result, pointer, sizeof(u32)); u32 result;
num_vertices = static_cast<u64>(result) / query->stride; std::memcpy(&result, pointer, sizeof(u32));
num_vertices = static_cast<u64>(result) / query->stride;
}
} }
query->value = [&]() -> u64 { query->value = [&]() -> u64 {
switch (query->topology) { switch (query->topology) {
@ -1360,7 +1360,9 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku
const auto check_value = [&](DAddr address) { const auto check_value = [&](DAddr address) {
u8* ptr = impl->device_memory.GetPointer<u8>(address); u8* ptr = impl->device_memory.GetPointer<u8>(address);
u64 value{}; u64 value{};
std::memcpy(&value, ptr, sizeof(value)); if (ptr != nullptr) {
std::memcpy(&value, ptr, sizeof(value));
}
return value == 0; return value == 0;
}; };
std::array<VideoCommon::LookupData*, 2> objects{&object_1, &object_2}; std::array<VideoCommon::LookupData*, 2> objects{&object_1, &object_2};

View file

@ -1045,37 +1045,16 @@ void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
regs.zeta.format == Tegra::DepthFormat::X8Z24_UNORM || regs.zeta.format == Tegra::DepthFormat::X8Z24_UNORM ||
regs.zeta.format == Tegra::DepthFormat::S8Z24_UNORM || regs.zeta.format == Tegra::DepthFormat::S8Z24_UNORM ||
regs.zeta.format == Tegra::DepthFormat::V8Z24_UNORM; regs.zeta.format == Tegra::DepthFormat::V8Z24_UNORM;
bool force_unorm = ([&] { if (is_d24 && !device.SupportsD24DepthBuffer() &&
if (!is_d24 || device.SupportsD24DepthBuffer()) { Settings::values.renderer_amdvlk_depth_bias_workaround) {
return false;
}
if (device.IsExtDepthBiasControlSupported()) {
return true;
}
if (!Settings::values.renderer_amdvlk_depth_bias_workaround) {
return false;
}
// the base formulas can be obtained from here: // the base formulas can be obtained from here:
// https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-output-merger-stage-depth-bias // https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-output-merger-stage-depth-bias
const double rescale_factor = const double rescale_factor =
static_cast<double>(1ULL << (32 - 24)) / (static_cast<double>(0x1.ep+127)); static_cast<double>(1ULL << (32 - 24)) / (static_cast<double>(0x1.ep+127));
units = static_cast<float>(static_cast<double>(units) * rescale_factor); units = static_cast<float>(static_cast<double>(units) * rescale_factor);
return false; }
})();
scheduler.Record([constant = units, clamp = regs.depth_bias_clamp, scheduler.Record([constant = units, clamp = regs.depth_bias_clamp,
factor = regs.slope_scale_depth_bias, force_unorm, factor = regs.slope_scale_depth_bias](vk::CommandBuffer cmdbuf) {
precise = device.HasExactDepthBiasControl()](vk::CommandBuffer cmdbuf) {
if (force_unorm) {
VkDepthBiasRepresentationInfoEXT info{
.sType = VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT,
.pNext = nullptr,
.depthBiasRepresentation =
VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT,
.depthBiasExact = precise ? VK_TRUE : VK_FALSE,
};
cmdbuf.SetDepthBias(constant, clamp, factor, &info);
return;
}
cmdbuf.SetDepthBias(constant, clamp, factor); cmdbuf.SetDepthBias(constant, clamp, factor);
}); });
} }

View file

@ -1135,13 +1135,6 @@ void Device::RemoveUnsuitableExtensions() {
RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color, RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
// VK_EXT_depth_bias_control
extensions.depth_bias_control =
features.depth_bias_control.depthBiasControl &&
features.depth_bias_control.leastRepresentableValueForceUnormRepresentation;
RemoveExtensionFeatureIfUnsuitable(extensions.depth_bias_control, features.depth_bias_control,
VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME);
// VK_EXT_depth_clip_control // VK_EXT_depth_clip_control
extensions.depth_clip_control = features.depth_clip_control.depthClipControl; extensions.depth_clip_control = features.depth_clip_control.depthClipControl;
RemoveExtensionFeatureIfUnsuitable(extensions.depth_clip_control, features.depth_clip_control, RemoveExtensionFeatureIfUnsuitable(extensions.depth_clip_control, features.depth_clip_control,

View file

@ -41,7 +41,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
// Define all features which may be used by the implementation and require an extension here. // Define all features which may be used by the implementation and require an extension here.
#define FOR_EACH_VK_FEATURE_EXT(FEATURE) \ #define FOR_EACH_VK_FEATURE_EXT(FEATURE) \
FEATURE(EXT, CustomBorderColor, CUSTOM_BORDER_COLOR, custom_border_color) \ FEATURE(EXT, CustomBorderColor, CUSTOM_BORDER_COLOR, custom_border_color) \
FEATURE(EXT, DepthBiasControl, DEPTH_BIAS_CONTROL, depth_bias_control) \
FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \ FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \
FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \ FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \
FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \ FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \
@ -97,7 +96,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
#define FOR_EACH_VK_RECOMMENDED_EXTENSION(EXTENSION_NAME) \ #define FOR_EACH_VK_RECOMMENDED_EXTENSION(EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME) \ EXTENSION_NAME(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME) \ EXTENSION_NAME(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME) \ EXTENSION_NAME(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) \ EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME) \ EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME) \
@ -150,9 +148,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
// Define features where the absence of the feature may result in a degraded experience. // Define features where the absence of the feature may result in a degraded experience.
#define FOR_EACH_VK_RECOMMENDED_FEATURE(FEATURE_NAME) \ #define FOR_EACH_VK_RECOMMENDED_FEATURE(FEATURE_NAME) \
FEATURE_NAME(custom_border_color, customBorderColors) \ FEATURE_NAME(custom_border_color, customBorderColors) \
FEATURE_NAME(depth_bias_control, depthBiasControl) \
FEATURE_NAME(depth_bias_control, leastRepresentableValueForceUnormRepresentation) \
FEATURE_NAME(depth_bias_control, depthBiasExact) \
FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \ FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \
FEATURE_NAME(format_a4b4g4r4, formatA4B4G4R4) \ FEATURE_NAME(format_a4b4g4r4, formatA4B4G4R4) \
FEATURE_NAME(index_type_uint8, indexTypeUint8) \ FEATURE_NAME(index_type_uint8, indexTypeUint8) \
@ -479,11 +474,6 @@ public:
return extensions.depth_clip_control; return extensions.depth_clip_control;
} }
/// Returns true if the device supports VK_EXT_depth_bias_control.
bool IsExtDepthBiasControlSupported() const {
return extensions.depth_bias_control;
}
/// Returns true if the device supports VK_EXT_shader_viewport_index_layer. /// Returns true if the device supports VK_EXT_shader_viewport_index_layer.
bool IsExtShaderViewportIndexLayerSupported() const { bool IsExtShaderViewportIndexLayerSupported() const {
return extensions.shader_viewport_index_layer; return extensions.shader_viewport_index_layer;
@ -649,10 +639,6 @@ public:
return features.robustness2.nullDescriptor; return features.robustness2.nullDescriptor;
} }
bool HasExactDepthBiasControl() const {
return features.depth_bias_control.depthBiasExact;
}
u32 GetMaxVertexInputAttributes() const { u32 GetMaxVertexInputAttributes() const {
return properties.properties.limits.maxVertexInputAttributes; return properties.properties.limits.maxVertexInputAttributes;
} }