mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-29 11:53:24 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f199597158 | |||
| 9c313fb787 | |||
| eec29b83f3 | |||
| a57041d62f | |||
| 4956bc86c3 | |||
| e8b1dc7c0b | |||
| e81d170458 | |||
| 7ed7e5e31d | |||
| eb32b8766a | |||
| a484e6c34b | |||
| 84490a7d6f | |||
| 933f79af95 | |||
| f532357793 | |||
| ab92e5fa52 | |||
| 791880f9bf | |||
| e058a15074 | |||
| 6313800aee | |||
| 5428dbbd14 | |||
| 9694216ad7 | |||
| 4fbdc133dd | |||
| f210f16e8c | |||
| 20bf6bc282 | |||
| 99e95eebb1 |
@@ -121,15 +121,6 @@ void BufferCache<P>::WriteMemory(DAddr device_addr, u64 size) {
|
|||||||
memory_tracker.MarkRegionAsCpuModified(device_addr, size);
|
memory_tracker.MarkRegionAsCpuModified(device_addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
|
||||||
void BufferCache<P>::CpuWriteInvalidate(DAddr device_addr, u64 size) {
|
|
||||||
if (!memory_tracker.CpuMarkIfNotGpuModified(device_addr, size)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
WriteMemory(device_addr, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
void BufferCache<P>::CachedWriteMemory(DAddr device_addr, u64 size) {
|
void BufferCache<P>::CachedWriteMemory(DAddr device_addr, u64 size) {
|
||||||
const bool is_dirty = IsRegionRegistered(device_addr, size);
|
const bool is_dirty = IsRegionRegistered(device_addr, size);
|
||||||
@@ -1721,9 +1712,6 @@ void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept {
|
|||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 size) {
|
bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 size) {
|
||||||
if (!memory_tracker.HasCpuModifiedCheap(device_addr, size)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
upload_copies.clear();
|
upload_copies.clear();
|
||||||
u64 total_size_bytes = 0;
|
u64 total_size_bytes = 0;
|
||||||
u64 largest_copy = 0;
|
u64 largest_copy = 0;
|
||||||
|
|||||||
@@ -217,8 +217,6 @@ public:
|
|||||||
|
|
||||||
void WriteMemory(DAddr device_addr, u64 size);
|
void WriteMemory(DAddr device_addr, u64 size);
|
||||||
|
|
||||||
void CpuWriteInvalidate(DAddr device_addr, u64 size);
|
|
||||||
|
|
||||||
void CachedWriteMemory(DAddr device_addr, u64 size);
|
void CachedWriteMemory(DAddr device_addr, u64 size);
|
||||||
|
|
||||||
bool OnCPUWrite(DAddr device_addr, u64 size);
|
bool OnCPUWrite(DAddr device_addr, u64 size);
|
||||||
|
|||||||
@@ -7,11 +7,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <mutex>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <ankerl/unordered_dense.h>
|
#include <ankerl/unordered_dense.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -51,24 +49,6 @@ public:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool HasCpuModifiedCheap(VAddr query_cpu_addr, u64 query_size) noexcept {
|
|
||||||
std::size_t remaining_size{query_size};
|
|
||||||
std::size_t page_index{query_cpu_addr >> HIGHER_PAGE_BITS};
|
|
||||||
u64 page_offset{query_cpu_addr & HIGHER_PAGE_MASK};
|
|
||||||
while (remaining_size > 0) {
|
|
||||||
const std::size_t copy_amount{
|
|
||||||
std::min<std::size_t>(HIGHER_PAGE_SIZE - page_offset, remaining_size)};
|
|
||||||
const Manager* manager = top_tier[page_index].load(std::memory_order_acquire);
|
|
||||||
if (manager == nullptr || manager->CpuModifiedPageCount() != 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
page_index++;
|
|
||||||
page_offset = 0;
|
|
||||||
remaining_size -= copy_amount;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if a region has been modified from the CPU
|
/// Returns true if a region has been modified from the CPU
|
||||||
[[nodiscard]] bool IsRegionCpuModified(VAddr query_cpu_addr, u64 query_size) noexcept {
|
[[nodiscard]] bool IsRegionCpuModified(VAddr query_cpu_addr, u64 query_size) noexcept {
|
||||||
return IteratePages<true>(query_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) {
|
return IteratePages<true>(query_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) {
|
||||||
@@ -150,28 +130,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FlushCachedWrites() noexcept {
|
void FlushCachedWrites() noexcept {
|
||||||
std::scoped_lock lk{tracker_mutex};
|
|
||||||
for (auto id : cached_pages) {
|
for (auto id : cached_pages) {
|
||||||
top_tier[id].load(std::memory_order_relaxed)->FlushCachedWrites();
|
top_tier[id]->FlushCachedWrites();
|
||||||
}
|
}
|
||||||
cached_pages.clear();
|
cached_pages.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool CpuMarkIfNotGpuModified(VAddr addr, u64 size) {
|
|
||||||
std::scoped_lock lk{tracker_mutex};
|
|
||||||
const bool gpu = IteratePagesNoLock<false>(
|
|
||||||
addr, size, [](Manager* manager, u64 offset, size_t sz) {
|
|
||||||
return manager->IsRegionModified(Type::GPU, offset, sz);
|
|
||||||
});
|
|
||||||
if (gpu) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
IteratePagesNoLock<true>(addr, size, [](Manager* manager, u64 offset, size_t sz) {
|
|
||||||
manager->ChangeRegionState(Type::CPU, true, manager->cpu_addr + offset, sz);
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call 'func' for each CPU modified range and unmark those pages as CPU modified
|
/// Call 'func' for each CPU modified range and unmark those pages as CPU modified
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
void ForEachUploadRange(VAddr query_cpu_range, u64 query_size, Func&& func) {
|
void ForEachUploadRange(VAddr query_cpu_range, u64 query_size, Func&& func) {
|
||||||
@@ -198,12 +162,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
template <bool create_region_on_fail, typename Func>
|
template <bool create_region_on_fail, typename Func>
|
||||||
bool IteratePages(VAddr cpu_address, size_t size, Func&& func) {
|
bool IteratePages(VAddr cpu_address, size_t size, Func&& func) {
|
||||||
std::scoped_lock lk{tracker_mutex};
|
|
||||||
return IteratePagesNoLock<create_region_on_fail>(cpu_address, size, std::forward<Func>(func));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool create_region_on_fail, typename Func>
|
|
||||||
bool IteratePagesNoLock(VAddr cpu_address, size_t size, Func&& func) {
|
|
||||||
using FuncReturn = typename std::invoke_result<Func, Manager*, u64, size_t>::type;
|
using FuncReturn = typename std::invoke_result<Func, Manager*, u64, size_t>::type;
|
||||||
static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
|
static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
|
||||||
std::size_t remaining_size{size};
|
std::size_t remaining_size{size};
|
||||||
@@ -212,7 +170,7 @@ private:
|
|||||||
while (remaining_size > 0) {
|
while (remaining_size > 0) {
|
||||||
const std::size_t copy_amount{
|
const std::size_t copy_amount{
|
||||||
std::min<std::size_t>(HIGHER_PAGE_SIZE - page_offset, remaining_size)};
|
std::min<std::size_t>(HIGHER_PAGE_SIZE - page_offset, remaining_size)};
|
||||||
auto* manager{top_tier[page_index].load(std::memory_order_relaxed)};
|
auto* manager{top_tier[page_index]};
|
||||||
if (manager) {
|
if (manager) {
|
||||||
if constexpr (BOOL_BREAK) {
|
if constexpr (BOOL_BREAK) {
|
||||||
if (func(manager, page_offset, copy_amount)) {
|
if (func(manager, page_offset, copy_amount)) {
|
||||||
@@ -223,7 +181,7 @@ private:
|
|||||||
}
|
}
|
||||||
} else if constexpr (create_region_on_fail) {
|
} else if constexpr (create_region_on_fail) {
|
||||||
CreateRegion(page_index);
|
CreateRegion(page_index);
|
||||||
manager = top_tier[page_index].load(std::memory_order_relaxed);
|
manager = top_tier[page_index];
|
||||||
if constexpr (BOOL_BREAK) {
|
if constexpr (BOOL_BREAK) {
|
||||||
if (func(manager, page_offset, copy_amount)) {
|
if (func(manager, page_offset, copy_amount)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -241,7 +199,6 @@ private:
|
|||||||
|
|
||||||
template <bool create_region_on_fail, typename Func>
|
template <bool create_region_on_fail, typename Func>
|
||||||
std::pair<u64, u64> IteratePairs(VAddr cpu_address, size_t size, Func&& func) {
|
std::pair<u64, u64> IteratePairs(VAddr cpu_address, size_t size, Func&& func) {
|
||||||
std::scoped_lock lk{tracker_mutex};
|
|
||||||
std::size_t remaining_size{size};
|
std::size_t remaining_size{size};
|
||||||
std::size_t page_index{cpu_address >> HIGHER_PAGE_BITS};
|
std::size_t page_index{cpu_address >> HIGHER_PAGE_BITS};
|
||||||
u64 page_offset{cpu_address & HIGHER_PAGE_MASK};
|
u64 page_offset{cpu_address & HIGHER_PAGE_MASK};
|
||||||
@@ -250,7 +207,7 @@ private:
|
|||||||
while (remaining_size > 0) {
|
while (remaining_size > 0) {
|
||||||
const std::size_t copy_amount{
|
const std::size_t copy_amount{
|
||||||
std::min<std::size_t>(HIGHER_PAGE_SIZE - page_offset, remaining_size)};
|
std::min<std::size_t>(HIGHER_PAGE_SIZE - page_offset, remaining_size)};
|
||||||
auto* manager{top_tier[page_index].load(std::memory_order_relaxed)};
|
auto* manager{top_tier[page_index]};
|
||||||
const auto execute = [&] {
|
const auto execute = [&] {
|
||||||
auto [new_begin, new_end] = func(manager, page_offset, copy_amount);
|
auto [new_begin, new_end] = func(manager, page_offset, copy_amount);
|
||||||
if (new_begin != 0 || new_end != 0) {
|
if (new_begin != 0 || new_end != 0) {
|
||||||
@@ -263,7 +220,7 @@ private:
|
|||||||
execute();
|
execute();
|
||||||
} else if constexpr (create_region_on_fail) {
|
} else if constexpr (create_region_on_fail) {
|
||||||
CreateRegion(page_index);
|
CreateRegion(page_index);
|
||||||
manager = top_tier[page_index].load(std::memory_order_relaxed);
|
manager = top_tier[page_index];
|
||||||
execute();
|
execute();
|
||||||
}
|
}
|
||||||
page_index++;
|
page_index++;
|
||||||
@@ -279,7 +236,7 @@ private:
|
|||||||
|
|
||||||
void CreateRegion(std::size_t page_index) {
|
void CreateRegion(std::size_t page_index) {
|
||||||
const VAddr base_cpu_addr = page_index << HIGHER_PAGE_BITS;
|
const VAddr base_cpu_addr = page_index << HIGHER_PAGE_BITS;
|
||||||
top_tier[page_index].store(GetNewManager(base_cpu_addr), std::memory_order_release);
|
top_tier[page_index] = GetNewManager(base_cpu_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* GetNewManager(VAddr base_cpu_address) {
|
Manager* GetNewManager(VAddr base_cpu_address) {
|
||||||
@@ -297,12 +254,11 @@ private:
|
|||||||
return new_manager;
|
return new_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<std::atomic<Manager*>, NUM_HIGH_PAGES> top_tier{};
|
std::array<Manager*, NUM_HIGH_PAGES> top_tier{};
|
||||||
std::deque<std::array<Manager, MANAGER_POOL_SIZE>> manager_pool;
|
std::deque<std::array<Manager, MANAGER_POOL_SIZE>> manager_pool;
|
||||||
std::deque<Manager*> free_managers;
|
std::deque<Manager*> free_managers;
|
||||||
ankerl::unordered_dense::set<u32> cached_pages;
|
ankerl::unordered_dense::set<u32> cached_pages;
|
||||||
DeviceTracker* device_tracker = nullptr;
|
DeviceTracker* device_tracker = nullptr;
|
||||||
std::mutex tracker_mutex;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <span>
|
#include <span>
|
||||||
@@ -49,11 +48,6 @@ struct WordManager {
|
|||||||
u64 const last_word = (~u64{0} << shift) >> shift;
|
u64 const last_word = (~u64{0} << shift) >> shift;
|
||||||
heap[num_words * size_t(Type::CPU) + num_words - 1] = last_word;
|
heap[num_words * size_t(Type::CPU) + num_words - 1] = last_word;
|
||||||
heap[num_words * size_t(Type::Untracked) + num_words - 1] = last_word;
|
heap[num_words * size_t(Type::Untracked) + num_words - 1] = last_word;
|
||||||
u32 cpu_pages = 0;
|
|
||||||
for (size_t i = 0; i < num_words; ++i) {
|
|
||||||
cpu_pages += static_cast<u32>(std::popcount(heap[num_words * size_t(Type::CPU) + i]));
|
|
||||||
}
|
|
||||||
cpu_modified_pages.store(cpu_pages, std::memory_order_relaxed);
|
|
||||||
}
|
}
|
||||||
explicit WordManager() = default;
|
explicit WordManager() = default;
|
||||||
|
|
||||||
@@ -126,15 +120,10 @@ struct WordManager {
|
|||||||
[[maybe_unused]] std::span<u64> untracked_words = Span(Type::Untracked);
|
[[maybe_unused]] std::span<u64> untracked_words = Span(Type::Untracked);
|
||||||
[[maybe_unused]] std::span<u64> cached_words = Span(Type::CachedCPU);
|
[[maybe_unused]] std::span<u64> cached_words = Span(Type::CachedCPU);
|
||||||
std::vector<std::pair<VAddr, u64>> ranges;
|
std::vector<std::pair<VAddr, u64>> ranges;
|
||||||
s64 cpu_delta = 0;
|
|
||||||
IterateWords(dirty_addr - cpu_addr, size, [&](size_t index, u64 mask) {
|
IterateWords(dirty_addr - cpu_addr, size, [&](size_t index, u64 mask) {
|
||||||
if (type == Type::CPU || type == Type::CachedCPU) {
|
if (type == Type::CPU || type == Type::CachedCPU) {
|
||||||
CollectChangedRanges(!enable, index, untracked_words[index], mask, ranges);
|
CollectChangedRanges(!enable, index, untracked_words[index], mask, ranges);
|
||||||
}
|
}
|
||||||
if (type == Type::CPU) {
|
|
||||||
const u64 old = state_words[index];
|
|
||||||
cpu_delta += enable ? std::popcount(~old & mask) : -std::popcount(old & mask);
|
|
||||||
}
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
state_words[index] |= mask;
|
state_words[index] |= mask;
|
||||||
if (type == Type::CPU || type == Type::CachedCPU)
|
if (type == Type::CPU || type == Type::CachedCPU)
|
||||||
@@ -149,9 +138,6 @@ struct WordManager {
|
|||||||
untracked_words[index] &= ~mask;
|
untracked_words[index] &= ~mask;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (cpu_delta != 0) {
|
|
||||||
cpu_modified_pages.fetch_add(static_cast<u32>(cpu_delta), std::memory_order_release);
|
|
||||||
}
|
|
||||||
if (!ranges.empty()) {
|
if (!ranges.empty()) {
|
||||||
ApplyCollectedRanges(ranges, (!enable) ? 1 : -1);
|
ApplyCollectedRanges(ranges, (!enable) ? 1 : -1);
|
||||||
}
|
}
|
||||||
@@ -179,7 +165,6 @@ struct WordManager {
|
|||||||
(pending_pointer - pending_offset) * BYTES_PER_PAGE);
|
(pending_pointer - pending_offset) * BYTES_PER_PAGE);
|
||||||
};
|
};
|
||||||
std::vector<std::pair<VAddr, u64>> ranges;
|
std::vector<std::pair<VAddr, u64>> ranges;
|
||||||
s64 cpu_delta = 0;
|
|
||||||
IterateWords(offset, size, [&](size_t index, u64 mask) {
|
IterateWords(offset, size, [&](size_t index, u64 mask) {
|
||||||
if (type == Type::GPU)
|
if (type == Type::GPU)
|
||||||
mask &= ~untracked_words[index];
|
mask &= ~untracked_words[index];
|
||||||
@@ -188,8 +173,6 @@ struct WordManager {
|
|||||||
if (type == Type::CPU || type == Type::CachedCPU) {
|
if (type == Type::CPU || type == Type::CachedCPU) {
|
||||||
CollectChangedRanges(true, index, untracked_words[index], mask, ranges);
|
CollectChangedRanges(true, index, untracked_words[index], mask, ranges);
|
||||||
}
|
}
|
||||||
if (type == Type::CPU)
|
|
||||||
cpu_delta -= std::popcount(word);
|
|
||||||
state_words[index] &= ~mask;
|
state_words[index] &= ~mask;
|
||||||
if (type == Type::CPU || type == Type::CachedCPU)
|
if (type == Type::CPU || type == Type::CachedCPU)
|
||||||
untracked_words[index] &= ~mask;
|
untracked_words[index] &= ~mask;
|
||||||
@@ -211,9 +194,6 @@ struct WordManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (cpu_delta != 0) {
|
|
||||||
cpu_modified_pages.fetch_add(static_cast<u32>(cpu_delta), std::memory_order_release);
|
|
||||||
}
|
|
||||||
if (pending) {
|
if (pending) {
|
||||||
release();
|
release();
|
||||||
}
|
}
|
||||||
@@ -268,18 +248,13 @@ struct WordManager {
|
|||||||
auto const untracked_words = Span(Type::Untracked);
|
auto const untracked_words = Span(Type::Untracked);
|
||||||
auto const cpu_words = Span(Type::CPU);
|
auto const cpu_words = Span(Type::CPU);
|
||||||
std::vector<std::pair<VAddr, u64>> ranges;
|
std::vector<std::pair<VAddr, u64>> ranges;
|
||||||
s64 cpu_delta = 0;
|
|
||||||
for (u64 word_index = 0; word_index < num_words; ++word_index) {
|
for (u64 word_index = 0; word_index < num_words; ++word_index) {
|
||||||
const u64 cached_bits = cached_words[word_index];
|
const u64 cached_bits = cached_words[word_index];
|
||||||
CollectChangedRanges(false, word_index, untracked_words[word_index], cached_bits, ranges);
|
CollectChangedRanges(false, word_index, untracked_words[word_index], cached_bits, ranges);
|
||||||
cpu_delta += std::popcount(~cpu_words[word_index] & cached_bits);
|
|
||||||
untracked_words[word_index] |= cached_bits;
|
untracked_words[word_index] |= cached_bits;
|
||||||
cpu_words[word_index] |= cached_bits;
|
cpu_words[word_index] |= cached_bits;
|
||||||
cached_words[word_index] = 0;
|
cached_words[word_index] = 0;
|
||||||
}
|
}
|
||||||
if (cpu_delta != 0) {
|
|
||||||
cpu_modified_pages.fetch_add(static_cast<u32>(cpu_delta), std::memory_order_release);
|
|
||||||
}
|
|
||||||
if (!ranges.empty()) {
|
if (!ranges.empty()) {
|
||||||
ApplyCollectedRanges(ranges, -1);
|
ApplyCollectedRanges(ranges, -1);
|
||||||
}
|
}
|
||||||
@@ -344,14 +319,9 @@ struct WordManager {
|
|||||||
return std::span<const u64>(heap.data() + num_words * size_t(type), num_words);
|
return std::span<const u64>(heap.data() + num_words * size_t(type), num_words);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] u32 CpuModifiedPageCount() const noexcept {
|
|
||||||
return cpu_modified_pages.load(std::memory_order_acquire);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u64, size_t(Type::Max) * num_words> heap = {};
|
std::array<u64, size_t(Type::Max) * num_words> heap = {};
|
||||||
DeviceTracker* tracker = nullptr;
|
DeviceTracker* tracker = nullptr;
|
||||||
VAddr cpu_addr = 0;
|
VAddr cpu_addr = 0;
|
||||||
std::atomic<u32> cpu_modified_pages{0};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ set(GLSL_INCLUDES
|
|||||||
|
|
||||||
set(SHADER_FILES
|
set(SHADER_FILES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/astc_decoder.comp
|
${CMAKE_CURRENT_SOURCE_DIR}/astc_decoder.comp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/astc_decoder.frag
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/astc_decoder.vert
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/blit_color_float.frag
|
${CMAKE_CURRENT_SOURCE_DIR}/blit_color_float.frag
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_2d.comp
|
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_2d.comp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/blit_color_msaa.frag
|
${CMAKE_CURRENT_SOURCE_DIR}/blit_color_msaa.frag
|
||||||
|
|||||||
@@ -964,70 +964,35 @@ void ComputeEndpoints(out uvec4 ep1, out uvec4 ep2, uint color_endpoint_mode, ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint UnquantizeTexelWeight(EncodingData val) {
|
uint UnquantizeTexelWeight(EncodingData val) {
|
||||||
const uint encoding = Encoding(val);
|
uint encoding = Encoding(val), bitlen = NumBits(val), bitval = BitValue(val);
|
||||||
const uint bitlen = NumBits(val);
|
if (encoding == JUST_BITS) {
|
||||||
const uint bitval = BitValue(val);
|
return (bitlen >= 1 && bitlen <= 5)
|
||||||
const uint A = ReplicateBitTo7((bitval & 1));
|
? uint(floor(0.5f + float(bitval) * 64.0f / float((1 << bitlen) - 1)))
|
||||||
uint B = 0, C = 0, D = 0;
|
: FastReplicateTo6(bitval, bitlen);
|
||||||
uint result = 0;
|
} else if (encoding == TRIT || encoding == QUINT) {
|
||||||
const uint bitlen_0_results[5] = {0, 16, 32, 48, 64};
|
uint B = 0, C = 0, D = 0;
|
||||||
switch (encoding) {
|
uint b_mask = (0x3100 >> (bitlen * 4)) & 0xf;
|
||||||
case JUST_BITS:
|
uint b = (bitval >> 1) & b_mask;
|
||||||
return FastReplicateTo6(bitval, bitlen);
|
|
||||||
case TRIT: {
|
|
||||||
D = QuintTritValue(val);
|
D = QuintTritValue(val);
|
||||||
switch (bitlen) {
|
if (encoding == TRIT) {
|
||||||
case 0:
|
switch (bitlen) {
|
||||||
return bitlen_0_results[D * 2];
|
case 0: return D * 32; //0,32,64
|
||||||
case 1: {
|
case 1: C = 50; break;
|
||||||
C = 50;
|
case 2: C = 23; B = (b << 6) | (b << 2) | b; break;
|
||||||
break;
|
case 3: C = 11; B = (b << 5) | b; break;
|
||||||
|
}
|
||||||
|
} else if (encoding == QUINT) {
|
||||||
|
switch (bitlen) {
|
||||||
|
case 0: return D * 16; //0, 16, 32, 48, 64
|
||||||
|
case 1: C = 28; break;
|
||||||
|
case 2: C = 13; B = (b << 6) | (b << 1); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case 2: {
|
uint A = ReplicateBitTo7(bitval & 1);
|
||||||
C = 23;
|
uint res = (A & 0x20) | (((D * C + B) ^ A) >> 2);
|
||||||
const uint b = (bitval >> 1) & 1;
|
return res + (res > 32 ? 1 : 0);
|
||||||
B = (b << 6) | (b << 2) | b;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: {
|
|
||||||
C = 11;
|
|
||||||
const uint cb = (bitval >> 1) & 3;
|
|
||||||
B = (cb << 5) | cb;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case QUINT: {
|
return 0;
|
||||||
D = QuintTritValue(val);
|
|
||||||
switch (bitlen) {
|
|
||||||
case 0:
|
|
||||||
return bitlen_0_results[D];
|
|
||||||
case 1: {
|
|
||||||
C = 28;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2: {
|
|
||||||
C = 13;
|
|
||||||
const uint b = (bitval >> 1) & 1;
|
|
||||||
B = (b << 6) | (b << 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (encoding != JUST_BITS && bitlen > 0) {
|
|
||||||
result = D * C + B;
|
|
||||||
result ^= A;
|
|
||||||
result = (A & 0x20) | (result >> 2);
|
|
||||||
}
|
|
||||||
if (result > 32) {
|
|
||||||
result += 1;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnquantizeTexelWeights(uvec2 size, bool is_dual_plane) {
|
void UnquantizeTexelWeights(uvec2 size, bool is_dual_plane) {
|
||||||
@@ -1429,10 +1394,11 @@ void DecompressBlock(ivec3 coord) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint SwizzleOffset(uvec2 pos) {
|
uint SwizzleOffset(uvec2 pos) {
|
||||||
const uint x = pos.x;
|
return ((pos.x & 32u) << 3u) |
|
||||||
const uint y = pos.y;
|
((pos.y & 6u) << 5u) |
|
||||||
return ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 +
|
((pos.x & 16u) << 1u) |
|
||||||
((x % 32) / 16) * 32 + (y % 2) * 16 + (x % 16);
|
((pos.y & 1u) << 4u) |
|
||||||
|
(pos.x & 15u);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
|
|
||||||
#ifdef VULKAN
|
|
||||||
#define VERTEX_ID gl_VertexIndex
|
|
||||||
#else
|
|
||||||
#define VERTEX_ID gl_VertexID
|
|
||||||
out gl_PerVertex {
|
|
||||||
vec4 gl_Position;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
float x = float((VERTEX_ID & 1) << 2);
|
|
||||||
float y = float((VERTEX_ID & 2) << 1);
|
|
||||||
gl_Position = vec4(x - 1.0, y - 1.0, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
@@ -545,6 +545,10 @@ void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view)
|
|||||||
|
|
||||||
void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
|
void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
|
||||||
const VkRenderPass render_pass = framebuffer->RenderPass();
|
const VkRenderPass render_pass = framebuffer->RenderPass();
|
||||||
|
if (!render_pass) {
|
||||||
|
framebuffer->BeginRendering(cmdbuf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
||||||
const VkExtent2D render_area = framebuffer->RenderArea();
|
const VkExtent2D render_area = framebuffer->RenderArea();
|
||||||
const VkRenderPassBeginInfo renderpass_bi{
|
const VkRenderPassBeginInfo renderpass_bi{
|
||||||
@@ -561,6 +565,31 @@ void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer)
|
|||||||
};
|
};
|
||||||
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
|
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EndRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
|
||||||
|
if (framebuffer->RenderPass()) {
|
||||||
|
cmdbuf.EndRenderPass();
|
||||||
|
} else {
|
||||||
|
cmdbuf.EndRendering();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] VkPipelineRenderingCreateInfo MakePipelineRenderingCreateInfo(
|
||||||
|
const Framebuffer* framebuffer) {
|
||||||
|
return VkPipelineRenderingCreateInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.viewMask = 0,
|
||||||
|
.colorAttachmentCount = framebuffer->NumColorAttachments(),
|
||||||
|
.pColorAttachmentFormats = framebuffer->ColorAttachmentFormats().data(),
|
||||||
|
.depthAttachmentFormat = framebuffer->HasAspectDepthBit()
|
||||||
|
? framebuffer->DepthAttachmentFormat()
|
||||||
|
: VK_FORMAT_UNDEFINED,
|
||||||
|
.stencilAttachmentFormat = framebuffer->HasAspectStencilBit()
|
||||||
|
? framebuffer->DepthAttachmentFormat()
|
||||||
|
: VK_FORMAT_UNDEFINED,
|
||||||
|
};
|
||||||
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
|
BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
|
||||||
@@ -623,10 +652,12 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
|
|||||||
const BlitImagePipelineKey key{
|
const BlitImagePipelineKey key{
|
||||||
.renderpass = dst_framebuffer->RenderPass(),
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
.operation = operation,
|
.operation = operation,
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
};
|
};
|
||||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||||
const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
|
const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
|
||||||
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key, dst_framebuffer);
|
||||||
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
|
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
|
||||||
|
|
||||||
RecordShaderReadBarrier(scheduler, src_image_view);
|
RecordShaderReadBarrier(scheduler, src_image_view);
|
||||||
@@ -651,9 +682,11 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
|
|||||||
const BlitImagePipelineKey key{
|
const BlitImagePipelineKey key{
|
||||||
.renderpass = dst_framebuffer->RenderPass(),
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
.operation = Tegra::Engines::Fermi2D::Operation::SrcCopy,
|
.operation = Tegra::Engines::Fermi2D::Operation::SrcCopy,
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
};
|
};
|
||||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||||
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key, dst_framebuffer);
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region,
|
scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region,
|
||||||
src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) {
|
src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) {
|
||||||
@@ -666,7 +699,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
|
|||||||
nullptr);
|
nullptr);
|
||||||
BindBlitState(cmdbuf, layout, dst_region, src_region, src_size);
|
BindBlitState(cmdbuf, layout, dst_region, src_region, src_size);
|
||||||
cmdbuf.Draw(3, 1, 0, 0);
|
cmdbuf.Draw(3, 1, 0, 0);
|
||||||
cmdbuf.EndRenderPass();
|
EndRenderPass(cmdbuf, dst_framebuffer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,10 +709,12 @@ void BlitImageHelper::BlitColorMSAA(const Framebuffer* dst_framebuffer,
|
|||||||
const BlitMSAAPipelineKey key{
|
const BlitMSAAPipelineKey key{
|
||||||
.renderpass = dst_framebuffer->RenderPass(),
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
.samples = dst_framebuffer->Samples(),
|
.samples = dst_framebuffer->Samples(),
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
};
|
};
|
||||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||||
const VkSampler sampler = *nearest_sampler;
|
const VkSampler sampler = *nearest_sampler;
|
||||||
const VkPipeline pipeline = FindOrEmplaceBlitColorMSAAPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceBlitColorMSAAPipeline(key, dst_framebuffer);
|
||||||
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
|
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
|
||||||
|
|
||||||
RecordShaderReadBarrier(scheduler, src_image_view);
|
RecordShaderReadBarrier(scheduler, src_image_view);
|
||||||
@@ -703,7 +738,7 @@ void BlitImageHelper::ResolveDepthStencil(const Framebuffer* dst_framebuffer,
|
|||||||
const bool resolve_stencil =
|
const bool resolve_stencil =
|
||||||
dst_framebuffer->HasAspectStencilBit() && device.IsExtShaderStencilExportSupported();
|
dst_framebuffer->HasAspectStencilBit() && device.IsExtShaderStencilExportSupported();
|
||||||
const VkPipeline pipeline =
|
const VkPipeline pipeline =
|
||||||
FindOrEmplaceResolveDepthStencilPipeline(dst_framebuffer->RenderPass(), resolve_stencil);
|
FindOrEmplaceResolveDepthStencilPipeline(dst_framebuffer, resolve_stencil);
|
||||||
const VkPipelineLayout layout =
|
const VkPipelineLayout layout =
|
||||||
resolve_stencil ? *two_textures_pipeline_layout : *one_texture_pipeline_layout;
|
resolve_stencil ? *two_textures_pipeline_layout : *one_texture_pipeline_layout;
|
||||||
const VkSampler sampler = *nearest_sampler;
|
const VkSampler sampler = *nearest_sampler;
|
||||||
@@ -747,10 +782,12 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
|
|||||||
const BlitImagePipelineKey key{
|
const BlitImagePipelineKey key{
|
||||||
.renderpass = dst_framebuffer->RenderPass(),
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
.operation = operation,
|
.operation = operation,
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
};
|
};
|
||||||
const VkPipelineLayout layout = *two_textures_pipeline_layout;
|
const VkPipelineLayout layout = *two_textures_pipeline_layout;
|
||||||
const VkSampler sampler = *nearest_sampler;
|
const VkSampler sampler = *nearest_sampler;
|
||||||
const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key, dst_framebuffer);
|
||||||
const VkImageView src_depth_view = src_image_view.DepthView();
|
const VkImageView src_depth_view = src_image_view.DepthView();
|
||||||
const VkImageView src_stencil_view = src_image_view.StencilView();
|
const VkImageView src_stencil_view = src_image_view.StencilView();
|
||||||
|
|
||||||
@@ -772,25 +809,25 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
|
|||||||
|
|
||||||
void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass());
|
ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer);
|
||||||
Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass());
|
ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer);
|
||||||
Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass());
|
ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer);
|
||||||
Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass());
|
ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer);
|
||||||
Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,35 +838,35 @@ void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
|
|||||||
LOG_WARNING(Render_Vulkan, "ConvertABGR8ToD24S8 requires shader_stencil_export, skipping");
|
LOG_WARNING(Render_Vulkan, "ConvertABGR8ToD24S8 requires shader_stencil_export, skipping");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer,
|
||||||
convert_abgr8_to_d24s8_frag);
|
convert_abgr8_to_d24s8_frag);
|
||||||
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertABGR8ToD32F(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertABGR8ToD32F(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
ConvertPipelineDepthTargetEx(convert_abgr8_to_d32f_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineDepthTargetEx(convert_abgr8_to_d32f_pipeline, dst_framebuffer,
|
||||||
convert_abgr8_to_d32f_frag);
|
convert_abgr8_to_d32f_frag);
|
||||||
Convert(*convert_abgr8_to_d32f_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_abgr8_to_d32f_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertD32FToABGR8(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertD32FToABGR8(const Framebuffer* dst_framebuffer,
|
||||||
ImageView& src_image_view) {
|
ImageView& src_image_view) {
|
||||||
ConvertPipelineColorTargetEx(convert_d32f_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineColorTargetEx(convert_d32f_to_abgr8_pipeline, dst_framebuffer,
|
||||||
convert_d32f_to_abgr8_frag);
|
convert_d32f_to_abgr8_frag);
|
||||||
ConvertDepthStencil(*convert_d32f_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
ConvertDepthStencil(*convert_d32f_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
|
||||||
ImageView& src_image_view) {
|
ImageView& src_image_view) {
|
||||||
ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer,
|
||||||
convert_d24s8_to_abgr8_frag);
|
convert_d24s8_to_abgr8_frag);
|
||||||
ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer,
|
||||||
ImageView& src_image_view) {
|
ImageView& src_image_view) {
|
||||||
ConvertPipelineColorTargetEx(convert_s8d24_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineColorTargetEx(convert_s8d24_to_abgr8_pipeline, dst_framebuffer,
|
||||||
convert_s8d24_to_abgr8_frag);
|
convert_s8d24_to_abgr8_frag);
|
||||||
ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
@@ -840,8 +877,10 @@ void BlitImageHelper::ClearColor(const Framebuffer* dst_framebuffer, u8 color_ma
|
|||||||
const BlitImagePipelineKey key{
|
const BlitImagePipelineKey key{
|
||||||
.renderpass = dst_framebuffer->RenderPass(),
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
.operation = Tegra::Engines::Fermi2D::Operation::BlendPremult,
|
.operation = Tegra::Engines::Fermi2D::Operation::BlendPremult,
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
};
|
};
|
||||||
const VkPipeline pipeline = FindOrEmplaceClearColorPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceClearColorPipeline(key, dst_framebuffer);
|
||||||
const VkPipelineLayout layout = *clear_color_pipeline_layout;
|
const VkPipelineLayout layout = *clear_color_pipeline_layout;
|
||||||
scheduler.RequestRenderpass(dst_framebuffer);
|
scheduler.RequestRenderpass(dst_framebuffer);
|
||||||
scheduler.Record(
|
scheduler.Record(
|
||||||
@@ -867,8 +906,10 @@ void BlitImageHelper::ClearDepthStencil(const Framebuffer* dst_framebuffer, bool
|
|||||||
.stencil_mask = stencil_mask,
|
.stencil_mask = stencil_mask,
|
||||||
.stencil_compare_mask = stencil_compare_mask,
|
.stencil_compare_mask = stencil_compare_mask,
|
||||||
.stencil_ref = stencil_ref,
|
.stencil_ref = stencil_ref,
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
};
|
};
|
||||||
const VkPipeline pipeline = FindOrEmplaceClearStencilPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceClearStencilPipeline(key, dst_framebuffer);
|
||||||
const VkPipelineLayout layout = *clear_color_pipeline_layout;
|
const VkPipelineLayout layout = *clear_color_pipeline_layout;
|
||||||
scheduler.RequestRenderpass(dst_framebuffer);
|
scheduler.RequestRenderpass(dst_framebuffer);
|
||||||
scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) {
|
||||||
@@ -1140,12 +1181,14 @@ void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer
|
|||||||
scheduler.InvalidateState();
|
scheduler.InvalidateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) {
|
VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer) {
|
||||||
const auto it = std::ranges::find(blit_color_keys, key);
|
const auto it = std::ranges::find(blit_color_keys, key);
|
||||||
if (it != blit_color_keys.end()) {
|
if (it != blit_color_keys.end()) {
|
||||||
return *blit_color_pipelines[std::distance(blit_color_keys.begin(), it)];
|
return *blit_color_pipelines[std::distance(blit_color_keys.begin(), it)];
|
||||||
}
|
}
|
||||||
blit_color_keys.push_back(key);
|
blit_color_keys.push_back(key);
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
|
|
||||||
const std::array stages = MakeStages(*full_screen_vert, *blit_color_to_color_frag);
|
const std::array stages = MakeStages(*full_screen_vert, *blit_color_to_color_frag);
|
||||||
const VkPipelineColorBlendAttachmentState blend_attachment{
|
const VkPipelineColorBlendAttachmentState blend_attachment{
|
||||||
@@ -1173,7 +1216,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe
|
|||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = key.renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -1195,17 +1238,19 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe
|
|||||||
return *blit_color_pipelines.back();
|
return *blit_color_pipelines.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key) {
|
VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer) {
|
||||||
const auto it = std::ranges::find(blit_depth_stencil_keys, key);
|
const auto it = std::ranges::find(blit_depth_stencil_keys, key);
|
||||||
if (it != blit_depth_stencil_keys.end()) {
|
if (it != blit_depth_stencil_keys.end()) {
|
||||||
return *blit_depth_stencil_pipelines[std::distance(blit_depth_stencil_keys.begin(), it)];
|
return *blit_depth_stencil_pipelines[std::distance(blit_depth_stencil_keys.begin(), it)];
|
||||||
}
|
}
|
||||||
blit_depth_stencil_keys.push_back(key);
|
blit_depth_stencil_keys.push_back(key);
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag);
|
const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag);
|
||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = key.renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -1227,38 +1272,46 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip
|
|||||||
return *blit_depth_stencil_pipelines.back();
|
return *blit_depth_stencil_pipelines.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key) {
|
VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer) {
|
||||||
const auto it = std::ranges::find(clear_color_keys, key);
|
const auto it = std::ranges::find(clear_color_keys, key);
|
||||||
if (it != clear_color_keys.end()) {
|
if (it != clear_color_keys.end()) {
|
||||||
return *clear_color_pipelines[std::distance(clear_color_keys.begin(), it)];
|
return *clear_color_pipelines[std::distance(clear_color_keys.begin(), it)];
|
||||||
}
|
}
|
||||||
clear_color_keys.push_back(key);
|
clear_color_keys.push_back(key);
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
const std::array stages = MakeStages(*clear_color_vert, *clear_color_frag);
|
const std::array stages = MakeStages(*clear_color_vert, *clear_color_frag);
|
||||||
const VkPipelineColorBlendAttachmentState color_blend_attachment_state{
|
const u32 num_color = framebuffer->NumColorAttachments();
|
||||||
.blendEnable = VK_TRUE,
|
constexpr VkColorComponentFlags full_write_mask =
|
||||||
.srcColorBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR,
|
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
|
||||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
|
VK_COLOR_COMPONENT_A_BIT;
|
||||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
std::array<VkPipelineColorBlendAttachmentState, VideoCommon::NUM_RT> blend_attachments{};
|
||||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_ALPHA,
|
for (u32 index = 0; index < num_color; ++index) {
|
||||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
|
blend_attachments[index] = VkPipelineColorBlendAttachmentState{
|
||||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
.blendEnable = index == 0 ? VK_TRUE : VK_FALSE,
|
||||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
.srcColorBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR,
|
||||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
|
||||||
};
|
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||||
|
.srcAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_ALPHA,
|
||||||
|
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
|
||||||
|
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||||
|
.colorWriteMask = index == 0 ? full_write_mask : VkColorComponentFlags{0},
|
||||||
|
};
|
||||||
|
}
|
||||||
const VkPipelineColorBlendStateCreateInfo color_blend_state_generic_create_info{
|
const VkPipelineColorBlendStateCreateInfo color_blend_state_generic_create_info{
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.logicOpEnable = VK_FALSE,
|
.logicOpEnable = VK_FALSE,
|
||||||
.logicOp = VK_LOGIC_OP_CLEAR,
|
.logicOp = VK_LOGIC_OP_CLEAR,
|
||||||
.attachmentCount = 1,
|
.attachmentCount = num_color,
|
||||||
.pAttachments = &color_blend_attachment_state,
|
.pAttachments = blend_attachments.data(),
|
||||||
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
|
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
|
||||||
};
|
};
|
||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = key.renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -1281,13 +1334,26 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipel
|
|||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
||||||
const BlitDepthStencilPipelineKey& key) {
|
const BlitDepthStencilPipelineKey& key, const Framebuffer* framebuffer) {
|
||||||
const auto it = std::ranges::find(clear_stencil_keys, key);
|
const auto it = std::ranges::find(clear_stencil_keys, key);
|
||||||
if (it != clear_stencil_keys.end()) {
|
if (it != clear_stencil_keys.end()) {
|
||||||
return *clear_stencil_pipelines[std::distance(clear_stencil_keys.begin(), it)];
|
return *clear_stencil_pipelines[std::distance(clear_stencil_keys.begin(), it)];
|
||||||
}
|
}
|
||||||
clear_stencil_keys.push_back(key);
|
clear_stencil_keys.push_back(key);
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
const std::array stages = MakeStages(*clear_color_vert, *clear_stencil_frag);
|
const std::array stages = MakeStages(*clear_color_vert, *clear_stencil_frag);
|
||||||
|
const u32 num_color = framebuffer->NumColorAttachments();
|
||||||
|
std::array<VkPipelineColorBlendAttachmentState, VideoCommon::NUM_RT> blend_attachments{};
|
||||||
|
const VkPipelineColorBlendStateCreateInfo color_blend_ci{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.logicOpEnable = VK_FALSE,
|
||||||
|
.logicOp = VK_LOGIC_OP_CLEAR,
|
||||||
|
.attachmentCount = num_color,
|
||||||
|
.pAttachments = blend_attachments.data(),
|
||||||
|
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
|
||||||
|
};
|
||||||
const auto stencil = VkStencilOpState{
|
const auto stencil = VkStencilOpState{
|
||||||
.failOp = VK_STENCIL_OP_KEEP,
|
.failOp = VK_STENCIL_OP_KEEP,
|
||||||
.passOp = VK_STENCIL_OP_REPLACE,
|
.passOp = VK_STENCIL_OP_REPLACE,
|
||||||
@@ -1314,7 +1380,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
|||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = key.renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -1325,7 +1391,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
|||||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
.pDepthStencilState = &depth_stencil_ci,
|
.pDepthStencilState = &depth_stencil_ci,
|
||||||
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
|
.pColorBlendState = &color_blend_ci,
|
||||||
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
.layout = *clear_color_pipeline_layout,
|
.layout = *clear_color_pipeline_layout,
|
||||||
.renderPass = key.renderpass,
|
.renderPass = key.renderpass,
|
||||||
@@ -1336,12 +1402,14 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
|||||||
return *clear_stencil_pipelines.back();
|
return *clear_stencil_pipelines.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key) {
|
VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer) {
|
||||||
const auto it = std::ranges::find(blit_msaa_color_keys, key);
|
const auto it = std::ranges::find(blit_msaa_color_keys, key);
|
||||||
if (it != blit_msaa_color_keys.end()) {
|
if (it != blit_msaa_color_keys.end()) {
|
||||||
return *blit_msaa_color_pipelines[std::distance(blit_msaa_color_keys.begin(), it)];
|
return *blit_msaa_color_pipelines[std::distance(blit_msaa_color_keys.begin(), it)];
|
||||||
}
|
}
|
||||||
blit_msaa_color_keys.push_back(key);
|
blit_msaa_color_keys.push_back(key);
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
const std::array stages = MakeStages(*full_screen_vert, *blit_color_msaa_frag);
|
const std::array stages = MakeStages(*full_screen_vert, *blit_color_msaa_frag);
|
||||||
const VkPipelineMultisampleStateCreateInfo multisample_ci{
|
const VkPipelineMultisampleStateCreateInfo multisample_ci{
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
@@ -1357,7 +1425,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPip
|
|||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
blit_msaa_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
blit_msaa_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = key.renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -1379,22 +1447,28 @@ VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPip
|
|||||||
return *blit_msaa_color_pipelines.back();
|
return *blit_msaa_color_pipelines.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline BlitImageHelper::FindOrEmplaceResolveDepthStencilPipeline(VkRenderPass renderpass,
|
VkPipeline BlitImageHelper::FindOrEmplaceResolveDepthStencilPipeline(
|
||||||
bool resolve_stencil) {
|
const Framebuffer* framebuffer, bool resolve_stencil) {
|
||||||
|
const VkRenderPass renderpass = framebuffer->RenderPass();
|
||||||
|
const ResolveDepthStencilPipelineKey key{
|
||||||
|
.renderpass = renderpass,
|
||||||
|
.depth_format = framebuffer->DepthAttachmentFormat(),
|
||||||
|
};
|
||||||
auto& keys = resolve_stencil ? resolve_depth_stencil_keys : resolve_depth_keys;
|
auto& keys = resolve_stencil ? resolve_depth_stencil_keys : resolve_depth_keys;
|
||||||
auto& pipelines = resolve_stencil ? resolve_depth_stencil_pipelines : resolve_depth_pipelines;
|
auto& pipelines = resolve_stencil ? resolve_depth_stencil_pipelines : resolve_depth_pipelines;
|
||||||
const auto it = std::ranges::find(keys, renderpass);
|
const auto it = std::ranges::find(keys, key);
|
||||||
if (it != keys.end()) {
|
if (it != keys.end()) {
|
||||||
return *pipelines[std::distance(keys.begin(), it)];
|
return *pipelines[std::distance(keys.begin(), it)];
|
||||||
}
|
}
|
||||||
keys.push_back(renderpass);
|
keys.push_back(key);
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
const std::array stages =
|
const std::array stages =
|
||||||
MakeStages(*full_screen_vert,
|
MakeStages(*full_screen_vert,
|
||||||
resolve_stencil ? *blit_depth_stencil_msaa_frag : *blit_depth_msaa_frag);
|
resolve_stencil ? *blit_depth_stencil_msaa_frag : *blit_depth_msaa_frag);
|
||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -1462,25 +1536,29 @@ VkPipeline BlitImageHelper::FindOrEmplaceMSAACopyPipeline(const MSAACopyPipeline
|
|||||||
return *msaa_copy_pipelines.back();
|
return *msaa_copy_pipelines.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
|
void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline,
|
||||||
ConvertPipeline(pipeline, renderpass, false);
|
const Framebuffer* framebuffer) {
|
||||||
|
ConvertPipeline(pipeline, framebuffer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
|
void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline,
|
||||||
ConvertPipeline(pipeline, renderpass, true);
|
const Framebuffer* framebuffer) {
|
||||||
|
ConvertPipeline(pipeline, framebuffer, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module, bool single_texture,
|
vk::ShaderModule& module, bool single_texture,
|
||||||
bool is_target_depth) {
|
bool is_target_depth) {
|
||||||
if (pipeline) {
|
if (pipeline) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const VkRenderPass renderpass = framebuffer->RenderPass();
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
const std::array stages = MakeStages(*full_screen_vert, *module);
|
const std::array stages = MakeStages(*full_screen_vert, *module);
|
||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
|
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -1502,28 +1580,32 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline,
|
||||||
|
const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module) {
|
vk::ShaderModule& module) {
|
||||||
ConvertPipelineEx(pipeline, renderpass, module, false, false);
|
ConvertPipelineEx(pipeline, framebuffer, module, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline,
|
||||||
|
const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module) {
|
vk::ShaderModule& module) {
|
||||||
ConvertPipelineEx(pipeline, renderpass, module, true, true);
|
ConvertPipelineEx(pipeline, framebuffer, module, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
bool is_target_depth) {
|
bool is_target_depth) {
|
||||||
if (pipeline) {
|
if (pipeline) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const VkRenderPass renderpass = framebuffer->RenderPass();
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
VkShaderModule frag_shader =
|
VkShaderModule frag_shader =
|
||||||
is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
|
is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
|
||||||
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
|
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
|
||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
|
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ struct BlitImagePipelineKey {
|
|||||||
|
|
||||||
VkRenderPass renderpass;
|
VkRenderPass renderpass;
|
||||||
Tegra::Engines::Fermi2D::Operation operation;
|
Tegra::Engines::Fermi2D::Operation operation;
|
||||||
|
std::array<VkFormat, VideoCommon::NUM_RT> color_formats;
|
||||||
|
VkFormat depth_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BlitDepthStencilPipelineKey {
|
struct BlitDepthStencilPipelineKey {
|
||||||
@@ -43,6 +45,8 @@ struct BlitDepthStencilPipelineKey {
|
|||||||
u8 stencil_mask;
|
u8 stencil_mask;
|
||||||
u32 stencil_compare_mask;
|
u32 stencil_compare_mask;
|
||||||
u32 stencil_ref;
|
u32 stencil_ref;
|
||||||
|
std::array<VkFormat, VideoCommon::NUM_RT> color_formats;
|
||||||
|
VkFormat depth_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MSAACopyPipelineKey {
|
struct MSAACopyPipelineKey {
|
||||||
@@ -58,6 +62,15 @@ struct BlitMSAAPipelineKey {
|
|||||||
|
|
||||||
VkRenderPass renderpass;
|
VkRenderPass renderpass;
|
||||||
VkSampleCountFlagBits samples;
|
VkSampleCountFlagBits samples;
|
||||||
|
std::array<VkFormat, VideoCommon::NUM_RT> color_formats;
|
||||||
|
VkFormat depth_format;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResolveDepthStencilPipelineKey {
|
||||||
|
constexpr auto operator<=>(const ResolveDepthStencilPipelineKey&) const noexcept = default;
|
||||||
|
|
||||||
|
VkRenderPass renderpass;
|
||||||
|
VkFormat depth_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlitImageHelper {
|
class BlitImageHelper {
|
||||||
@@ -123,31 +136,36 @@ private:
|
|||||||
void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
||||||
ImageView& src_image_view);
|
ImageView& src_image_view);
|
||||||
|
|
||||||
[[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key);
|
[[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer);
|
||||||
|
|
||||||
[[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key);
|
[[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer);
|
||||||
|
|
||||||
[[nodiscard]] VkPipeline FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key);
|
[[nodiscard]] VkPipeline FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer);
|
||||||
[[nodiscard]] VkPipeline FindOrEmplaceClearStencilPipeline(
|
[[nodiscard]] VkPipeline FindOrEmplaceClearStencilPipeline(
|
||||||
const BlitDepthStencilPipelineKey& key);
|
const BlitDepthStencilPipelineKey& key, const Framebuffer* framebuffer);
|
||||||
[[nodiscard]] VkPipeline FindOrEmplaceMSAACopyPipeline(const MSAACopyPipelineKey& key);
|
[[nodiscard]] VkPipeline FindOrEmplaceMSAACopyPipeline(const MSAACopyPipelineKey& key);
|
||||||
[[nodiscard]] VkPipeline FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key);
|
[[nodiscard]] VkPipeline FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key,
|
||||||
[[nodiscard]] VkPipeline FindOrEmplaceResolveDepthStencilPipeline(VkRenderPass renderpass,
|
const Framebuffer* framebuffer);
|
||||||
|
[[nodiscard]] VkPipeline FindOrEmplaceResolveDepthStencilPipeline(const Framebuffer* framebuffer,
|
||||||
bool resolve_stencil);
|
bool resolve_stencil);
|
||||||
|
|
||||||
void ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, bool is_target_depth);
|
void ConvertPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
|
bool is_target_depth);
|
||||||
|
|
||||||
void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
|
void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer);
|
||||||
|
|
||||||
void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
|
void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer);
|
||||||
|
|
||||||
void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void ConvertPipelineEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module, bool single_texture, bool is_target_depth);
|
vk::ShaderModule& module, bool single_texture, bool is_target_depth);
|
||||||
|
|
||||||
void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module);
|
vk::ShaderModule& module);
|
||||||
|
|
||||||
void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module);
|
vk::ShaderModule& module);
|
||||||
|
|
||||||
const Device& device;
|
const Device& device;
|
||||||
@@ -195,9 +213,9 @@ private:
|
|||||||
std::vector<vk::Pipeline> msaa_copy_pipelines;
|
std::vector<vk::Pipeline> msaa_copy_pipelines;
|
||||||
std::vector<BlitMSAAPipelineKey> blit_msaa_color_keys;
|
std::vector<BlitMSAAPipelineKey> blit_msaa_color_keys;
|
||||||
std::vector<vk::Pipeline> blit_msaa_color_pipelines;
|
std::vector<vk::Pipeline> blit_msaa_color_pipelines;
|
||||||
std::vector<VkRenderPass> resolve_depth_keys;
|
std::vector<ResolveDepthStencilPipelineKey> resolve_depth_keys;
|
||||||
std::vector<vk::Pipeline> resolve_depth_pipelines;
|
std::vector<vk::Pipeline> resolve_depth_pipelines;
|
||||||
std::vector<VkRenderPass> resolve_depth_stencil_keys;
|
std::vector<ResolveDepthStencilPipelineKey> resolve_depth_stencil_keys;
|
||||||
std::vector<vk::Pipeline> resolve_depth_stencil_pipelines;
|
std::vector<vk::Pipeline> resolve_depth_stencil_pipelines;
|
||||||
struct MSAACopyResources {
|
struct MSAACopyResources {
|
||||||
u64 tick;
|
u64 tick;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
@@ -18,8 +17,6 @@
|
|||||||
#include "common/div_ceil.h"
|
#include "common/div_ceil.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "video_core/host_shaders/astc_decoder_comp_spv.h"
|
#include "video_core/host_shaders/astc_decoder_comp_spv.h"
|
||||||
#include "video_core/host_shaders/astc_decoder_frag_spv.h"
|
|
||||||
#include "video_core/host_shaders/astc_decoder_vert_spv.h"
|
|
||||||
#include "video_core/host_shaders/queries_prefix_scan_sum_comp_spv.h"
|
#include "video_core/host_shaders/queries_prefix_scan_sum_comp_spv.h"
|
||||||
#include "video_core/host_shaders/queries_prefix_scan_sum_nosubgroups_comp_spv.h"
|
#include "video_core/host_shaders/queries_prefix_scan_sum_nosubgroups_comp_spv.h"
|
||||||
#include "video_core/host_shaders/resolve_conditional_render_comp_spv.h"
|
#include "video_core/host_shaders/resolve_conditional_render_comp_spv.h"
|
||||||
@@ -28,11 +25,8 @@
|
|||||||
#include "video_core/host_shaders/block_linear_unswizzle_3d_bcn_comp_spv.h"
|
#include "video_core/host_shaders/block_linear_unswizzle_3d_bcn_comp_spv.h"
|
||||||
#include "video_core/renderer_vulkan/vk_compute_pass.h"
|
#include "video_core/renderer_vulkan/vk_compute_pass.h"
|
||||||
#include "video_core/surface.h"
|
#include "video_core/surface.h"
|
||||||
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
|
||||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||||
#include "video_core/renderer_vulkan/vk_render_pass_cache.h"
|
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
#include "video_core/renderer_vulkan/vk_shader_util.h"
|
|
||||||
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
||||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||||
#include "video_core/texture_cache/accelerated_swizzle.h"
|
#include "video_core/texture_cache/accelerated_swizzle.h"
|
||||||
@@ -619,394 +613,7 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
|
|||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, 0, image_barrier);
|
vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, 0, image_barrier);
|
||||||
});
|
});
|
||||||
}
|
scheduler.Finish();
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct AstcFragPushConstants {
|
|
||||||
std::array<u32, 2> blocks_dims;
|
|
||||||
u32 layer_stride;
|
|
||||||
u32 block_size;
|
|
||||||
u32 x_shift;
|
|
||||||
u32 block_height;
|
|
||||||
u32 block_height_mask;
|
|
||||||
u32 dest_layer;
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr VkDescriptorSetLayoutBinding ASTC_FRAG_BINDING{
|
|
||||||
.binding = 0,
|
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
||||||
.pImmutableSamplers = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr VkDescriptorUpdateTemplateEntry ASTC_FRAG_TEMPLATE{
|
|
||||||
.dstBinding = 0,
|
|
||||||
.dstArrayElement = 0,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
||||||
.offset = 0,
|
|
||||||
.stride = sizeof(DescriptorUpdateEntry),
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr DescriptorBankInfo ASTC_FRAG_BANK_INFO{
|
|
||||||
.uniform_buffers = 0,
|
|
||||||
.storage_buffers = 1,
|
|
||||||
.texture_buffers = 0,
|
|
||||||
.image_buffers = 0,
|
|
||||||
.textures = 0,
|
|
||||||
.images = 0,
|
|
||||||
.score = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr VkPushConstantRange ASTC_FRAG_PUSH_CONSTANT_RANGE{
|
|
||||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
||||||
.offset = 0,
|
|
||||||
.size = static_cast<u32>(sizeof(AstcFragPushConstants)),
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr VkPipelineVertexInputStateCreateInfo ASTC_FRAG_VERTEX_INPUT{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.vertexBindingDescriptionCount = 0,
|
|
||||||
.pVertexBindingDescriptions = nullptr,
|
|
||||||
.vertexAttributeDescriptionCount = 0,
|
|
||||||
.pVertexAttributeDescriptions = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr VkPipelineInputAssemblyStateCreateInfo ASTC_FRAG_INPUT_ASSEMBLY{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
||||||
.primitiveRestartEnable = VK_FALSE,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr VkPipelineViewportStateCreateInfo ASTC_FRAG_VIEWPORT{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.viewportCount = 1,
|
|
||||||
.pViewports = nullptr,
|
|
||||||
.scissorCount = 1,
|
|
||||||
.pScissors = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr VkPipelineRasterizationStateCreateInfo ASTC_FRAG_RASTERIZATION{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.depthClampEnable = VK_FALSE,
|
|
||||||
.rasterizerDiscardEnable = VK_FALSE,
|
|
||||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
|
||||||
.cullMode = VK_CULL_MODE_NONE,
|
|
||||||
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
|
|
||||||
.depthBiasEnable = VK_FALSE,
|
|
||||||
.depthBiasConstantFactor = 0.0f,
|
|
||||||
.depthBiasClamp = 0.0f,
|
|
||||||
.depthBiasSlopeFactor = 0.0f,
|
|
||||||
.lineWidth = 1.0f,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr VkPipelineMultisampleStateCreateInfo ASTC_FRAG_MULTISAMPLE{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
|
||||||
.sampleShadingEnable = VK_FALSE,
|
|
||||||
.minSampleShading = 0.0f,
|
|
||||||
.pSampleMask = nullptr,
|
|
||||||
.alphaToCoverageEnable = VK_FALSE,
|
|
||||||
.alphaToOneEnable = VK_FALSE,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr VkPipelineColorBlendAttachmentState ASTC_FRAG_BLEND_ATTACHMENT{
|
|
||||||
.blendEnable = VK_FALSE,
|
|
||||||
.srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
||||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
|
|
||||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
|
||||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
||||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
|
||||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
|
||||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
|
||||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr std::array ASTC_FRAG_DYNAMIC_STATES{VK_DYNAMIC_STATE_VIEWPORT,
|
|
||||||
VK_DYNAMIC_STATE_SCISSOR};
|
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
ASTCDecoderFragmentPass::ASTCDecoderFragmentPass(
|
|
||||||
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
|
||||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_,
|
|
||||||
RenderPassCache& render_pass_cache_)
|
|
||||||
: device{device_}, scheduler{scheduler_},
|
|
||||||
compute_pass_descriptor_queue{compute_pass_descriptor_queue_},
|
|
||||||
render_pass_cache{render_pass_cache_},
|
|
||||||
descriptor_set_layout{device.GetLogical().CreateDescriptorSetLayout({
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.bindingCount = 1,
|
|
||||||
.pBindings = &ASTC_FRAG_BINDING,
|
|
||||||
})},
|
|
||||||
descriptor_template{device.GetLogical().CreateDescriptorUpdateTemplate({
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.descriptorUpdateEntryCount = 1,
|
|
||||||
.pDescriptorUpdateEntries = &ASTC_FRAG_TEMPLATE,
|
|
||||||
.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
|
|
||||||
.descriptorSetLayout = *descriptor_set_layout,
|
|
||||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
||||||
.pipelineLayout = VK_NULL_HANDLE,
|
|
||||||
.set = 0,
|
|
||||||
})},
|
|
||||||
pipeline_layout{device.GetLogical().CreatePipelineLayout({
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.setLayoutCount = 1,
|
|
||||||
.pSetLayouts = descriptor_set_layout.address(),
|
|
||||||
.pushConstantRangeCount = 1,
|
|
||||||
.pPushConstantRanges = &ASTC_FRAG_PUSH_CONSTANT_RANGE,
|
|
||||||
})},
|
|
||||||
descriptor_allocator{descriptor_pool_.Allocator(device_, scheduler_, *descriptor_set_layout,
|
|
||||||
ASTC_FRAG_BANK_INFO)},
|
|
||||||
vertex_shader{BuildShader(device, ASTC_DECODER_VERT_SPV)},
|
|
||||||
fragment_shader{BuildShader(device, ASTC_DECODER_FRAG_SPV)} {}
|
|
||||||
|
|
||||||
ASTCDecoderFragmentPass::~ASTCDecoderFragmentPass() = default;
|
|
||||||
|
|
||||||
VkPipeline ASTCDecoderFragmentPass::FindOrEmplacePipeline(VkRenderPass render_pass) {
|
|
||||||
const auto it = std::ranges::find(pipeline_keys, render_pass);
|
|
||||||
if (it != pipeline_keys.end()) {
|
|
||||||
return *pipelines[std::distance(pipeline_keys.begin(), it)];
|
|
||||||
}
|
|
||||||
pipeline_keys.push_back(render_pass);
|
|
||||||
const std::array stages{
|
|
||||||
VkPipelineShaderStageCreateInfo{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
||||||
.module = *vertex_shader,
|
|
||||||
.pName = "main",
|
|
||||||
.pSpecializationInfo = nullptr,
|
|
||||||
},
|
|
||||||
VkPipelineShaderStageCreateInfo{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
||||||
.module = *fragment_shader,
|
|
||||||
.pName = "main",
|
|
||||||
.pSpecializationInfo = nullptr,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const VkPipelineColorBlendStateCreateInfo color_blend{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.logicOpEnable = VK_FALSE,
|
|
||||||
.logicOp = VK_LOGIC_OP_CLEAR,
|
|
||||||
.attachmentCount = 1,
|
|
||||||
.pAttachments = &ASTC_FRAG_BLEND_ATTACHMENT,
|
|
||||||
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
|
|
||||||
};
|
|
||||||
const VkPipelineDynamicStateCreateInfo dynamic_state{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.dynamicStateCount = static_cast<u32>(ASTC_FRAG_DYNAMIC_STATES.size()),
|
|
||||||
.pDynamicStates = ASTC_FRAG_DYNAMIC_STATES.data(),
|
|
||||||
};
|
|
||||||
pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
|
||||||
.pStages = stages.data(),
|
|
||||||
.pVertexInputState = &ASTC_FRAG_VERTEX_INPUT,
|
|
||||||
.pInputAssemblyState = &ASTC_FRAG_INPUT_ASSEMBLY,
|
|
||||||
.pTessellationState = nullptr,
|
|
||||||
.pViewportState = &ASTC_FRAG_VIEWPORT,
|
|
||||||
.pRasterizationState = &ASTC_FRAG_RASTERIZATION,
|
|
||||||
.pMultisampleState = &ASTC_FRAG_MULTISAMPLE,
|
|
||||||
.pDepthStencilState = nullptr,
|
|
||||||
.pColorBlendState = &color_blend,
|
|
||||||
.pDynamicState = &dynamic_state,
|
|
||||||
.layout = *pipeline_layout,
|
|
||||||
.renderPass = render_pass,
|
|
||||||
.subpass = 0,
|
|
||||||
.basePipelineHandle = VK_NULL_HANDLE,
|
|
||||||
.basePipelineIndex = 0,
|
|
||||||
}));
|
|
||||||
return *pipelines.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASTCDecoderFragmentPass::Assemble(Image& image, const StagingBufferRef& map,
|
|
||||||
std::span<const VideoCommon::SwizzleParameters> swizzles,
|
|
||||||
VideoCore::Surface::PixelFormat decoded_format) {
|
|
||||||
using namespace VideoCommon::Accelerated;
|
|
||||||
while (!frame_resources.empty() && scheduler.IsFree(frame_resources.front().tick)) {
|
|
||||||
frame_resources.pop_front();
|
|
||||||
}
|
|
||||||
const std::array<u32, 2> block_dims{
|
|
||||||
VideoCore::Surface::DefaultBlockWidth(image.info.format),
|
|
||||||
VideoCore::Surface::DefaultBlockHeight(image.info.format),
|
|
||||||
};
|
|
||||||
RenderPassKey key{};
|
|
||||||
key.color_formats.fill(VideoCore::Surface::PixelFormat::Invalid);
|
|
||||||
key.color_formats[0] = decoded_format;
|
|
||||||
key.depth_format = VideoCore::Surface::PixelFormat::Invalid;
|
|
||||||
key.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
const VkRenderPass render_pass = render_pass_cache.Get(key);
|
|
||||||
const VkPipeline pipeline = FindOrEmplacePipeline(render_pass);
|
|
||||||
const VkFormat vk_format =
|
|
||||||
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, decoded_format).format;
|
|
||||||
const VkImage vk_image = image.Handle();
|
|
||||||
const VkImageAspectFlags aspect_mask = image.AspectMask();
|
|
||||||
|
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
|
||||||
const bool is_initialized = image.ExchangeInitialization();
|
|
||||||
scheduler.Record([vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) {
|
|
||||||
const VkImageMemoryBarrier barrier{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.srcAccessMask = static_cast<VkAccessFlags>(
|
|
||||||
is_initialized ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_NONE),
|
|
||||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
||||||
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
|
||||||
.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.image = vk_image,
|
|
||||||
.subresourceRange{
|
|
||||||
.aspectMask = aspect_mask,
|
|
||||||
.baseMipLevel = 0,
|
|
||||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER,
|
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, barrier);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
|
|
||||||
const size_t input_offset = swizzle.buffer_offset + map.offset;
|
|
||||||
const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
|
|
||||||
const u32 level = swizzle.level;
|
|
||||||
const u32 width = std::max(1u, image.info.size.width >> level);
|
|
||||||
const u32 height = std::max(1u, image.info.size.height >> level);
|
|
||||||
const u32 layers = image.info.resources.layers;
|
|
||||||
for (u32 layer = 0; layer < layers; ++layer) {
|
|
||||||
vk::ImageView view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.image = vk_image,
|
|
||||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
||||||
.format = vk_format,
|
|
||||||
.components{},
|
|
||||||
.subresourceRange{
|
|
||||||
.aspectMask = aspect_mask,
|
|
||||||
.baseMipLevel = level,
|
|
||||||
.levelCount = 1,
|
|
||||||
.baseArrayLayer = layer,
|
|
||||||
.layerCount = 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
vk::Framebuffer framebuffer =
|
|
||||||
device.GetLogical().CreateFramebuffer(VkFramebufferCreateInfo{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.renderPass = render_pass,
|
|
||||||
.attachmentCount = 1,
|
|
||||||
.pAttachments = view.address(),
|
|
||||||
.width = width,
|
|
||||||
.height = height,
|
|
||||||
.layers = 1,
|
|
||||||
});
|
|
||||||
const AstcFragPushConstants pc{
|
|
||||||
.blocks_dims = block_dims,
|
|
||||||
.layer_stride = params.layer_stride,
|
|
||||||
.block_size = params.block_size,
|
|
||||||
.x_shift = params.x_shift,
|
|
||||||
.block_height = params.block_height,
|
|
||||||
.block_height_mask = params.block_height_mask,
|
|
||||||
.dest_layer = layer,
|
|
||||||
};
|
|
||||||
compute_pass_descriptor_queue.Acquire(scheduler, 1);
|
|
||||||
compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset,
|
|
||||||
image.guest_size_bytes - swizzle.buffer_offset);
|
|
||||||
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
|
|
||||||
scheduler.Record([this, pipeline, render_pass, descriptor_data, pc, width, height,
|
|
||||||
fb = *framebuffer](vk::CommandBuffer cmdbuf) {
|
|
||||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
|
||||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
|
||||||
const VkRenderPassBeginInfo begin{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.renderPass = render_pass,
|
|
||||||
.framebuffer = fb,
|
|
||||||
.renderArea{.offset = {0, 0}, .extent = {width, height}},
|
|
||||||
.clearValueCount = 0,
|
|
||||||
.pClearValues = nullptr,
|
|
||||||
};
|
|
||||||
const VkViewport viewport{
|
|
||||||
.x = 0.0f,
|
|
||||||
.y = 0.0f,
|
|
||||||
.width = static_cast<float>(width),
|
|
||||||
.height = static_cast<float>(height),
|
|
||||||
.minDepth = 0.0f,
|
|
||||||
.maxDepth = 1.0f,
|
|
||||||
};
|
|
||||||
const VkRect2D scissor{.offset = {0, 0}, .extent = {width, height}};
|
|
||||||
cmdbuf.BeginRenderPass(begin, VK_SUBPASS_CONTENTS_INLINE);
|
|
||||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
|
||||||
cmdbuf.SetViewport(0, viewport);
|
|
||||||
cmdbuf.SetScissor(0, scissor);
|
|
||||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0, set,
|
|
||||||
{});
|
|
||||||
cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, pc);
|
|
||||||
cmdbuf.Draw(3, 1, 0, 0);
|
|
||||||
cmdbuf.EndRenderPass();
|
|
||||||
});
|
|
||||||
frame_resources.push_back(FrameResources{
|
|
||||||
.tick = scheduler.CurrentTick(),
|
|
||||||
.view = std::move(view),
|
|
||||||
.framebuffer = std::move(framebuffer),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scheduler.Record([vk_image, aspect_mask](vk::CommandBuffer cmdbuf) {
|
|
||||||
const VkImageMemoryBarrier barrier{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
||||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
|
||||||
.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
||||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.image = vk_image,
|
|
||||||
.subresourceRange{
|
|
||||||
.aspectMask = aspect_mask,
|
|
||||||
.baseMipLevel = 0,
|
|
||||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, 0, barrier);
|
|
||||||
});
|
|
||||||
scheduler.InvalidateState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u32 BL3D_BINDING_INPUT_BUFFER = 0;
|
constexpr u32 BL3D_BINDING_INPUT_BUFFER = 0;
|
||||||
|
|||||||
@@ -6,15 +6,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/surface.h"
|
|
||||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||||
#include "video_core/texture_cache/types.h"
|
#include "video_core/texture_cache/types.h"
|
||||||
@@ -140,44 +137,6 @@ private:
|
|||||||
MemoryAllocator& memory_allocator;
|
MemoryAllocator& memory_allocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RenderPassCache;
|
|
||||||
|
|
||||||
class ASTCDecoderFragmentPass final {
|
|
||||||
public:
|
|
||||||
explicit ASTCDecoderFragmentPass(const Device& device_, Scheduler& scheduler_,
|
|
||||||
DescriptorPool& descriptor_pool_,
|
|
||||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_,
|
|
||||||
RenderPassCache& render_pass_cache_);
|
|
||||||
~ASTCDecoderFragmentPass();
|
|
||||||
|
|
||||||
void Assemble(Image& image, const StagingBufferRef& map,
|
|
||||||
std::span<const VideoCommon::SwizzleParameters> swizzles,
|
|
||||||
VideoCore::Surface::PixelFormat decoded_format);
|
|
||||||
|
|
||||||
private:
|
|
||||||
VkPipeline FindOrEmplacePipeline(VkRenderPass render_pass);
|
|
||||||
|
|
||||||
const Device& device;
|
|
||||||
Scheduler& scheduler;
|
|
||||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
|
||||||
RenderPassCache& render_pass_cache;
|
|
||||||
vk::DescriptorSetLayout descriptor_set_layout;
|
|
||||||
vk::DescriptorUpdateTemplate descriptor_template;
|
|
||||||
vk::PipelineLayout pipeline_layout;
|
|
||||||
DescriptorAllocator descriptor_allocator;
|
|
||||||
vk::ShaderModule vertex_shader;
|
|
||||||
vk::ShaderModule fragment_shader;
|
|
||||||
std::vector<VkRenderPass> pipeline_keys;
|
|
||||||
std::vector<vk::Pipeline> pipelines;
|
|
||||||
|
|
||||||
struct FrameResources {
|
|
||||||
u64 tick;
|
|
||||||
vk::ImageView view;
|
|
||||||
vk::Framebuffer framebuffer;
|
|
||||||
};
|
|
||||||
std::deque<FrameResources> frame_resources;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BlockLinearUnswizzle3DPass final : public ComputePass {
|
class BlockLinearUnswizzle3DPass final : public ComputePass {
|
||||||
public:
|
public:
|
||||||
explicit BlockLinearUnswizzle3DPass(const Device& device_, Scheduler& scheduler_,
|
explicit BlockLinearUnswizzle3DPass(const Device& device_, Scheduler& scheduler_,
|
||||||
|
|||||||
@@ -290,7 +290,10 @@ GraphicsPipeline::GraphicsPipeline(
|
|||||||
descriptor_update_template =
|
descriptor_update_template =
|
||||||
builder.CreateTemplate(set_layout, *pipeline_layout, uses_push_descriptor);
|
builder.CreateTemplate(set_layout, *pipeline_layout, uses_push_descriptor);
|
||||||
|
|
||||||
const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(key.state, device))};
|
VkRenderPass render_pass{};
|
||||||
|
if (!device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
render_pass = render_pass_cache.Get(MakeRenderPassKey(key.state, device));
|
||||||
|
}
|
||||||
Validate();
|
Validate();
|
||||||
try {
|
try {
|
||||||
MakePipeline(render_pass);
|
MakePipeline(render_pass);
|
||||||
@@ -996,9 +999,47 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
|||||||
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
|
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RenderPassKey renderpass_key{MakeRenderPassKey(key.state, device)};
|
||||||
|
std::array<VkFormat, Maxwell::NumRenderTargets> color_attachment_formats{};
|
||||||
|
for (size_t index = 0; index < renderpass_key.color_formats.size(); ++index) {
|
||||||
|
const PixelFormat pixel_format{renderpass_key.color_formats[index]};
|
||||||
|
if (pixel_format == PixelFormat::Invalid) {
|
||||||
|
color_attachment_formats[index] = VK_FORMAT_UNDEFINED;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
color_attachment_formats[index] =
|
||||||
|
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true, pixel_format).format;
|
||||||
|
}
|
||||||
|
VkFormat depth_attachment_format{VK_FORMAT_UNDEFINED};
|
||||||
|
VkFormat stencil_attachment_format{VK_FORMAT_UNDEFINED};
|
||||||
|
if (renderpass_key.depth_format != PixelFormat::Invalid) {
|
||||||
|
const VkFormat format{
|
||||||
|
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true,
|
||||||
|
renderpass_key.depth_format)
|
||||||
|
.format};
|
||||||
|
const auto surface_type{VideoCore::Surface::GetFormatType(renderpass_key.depth_format)};
|
||||||
|
if (surface_type == VideoCore::Surface::SurfaceType::Depth ||
|
||||||
|
surface_type == VideoCore::Surface::SurfaceType::DepthStencil) {
|
||||||
|
depth_attachment_format = format;
|
||||||
|
}
|
||||||
|
if (surface_type == VideoCore::Surface::SurfaceType::Stencil ||
|
||||||
|
surface_type == VideoCore::Surface::SurfaceType::DepthStencil) {
|
||||||
|
stencil_attachment_format = format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.viewMask = 0,
|
||||||
|
.colorAttachmentCount = static_cast<u32>(NumAttachments(key.state)),
|
||||||
|
.pColorAttachmentFormats = color_attachment_formats.data(),
|
||||||
|
.depthAttachmentFormat = depth_attachment_format,
|
||||||
|
.stencilAttachmentFormat = stencil_attachment_format,
|
||||||
|
};
|
||||||
|
|
||||||
pipeline = device.GetLogical().CreateGraphicsPipeline({
|
pipeline = device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = device.IsKhrDynamicRenderingSupported() ? &rendering_ci : nullptr,
|
||||||
.flags = flags,
|
.flags = flags,
|
||||||
.stageCount = static_cast<u32>(shader_stages.size()),
|
.stageCount = static_cast<u32>(shader_stages.size()),
|
||||||
.pStages = shader_stages.data(),
|
.pStages = shader_stages.data(),
|
||||||
|
|||||||
@@ -167,7 +167,6 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
|
|||||||
}
|
}
|
||||||
const Shader::Stage stage{program.stage};
|
const Shader::Stage stage{program.stage};
|
||||||
const bool has_geometry{key.unique_hashes[4] != 0 && !programs[4].is_geometry_passthrough};
|
const bool has_geometry{key.unique_hashes[4] != 0 && !programs[4].is_geometry_passthrough};
|
||||||
const bool has_tessellation{key.unique_hashes[3] != 0};
|
|
||||||
const bool gl_ndc{key.state.ndc_minus_one_to_one != 0};
|
const bool gl_ndc{key.state.ndc_minus_one_to_one != 0};
|
||||||
const float point_size{std::bit_cast<float>(key.state.point_size)};
|
const float point_size{std::bit_cast<float>(key.state.point_size)};
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
@@ -186,9 +185,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
|
|||||||
LOG_WARNING(Render_Vulkan, "XFB requested in pipeline key but device lacks VK_EXT_transform_feedback; ignoring XFB decorations");
|
LOG_WARNING(Render_Vulkan, "XFB requested in pipeline key but device lacks VK_EXT_transform_feedback; ignoring XFB decorations");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!has_tessellation) {
|
info.convert_depth_mode = gl_ndc;
|
||||||
info.convert_depth_mode = gl_ndc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (key.state.dynamic_vertex_input) {
|
if (key.state.dynamic_vertex_input) {
|
||||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
||||||
@@ -227,9 +224,6 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
|
|||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
return Shader::TessSpacing::Equal;
|
return Shader::TessSpacing::Equal;
|
||||||
}();
|
}();
|
||||||
if (!has_geometry) {
|
|
||||||
info.convert_depth_mode = gl_ndc;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Shader::Stage::Geometry:
|
case Shader::Stage::Geometry:
|
||||||
if (program.output_topology == Shader::OutputTopology::PointList) {
|
if (program.output_topology == Shader::OutputTopology::PointList) {
|
||||||
|
|||||||
@@ -773,7 +773,6 @@ bool RasterizerVulkan::OnCPUWrite(DAddr addr, u64 size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static constexpr bool ENABLE_TEXTURE_CACHE_INVALIDATION_SKIP = true;
|
static constexpr bool ENABLE_TEXTURE_CACHE_INVALIDATION_SKIP = true;
|
||||||
static constexpr bool ENABLE_FINE_GRAINED_TRACKER_LOCK = true;
|
|
||||||
|
|
||||||
void RasterizerVulkan::OnCacheInvalidation(DAddr addr, u64 size) {
|
void RasterizerVulkan::OnCacheInvalidation(DAddr addr, u64 size) {
|
||||||
if (addr == 0 || size == 0) {
|
if (addr == 0 || size == 0) {
|
||||||
@@ -785,9 +784,7 @@ void RasterizerVulkan::OnCacheInvalidation(DAddr addr, u64 size) {
|
|||||||
std::scoped_lock lock{texture_cache.mutex};
|
std::scoped_lock lock{texture_cache.mutex};
|
||||||
texture_cache.WriteMemory(addr, size);
|
texture_cache.WriteMemory(addr, size);
|
||||||
}
|
}
|
||||||
if (ENABLE_FINE_GRAINED_TRACKER_LOCK) {
|
{
|
||||||
buffer_cache.CpuWriteInvalidate(addr, size);
|
|
||||||
} else {
|
|
||||||
std::scoped_lock lock{buffer_cache.mutex};
|
std::scoped_lock lock{buffer_cache.mutex};
|
||||||
buffer_cache.WriteMemory(addr, size);
|
buffer_cache.WriteMemory(addr, size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,13 +93,53 @@ void Scheduler::DispatchWork() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scheduler::BeginDynamicRendering(const Framebuffer* framebuffer, const DeferredClear* clear) {
|
||||||
|
const VkExtent2D render_area = framebuffer->RenderArea();
|
||||||
|
std::array<VkImageView, 9> attachment_views{};
|
||||||
|
const auto& color_views = framebuffer->ColorAttachments();
|
||||||
|
for (size_t index = 0; index < color_views.size(); ++index) {
|
||||||
|
attachment_views[index] = color_views[index];
|
||||||
|
}
|
||||||
|
attachment_views[8] = framebuffer->DepthAttachment();
|
||||||
|
state.renderpass = VkRenderPass{};
|
||||||
|
state.framebuffer = VkFramebuffer{};
|
||||||
|
state.attachment_views = attachment_views;
|
||||||
|
state.color_resolve_views = framebuffer->ColorResolveAttachments();
|
||||||
|
state.color_resolve_modes = framebuffer->ColorResolveModes();
|
||||||
|
state.discards_msaa_color = framebuffer->DiscardsMsaaColor();
|
||||||
|
state.discards_msaa_depth = framebuffer->DiscardsMsaaDepth();
|
||||||
|
state.render_area = render_area;
|
||||||
|
state.num_color = framebuffer->NumColorAttachments();
|
||||||
|
state.has_depth = framebuffer->HasAspectDepthBit();
|
||||||
|
state.has_stencil = framebuffer->HasAspectStencilBit();
|
||||||
|
state.layer_count = framebuffer->NumLayers();
|
||||||
|
state.rendering = true;
|
||||||
|
|
||||||
|
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
||||||
|
const std::string render_pass_info =
|
||||||
|
fmt::format("renderArea={}x{}, numImages={}", render_area.width, render_area.height,
|
||||||
|
framebuffer->NumImages());
|
||||||
|
GPU::Logging::GPULogger::GetInstance().LogRenderPassBegin(render_pass_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
RecordDynamicBegin(clear);
|
||||||
|
num_renderpass_images = framebuffer->NumImages();
|
||||||
|
renderpass_images = framebuffer->Images();
|
||||||
|
renderpass_image_ranges = framebuffer->ImageRanges();
|
||||||
|
}
|
||||||
|
|
||||||
void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass,
|
void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass,
|
||||||
const VkClearValue* clear_values, u32 clear_value_count) {
|
const VkClearValue* clear_values, u32 clear_value_count) {
|
||||||
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
if (device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
BeginDynamicRendering(framebuffer, nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const VkExtent2D render_area = framebuffer->RenderArea();
|
const VkExtent2D render_area = framebuffer->RenderArea();
|
||||||
|
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
||||||
state.renderpass = renderpass;
|
state.renderpass = renderpass;
|
||||||
state.framebuffer = framebuffer_handle;
|
state.framebuffer = framebuffer_handle;
|
||||||
state.render_area = render_area;
|
state.render_area = render_area;
|
||||||
|
state.rendering = true;
|
||||||
|
|
||||||
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
||||||
const std::string render_pass_info =
|
const std::string render_pass_info =
|
||||||
@@ -141,6 +181,12 @@ void Scheduler::RealizeDeferredClear() {
|
|||||||
const DeferredClear dc = deferred_clear;
|
const DeferredClear dc = deferred_clear;
|
||||||
deferred_clear = {};
|
deferred_clear = {};
|
||||||
|
|
||||||
|
if (device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
EndRenderPass();
|
||||||
|
BeginDynamicRendering(dc.framebuffer, &dc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::array<VkClearValue, 9> clear_values{};
|
std::array<VkClearValue, 9> clear_values{};
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
const RenderPassKey& base = dc.framebuffer->RenderPassKeyBase();
|
const RenderPassKey& base = dc.framebuffer->RenderPassKeyBase();
|
||||||
@@ -195,9 +241,25 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) {
|
|||||||
RealizeDeferredClear();
|
RealizeDeferredClear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const VkExtent2D render_area = framebuffer->RenderArea();
|
||||||
|
if (device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
std::array<VkImageView, 9> attachment_views{};
|
||||||
|
const auto& color_views = framebuffer->ColorAttachments();
|
||||||
|
for (size_t index = 0; index < color_views.size(); ++index) {
|
||||||
|
attachment_views[index] = color_views[index];
|
||||||
|
}
|
||||||
|
attachment_views[8] = framebuffer->DepthAttachment();
|
||||||
|
if (state.rendering && attachment_views == state.attachment_views &&
|
||||||
|
render_area.width == state.render_area.width &&
|
||||||
|
render_area.height == state.render_area.height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EndRenderPass();
|
||||||
|
BeginDynamicRendering(framebuffer, nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const VkRenderPass renderpass = framebuffer->RenderPass();
|
const VkRenderPass renderpass = framebuffer->RenderPass();
|
||||||
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
||||||
const VkExtent2D render_area = framebuffer->RenderArea();
|
|
||||||
if (renderpass == state.renderpass && framebuffer_handle == state.framebuffer &&
|
if (renderpass == state.renderpass && framebuffer_handle == state.framebuffer &&
|
||||||
render_area.width == state.render_area.width &&
|
render_area.width == state.render_area.width &&
|
||||||
render_area.height == state.render_area.height) {
|
render_area.height == state.render_area.height) {
|
||||||
@@ -372,6 +434,80 @@ void Scheduler::InvalidateState() {
|
|||||||
state_tracker.InvalidateCommandBufferState();
|
state_tracker.InvalidateCommandBufferState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scheduler::RecordDynamicBegin(const DeferredClear* clear) {
|
||||||
|
const std::array<VkImageView, 9> views = state.attachment_views;
|
||||||
|
const std::array<VkImageView, 8> resolve_views = state.color_resolve_views;
|
||||||
|
const std::array<VkResolveModeFlagBits, 8> resolve_modes = state.color_resolve_modes;
|
||||||
|
const u32 num_color = state.num_color;
|
||||||
|
const bool has_depth = state.has_depth;
|
||||||
|
const bool has_stencil = state.has_stencil;
|
||||||
|
const u32 layers = state.layer_count;
|
||||||
|
const VkExtent2D render_area = state.render_area;
|
||||||
|
const u32 color_clear_mask = clear ? clear->color_clear_mask : 0u;
|
||||||
|
const u32 color_discard_mask =
|
||||||
|
clear != nullptr && state.discards_msaa_color ? clear->color_clear_mask : 0u;
|
||||||
|
const std::array<VkClearValue, 8> color_clear_values =
|
||||||
|
clear ? clear->color_values : std::array<VkClearValue, 8>{};
|
||||||
|
const bool ds_clear = clear != nullptr && clear->depth_stencil;
|
||||||
|
const VkClearValue ds_clear_value = clear ? clear->depth_stencil_value : VkClearValue{};
|
||||||
|
const bool ds_discard = state.discards_msaa_depth;
|
||||||
|
Record([views, resolve_views, resolve_modes, num_color, has_depth, has_stencil, layers,
|
||||||
|
render_area, color_clear_mask, color_discard_mask, color_clear_values, ds_clear,
|
||||||
|
ds_clear_value, ds_discard](vk::CommandBuffer cmdbuf) {
|
||||||
|
std::array<VkRenderingAttachmentInfo, VideoCommon::NUM_RT> color_infos{};
|
||||||
|
for (u32 index = 0; index < num_color; ++index) {
|
||||||
|
const bool clear_slot = ((color_clear_mask >> index) & 1u) != 0;
|
||||||
|
const VkImageView resolve_view = resolve_views[index];
|
||||||
|
const bool has_resolve = resolve_view != VK_NULL_HANDLE;
|
||||||
|
const bool discard_slot = has_resolve && ((color_discard_mask >> index) & 1u) != 0;
|
||||||
|
color_infos[index] = VkRenderingAttachmentInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.imageView = views[index],
|
||||||
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.resolveMode = has_resolve ? resolve_modes[index] : VK_RESOLVE_MODE_NONE,
|
||||||
|
.resolveImageView = resolve_view,
|
||||||
|
.resolveImageLayout =
|
||||||
|
has_resolve ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.loadOp = clear_slot ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
.storeOp = discard_slot ? VK_ATTACHMENT_STORE_OP_DONT_CARE
|
||||||
|
: VK_ATTACHMENT_STORE_OP_STORE,
|
||||||
|
.clearValue = clear_slot ? color_clear_values[index] : VkClearValue{},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const VkRenderingAttachmentInfo depth_info{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.imageView = views[8],
|
||||||
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.resolveMode = VK_RESOLVE_MODE_NONE,
|
||||||
|
.resolveImageView = VK_NULL_HANDLE,
|
||||||
|
.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.loadOp = ds_clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
.storeOp = ds_discard ? VK_ATTACHMENT_STORE_OP_DONT_CARE
|
||||||
|
: VK_ATTACHMENT_STORE_OP_STORE,
|
||||||
|
.clearValue = ds_clear ? ds_clear_value : VkClearValue{},
|
||||||
|
};
|
||||||
|
const VkRenderingInfo rendering_info{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.renderArea =
|
||||||
|
{
|
||||||
|
.offset = {.x = 0, .y = 0},
|
||||||
|
.extent = render_area,
|
||||||
|
},
|
||||||
|
.layerCount = layers,
|
||||||
|
.viewMask = 0,
|
||||||
|
.colorAttachmentCount = num_color,
|
||||||
|
.pColorAttachments = color_infos.data(),
|
||||||
|
.pDepthAttachment = has_depth ? &depth_info : nullptr,
|
||||||
|
.pStencilAttachment = has_stencil ? &depth_info : nullptr,
|
||||||
|
};
|
||||||
|
cmdbuf.BeginRendering(rendering_info);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Scheduler::EndPendingOperations() {
|
void Scheduler::EndPendingOperations() {
|
||||||
query_cache->CounterReset(VideoCommon::QueryType::ZPassPixelCount64);
|
query_cache->CounterReset(VideoCommon::QueryType::ZPassPixelCount64);
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
@@ -380,7 +516,7 @@ void Scheduler::EndPendingOperations() {
|
|||||||
void Scheduler::EndRenderPass()
|
void Scheduler::EndRenderPass()
|
||||||
{
|
{
|
||||||
RealizeDeferredClear();
|
RealizeDeferredClear();
|
||||||
if (!state.renderpass) {
|
if (!state.rendering) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,7 +534,8 @@ void Scheduler::EndRenderPass()
|
|||||||
Record([num_images = num_renderpass_images,
|
Record([num_images = num_renderpass_images,
|
||||||
images = renderpass_images,
|
images = renderpass_images,
|
||||||
ranges = renderpass_image_ranges,
|
ranges = renderpass_image_ranges,
|
||||||
has_transform_feedback = device.IsExtTransformFeedbackSupported()](
|
has_transform_feedback = device.IsExtTransformFeedbackSupported(),
|
||||||
|
dynamic_rendering = device.IsKhrDynamicRenderingSupported()](
|
||||||
vk::CommandBuffer cmdbuf) {
|
vk::CommandBuffer cmdbuf) {
|
||||||
std::array<VkImageMemoryBarrier, 9> barriers;
|
std::array<VkImageMemoryBarrier, 9> barriers;
|
||||||
for (size_t i = 0; i < num_images; ++i) {
|
for (size_t i = 0; i < num_images; ++i) {
|
||||||
@@ -435,7 +572,11 @@ void Scheduler::EndRenderPass()
|
|||||||
.subresourceRange = range,
|
.subresourceRange = range,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
cmdbuf.EndRenderPass();
|
if (dynamic_rendering) {
|
||||||
|
cmdbuf.EndRendering();
|
||||||
|
} else {
|
||||||
|
cmdbuf.EndRenderPass();
|
||||||
|
}
|
||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
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_GRAPHICS_COMPUTE,
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
|
||||||
0, nullptr, nullptr, vk::Span(barriers.data(), num_images));
|
0, nullptr, nullptr, vk::Span(barriers.data(), num_images));
|
||||||
@@ -453,6 +594,9 @@ void Scheduler::EndRenderPass()
|
|||||||
});
|
});
|
||||||
|
|
||||||
state.renderpass = VkRenderPass{};
|
state.renderpass = VkRenderPass{};
|
||||||
|
state.framebuffer = VkFramebuffer{};
|
||||||
|
state.attachment_views = {};
|
||||||
|
state.rendering = false;
|
||||||
num_renderpass_images = 0;
|
num_renderpass_images = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public:
|
|||||||
|
|
||||||
/// Returns true when a render pass is currently active in the scheduler state.
|
/// Returns true when a render pass is currently active in the scheduler state.
|
||||||
bool IsRenderPassActive() const {
|
bool IsRenderPassActive() const {
|
||||||
return state.renderpass != VK_NULL_HANDLE;
|
return state.rendering;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the pipeline to the current execution context.
|
/// Update the pipeline to the current execution context.
|
||||||
@@ -250,8 +250,18 @@ private:
|
|||||||
struct State {
|
struct State {
|
||||||
VkRenderPass renderpass{};
|
VkRenderPass renderpass{};
|
||||||
VkFramebuffer framebuffer{};
|
VkFramebuffer framebuffer{};
|
||||||
|
std::array<VkImageView, 9> attachment_views{};
|
||||||
|
std::array<VkImageView, 8> color_resolve_views{};
|
||||||
|
std::array<VkResolveModeFlagBits, 8> color_resolve_modes{};
|
||||||
VkExtent2D render_area = {0, 0};
|
VkExtent2D render_area = {0, 0};
|
||||||
GraphicsPipeline* graphics_pipeline = nullptr;
|
GraphicsPipeline* graphics_pipeline = nullptr;
|
||||||
|
bool rendering = false;
|
||||||
|
bool discards_msaa_color = false;
|
||||||
|
bool discards_msaa_depth = false;
|
||||||
|
u32 num_color = 0;
|
||||||
|
bool has_depth = false;
|
||||||
|
bool has_stencil = false;
|
||||||
|
u32 layer_count = 1;
|
||||||
bool is_rescaling = false;
|
bool is_rescaling = false;
|
||||||
bool rescaling_defined = false;
|
bool rescaling_defined = false;
|
||||||
bool needs_state_enable_refresh = false;
|
bool needs_state_enable_refresh = false;
|
||||||
@@ -269,6 +279,9 @@ private:
|
|||||||
void BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass,
|
void BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass,
|
||||||
const VkClearValue* clear_values, u32 clear_value_count);
|
const VkClearValue* clear_values, u32 clear_value_count);
|
||||||
|
|
||||||
|
/// Begins a dynamic rendering pass, optionally realizing a deferred clear via load ops.
|
||||||
|
void BeginDynamicRendering(const Framebuffer* framebuffer, const DeferredClear* clear);
|
||||||
|
|
||||||
/// If a deferred clear is pending.
|
/// If a deferred clear is pending.
|
||||||
void RealizeDeferredClear();
|
void RealizeDeferredClear();
|
||||||
|
|
||||||
@@ -282,6 +295,8 @@ private:
|
|||||||
|
|
||||||
void EndPendingOperations();
|
void EndPendingOperations();
|
||||||
|
|
||||||
|
void RecordDynamicBegin(const DeferredClear* clear);
|
||||||
|
|
||||||
void EndRenderPass();
|
void EndRenderPass();
|
||||||
|
|
||||||
void AcquireNewChunk();
|
void AcquireNewChunk();
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ using VideoCore::Surface::SurfaceType;
|
|||||||
namespace {
|
namespace {
|
||||||
constexpr bool ENABLE_MSAA_RESOLVE_CONSUME = true;
|
constexpr bool ENABLE_MSAA_RESOLVE_CONSUME = true;
|
||||||
constexpr bool ENABLE_MSAA_COLOR_DISCARD = true;
|
constexpr bool ENABLE_MSAA_COLOR_DISCARD = true;
|
||||||
|
constexpr bool ENABLE_MSAA_DEPTH_DISCARD = true;
|
||||||
|
|
||||||
constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
|
constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
|
||||||
if (color == std::array<float, 4>{0, 0, 0, 0}) {
|
if (color == std::array<float, 4>{0, 0, 0, 0}) {
|
||||||
@@ -129,9 +130,6 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
|
|||||||
if (info.storage) {
|
if (info.storage) {
|
||||||
usage |= VK_IMAGE_USAGE_STORAGE_BIT;
|
usage |= VK_IMAGE_USAGE_STORAGE_BIT;
|
||||||
}
|
}
|
||||||
if (IsPixelFormatASTC(format)) {
|
|
||||||
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
||||||
}
|
|
||||||
return usage;
|
return usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -914,10 +912,6 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
|
|||||||
if (Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu) {
|
if (Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu) {
|
||||||
astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
|
astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
|
||||||
compute_pass_descriptor_queue, memory_allocator);
|
compute_pass_descriptor_queue, memory_allocator);
|
||||||
if (device.IsTiler()) {
|
|
||||||
astc_decoder_fragment_pass.emplace(device, scheduler, descriptor_pool,
|
|
||||||
compute_pass_descriptor_queue, render_pass_cache);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!device.IsKhrImageFormatListSupported()) {
|
if (!device.IsKhrImageFormatListSupported()) {
|
||||||
return;
|
return;
|
||||||
@@ -1048,6 +1042,32 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk
|
|||||||
shadow.extent = extent;
|
shadow.extent = extent;
|
||||||
shadow.layers = layers;
|
shadow.layers = layers;
|
||||||
shadow.up_to_date = true;
|
shadow.up_to_date = true;
|
||||||
|
if (device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
scheduler.RecordWithUploadBuffer(
|
||||||
|
[image = *shadow.image, layers](vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) {
|
||||||
|
const VkImageMemoryBarrier barrier{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.srcAccessMask = 0,
|
||||||
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = image,
|
||||||
|
.subresourceRange{
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = layers,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
upload_cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
|
||||||
|
barrier);
|
||||||
|
});
|
||||||
|
}
|
||||||
return *shadow.view;
|
return *shadow.view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1360,7 +1380,7 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) {
|
void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) {
|
||||||
if (!dst->RenderPass()) {
|
if (!dst->RenderPass() && !device.IsKhrDynamicRenderingSupported()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2690,7 +2710,7 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
|
|||||||
.height = key.size.height,
|
.height = key.size.height,
|
||||||
}} {
|
}} {
|
||||||
CreateFramebuffer(runtime, color_buffers, depth_buffer, key.is_rescaled);
|
CreateFramebuffer(runtime, color_buffers, depth_buffer, key.is_rescaled);
|
||||||
if (runtime.device.HasDebuggingToolAttached()) {
|
if (runtime.device.HasDebuggingToolAttached() && framebuffer) {
|
||||||
framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str());
|
framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2733,6 +2753,12 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
|||||||
image_ranges[num_images] = MakeSubresourceRange(color_buffer);
|
image_ranges[num_images] = MakeSubresourceRange(color_buffer);
|
||||||
rt_map[index] = num_images;
|
rt_map[index] = num_images;
|
||||||
samples = color_buffer->Samples();
|
samples = color_buffer->Samples();
|
||||||
|
color_attachments[index] = color_buffer->RenderTarget();
|
||||||
|
color_attachment_formats[index] =
|
||||||
|
MaxwellToVK::SurfaceFormat(runtime.device, FormatType::Optimal, true,
|
||||||
|
color_buffer->format)
|
||||||
|
.format;
|
||||||
|
num_color_attachments = static_cast<u32>(index + 1);
|
||||||
++num_images;
|
++num_images;
|
||||||
}
|
}
|
||||||
const size_t num_colors = attachments.size();
|
const size_t num_colors = attachments.size();
|
||||||
@@ -2748,6 +2774,11 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
|||||||
const VkImageSubresourceRange subresource_range = MakeSubresourceRange(depth_buffer);
|
const VkImageSubresourceRange subresource_range = MakeSubresourceRange(depth_buffer);
|
||||||
image_ranges[num_images] = subresource_range;
|
image_ranges[num_images] = subresource_range;
|
||||||
samples = depth_buffer->Samples();
|
samples = depth_buffer->Samples();
|
||||||
|
depth_attachment = depth_buffer->RenderTarget();
|
||||||
|
depth_attachment_format =
|
||||||
|
MaxwellToVK::SurfaceFormat(runtime.device, FormatType::Optimal, true,
|
||||||
|
depth_buffer->format)
|
||||||
|
.format;
|
||||||
++num_images;
|
++num_images;
|
||||||
has_depth = (subresource_range.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
|
has_depth = (subresource_range.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
|
||||||
has_stencil = (subresource_range.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
|
has_stencil = (subresource_range.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
|
||||||
@@ -2761,8 +2792,9 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
|||||||
|
|
||||||
discard_msaa_color =
|
discard_msaa_color =
|
||||||
ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_COLOR_DISCARD && do_resolve_color;
|
ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_COLOR_DISCARD && do_resolve_color;
|
||||||
|
discard_msaa_depth = ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_DEPTH_DISCARD &&
|
||||||
|
samples != VK_SAMPLE_COUNT_1_BIT && has_depth && runtime.device.IsTiler();
|
||||||
|
|
||||||
renderpass = runtime.render_pass_cache.Get(renderpass_key);
|
|
||||||
render_pass_key = renderpass_key;
|
render_pass_key = renderpass_key;
|
||||||
render_pass_cache = &runtime.render_pass_cache;
|
render_pass_cache = &runtime.render_pass_cache;
|
||||||
render_area.width = (std::min)(render_area.width, width);
|
render_area.width = (std::min)(render_area.width, width);
|
||||||
@@ -2777,10 +2809,15 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
|||||||
}
|
}
|
||||||
const VkFormat vk_format =
|
const VkFormat vk_format =
|
||||||
MaxwellToVK::SurfaceFormat(runtime.device, FormatType::Optimal, true, format).format;
|
MaxwellToVK::SurfaceFormat(runtime.device, FormatType::Optimal, true, format).format;
|
||||||
|
color_resolve_modes[index] = VideoCore::Surface::IsPixelFormatInteger(format)
|
||||||
|
? VK_RESOLVE_MODE_SAMPLE_ZERO_BIT
|
||||||
|
: VK_RESOLVE_MODE_AVERAGE_BIT;
|
||||||
if (ENABLE_MSAA_RESOLVE_CONSUME) {
|
if (ENABLE_MSAA_RESOLVE_CONSUME) {
|
||||||
const VkImage msaa_image = images[rt_map[index]];
|
const VkImage msaa_image = images[rt_map[index]];
|
||||||
attachments.push_back(runtime.GetOrCreateResolveShadow(msaa_image, vk_format,
|
const VkImageView shadow_view = runtime.GetOrCreateResolveShadow(
|
||||||
render_area, layers));
|
msaa_image, vk_format, render_area, layers);
|
||||||
|
color_resolve_attachments[index] = shadow_view;
|
||||||
|
attachments.push_back(shadow_view);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
VkImageCreateInfo resolve_ci{
|
VkImageCreateInfo resolve_ci{
|
||||||
@@ -2819,6 +2856,33 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
|||||||
.layerCount = layers,
|
.layerCount = layers,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
if (runtime.device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
runtime.scheduler.RecordWithUploadBuffer(
|
||||||
|
[image = *resolve_image, layers](vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) {
|
||||||
|
const VkImageMemoryBarrier barrier{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.srcAccessMask = 0,
|
||||||
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = image,
|
||||||
|
.subresourceRange{
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = layers,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
upload_cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
0, barrier);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
color_resolve_attachments[index] = *resolve_view;
|
||||||
attachments.push_back(*resolve_view);
|
attachments.push_back(*resolve_view);
|
||||||
resolve_images.push_back(std::move(resolve_image));
|
resolve_images.push_back(std::move(resolve_image));
|
||||||
resolve_image_views.push_back(std::move(resolve_view));
|
resolve_image_views.push_back(std::move(resolve_view));
|
||||||
@@ -2826,6 +2890,11 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
|||||||
}
|
}
|
||||||
|
|
||||||
num_color_buffers = static_cast<u32>(num_colors);
|
num_color_buffers = static_cast<u32>(num_colors);
|
||||||
|
layer_count = static_cast<u32>((std::max)(num_layers, 1));
|
||||||
|
if (runtime.device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renderpass = runtime.render_pass_cache.Get(renderpass_key);
|
||||||
framebuffer = runtime.device.GetLogical().CreateFramebuffer({
|
framebuffer = runtime.device.GetLogical().CreateFramebuffer({
|
||||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
@@ -2835,7 +2904,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
|||||||
.pAttachments = attachments.data(),
|
.pAttachments = attachments.data(),
|
||||||
.width = render_area.width,
|
.width = render_area.width,
|
||||||
.height = render_area.height,
|
.height = render_area.height,
|
||||||
.layers = static_cast<u32>((std::max)(num_layers, 1)),
|
.layers = layer_count,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2851,19 +2920,59 @@ VkRenderPass Framebuffer::RenderPassVariant(u32 color_clear_mask, bool depth_ste
|
|||||||
return render_pass_cache->Get(key);
|
return render_pass_cache->Get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Framebuffer::BeginRendering(vk::CommandBuffer cmdbuf) const {
|
||||||
|
std::array<VkRenderingAttachmentInfo, NUM_RT> color_attachment_infos{};
|
||||||
|
for (size_t index = 0; index < num_color_attachments; ++index) {
|
||||||
|
color_attachment_infos[index] = VkRenderingAttachmentInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.imageView = color_attachments[index],
|
||||||
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.resolveMode = VK_RESOLVE_MODE_NONE,
|
||||||
|
.resolveImageView = VK_NULL_HANDLE,
|
||||||
|
.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||||
|
.clearValue = {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const VkRenderingAttachmentInfo depth_attachment_info{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.imageView = depth_attachment,
|
||||||
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.resolveMode = VK_RESOLVE_MODE_NONE,
|
||||||
|
.resolveImageView = VK_NULL_HANDLE,
|
||||||
|
.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||||
|
.clearValue = {},
|
||||||
|
};
|
||||||
|
const VkRenderingInfo rendering_info{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.renderArea =
|
||||||
|
{
|
||||||
|
.offset = {.x = 0, .y = 0},
|
||||||
|
.extent = render_area,
|
||||||
|
},
|
||||||
|
.layerCount = layer_count,
|
||||||
|
.viewMask = 0,
|
||||||
|
.colorAttachmentCount = num_color_attachments,
|
||||||
|
.pColorAttachments = color_attachment_infos.data(),
|
||||||
|
.pDepthAttachment = has_depth ? &depth_attachment_info : nullptr,
|
||||||
|
.pStencilAttachment = has_stencil ? &depth_attachment_info : nullptr,
|
||||||
|
};
|
||||||
|
cmdbuf.BeginRendering(rendering_info);
|
||||||
|
}
|
||||||
|
|
||||||
void TextureCacheRuntime::AccelerateImageUpload(
|
void TextureCacheRuntime::AccelerateImageUpload(
|
||||||
Image& image, const StagingBufferRef& map,
|
Image& image, const StagingBufferRef& map,
|
||||||
std::span<const VideoCommon::SwizzleParameters> swizzles,
|
std::span<const VideoCommon::SwizzleParameters> swizzles,
|
||||||
u32 z_start, u32 z_count) {
|
u32 z_start, u32 z_count) {
|
||||||
|
|
||||||
if (IsPixelFormatASTC(image.info.format)) {
|
if (IsPixelFormatASTC(image.info.format)) {
|
||||||
if (astc_decoder_fragment_pass) {
|
|
||||||
const VideoCore::Surface::PixelFormat decoded_format =
|
|
||||||
WillUseWidenedAstcFormat(device, image.info)
|
|
||||||
? VideoCore::Surface::PixelFormat::R32G32B32A32_FLOAT
|
|
||||||
: VideoCore::Surface::PixelFormat::A8B8G8R8_UNORM;
|
|
||||||
return astc_decoder_fragment_pass->Assemble(image, map, swizzles, decoded_format);
|
|
||||||
}
|
|
||||||
return astc_decoder_pass->Assemble(image, map, swizzles);
|
return astc_decoder_pass->Assemble(image, map, swizzles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public:
|
|||||||
|
|
||||||
void AccelerateImageUpload(Image&, const StagingBufferRef&,
|
void AccelerateImageUpload(Image&, const StagingBufferRef&,
|
||||||
std::span<const VideoCommon::SwizzleParameters>,
|
std::span<const VideoCommon::SwizzleParameters>,
|
||||||
u32 z_start = 0, u32 z_count = 0);
|
u32 z_start, u32 z_count);
|
||||||
|
|
||||||
void InsertUploadMemoryBarrier() {}
|
void InsertUploadMemoryBarrier() {}
|
||||||
|
|
||||||
@@ -147,7 +147,6 @@ public:
|
|||||||
BlitImageHelper& blit_image_helper;
|
BlitImageHelper& blit_image_helper;
|
||||||
RenderPassCache& render_pass_cache;
|
RenderPassCache& render_pass_cache;
|
||||||
std::optional<ASTCDecoderPass> astc_decoder_pass;
|
std::optional<ASTCDecoderPass> astc_decoder_pass;
|
||||||
std::optional<ASTCDecoderFragmentPass> astc_decoder_fragment_pass;
|
|
||||||
|
|
||||||
std::optional<BlockLinearUnswizzle3DPass> bl3d_unswizzle_pass;
|
std::optional<BlockLinearUnswizzle3DPass> bl3d_unswizzle_pass;
|
||||||
const Settings::ResolutionScalingInfo& resolution;
|
const Settings::ResolutionScalingInfo& resolution;
|
||||||
@@ -179,6 +178,8 @@ public:
|
|||||||
std::span<ImageView*, NUM_RT> color_buffers, ImageView* depth_buffer,
|
std::span<ImageView*, NUM_RT> color_buffers, ImageView* depth_buffer,
|
||||||
bool is_rescaled = false);
|
bool is_rescaled = false);
|
||||||
|
|
||||||
|
void BeginRendering(vk::CommandBuffer cmdbuf) const;
|
||||||
|
|
||||||
[[nodiscard]] VkFramebuffer Handle() const noexcept {
|
[[nodiscard]] VkFramebuffer Handle() const noexcept {
|
||||||
return *framebuffer;
|
return *framebuffer;
|
||||||
}
|
}
|
||||||
@@ -194,6 +195,39 @@ public:
|
|||||||
[[nodiscard]] VkRenderPass RenderPassVariant(u32 color_clear_mask, bool depth_stencil_clear,
|
[[nodiscard]] VkRenderPass RenderPassVariant(u32 color_clear_mask, bool depth_stencil_clear,
|
||||||
u32 color_discard_mask) const;
|
u32 color_discard_mask) const;
|
||||||
|
|
||||||
|
[[nodiscard]] u32 NumColorAttachments() const noexcept {
|
||||||
|
return num_color_attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::array<VkImageView, NUM_RT>& ColorAttachments() const noexcept {
|
||||||
|
return color_attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::array<VkFormat, NUM_RT>& ColorAttachmentFormats() const noexcept {
|
||||||
|
return color_attachment_formats;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::array<VkImageView, NUM_RT>& ColorResolveAttachments() const noexcept {
|
||||||
|
return color_resolve_attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::array<VkResolveModeFlagBits, NUM_RT>& ColorResolveModes()
|
||||||
|
const noexcept {
|
||||||
|
return color_resolve_modes;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] VkImageView DepthAttachment() const noexcept {
|
||||||
|
return depth_attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] VkFormat DepthAttachmentFormat() const noexcept {
|
||||||
|
return depth_attachment_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] u32 NumLayers() const noexcept {
|
||||||
|
return layer_count;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] VkExtent2D RenderArea() const noexcept {
|
[[nodiscard]] VkExtent2D RenderArea() const noexcept {
|
||||||
return render_area;
|
return render_area;
|
||||||
}
|
}
|
||||||
@@ -246,6 +280,10 @@ public:
|
|||||||
return discard_msaa_color;
|
return discard_msaa_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool DiscardsMsaaDepth() const noexcept {
|
||||||
|
return discard_msaa_depth;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vk::Framebuffer framebuffer;
|
vk::Framebuffer framebuffer;
|
||||||
VkRenderPass renderpass{};
|
VkRenderPass renderpass{};
|
||||||
@@ -256,6 +294,14 @@ private:
|
|||||||
std::array<VkImage, 9> images{};
|
std::array<VkImage, 9> images{};
|
||||||
std::array<VkImageSubresourceRange, 9> image_ranges{};
|
std::array<VkImageSubresourceRange, 9> image_ranges{};
|
||||||
std::array<size_t, NUM_RT> rt_map{};
|
std::array<size_t, NUM_RT> rt_map{};
|
||||||
|
std::array<VkImageView, NUM_RT> color_attachments{};
|
||||||
|
std::array<VkFormat, NUM_RT> color_attachment_formats{};
|
||||||
|
std::array<VkImageView, NUM_RT> color_resolve_attachments{};
|
||||||
|
std::array<VkResolveModeFlagBits, NUM_RT> color_resolve_modes{};
|
||||||
|
VkImageView depth_attachment{};
|
||||||
|
VkFormat depth_attachment_format = VK_FORMAT_UNDEFINED;
|
||||||
|
u32 num_color_attachments = 0;
|
||||||
|
u32 layer_count = 1;
|
||||||
bool has_depth{};
|
bool has_depth{};
|
||||||
bool has_stencil{};
|
bool has_stencil{};
|
||||||
bool is_rescaled{};
|
bool is_rescaled{};
|
||||||
@@ -264,6 +310,7 @@ private:
|
|||||||
RenderPassKey render_pass_key{};
|
RenderPassKey render_pass_key{};
|
||||||
RenderPassCache* render_pass_cache{nullptr};
|
RenderPassCache* render_pass_cache{nullptr};
|
||||||
bool discard_msaa_color{};
|
bool discard_msaa_color{};
|
||||||
|
bool discard_msaa_depth{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Image : public VideoCommon::ImageBase {
|
class Image : public VideoCommon::ImageBase {
|
||||||
|
|||||||
@@ -517,22 +517,16 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||||||
VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME);
|
VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME);
|
||||||
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken shader float controls.");
|
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken shader float controls.");
|
||||||
RemoveExtension(extensions.shader_float_controls, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
|
RemoveExtension(extensions.shader_float_controls, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
|
||||||
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken workgroup memory explicit layout.");
|
|
||||||
RemoveExtensionFeature(extensions.workgroup_memory_explicit_layout,
|
|
||||||
features.workgroup_memory_explicit_layout,
|
|
||||||
VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME);
|
|
||||||
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken conservative rasterization.");
|
|
||||||
RemoveExtension(extensions.conservative_rasterization,
|
|
||||||
VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME);
|
|
||||||
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken depth clip control.");
|
|
||||||
RemoveExtensionFeature(extensions.depth_clip_control, features.depth_clip_control,
|
|
||||||
VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
|
|
||||||
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken shader atomic int64.");
|
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken shader atomic int64.");
|
||||||
RemoveExtensionFeature(extensions.shader_atomic_int64, features.shader_atomic_int64,
|
RemoveExtensionFeature(extensions.shader_atomic_int64, features.shader_atomic_int64,
|
||||||
VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
|
VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
|
||||||
features.shader_atomic_int64.shaderBufferInt64Atomics = false;
|
features.shader_atomic_int64.shaderBufferInt64Atomics = false;
|
||||||
features.shader_atomic_int64.shaderSharedInt64Atomics = false;
|
features.shader_atomic_int64.shaderSharedInt64Atomics = false;
|
||||||
features.features.shaderInt64 = false;
|
features.features.shaderInt64 = false;
|
||||||
|
LOG_WARNING(Render_Vulkan, "Qualcomm drivers have broken workgroup memory explicit layout.");
|
||||||
|
RemoveExtensionFeature(extensions.workgroup_memory_explicit_layout,
|
||||||
|
features.workgroup_memory_explicit_layout,
|
||||||
|
VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
#if defined(__ANDROID__) && defined(ARCHITECTURE_arm64)
|
#if defined(__ANDROID__) && defined(ARCHITECTURE_arm64)
|
||||||
// BCn patching only safe on Android 9+ (API 28+). Older versions crash on driver load.
|
// BCn patching only safe on Android 9+ (API 28+). Older versions crash on driver load.
|
||||||
@@ -1379,6 +1373,11 @@ void Device::RemoveUnsuitableExtensions() {
|
|||||||
extensions.maintenance3 = loaded_extensions.contains(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
|
extensions.maintenance3 = loaded_extensions.contains(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
|
||||||
RemoveExtensionIfUnsuitable(extensions.maintenance3, VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
|
RemoveExtensionIfUnsuitable(extensions.maintenance3, VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_KHR_dynamic_rendering
|
||||||
|
extensions.dynamic_rendering = features.dynamic_rendering.dynamicRendering;
|
||||||
|
RemoveExtensionFeatureIfUnsuitable(extensions.dynamic_rendering, features.dynamic_rendering,
|
||||||
|
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
|
||||||
|
|
||||||
// VK_KHR_maintenance4
|
// VK_KHR_maintenance4
|
||||||
extensions.maintenance4 = features.maintenance4.maintenance4;
|
extensions.maintenance4 = features.maintenance4.maintenance4;
|
||||||
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance4, features.maintenance4,
|
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance4, features.maintenance4,
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
|||||||
FEATURE(EXT, ShaderDemoteToHelperInvocation, SHADER_DEMOTE_TO_HELPER_INVOCATION, \
|
FEATURE(EXT, ShaderDemoteToHelperInvocation, SHADER_DEMOTE_TO_HELPER_INVOCATION, \
|
||||||
shader_demote_to_helper_invocation) \
|
shader_demote_to_helper_invocation) \
|
||||||
FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control) \
|
FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control) \
|
||||||
|
FEATURE(KHR, DynamicRendering, DYNAMIC_RENDERING, dynamic_rendering) \
|
||||||
FEATURE(KHR, Maintenance4, MAINTENANCE_4, maintenance4) \
|
FEATURE(KHR, Maintenance4, MAINTENANCE_4, maintenance4) \
|
||||||
FEATURE(KHR, Synchronization2, SYNCHRONIZATION_2, synchronization2)
|
FEATURE(KHR, Synchronization2, SYNCHRONIZATION_2, synchronization2)
|
||||||
|
|
||||||
@@ -941,6 +942,13 @@ FN_MAX_LIMIT_LIST
|
|||||||
return extensions.maintenance3;
|
return extensions.maintenance3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr bool ENABLE_DYNAMIC_RENDERING = false;
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_KHR_dynamic_rendering.
|
||||||
|
bool IsKhrDynamicRenderingSupported() const {
|
||||||
|
return ENABLE_DYNAMIC_RENDERING && extensions.dynamic_rendering;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports VK_KHR_maintenance4.
|
/// Returns true if the device supports VK_KHR_maintenance4.
|
||||||
bool IsKhrMaintenance4Supported() const {
|
bool IsKhrMaintenance4Supported() const {
|
||||||
return extensions.maintenance4;
|
return extensions.maintenance4;
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
|||||||
X(vkCmdBeginConditionalRenderingEXT);
|
X(vkCmdBeginConditionalRenderingEXT);
|
||||||
X(vkCmdBeginQuery);
|
X(vkCmdBeginQuery);
|
||||||
X(vkCmdBeginRenderPass);
|
X(vkCmdBeginRenderPass);
|
||||||
|
X(vkCmdBeginRendering);
|
||||||
X(vkCmdBeginTransformFeedbackEXT);
|
X(vkCmdBeginTransformFeedbackEXT);
|
||||||
X(vkCmdBeginDebugUtilsLabelEXT);
|
X(vkCmdBeginDebugUtilsLabelEXT);
|
||||||
X(vkCmdBindDescriptorSets);
|
X(vkCmdBindDescriptorSets);
|
||||||
@@ -119,6 +120,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
|||||||
X(vkCmdEndConditionalRenderingEXT);
|
X(vkCmdEndConditionalRenderingEXT);
|
||||||
X(vkCmdEndQuery);
|
X(vkCmdEndQuery);
|
||||||
X(vkCmdEndRenderPass);
|
X(vkCmdEndRenderPass);
|
||||||
|
X(vkCmdEndRendering);
|
||||||
X(vkCmdEndTransformFeedbackEXT);
|
X(vkCmdEndTransformFeedbackEXT);
|
||||||
X(vkCmdEndDebugUtilsLabelEXT);
|
X(vkCmdEndDebugUtilsLabelEXT);
|
||||||
X(vkCmdFillBuffer);
|
X(vkCmdFillBuffer);
|
||||||
@@ -258,6 +260,12 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
|||||||
Proc(dld.vkCmdDrawIndexedIndirectCount, dld, "vkCmdDrawIndexedIndirectCountKHR", device);
|
Proc(dld.vkCmdDrawIndexedIndirectCount, dld, "vkCmdDrawIndexedIndirectCountKHR", device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Support for dynamic rendering is optional until Vulkan 1.3
|
||||||
|
if (!dld.vkCmdBeginRendering) {
|
||||||
|
Proc(dld.vkCmdBeginRendering, dld, "vkCmdBeginRenderingKHR", device);
|
||||||
|
Proc(dld.vkCmdEndRendering, dld, "vkCmdEndRenderingKHR", device);
|
||||||
|
}
|
||||||
|
|
||||||
// Synchronization2 is core in Vulkan 1.3, otherwise requires VK_KHR_synchronization2
|
// Synchronization2 is core in Vulkan 1.3, otherwise requires VK_KHR_synchronization2
|
||||||
if (!dld.vkCmdPipelineBarrier2) {
|
if (!dld.vkCmdPipelineBarrier2) {
|
||||||
Proc(dld.vkCmdPipelineBarrier2, dld, "vkCmdPipelineBarrier2KHR", device);
|
Proc(dld.vkCmdPipelineBarrier2, dld, "vkCmdPipelineBarrier2KHR", device);
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ struct DeviceDispatch : InstanceDispatch {
|
|||||||
PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT{};
|
PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT{};
|
||||||
PFN_vkCmdBeginQuery vkCmdBeginQuery{};
|
PFN_vkCmdBeginQuery vkCmdBeginQuery{};
|
||||||
PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass{};
|
PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass{};
|
||||||
|
PFN_vkCmdBeginRendering vkCmdBeginRendering{};
|
||||||
PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT{};
|
PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT{};
|
||||||
PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets{};
|
PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets{};
|
||||||
PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer{};
|
PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer{};
|
||||||
@@ -236,6 +237,7 @@ struct DeviceDispatch : InstanceDispatch {
|
|||||||
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{};
|
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{};
|
||||||
PFN_vkCmdEndQuery vkCmdEndQuery{};
|
PFN_vkCmdEndQuery vkCmdEndQuery{};
|
||||||
PFN_vkCmdEndRenderPass vkCmdEndRenderPass{};
|
PFN_vkCmdEndRenderPass vkCmdEndRenderPass{};
|
||||||
|
PFN_vkCmdEndRendering vkCmdEndRendering{};
|
||||||
PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT{};
|
PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT{};
|
||||||
PFN_vkCmdFillBuffer vkCmdFillBuffer{};
|
PFN_vkCmdFillBuffer vkCmdFillBuffer{};
|
||||||
PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier{};
|
PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier{};
|
||||||
@@ -1191,6 +1193,14 @@ public:
|
|||||||
dld->vkCmdEndRenderPass(handle);
|
dld->vkCmdEndRenderPass(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BeginRendering(const VkRenderingInfo& rendering_info) const noexcept {
|
||||||
|
dld->vkCmdBeginRendering(handle, &rendering_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndRendering() const noexcept {
|
||||||
|
dld->vkCmdEndRendering(handle);
|
||||||
|
}
|
||||||
|
|
||||||
void BeginQuery(VkQueryPool query_pool, u32 query, VkQueryControlFlags flags) const noexcept {
|
void BeginQuery(VkQueryPool query_pool, u32 query, VkQueryControlFlags flags) const noexcept {
|
||||||
dld->vkCmdBeginQuery(handle, query_pool, query, flags);
|
dld->vkCmdBeginQuery(handle, query_pool, query, flags);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user