Compare commits

..

20 Commits

Author SHA1 Message Date
Feng Chen
f2a4204245 Simply legacy attribute implement 2021-11-04 09:26:16 +08:00
vonchenplus
49f9a44235 Support gl_FogFragCoord attribute 2021-10-31 23:34:17 +08:00
vonchenplus
36c21ff6cb Support gl_BackSecondaryColor attribute 2021-10-26 23:14:40 +08:00
vonchenplus
92bebecf46 Support gl_FrontSecondaryColor attribute 2021-10-26 23:09:44 +08:00
vonchenplus
b04c7b6343 Support gl_BackColor attribute 2021-10-26 23:01:57 +08:00
Ameer J
3c8c17be4d Merge pull request #7218 from bylaws/aswdqdsam
Fixup channel submit IOCTL syncpoint parameters
2021-10-24 19:35:00 -04:00
Ameer J
aed5878dd3 Merge pull request #7222 from FernandoS27/fix-indixed-textures-again
TexturePass: Fix clamping  of images as this allowed negative indices.
2021-10-24 15:16:31 -04:00
Fernando Sahmkow
e5291e2031 TexturePass: Fix clamping of images as this allowed negative indices. 2021-10-24 20:46:36 +02:00
Mai M
3be87bed8d Merge pull request #7221 from astrelsky/stepfix
Fixed ARM_Dynamic_64 Step
2021-10-24 14:43:40 -04:00
Andrew Strelsky
31b9797296 Fixed ARM_Dynamic_64 Step 2021-10-24 11:16:32 -04:00
Fernando S
5299554bb0 Merge pull request #7206 from vonchenplus/fix_vulkan_viewport_issue
Vulkan Rasterizer: Fix viewport issue
2021-10-24 01:53:04 +02:00
Billy Laws
2dbef58eeb Fixup channel submit IOCTL syncpoint parameters
The current arguments worked by happenstance as games only ever submit
one syncpoint and request one fence back, if a game were to do something
other than this then the arguments would've been parsed entirely wrong.
2021-10-24 00:01:35 +01:00
Ameer J
494e34af6a Merge pull request #7070 from FernandoS27/want-you-bad
Vulkan Rasterizer: Correct DepthBias/PolygonOffset on Vulkan.
2021-10-23 18:02:23 -04:00
Fernando Sahmkow
ad8afaf1ef Vulran Rasterizer: address feedback. 2021-10-23 23:46:29 +02:00
Narr the Reg
2686bf6734 Merge pull request #7217 from yuzu-emu/revert-6515-gc_thread_safe
Revert "input_common: Fix data race on GC implementation"
2021-10-23 16:41:09 -05:00
Fernando S
33e92c15eb Revert "input_common: Fix data race on GC implementation" 2021-10-23 23:32:16 +02:00
Fernando S
7461196839 Merge pull request #6515 from german77/gc_thread_safe
input_common: Fix data race on GC implementation
2021-10-23 23:28:22 +02:00
Feng Chen
b769bea61b Fix vulkan viewport issue 2021-10-22 22:56:31 +08:00
Fernando Sahmkow
60a3980561 Vulkan Rasterizer: Correct DepthBias/PolygonOffset on Vulkan. 2021-09-23 03:49:10 +02:00
Rodrigo Locatti
d4cab35533 input_common: Fix data race on GC implementation 2021-08-07 16:46:26 -05:00
28 changed files with 247 additions and 384 deletions

View File

@@ -1,240 +0,0 @@
/*
Copyright (c) 2020 Erik Rigtorp <erik@rigtorp.se>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4324)
#endif
#include <atomic>
#include <cassert>
#include <cstddef> // offsetof
#include <memory>
#include <new>
#include <stdexcept>
namespace Common {
namespace mpmc {
static constexpr size_t hardwareInterferenceSize = 64;
template <typename T>
using AlignedAllocator = std::allocator<T>;
template <typename T>
struct Slot {
~Slot() noexcept {
if (turn & 1) {
destroy();
}
}
template <typename... Args>
void construct(Args&&... args) noexcept {
static_assert(std::is_nothrow_constructible<T, Args&&...>::value,
"T must be nothrow constructible with Args&&...");
new (&storage) T(std::forward<Args>(args)...);
}
void destroy() noexcept {
static_assert(std::is_nothrow_destructible<T>::value, "T must be nothrow destructible");
reinterpret_cast<T*>(&storage)->~T();
}
T&& move() noexcept {
return reinterpret_cast<T&&>(storage);
}
// Align to avoid false sharing between adjacent slots
alignas(hardwareInterferenceSize) std::atomic<size_t> turn = {0};
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;
};
template <typename T, typename Allocator = AlignedAllocator<Slot<T>>>
class Queue {
private:
static_assert(std::is_nothrow_copy_assignable<T>::value ||
std::is_nothrow_move_assignable<T>::value,
"T must be nothrow copy or move assignable");
static_assert(std::is_nothrow_destructible<T>::value, "T must be nothrow destructible");
public:
explicit Queue(const size_t capacity, const Allocator& allocator = Allocator())
: capacity_(capacity), allocator_(allocator), head_(0), tail_(0) {
if (capacity_ < 1) {
throw std::invalid_argument("capacity < 1");
}
// Allocate one extra slot to prevent false sharing on the last slot
slots_ = allocator_.allocate(capacity_ + 1);
// Allocators are not required to honor alignment for over-aligned types
// (see http://eel.is/c++draft/allocator.requirements#10) so we verify
// alignment here
if (reinterpret_cast<size_t>(slots_) % alignof(Slot<T>) != 0) {
allocator_.deallocate(slots_, capacity_ + 1);
throw std::bad_alloc();
}
for (size_t i = 0; i < capacity_; ++i) {
new (&slots_[i]) Slot<T>();
}
static_assert(alignof(Slot<T>) == hardwareInterferenceSize,
"Slot must be aligned to cache line boundary to prevent false sharing");
static_assert(sizeof(Slot<T>) % hardwareInterferenceSize == 0,
"Slot size must be a multiple of cache line size to prevent "
"false sharing between adjacent slots");
static_assert(sizeof(Queue) % hardwareInterferenceSize == 0,
"Queue size must be a multiple of cache line size to "
"prevent false sharing between adjacent queues");
static_assert(offsetof(Queue, tail_) - offsetof(Queue, head_) ==
static_cast<std::ptrdiff_t>(hardwareInterferenceSize),
"head and tail must be a cache line apart to prevent false sharing");
}
~Queue() noexcept {
for (size_t i = 0; i < capacity_; ++i) {
slots_[i].~Slot();
}
allocator_.deallocate(slots_, capacity_ + 1);
}
// non-copyable and non-movable
Queue(const Queue&) = delete;
Queue& operator=(const Queue&) = delete;
template <typename... Args>
void emplace(Args&&... args) noexcept {
static_assert(std::is_nothrow_constructible<T, Args&&...>::value,
"T must be nothrow constructible with Args&&...");
auto const head = head_.fetch_add(1);
auto& slot = slots_[idx(head)];
while (turn(head) * 2 != slot.turn.load(std::memory_order_acquire))
;
slot.construct(std::forward<Args>(args)...);
slot.turn.store(turn(head) * 2 + 1, std::memory_order_release);
}
template <typename... Args>
bool try_emplace(Args&&... args) noexcept {
static_assert(std::is_nothrow_constructible<T, Args&&...>::value,
"T must be nothrow constructible with Args&&...");
auto head = head_.load(std::memory_order_acquire);
for (;;) {
auto& slot = slots_[idx(head)];
if (turn(head) * 2 == slot.turn.load(std::memory_order_acquire)) {
if (head_.compare_exchange_strong(head, head + 1)) {
slot.construct(std::forward<Args>(args)...);
slot.turn.store(turn(head) * 2 + 1, std::memory_order_release);
return true;
}
} else {
auto const prevHead = head;
head = head_.load(std::memory_order_acquire);
if (head == prevHead) {
return false;
}
}
}
}
void push(const T& v) noexcept {
static_assert(std::is_nothrow_copy_constructible<T>::value,
"T must be nothrow copy constructible");
emplace(v);
}
template <typename P, typename = typename std::enable_if<
std::is_nothrow_constructible<T, P&&>::value>::type>
void push(P&& v) noexcept {
emplace(std::forward<P>(v));
}
bool try_push(const T& v) noexcept {
static_assert(std::is_nothrow_copy_constructible<T>::value,
"T must be nothrow copy constructible");
return try_emplace(v);
}
template <typename P, typename = typename std::enable_if<
std::is_nothrow_constructible<T, P&&>::value>::type>
bool try_push(P&& v) noexcept {
return try_emplace(std::forward<P>(v));
}
void pop(T& v) noexcept {
auto const tail = tail_.fetch_add(1);
auto& slot = slots_[idx(tail)];
while (turn(tail) * 2 + 1 != slot.turn.load(std::memory_order_acquire))
;
v = slot.move();
slot.destroy();
slot.turn.store(turn(tail) * 2 + 2, std::memory_order_release);
}
bool try_pop(T& v) noexcept {
auto tail = tail_.load(std::memory_order_acquire);
for (;;) {
auto& slot = slots_[idx(tail)];
if (turn(tail) * 2 + 1 == slot.turn.load(std::memory_order_acquire)) {
if (tail_.compare_exchange_strong(tail, tail + 1)) {
v = slot.move();
slot.destroy();
slot.turn.store(turn(tail) * 2 + 2, std::memory_order_release);
return true;
}
} else {
auto const prevTail = tail;
tail = tail_.load(std::memory_order_acquire);
if (tail == prevTail) {
return false;
}
}
}
}
private:
constexpr size_t idx(size_t i) const noexcept {
return i % capacity_;
}
constexpr size_t turn(size_t i) const noexcept {
return i / capacity_;
}
private:
const size_t capacity_;
Slot<T>* slots_;
[[no_unique_address]] Allocator allocator_;
// Align to avoid false sharing between head_ and tail_
alignas(hardwareInterferenceSize) std::atomic<size_t> head_;
alignas(hardwareInterferenceSize) std::atomic<size_t> tail_;
};
} // namespace mpmc
template <typename T, typename Allocator = mpmc::AlignedAllocator<mpmc::Slot<T>>>
using MPMCQueue = mpmc::Queue<T, Allocator>;
} // namespace Common
#ifdef _MSC_VER
#pragma warning(pop)
#endif

View File

@@ -263,7 +263,7 @@ void ARM_Dynarmic_64::Run() {
}
void ARM_Dynarmic_64::Step() {
cb->InterpreterFallback(jit->GetPC(), 1);
jit->Step();
}
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,

View File

@@ -69,8 +69,7 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
std::vector<Reloc> relocs(params.relocation_count);
std::vector<u32> reloc_shifts(params.relocation_count);
std::vector<SyncptIncr> syncpt_increments(params.syncpoint_count);
std::vector<SyncptIncr> wait_checks(params.syncpoint_count);
std::vector<Fence> fences(params.fence_count);
std::vector<u32> fence_thresholds(params.fence_count);
// Slice input into their respective buffers
std::size_t offset = sizeof(IoctlSubmit);
@@ -78,15 +77,13 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
offset += SliceVectors(input, relocs, params.relocation_count, offset);
offset += SliceVectors(input, reloc_shifts, params.relocation_count, offset);
offset += SliceVectors(input, syncpt_increments, params.syncpoint_count, offset);
offset += SliceVectors(input, wait_checks, params.syncpoint_count, offset);
offset += SliceVectors(input, fences, params.fence_count, offset);
offset += SliceVectors(input, fence_thresholds, params.fence_count, offset);
auto& gpu = system.GPU();
if (gpu.UseNvdec()) {
for (std::size_t i = 0; i < syncpt_increments.size(); i++) {
const SyncptIncr& syncpt_incr = syncpt_increments[i];
fences[i].id = syncpt_incr.id;
fences[i].value =
fence_thresholds[i] =
syncpoint_manager.IncreaseSyncpoint(syncpt_incr.id, syncpt_incr.increments);
}
}
@@ -98,11 +95,6 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
cmdlist.size() * sizeof(u32));
gpu.PushCommandBuffer(cmdlist);
}
if (gpu.UseNvdec()) {
fences[0].value = syncpoint_manager.IncreaseSyncpoint(fences[0].id, 1);
Tegra::ChCommandHeaderList cmdlist{{(4 << 28) | fences[0].id}};
gpu.PushCommandBuffer(cmdlist);
}
std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
// Some games expect command_buffers to be written back
offset = sizeof(IoctlSubmit);
@@ -110,8 +102,7 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
offset += WriteVectors(output, relocs, offset);
offset += WriteVectors(output, reloc_shifts, offset);
offset += WriteVectors(output, syncpt_increments, offset);
offset += WriteVectors(output, wait_checks, offset);
offset += WriteVectors(output, fences, offset);
offset += WriteVectors(output, fence_thresholds, offset);
return NvResult::Success;
}

View File

@@ -56,19 +56,16 @@ protected:
s32 target{};
s32 target_offset{};
};
static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");
static_assert(sizeof(Reloc) == 0x10, "Reloc has incorrect size");
struct SyncptIncr {
u32 id{};
u32 increments{};
u32 unk0{};
u32 unk1{};
u32 unk2{};
};
static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");
struct Fence {
u32 id{};
u32 value{};
};
static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");
static_assert(sizeof(SyncptIncr) == 0x14, "SyncptIncr has incorrect size");
struct IoctlGetSyncpoint {
// Input

View File

@@ -170,7 +170,7 @@ void Adapter::UpdateYuzuSettings(std::size_t port) {
if (pads[port].buttons != 0) {
pad_status.button = pads[port].last_button;
pad_queue.push(pad_status);
pad_queue.Push(pad_status);
}
// Accounting for a threshold here to ensure an intentional press
@@ -181,7 +181,7 @@ void Adapter::UpdateYuzuSettings(std::size_t port) {
pad_status.axis = static_cast<PadAxes>(i);
pad_status.axis_value = value;
pad_status.axis_threshold = axis_threshold;
pad_queue.push(pad_status);
pad_queue.Push(pad_status);
}
}
}
@@ -478,18 +478,20 @@ bool Adapter::DeviceConnected(std::size_t port) const {
}
void Adapter::BeginConfiguration() {
pad_queue.Clear();
configuring = true;
}
void Adapter::EndConfiguration() {
pad_queue.Clear();
configuring = false;
}
Common::MPMCQueue<GCPadStatus>& Adapter::GetPadQueue() {
Common::SPSCQueue<GCPadStatus>& Adapter::GetPadQueue() {
return pad_queue;
}
const Common::MPMCQueue<GCPadStatus>& Adapter::GetPadQueue() const {
const Common::SPSCQueue<GCPadStatus>& Adapter::GetPadQueue() const {
return pad_queue;
}

View File

@@ -8,8 +8,8 @@
#include <mutex>
#include <thread>
#include <unordered_map>
#include "common/atomic_threadsafe_queue.h"
#include "common/common_types.h"
#include "common/threadsafe_queue.h"
#include "input_common/main.h"
struct libusb_context;
@@ -85,8 +85,8 @@ public:
void BeginConfiguration();
void EndConfiguration();
Common::MPMCQueue<GCPadStatus>& GetPadQueue();
const Common::MPMCQueue<GCPadStatus>& GetPadQueue() const;
Common::SPSCQueue<GCPadStatus>& GetPadQueue();
const Common::SPSCQueue<GCPadStatus>& GetPadQueue() const;
GCController& GetPadState(std::size_t port);
const GCController& GetPadState(std::size_t port) const;
@@ -145,7 +145,7 @@ private:
libusb_device_handle* usb_adapter_handle = nullptr;
std::array<GCController, 4> pads;
Common::MPMCQueue<GCPadStatus> pad_queue{1024};
Common::SPSCQueue<GCPadStatus> pad_queue;
std::thread adapter_input_thread;
std::thread adapter_scan_thread;

View File

@@ -7,7 +7,7 @@
#include <mutex>
#include <utility>
#include "common/assert.h"
#include "common/atomic_threadsafe_queue.h"
#include "common/threadsafe_queue.h"
#include "input_common/gcadapter/gc_adapter.h"
#include "input_common/gcadapter/gc_poller.h"
@@ -103,7 +103,7 @@ Common::ParamPackage GCButtonFactory::GetNextInput() const {
Common::ParamPackage params;
GCAdapter::GCPadStatus pad;
auto& queue = adapter->GetPadQueue();
while (queue.try_pop(pad)) {
while (queue.Pop(pad)) {
// This while loop will break on the earliest detected button
params.Set("engine", "gcpad");
params.Set("port", static_cast<s32>(pad.port));
@@ -263,7 +263,7 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() {
GCAdapter::GCPadStatus pad;
Common::ParamPackage params;
auto& queue = adapter->GetPadQueue();
while (queue.try_pop(pad)) {
while (queue.Pop(pad)) {
if (pad.button != GCAdapter::PadButton::Undefined) {
params.Set("engine", "gcpad");
params.Set("port", static_cast<s32>(pad.port));

View File

@@ -52,7 +52,7 @@ void Mouse::UpdateYuzuSettings() {
return;
}
mouse_queue.push(MouseStatus{
mouse_queue.Push(MouseStatus{
.button = last_button,
});
}
@@ -153,6 +153,7 @@ void Mouse::ReleaseAllButtons() {
void Mouse::BeginConfiguration() {
buttons = 0;
last_button = MouseButton::Undefined;
mouse_queue.Clear();
configuring = true;
}
@@ -164,6 +165,7 @@ void Mouse::EndConfiguration() {
info.data.axis = {0, 0};
}
last_button = MouseButton::Undefined;
mouse_queue.Clear();
configuring = false;
}
@@ -203,11 +205,11 @@ bool Mouse::UnlockButton(std::size_t button_) {
return button_state;
}
Common::MPMCQueue<MouseStatus>& Mouse::GetMouseQueue() {
Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() {
return mouse_queue;
}
const Common::MPMCQueue<MouseStatus>& Mouse::GetMouseQueue() const {
const Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() const {
return mouse_queue;
}

View File

@@ -9,8 +9,8 @@
#include <stop_token>
#include <thread>
#include "common/atomic_threadsafe_queue.h"
#include "common/common_types.h"
#include "common/threadsafe_queue.h"
#include "common/vector_math.h"
#include "core/frontend/input.h"
#include "input_common/motion_input.h"
@@ -79,8 +79,8 @@ public:
[[nodiscard]] bool ToggleButton(std::size_t button_);
[[nodiscard]] bool UnlockButton(std::size_t button_);
[[nodiscard]] Common::MPMCQueue<MouseStatus>& GetMouseQueue();
[[nodiscard]] const Common::MPMCQueue<MouseStatus>& GetMouseQueue() const;
[[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue();
[[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const;
[[nodiscard]] MouseData& GetMouseState(std::size_t button);
[[nodiscard]] const MouseData& GetMouseState(std::size_t button) const;
@@ -109,7 +109,7 @@ private:
std::jthread update_thread;
MouseButton last_button{MouseButton::Undefined};
std::array<MouseInfo, 7> mouse_info;
Common::MPMCQueue<MouseStatus> mouse_queue{1024};
Common::SPSCQueue<MouseStatus> mouse_queue;
bool configuring{false};
int mouse_panning_timout{};
};

View File

@@ -52,7 +52,7 @@ Common::ParamPackage MouseButtonFactory::GetNextInput() const {
MouseInput::MouseStatus pad;
Common::ParamPackage params;
auto& queue = mouse_input->GetMouseQueue();
while (queue.try_pop(pad)) {
while (queue.Pop(pad)) {
// This while loop will break on the earliest detected button
if (pad.button != MouseInput::MouseButton::Undefined) {
params.Set("engine", "mouse");
@@ -184,7 +184,7 @@ Common::ParamPackage MouseAnalogFactory::GetNextInput() const {
MouseInput::MouseStatus pad;
Common::ParamPackage params;
auto& queue = mouse_input->GetMouseQueue();
while (queue.try_pop(pad)) {
while (queue.Pop(pad)) {
// This while loop will break on the earliest detected button
if (pad.button != MouseInput::MouseButton::Undefined) {
params.Set("engine", "mouse");
@@ -227,7 +227,7 @@ Common::ParamPackage MouseMotionFactory::GetNextInput() const {
MouseInput::MouseStatus pad;
Common::ParamPackage params;
auto& queue = mouse_input->GetMouseQueue();
while (queue.try_pop(pad)) {
while (queue.Pop(pad)) {
// This while loop will break on the earliest detected button
if (pad.button != MouseInput::MouseButton::Undefined) {
params.Set("engine", "mouse");
@@ -275,7 +275,7 @@ Common::ParamPackage MouseTouchFactory::GetNextInput() const {
MouseInput::MouseStatus pad;
Common::ParamPackage params;
auto& queue = mouse_input->GetMouseQueue();
while (queue.try_pop(pad)) {
while (queue.Pop(pad)) {
// This while loop will break on the earliest detected button
if (pad.button != MouseInput::MouseButton::Undefined) {
params.Set("engine", "mouse");

View File

@@ -46,7 +46,7 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) {
// Don't handle the event if we are configuring
if (sdl_state->polling) {
sdl_state->event_queue.push(*event);
sdl_state->event_queue.Push(*event);
} else {
sdl_state->HandleGameControllerEvent(*event);
}
@@ -1460,6 +1460,7 @@ public:
explicit SDLPoller(SDLState& state_) : state(state_) {}
void Start([[maybe_unused]] const std::string& device_id) override {
state.event_queue.Clear();
state.polling = true;
}
@@ -1477,7 +1478,7 @@ public:
Common::ParamPackage GetNextInput() override {
SDL_Event event;
while (state.event_queue.try_pop(event)) {
while (state.event_queue.Pop(event)) {
const auto package = FromEvent(event);
if (package) {
return *package;
@@ -1549,7 +1550,7 @@ public:
Common::ParamPackage GetNextInput() override {
SDL_Event event;
while (state.event_queue.try_pop(event)) {
while (state.event_queue.Pop(event)) {
const auto package = FromEvent(event);
if (package) {
return *package;
@@ -1591,7 +1592,7 @@ public:
Common::ParamPackage GetNextInput() override {
SDL_Event event;
while (state.event_queue.try_pop(event)) {
while (state.event_queue.Pop(event)) {
if (event.type != SDL_JOYAXISMOTION) {
// Check for a button press
auto button_press = button_poller.FromEvent(event);

View File

@@ -12,8 +12,8 @@
#include <SDL.h>
#include "common/atomic_threadsafe_queue.h"
#include "common/common_types.h"
#include "common/threadsafe_queue.h"
#include "input_common/sdl/sdl.h"
union SDL_Event;
@@ -59,7 +59,7 @@ public:
/// Used by the Pollers during config
std::atomic<bool> polling = false;
Common::MPMCQueue<SDL_Event> event_queue{1024};
Common::SPSCQueue<SDL_Event> event_queue;
std::vector<Common::ParamPackage> GetInputDevices() override;

View File

@@ -338,7 +338,7 @@ void Client::UpdateYuzuSettings(std::size_t client, std::size_t pad_index,
gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]);
}
UDPPadStatus pad{
.host = clients[client].host.c_str(),
.host = clients[client].host,
.port = clients[client].port,
.pad_index = pad_index,
};
@@ -346,12 +346,12 @@ void Client::UpdateYuzuSettings(std::size_t client, std::size_t pad_index,
if (gyro[i] > 5.0f || gyro[i] < -5.0f) {
pad.motion = static_cast<PadMotion>(i);
pad.motion_value = gyro[i];
pad_queue.push(pad);
pad_queue.Push(pad);
}
if (acc[i] > 1.75f || acc[i] < -1.75f) {
pad.motion = static_cast<PadMotion>(i + 3);
pad.motion_value = acc[i];
pad_queue.push(pad);
pad_queue.Push(pad);
}
}
}
@@ -401,10 +401,12 @@ void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client,
}
void Client::BeginConfiguration() {
pad_queue.Clear();
configuring = true;
}
void Client::EndConfiguration() {
pad_queue.Clear();
configuring = false;
}
@@ -432,11 +434,11 @@ const Input::TouchStatus& Client::GetTouchState() const {
return touch_status;
}
Common::MPMCQueue<UDPPadStatus>& Client::GetPadQueue() {
Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() {
return pad_queue;
}
const Common::MPMCQueue<UDPPadStatus>& Client::GetPadQueue() const {
const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const {
return pad_queue;
}

View File

@@ -11,10 +11,10 @@
#include <string>
#include <thread>
#include <tuple>
#include "common/atomic_threadsafe_queue.h"
#include "common/common_types.h"
#include "common/param_package.h"
#include "common/thread.h"
#include "common/threadsafe_queue.h"
#include "common/vector_math.h"
#include "core/frontend/input.h"
#include "input_common/motion_input.h"
@@ -46,7 +46,7 @@ enum class PadTouch {
};
struct UDPPadStatus {
const char* host{"127.0.0.1"};
std::string host{"127.0.0.1"};
u16 port{26760};
std::size_t pad_index{};
PadMotion motion{PadMotion::Undefined};
@@ -85,8 +85,8 @@ public:
bool DeviceConnected(std::size_t pad) const;
void ReloadSockets();
Common::MPMCQueue<UDPPadStatus>& GetPadQueue();
const Common::MPMCQueue<UDPPadStatus>& GetPadQueue() const;
Common::SPSCQueue<UDPPadStatus>& GetPadQueue();
const Common::SPSCQueue<UDPPadStatus>& GetPadQueue() const;
DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad);
const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const;
@@ -146,7 +146,7 @@ private:
static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2;
std::array<PadData, MAX_UDP_CLIENTS * PADS_PER_CLIENT> pads{};
std::array<ClientConnection, MAX_UDP_CLIENTS> clients{};
Common::MPMCQueue<UDPPadStatus> pad_queue{1024};
Common::SPSCQueue<UDPPadStatus> pad_queue{};
Input::TouchStatus touch_status{};
std::array<std::size_t, MAX_TOUCH_FINGERS> finger_id{};
};

View File

@@ -59,7 +59,7 @@ Common::ParamPackage UDPMotionFactory::GetNextInput() {
Common::ParamPackage params;
CemuhookUDP::UDPPadStatus pad;
auto& queue = client->GetPadQueue();
while (queue.try_pop(pad)) {
while (queue.Pop(pad)) {
if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) {
continue;
}

View File

@@ -430,15 +430,33 @@ Id DescType(EmitContext& ctx, Id sampled_type, Id pointer_type, u32 count) {
}
}
size_t FindNextUnusedLocation(const std::bitset<IR::NUM_GENERICS>& used_locations,
size_t start_offset) {
size_t FindAndSetNextUnusedLocation(std::bitset<IR::NUM_GENERICS>& used_locations,
size_t& start_offset) {
for (size_t location = start_offset; location < used_locations.size(); ++location) {
if (!used_locations.test(location)) {
start_offset = location;
used_locations.set(location);
return location;
}
}
throw RuntimeError("Unable to get an unused location for legacy attribute");
}
Id DefineLegacyInput(EmitContext& ctx, std::bitset<IR::NUM_GENERICS>& used_locations,
size_t& start_offset) {
const Id id{DefineInput(ctx, ctx.F32[4], true)};
const size_t location = FindAndSetNextUnusedLocation(used_locations, start_offset);
ctx.Decorate(id, spv::Decoration::Location, location);
return id;
}
Id DefineLegacyOutput(EmitContext& ctx, std::bitset<IR::NUM_GENERICS>& used_locations,
size_t& start_offset, std::optional<u32> invocations) {
const Id id{DefineOutput(ctx, ctx.F32[4], invocations)};
const size_t location = FindAndSetNextUnusedLocation(used_locations, start_offset);
ctx.Decorate(id, spv::Decoration::Location, location);
return id;
}
} // Anonymous namespace
void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) {
@@ -520,6 +538,64 @@ Id EmitContext::BitOffset16(const IR::Value& offset) {
return OpBitwiseAnd(U32[1], OpShiftLeftLogical(U32[1], Def(offset), Const(3u)), Const(16u));
}
Id EmitContext::InputLegacyAttribute(IR::Attribute attribute) {
if (attribute >= IR::Attribute::ColorFrontDiffuseR &&
attribute <= IR::Attribute::ColorFrontDiffuseA) {
return input_front_color;
}
if (attribute >= IR::Attribute::ColorFrontSpecularR &&
attribute <= IR::Attribute::ColorFrontSpecularA) {
return input_front_secondary_color;
}
if (attribute >= IR::Attribute::ColorBackDiffuseR &&
attribute <= IR::Attribute::ColorBackDiffuseA) {
return input_back_color;
}
if (attribute >= IR::Attribute::ColorBackSpecularR &&
attribute <= IR::Attribute::ColorBackSpecularA) {
return input_back_secondary_color;
}
if (attribute == IR::Attribute::FogCoordinate) {
return input_fog_frag_coord;
}
if (attribute >= IR::Attribute::FixedFncTexture0S &&
attribute <= IR::Attribute::FixedFncTexture9Q) {
u32 index =
(static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4;
return input_fixed_fnc_textures[index];
}
throw InvalidArgument("Attribute is not legacy attribute {}", attribute);
}
Id EmitContext::OutputLegacyAttribute(IR::Attribute attribute) {
if (attribute >= IR::Attribute::ColorFrontDiffuseR &&
attribute <= IR::Attribute::ColorFrontDiffuseA) {
return output_front_color;
}
if (attribute >= IR::Attribute::ColorFrontSpecularR &&
attribute <= IR::Attribute::ColorFrontSpecularA) {
return output_front_secondary_color;
}
if (attribute >= IR::Attribute::ColorBackDiffuseR &&
attribute <= IR::Attribute::ColorBackDiffuseA) {
return output_back_color;
}
if (attribute >= IR::Attribute::ColorBackSpecularR &&
attribute <= IR::Attribute::ColorBackSpecularA) {
return output_back_secondary_color;
}
if (attribute == IR::Attribute::FogCoordinate) {
return output_fog_frag_coord;
}
if (attribute >= IR::Attribute::FixedFncTexture0S &&
attribute <= IR::Attribute::FixedFncTexture9Q) {
u32 index =
(static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4;
return output_fixed_fnc_textures[index];
}
throw InvalidArgument("Attribute is not legacy attribute {}", attribute);
}
void EmitContext::DefineCommonTypes(const Info& info) {
void_id = TypeVoid();
@@ -1279,22 +1355,26 @@ void EmitContext::DefineInputs(const IR::Program& program) {
}
size_t previous_unused_location = 0;
if (loads.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
const size_t location = FindNextUnusedLocation(used_locations, previous_unused_location);
previous_unused_location = location;
used_locations.set(location);
const Id id{DefineInput(*this, F32[4], true)};
Decorate(id, spv::Decoration::Location, location);
input_front_color = id;
input_front_color = DefineLegacyInput(*this, used_locations, previous_unused_location);
}
if (loads.AnyComponent(IR::Attribute::ColorFrontSpecularR)) {
input_front_secondary_color =
DefineLegacyInput(*this, used_locations, previous_unused_location);
}
if (loads.AnyComponent(IR::Attribute::ColorBackDiffuseR)) {
input_back_color = DefineLegacyInput(*this, used_locations, previous_unused_location);
}
if (loads.AnyComponent(IR::Attribute::ColorBackSpecularR)) {
input_back_secondary_color =
DefineLegacyInput(*this, used_locations, previous_unused_location);
}
if (loads.AnyComponent(IR::Attribute::FogCoordinate)) {
input_fog_frag_coord = DefineLegacyInput(*this, used_locations, previous_unused_location);
}
for (size_t index = 0; index < NUM_FIXEDFNCTEXTURE; ++index) {
if (loads.AnyComponent(IR::Attribute::FixedFncTexture0S + index * 4)) {
const size_t location =
FindNextUnusedLocation(used_locations, previous_unused_location);
previous_unused_location = location;
used_locations.set(location);
const Id id{DefineInput(*this, F32[4], true)};
Decorate(id, spv::Decoration::Location, location);
input_fixed_fnc_textures[index] = id;
input_fixed_fnc_textures[index] =
DefineLegacyInput(*this, used_locations, previous_unused_location);
}
}
if (stage == Stage::TessellationEval) {
@@ -1356,22 +1436,29 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
}
size_t previous_unused_location = 0;
if (info.stores.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
const size_t location = FindNextUnusedLocation(used_locations, previous_unused_location);
previous_unused_location = location;
used_locations.set(location);
const Id id{DefineOutput(*this, F32[4], invocations)};
Decorate(id, spv::Decoration::Location, static_cast<u32>(location));
output_front_color = id;
output_front_color =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
if (info.stores.AnyComponent(IR::Attribute::ColorFrontSpecularR)) {
output_front_secondary_color =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
if (info.stores.AnyComponent(IR::Attribute::ColorBackDiffuseR)) {
output_back_color =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
if (info.stores.AnyComponent(IR::Attribute::ColorBackSpecularR)) {
output_back_secondary_color =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
if (info.stores.AnyComponent(IR::Attribute::FogCoordinate)) {
output_fog_frag_coord =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
for (size_t index = 0; index < NUM_FIXEDFNCTEXTURE; ++index) {
if (info.stores.AnyComponent(IR::Attribute::FixedFncTexture0S + index * 4)) {
const size_t location =
FindNextUnusedLocation(used_locations, previous_unused_location);
previous_unused_location = location;
used_locations.set(location);
const Id id{DefineOutput(*this, F32[4], invocations)};
Decorate(id, spv::Decoration::Location, location);
output_fixed_fnc_textures[index] = id;
output_fixed_fnc_textures[index] =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
}
switch (stage) {

View File

@@ -113,6 +113,9 @@ public:
[[nodiscard]] Id BitOffset8(const IR::Value& offset);
[[nodiscard]] Id BitOffset16(const IR::Value& offset);
Id InputLegacyAttribute(IR::Attribute attribute);
Id OutputLegacyAttribute(IR::Attribute attribute);
Id Const(u32 value) {
return Constant(U32[1], value);
}
@@ -269,12 +272,20 @@ public:
Id input_position{};
Id input_front_color{};
Id input_front_secondary_color{};
Id input_back_color{};
Id input_back_secondary_color{};
Id input_fog_frag_coord{};
std::array<Id, 10> input_fixed_fnc_textures{};
std::array<Id, 32> input_generics{};
Id output_point_size{};
Id output_position{};
Id output_front_color{};
Id output_front_secondary_color{};
Id output_back_color{};
Id output_back_secondary_color{};
Id output_fog_frag_coord{};
std::array<Id, 10> output_fixed_fnc_textures{};
std::array<std::array<GenericElementInfo, 4>, 32> output_generics{};

View File

@@ -43,23 +43,12 @@ Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&...
}
}
bool IsFixedFncTexture(IR::Attribute attribute) {
return attribute >= IR::Attribute::FixedFncTexture0S &&
attribute <= IR::Attribute::FixedFncTexture9Q;
}
u32 FixedFncTextureAttributeIndex(IR::Attribute attribute) {
if (!IsFixedFncTexture(attribute)) {
throw InvalidArgument("Attribute {} is not a FixedFncTexture", attribute);
}
return (static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4u;
}
u32 FixedFncTextureAttributeElement(IR::Attribute attribute) {
if (!IsFixedFncTexture(attribute)) {
throw InvalidArgument("Attribute {} is not a FixedFncTexture", attribute);
}
return static_cast<u32>(attribute) % 4u;
bool IsLegacyAttribute(IR::Attribute attribute) {
return (attribute >= IR::Attribute::ColorFrontDiffuseR &&
attribute <= IR::Attribute::ColorBackSpecularA) ||
attribute == IR::Attribute::FogCoordinate ||
(attribute >= IR::Attribute::FixedFncTexture0S &&
attribute <= IR::Attribute::FixedFncTexture9Q);
}
template <typename... Args>
@@ -93,12 +82,16 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
return OutputAccessChain(ctx, ctx.output_f32, info.id, index_id);
}
}
if (IsFixedFncTexture(attr)) {
const u32 index{FixedFncTextureAttributeIndex(attr)};
const u32 element{FixedFncTextureAttributeElement(attr)};
const Id element_id{ctx.Const(element)};
return OutputAccessChain(ctx, ctx.output_f32, ctx.output_fixed_fnc_textures[index],
element_id);
if (IsLegacyAttribute(attr)) {
if (attr == IR::Attribute::FogCoordinate) {
return OutputAccessChain(ctx, ctx.output_f32, ctx.OutputLegacyAttribute(attr),
ctx.Const(0u));
} else {
const u32 element{static_cast<u32>(attr) % 4};
const Id element_id{ctx.Const(element)};
return OutputAccessChain(ctx, ctx.output_f32, ctx.OutputLegacyAttribute(attr),
element_id);
}
}
switch (attr) {
case IR::Attribute::PointSize:
@@ -111,14 +104,6 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
const Id element_id{ctx.Const(element)};
return OutputAccessChain(ctx, ctx.output_f32, ctx.output_position, element_id);
}
case IR::Attribute::ColorFrontDiffuseR:
case IR::Attribute::ColorFrontDiffuseG:
case IR::Attribute::ColorFrontDiffuseB:
case IR::Attribute::ColorFrontDiffuseA: {
const u32 element{static_cast<u32>(attr) % 4};
const Id element_id{ctx.Const(element)};
return OutputAccessChain(ctx, ctx.output_f32, ctx.output_front_color, element_id);
}
case IR::Attribute::ClipDistance0:
case IR::Attribute::ClipDistance1:
case IR::Attribute::ClipDistance2:
@@ -341,11 +326,17 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
const Id value{ctx.OpLoad(type->id, pointer)};
return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value;
}
if (IsFixedFncTexture(attr)) {
const u32 index{FixedFncTextureAttributeIndex(attr)};
const Id attr_id{ctx.input_fixed_fnc_textures[index]};
const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex, attr_id, ctx.Const(element))};
return ctx.OpLoad(ctx.F32[1], attr_ptr);
if (IsLegacyAttribute(attr)) {
if (attr == IR::Attribute::FogCoordinate) {
const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex,
ctx.InputLegacyAttribute(attr), ctx.Const(0u))};
return ctx.OpLoad(ctx.F32[1], attr_ptr);
} else {
const Id element_id{ctx.Const(element)};
const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex,
ctx.InputLegacyAttribute(attr), element_id)};
return ctx.OpLoad(ctx.F32[1], attr_ptr);
}
}
switch (attr) {
case IR::Attribute::PrimitiveId:
@@ -356,13 +347,6 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
case IR::Attribute::PositionW:
return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_position,
ctx.Const(element)));
case IR::Attribute::ColorFrontDiffuseR:
case IR::Attribute::ColorFrontDiffuseG:
case IR::Attribute::ColorFrontDiffuseB:
case IR::Attribute::ColorFrontDiffuseA: {
return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_front_color,
ctx.Const(element)));
}
case IR::Attribute::InstanceId:
if (ctx.profile.support_vertex_instance_id) {
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.instance_id));

View File

@@ -492,7 +492,7 @@ void TexturePass(Environment& env, IR::Program& program) {
const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)};
IR::IREmitter ir{*texture_inst.block, insert_point};
const IR::U32 shift{ir.Imm32(std::countr_zero(DESCRIPTOR_SIZE))};
inst->SetArg(0, ir.SMin(ir.ShiftRightArithmetic(cbuf.dynamic_offset, shift),
inst->SetArg(0, ir.UMin(ir.ShiftRightArithmetic(cbuf.dynamic_offset, shift),
ir.Imm32(DESCRIPTOR_SIZE - 1)));
} else {
inst->SetArg(0, IR::Value{});

View File

@@ -38,6 +38,9 @@ enum : u8 {
Shaders,
// Special entries
DepthBiasGlobal,
LastCommonEntry,
};

View File

@@ -32,10 +32,7 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
VideoCore::RasterizerInterface* const rasterizer = renderer.ReadRasterizer();
while (!stop_token.stop_requested()) {
CommandDataContainer next;
if (!state.queue.try_pop(next)) {
continue;
}
CommandDataContainer next = state.queue.PopWait(stop_token);
if (stop_token.stop_requested()) {
break;
}
@@ -122,7 +119,7 @@ u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) {
std::unique_lock lk(state.write_lock);
const u64 fence{++state.last_fence};
state.queue.push(CommandDataContainer(std::move(command_data), fence, block));
state.queue.Push(CommandDataContainer(std::move(command_data), fence, block));
if (block) {
state.cv.wait(lk, thread.get_stop_token(), [this, fence] {

View File

@@ -11,7 +11,7 @@
#include <thread>
#include <variant>
#include "common/atomic_threadsafe_queue.h"
#include "common/threadsafe_queue.h"
#include "video_core/framebuffer_config.h"
namespace Tegra {
@@ -97,9 +97,9 @@ struct CommandDataContainer {
/// Struct used to synchronize the GPU thread
struct SynchState final {
using CommandQueue = Common::MPMCQueue<CommandDataContainer>;
using CommandQueue = Common::SPSCQueue<CommandDataContainer, true>;
std::mutex write_lock;
CommandQueue queue{100000};
CommandQueue queue;
u64 last_fence{};
std::atomic<u64> signaled_fence{};
std::condition_variable_any cv;

View File

@@ -627,9 +627,21 @@ void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
if (!state_tracker.TouchDepthBias()) {
return;
}
scheduler.Record([constant = regs.polygon_offset_units, clamp = regs.polygon_offset_clamp,
float units = regs.polygon_offset_units / 2.0f;
const bool is_d24 = regs.zeta.format == Tegra::DepthFormat::S8_UINT_Z24_UNORM ||
regs.zeta.format == Tegra::DepthFormat::D24X8_UNORM ||
regs.zeta.format == Tegra::DepthFormat::D24S8_UNORM ||
regs.zeta.format == Tegra::DepthFormat::D24C8_UNORM;
if (is_d24 && !device.SupportsD24DepthBuffer()) {
// 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
const double rescale_factor =
static_cast<double>(1ULL << (32 - 24)) / (static_cast<double>(0x1.ep+127));
units = static_cast<float>(static_cast<double>(units) * rescale_factor);
}
scheduler.Record([constant = units, clamp = regs.polygon_offset_clamp,
factor = regs.polygon_offset_factor](vk::CommandBuffer cmdbuf) {
cmdbuf.SetDepthBias(constant, clamp, factor / 2.0f);
cmdbuf.SetDepthBias(constant, clamp, factor);
});
}

View File

@@ -54,6 +54,7 @@ void SetupDirtyViewports(Tables& tables) {
FillBlock(tables[0], OFF(viewport_transform), NUM(viewport_transform), Viewports);
FillBlock(tables[0], OFF(viewports), NUM(viewports), Viewports);
tables[0][OFF(viewport_transform_enabled)] = Viewports;
tables[1][OFF(screen_y_control)] = Viewports;
}
void SetupDirtyScissors(Tables& tables) {

View File

@@ -79,7 +79,8 @@ public:
}
bool TouchDepthBias() {
return Exchange(Dirty::DepthBias, false);
return Exchange(Dirty::DepthBias, false) ||
Exchange(VideoCommon::Dirty::DepthBiasGlobal, false);
}
bool TouchBlendConstants() {

View File

@@ -221,6 +221,7 @@ void TextureCache<P>::UpdateRenderTargets(bool is_clear) {
BindRenderTarget(&render_targets.depth_buffer_id, FindDepthBuffer(is_clear));
}
const ImageViewId depth_buffer_id = render_targets.depth_buffer_id;
PrepareImageView(depth_buffer_id, true, is_clear && IsFullClear(depth_buffer_id));
for (size_t index = 0; index < NUM_RT; ++index) {
@@ -230,6 +231,8 @@ void TextureCache<P>::UpdateRenderTargets(bool is_clear) {
maxwell3d.regs.render_area.width,
maxwell3d.regs.render_area.height,
};
flags[Dirty::DepthBiasGlobal] = true;
}
template <class P>

View File

@@ -623,6 +623,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
is_float16_supported = false;
}
supports_d24_depth =
IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, FormatType::Optimal);
graphics_queue = logical.GetQueue(graphics_family);
present_queue = logical.GetQueue(present_family);
}

View File

@@ -332,6 +332,10 @@ public:
return sets_per_pool;
}
bool SupportsD24DepthBuffer() const {
return supports_d24_depth;
}
private:
/// Checks if the physical device is suitable.
void CheckSuitability(bool requires_swapchain) const;
@@ -425,6 +429,7 @@ private:
bool has_broken_cube_compatibility{}; ///< Has broken cube compatiblity bit
bool has_renderdoc{}; ///< Has RenderDoc attached
bool has_nsight_graphics{}; ///< Has Nsight Graphics attached
bool supports_d24_depth{}; ///< Supports D24 depth buffers.
// Telemetry parameters
std::string vendor_name; ///< Device's driver name.