code: Run clang-format

This commit is contained in:
GPUCode
2022-10-07 12:13:27 +03:00
parent 6f3fc32a93
commit 915406354c
82 changed files with 1683 additions and 1950 deletions

View File

@ -8,7 +8,6 @@
#include <string> #include <string>
#include <thread> #include <thread>
// This needs to be included before getopt.h because the latter #defines symbols used by it // This needs to be included before getopt.h because the latter #defines symbols used by it
#include "common/microprofile.h"
#include "citra/config.h" #include "citra/config.h"
#include "citra/emu_window/emu_window_sdl2.h" #include "citra/emu_window/emu_window_sdl2.h"
#include "citra/lodepng_image_interface.h" #include "citra/lodepng_image_interface.h"
@ -17,6 +16,7 @@
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/backend.h" #include "common/logging/backend.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "core/core.h" #include "core/core.h"

View File

@ -98,11 +98,10 @@ void ConfigureCamera::ConnectEvents() {
} }
}); });
connect(ui->camera_file, &QLineEdit::textChanged, this, [this] { StopPreviewing(); }); connect(ui->camera_file, &QLineEdit::textChanged, this, [this] { StopPreviewing(); });
connect(ui->system_camera, connect(ui->system_camera, qOverload<int>(&QComboBox::currentIndexChanged), this,
qOverload<int>(&QComboBox::currentIndexChanged), this, [this] { StopPreviewing(); });
connect(ui->camera_flip, qOverload<int>(&QComboBox::currentIndexChanged), this,
[this] { StopPreviewing(); }); [this] { StopPreviewing(); });
connect(ui->camera_flip, qOverload<int>(&QComboBox::currentIndexChanged),
this, [this] { StopPreviewing(); });
} }
void ConfigureCamera::UpdateCameraMode() { void ConfigureCamera::UpdateCameraMode() {

View File

@ -92,7 +92,8 @@ void ConfigureGraphics::ApplyConfiguration() {
Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked(); Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked();
Settings::values.use_disk_shader_cache = ui->toggle_disk_shader_cache->isChecked(); Settings::values.use_disk_shader_cache = ui->toggle_disk_shader_cache->isChecked();
Settings::values.use_vsync_new = ui->toggle_vsync_new->isChecked(); Settings::values.use_vsync_new = ui->toggle_vsync_new->isChecked();
Settings::values.graphics_api = static_cast<Settings::GraphicsAPI>(ui->graphics_api_combo->currentIndex()); Settings::values.graphics_api =
static_cast<Settings::GraphicsAPI>(ui->graphics_api_combo->currentIndex());
Settings::values.physical_device = static_cast<u16>(ui->physical_device_combo->currentIndex()); Settings::values.physical_device = static_cast<u16>(ui->physical_device_combo->currentIndex());
} }

View File

@ -230,7 +230,8 @@ ConfigureInput::ConfigureInput(QWidget* parent)
continue; continue;
analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy( analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
Qt::CustomContextMenu); Qt::CustomContextMenu);
connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, this, [this, analog_id, sub_button_id]() { connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, this,
[this, analog_id, sub_button_id]() {
HandleClick( HandleClick(
analog_map_buttons[analog_id][sub_button_id], analog_map_buttons[analog_id][sub_button_id],
[this, analog_id, sub_button_id](const Common::ParamPackage& params) { [this, analog_id, sub_button_id](const Common::ParamPackage& params) {
@ -242,7 +243,8 @@ ConfigureInput::ConfigureInput(QWidget* parent)
InputCommon::Polling::DeviceType::Button); InputCommon::Polling::DeviceType::Button);
}); });
connect(analog_map_buttons[analog_id][sub_button_id], connect(analog_map_buttons[analog_id][sub_button_id],
&QPushButton::customContextMenuRequested, this, [this, analog_id, sub_button_id](const QPoint& menu_location) { &QPushButton::customContextMenuRequested, this,
[this, analog_id, sub_button_id](const QPoint& menu_location) {
QMenu context_menu; QMenu context_menu;
context_menu.addAction(tr("Clear"), this, [&] { context_menu.addAction(tr("Clear"), this, [&] {
analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
@ -280,8 +282,10 @@ ConfigureInput::ConfigureInput(QWidget* parent)
InputCommon::Polling::DeviceType::Analog); InputCommon::Polling::DeviceType::Analog);
} }
}); });
connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, this, [this, analog_id] { connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, this,
const int slider_value = analog_map_deadzone_and_modifier_slider[analog_id]->value(); [this, analog_id] {
const int slider_value =
analog_map_deadzone_and_modifier_slider[analog_id]->value();
const auto engine = analogs_param[analog_id].Get("engine", ""); const auto engine = analogs_param[analog_id].Get("engine", "");
if (engine == "sdl" || engine == "gcpad") { if (engine == "sdl" || engine == "gcpad") {
analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
@ -356,8 +360,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureInput::DeleteProfile); connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureInput::DeleteProfile);
connect(ui->buttonRename, &QPushButton::clicked, this, &ConfigureInput::RenameProfile); connect(ui->buttonRename, &QPushButton::clicked, this, &ConfigureInput::RenameProfile);
connect(ui->profile, qOverload<int>(&QComboBox::currentIndexChanged), this, connect(ui->profile, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int i) {
[this](int i) {
ApplyConfiguration(); ApplyConfiguration();
Settings::SaveProfile(Settings::values.current_input_profile_index); Settings::SaveProfile(Settings::values.current_input_profile_index);
Settings::LoadProfile(i); Settings::LoadProfile(i);

View File

@ -316,56 +316,46 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
case Format::RGBA8: { case Format::RGBA8: {
auto value = Color::DecodeRGBA8(pixel) / 255.0f; auto value = Color::DecodeRGBA8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2), .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.g(), 'f', 2), QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
QString::number(value.b(), 'f', 2),
QString::number(value.a(), 'f', 2));
} }
case Format::RGB8: { case Format::RGB8: {
auto value = Color::DecodeRGB8(pixel) / 255.0f; auto value = Color::DecodeRGB8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3") return QStringLiteral("Red: %1, Green: %2, Blue: %3")
.arg(QString::number(value.r(), 'f', 2), .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.g(), 'f', 2),
QString::number(value.b(), 'f', 2)); QString::number(value.b(), 'f', 2));
} }
case Format::RGB5A1: { case Format::RGB5A1: {
auto value = Color::DecodeRGB5A1(pixel) / 255.0f; auto value = Color::DecodeRGB5A1(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2), .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.g(), 'f', 2), QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
QString::number(value.b(), 'f', 2),
QString::number(value.a(), 'f', 2));
} }
case Format::RGB565: { case Format::RGB565: {
auto value = Color::DecodeRGB565(pixel) / 255.0f; auto value = Color::DecodeRGB565(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3") return QStringLiteral("Red: %1, Green: %2, Blue: %3")
.arg(QString::number(value.r(), 'f', 2), .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.g(), 'f', 2),
QString::number(value.b(), 'f', 2)); QString::number(value.b(), 'f', 2));
} }
case Format::RGBA4: { case Format::RGBA4: {
auto value = Color::DecodeRGBA4(pixel) / 255.0f; auto value = Color::DecodeRGBA4(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2), .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.g(), 'f', 2), QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
QString::number(value.b(), 'f', 2),
QString::number(value.a(), 'f', 2));
} }
case Format::IA8: case Format::IA8:
return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0], pixel[1]); return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0], pixel[1]);
case Format::RG8: { case Format::RG8: {
auto value = Color::DecodeRG8(pixel) / 255.0f; auto value = Color::DecodeRG8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2") return QStringLiteral("Red: %1, Green: %2")
.arg(QString::number(value.r(), 'f', 2), .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2));
QString::number(value.g(), 'f', 2));
} }
case Format::I8: case Format::I8:
return QStringLiteral("Index: %1").arg(*pixel); return QStringLiteral("Index: %1").arg(*pixel);
case Format::A8: case Format::A8:
return QStringLiteral("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2)); return QStringLiteral("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2));
case Format::IA4: case Format::IA4:
return QStringLiteral("Index: %1, Alpha: %2") return QStringLiteral("Index: %1, Alpha: %2").arg(*pixel & 0xF, (*pixel & 0xF0) >> 4);
.arg(*pixel & 0xF, (*pixel & 0xF0) >> 4);
case Format::I4: { case Format::I4: {
u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF; u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
return QStringLiteral("Index: %1").arg(i); return QStringLiteral("Index: %1").arg(i);

View File

@ -407,7 +407,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map)); static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
input_data_mapper->setMapping(input_data[i], i); input_data_mapper->setMapping(input_data[i], i);
} }
connect(input_data_mapper, &QSignalMapper::mappedInt, this, &GraphicsVertexShaderWidget::OnInputAttributeChanged); connect(input_data_mapper, &QSignalMapper::mappedInt, this,
&GraphicsVertexShaderWidget::OnInputAttributeChanged);
auto main_widget = new QWidget; auto main_widget = new QWidget;
auto main_layout = new QVBoxLayout; auto main_layout = new QVBoxLayout;

View File

@ -160,7 +160,8 @@ void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* event) {
} }
void MicroProfileWidget::wheelEvent(QWheelEvent* event) { void MicroProfileWidget::wheelEvent(QWheelEvent* event) {
MicroProfileMousePosition(event->position().x() / x_scale, event->position().y() / y_scale, event->angleDelta().y() / 120); MicroProfileMousePosition(event->position().x() / x_scale, event->position().y() / y_scale,
event->angleDelta().y() / 120);
event->accept(); event->accept();
} }

View File

@ -169,8 +169,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
* @return true if the haystack contains all words of userinput * @return true if the haystack contains all words of userinput
*/ */
static bool ContainsAllWords(const QString& haystack, const QString& userinput) { static bool ContainsAllWords(const QString& haystack, const QString& userinput) {
const QStringList userinput_split = const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts);
userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts);
return std::all_of(userinput_split.begin(), userinput_split.end(), return std::all_of(userinput_split.begin(), userinput_split.end(),
[&haystack](const QString& s) { return haystack.contains(s); }); [&haystack](const QString& s) { return haystack.contains(s); });

View File

@ -146,7 +146,9 @@ static void InitializeLogging() {
#endif #endif
} }
GMainWindow::GMainWindow() : ui{std::make_unique<Ui::MainWindow>()}, config{std::make_unique<Config>()}, emu_thread{nullptr} { GMainWindow::GMainWindow()
: ui{std::make_unique<Ui::MainWindow>()}, config{std::make_unique<Config>()}, emu_thread{
nullptr} {
InitializeLogging(); InitializeLogging();
Debugger::ToggleConsole(); Debugger::ToggleConsole();
Settings::LogSettings(); Settings::LogSettings();
@ -2112,27 +2114,20 @@ void GMainWindow::ShowMouseCursor() {
} }
void GMainWindow::UpdateAPIIndicator(bool override) { void GMainWindow::UpdateAPIIndicator(bool override) {
static std::array graphics_apis = { static std::array graphics_apis = {QStringLiteral("OPENGL"), QStringLiteral("OPENGLES"),
QStringLiteral("OPENGL"), QStringLiteral("VULKAN")};
QStringLiteral("OPENGLES"),
QStringLiteral("VULKAN")
};
static std::array graphics_api_colors = { static std::array graphics_api_colors = {QStringLiteral("#00ccdd"), QStringLiteral("#ba2a8d"),
QStringLiteral("#00ccdd"), QStringLiteral("#91242a")};
QStringLiteral("#ba2a8d"),
QStringLiteral("#91242a")
};
u32 api_index = static_cast<u32>(Settings::values.graphics_api); u32 api_index = static_cast<u32>(Settings::values.graphics_api);
if (override) { if (override) {
api_index = (api_index + 1) % graphics_apis.size(); api_index = (api_index + 1) % graphics_apis.size();
Settings::values.graphics_api = Settings::values.graphics_api = static_cast<Settings::GraphicsAPI>(api_index);
static_cast<Settings::GraphicsAPI>(api_index);
} }
const QString style_sheet = const QString style_sheet = QStringLiteral("QPushButton { font-weight: bold; color: %0; }")
QStringLiteral("QPushButton { font-weight: bold; color: %0; }").arg(graphics_api_colors[api_index]); .arg(graphics_api_colors[api_index]);
graphics_api_button->setText(graphics_apis[api_index]); graphics_api_button->setText(graphics_apis[api_index]);
graphics_api_button->setStyleSheet(style_sheet); graphics_api_button->setStyleSheet(style_sheet);

View File

@ -7,9 +7,9 @@
#include <array> #include <array>
#include <memory> #include <memory>
#include <QMainWindow> #include <QMainWindow>
#include <QPushButton>
#include <QTimer> #include <QTimer>
#include <QTranslator> #include <QTranslator>
#include <QPushButton>
#include "citra_qt/compatibility_list.h" #include "citra_qt/compatibility_list.h"
#include "citra_qt/hotkeys.h" #include "citra_qt/hotkeys.h"
#include "common/announce_multiplayer_room.h" #include "common/announce_multiplayer_room.h"

View File

@ -4,9 +4,9 @@
#pragma once #pragma once
#include <concepts>
#include <cstddef> #include <cstddef>
#include <cstring> #include <cstring>
#include <concepts>
#include "common/cityhash.h" #include "common/cityhash.h"
#include "common/common_types.h" #include "common/common_types.h"

View File

@ -4,8 +4,8 @@
#pragma once #pragma once
#include <fmt/format.h>
#include <type_traits> #include <type_traits>
#include <fmt/format.h>
// adapted from https://github.com/fmtlib/fmt/issues/2704 // adapted from https://github.com/fmtlib/fmt/issues/2704
// a generic formatter for enum classes // a generic formatter for enum classes

View File

@ -4,8 +4,8 @@
#pragma once #pragma once
#include <cstdlib>
#include <compare> #include <compare>
#include <cstdlib>
#include <type_traits> #include <type_traits>
namespace Common { namespace Common {

View File

@ -3,8 +3,8 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <span>
#include <memory> #include <memory>
#include <span>
#include <vector> #include <vector>
#include <boost/serialization/export.hpp> #include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp> #include <boost/serialization/shared_ptr.hpp>

View File

@ -140,8 +140,8 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
VAddr page_start = Common::AlignDown(source_address, Memory::CITRA_PAGE_SIZE); VAddr page_start = Common::AlignDown(source_address, Memory::CITRA_PAGE_SIZE);
u32 page_offset = source_address - page_start; u32 page_offset = source_address - page_start;
u32 num_pages = u32 num_pages = Common::AlignUp(page_offset + size, Memory::CITRA_PAGE_SIZE) >>
Common::AlignUp(page_offset + size, Memory::CITRA_PAGE_SIZE) >> Memory::CITRA_PAGE_BITS; Memory::CITRA_PAGE_BITS;
// Skip when the size is zero and num_pages == 0 // Skip when the size is zero and num_pages == 0
if (size == 0) { if (size == 0) {
@ -180,8 +180,9 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
next_vma.meminfo_state == MemoryState::Reserved); next_vma.meminfo_state == MemoryState::Reserved);
// Unmap the buffer and guard pages from the source process // Unmap the buffer and guard pages from the source process
ResultCode result = src_process->vm_manager.UnmapRange( ResultCode result =
page_start - Memory::CITRA_PAGE_SIZE, (num_pages + 2) * Memory::CITRA_PAGE_SIZE); src_process->vm_manager.UnmapRange(page_start - Memory::CITRA_PAGE_SIZE,
(num_pages + 2) * Memory::CITRA_PAGE_SIZE);
ASSERT(result == RESULT_SUCCESS); ASSERT(result == RESULT_SUCCESS);
mapped_buffer_context.erase(found); mapped_buffer_context.erase(found);

View File

@ -26,47 +26,66 @@ struct AppletTitleData {
static constexpr std::size_t NumApplets = 29; static constexpr std::size_t NumApplets = 29;
static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{ static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{
{{AppletId::HomeMenu, AppletId::None}, {0x4003000008202, 0x4003000008F02, 0x4003000009802, {{AppletId::HomeMenu, AppletId::None},
0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102}}, {0x4003000008202, 0x4003000008F02, 0x4003000009802, 0x4003000008202, 0x400300000A102,
{{AppletId::AlternateMenu, AppletId::None}, {0x4003000008102, 0x4003000008102, 0x4003000008102, 0x400300000A902, 0x400300000B102}},
0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102}}, {{AppletId::AlternateMenu, AppletId::None},
{{AppletId::Camera, AppletId::None}, {0x4003000008402, 0x4003000009002, 0x4003000009902, {0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102,
0x4003000008402, 0x400300000A202, 0x400300000AA02, 0x400300000B202}}, 0x4003000008102, 0x4003000008102}},
{{AppletId::FriendList, AppletId::None}, {0x4003000008D02, 0x4003000009602, 0x4003000009F02, {{AppletId::Camera, AppletId::None},
0x4003000008D02, 0x400300000A702, 0x400300000AF02, 0x400300000B702}}, {0x4003000008402, 0x4003000009002, 0x4003000009902, 0x4003000008402, 0x400300000A202,
{{AppletId::GameNotes, AppletId::None}, {0x4003000008702, 0x4003000009302, 0x4003000009C02, 0x400300000AA02, 0x400300000B202}},
0x4003000008702, 0x400300000A502, 0x400300000AD02, 0x400300000B502}}, {{AppletId::FriendList, AppletId::None},
{{AppletId::InternetBrowser, AppletId::None}, {0x4003000008802, 0x4003000009402, 0x4003000009D02, {0x4003000008D02, 0x4003000009602, 0x4003000009F02, 0x4003000008D02, 0x400300000A702,
0x4003000008802, 0x400300000A602, 0x400300000AE02, 0x400300000B602}}, 0x400300000AF02, 0x400300000B702}},
{{AppletId::InstructionManual, AppletId::None}, {0x4003000008602, 0x4003000009202, 0x4003000009B02, {{AppletId::GameNotes, AppletId::None},
0x4003000008602, 0x400300000A402, 0x400300000AC02, 0x400300000B402}}, {0x4003000008702, 0x4003000009302, 0x4003000009C02, 0x4003000008702, 0x400300000A502,
{{AppletId::Notifications, AppletId::None}, {0x4003000008E02, 0x4003000009702, 0x400300000A002, 0x400300000AD02, 0x400300000B502}},
0x4003000008E02, 0x400300000A802, 0x400300000B002, 0x400300000B802}}, {{AppletId::InternetBrowser, AppletId::None},
{{AppletId::Miiverse, AppletId::None}, {0x400300000BC02, 0x400300000BD02, 0x400300000BE02, {0x4003000008802, 0x4003000009402, 0x4003000009D02, 0x4003000008802, 0x400300000A602,
0x400300000BC02, 0x4003000009E02, 0x4003000009502, 0x400300000B902}}, 0x400300000AE02, 0x400300000B602}},
{{AppletId::InstructionManual, AppletId::None},
{0x4003000008602, 0x4003000009202, 0x4003000009B02, 0x4003000008602, 0x400300000A402,
0x400300000AC02, 0x400300000B402}},
{{AppletId::Notifications, AppletId::None},
{0x4003000008E02, 0x4003000009702, 0x400300000A002, 0x4003000008E02, 0x400300000A802,
0x400300000B002, 0x400300000B802}},
{{AppletId::Miiverse, AppletId::None},
{0x400300000BC02, 0x400300000BD02, 0x400300000BE02, 0x400300000BC02, 0x4003000009E02,
0x4003000009502, 0x400300000B902}},
// These values obtained from an older NS dump firmware 4.5 // These values obtained from an older NS dump firmware 4.5
{{AppletId::MiiversePost, AppletId::None}, {0x400300000BA02, 0x400300000BA02, 0x400300000BA02, {{AppletId::MiiversePost, AppletId::None},
0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02}}, {0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02,
0x400300000BA02, 0x400300000BA02}},
// {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02, // {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02,
// 0x4003000008302, 0x0, 0x0, 0x0}, // 0x4003000008302, 0x0, 0x0, 0x0},
{{AppletId::AmiiboSettings, AppletId::None}, {0x4003000009502, 0x4003000009E02, 0x400300000B902, {{AppletId::AmiiboSettings, AppletId::None},
0x4003000009502, 0x0, 0x4003000008C02, 0x400300000BF02}}, {0x4003000009502, 0x4003000009E02, 0x400300000B902, 0x4003000009502, 0x0, 0x4003000008C02,
{{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2}, {0x400300000C002, 0x400300000C802, 0x400300000BF02}},
0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402}}, {{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2},
{{AppletId::Ed1, AppletId::Ed2}, {0x400300000C102, 0x400300000C902, 0x400300000D102, {0x400300000C002, 0x400300000C802, 0x400300000D002, 0x400300000C002, 0x400300000D802,
0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502}}, 0x400300000DE02, 0x400300000E402}},
{{AppletId::PnoteApp, AppletId::PnoteApp2}, {0x400300000C302, 0x400300000CB02, 0x400300000D302, {{AppletId::Ed1, AppletId::Ed2},
0x400300000C302, 0x400300000DB02, 0x400300000E102, 0x400300000E702}}, {0x400300000C102, 0x400300000C902, 0x400300000D102, 0x400300000C102, 0x400300000D902,
{{AppletId::SnoteApp, AppletId::SnoteApp2}, {0x400300000C402, 0x400300000CC02, 0x400300000D402, 0x400300000DF02, 0x400300000E502}},
0x400300000C402, 0x400300000DC02, 0x400300000E202, 0x400300000E802}}, {{AppletId::PnoteApp, AppletId::PnoteApp2},
{{AppletId::Error, AppletId::Error2}, {0x400300000C502, 0x400300000C502, 0x400300000C502, {0x400300000C302, 0x400300000CB02, 0x400300000D302, 0x400300000C302, 0x400300000DB02,
0x400300000C502, 0x400300000CF02, 0x400300000CF02, 0x400300000CF02}}, 0x400300000E102, 0x400300000E702}},
{{AppletId::Mint, AppletId::Mint2}, {0x400300000C602, 0x400300000CE02, 0x400300000D602, {{AppletId::SnoteApp, AppletId::SnoteApp2},
0x400300000C602, 0x400300000DD02, 0x400300000E302, 0x400300000E902}}, {0x400300000C402, 0x400300000CC02, 0x400300000D402, 0x400300000C402, 0x400300000DC02,
{{AppletId::Extrapad, AppletId::Extrapad2}, {0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000E202, 0x400300000E802}},
0x400300000CD02, 0x400300000D502, 0x400300000D502, 0x400300000D502}}, {{AppletId::Error, AppletId::Error2},
{{AppletId::Memolib, AppletId::Memolib2}, {0x400300000F602, 0x400300000F602, 0x400300000F602, {0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000CF02,
0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602}}, 0x400300000CF02, 0x400300000CF02}},
{{AppletId::Mint, AppletId::Mint2},
{0x400300000C602, 0x400300000CE02, 0x400300000D602, 0x400300000C602, 0x400300000DD02,
0x400300000E302, 0x400300000E902}},
{{AppletId::Extrapad, AppletId::Extrapad2},
{0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000D502,
0x400300000D502, 0x400300000D502}},
{{AppletId::Memolib, AppletId::Memolib2},
{0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602,
0x400300000F602, 0x400300000F602}},
// TODO(Subv): Fill in the rest of the titleids // TODO(Subv): Fill in the rest of the titleids
}}; }};

View File

@ -111,7 +111,8 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
codeset->RODataSegment().offset + codeset->RODataSegment().size; codeset->RODataSegment().offset + codeset->RODataSegment().size;
codeset->DataSegment().addr = overlay_ncch->exheader_header.codeset_info.data.address; codeset->DataSegment().addr = overlay_ncch->exheader_header.codeset_info.data.address;
codeset->DataSegment().size = codeset->DataSegment().size =
overlay_ncch->exheader_header.codeset_info.data.num_max_pages * Memory::CITRA_PAGE_SIZE + overlay_ncch->exheader_header.codeset_info.data.num_max_pages *
Memory::CITRA_PAGE_SIZE +
bss_page_size; bss_page_size;
// Apply patches now that the entire codeset (including .bss) has been allocated // Apply patches now that the entire codeset (including .bss) has been allocated

View File

@ -221,8 +221,8 @@ std::shared_ptr<PageTable> MemorySystem::GetCurrentPageTable() const {
void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory,
PageType type) { PageType type) {
LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), base * CITRA_PAGE_SIZE, LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(),
(base + size) * CITRA_PAGE_SIZE); base * CITRA_PAGE_SIZE, (base + size) * CITRA_PAGE_SIZE);
RasterizerFlushVirtualRegion(base << CITRA_PAGE_BITS, size * CITRA_PAGE_SIZE, RasterizerFlushVirtualRegion(base << CITRA_PAGE_BITS, size * CITRA_PAGE_SIZE,
FlushMode::FlushAndInvalidate); FlushMode::FlushAndInvalidate);
@ -256,7 +256,8 @@ void MemorySystem::MapIoRegion(PageTable& page_table, VAddr base, u32 size,
MMIORegionPointer mmio_handler) { MMIORegionPointer mmio_handler) {
ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr, PageType::Special); MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr,
PageType::Special);
page_table.special_regions.emplace_back(SpecialRegion{base, size, mmio_handler}); page_table.special_regions.emplace_back(SpecialRegion{base, size, mmio_handler});
} }
@ -264,7 +265,8 @@ void MemorySystem::MapIoRegion(PageTable& page_table, VAddr base, u32 size,
void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) { void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) {
ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr, PageType::Unmapped); MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr,
PageType::Unmapped);
} }
MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) const { MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) const {
@ -494,8 +496,7 @@ MemoryRef MemorySystem::GetPhysicalRef(PAddr address) const {
std::make_pair(N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE), std::make_pair(N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE),
}; };
const auto area = const auto area = std::ranges::find_if(memory_areas, [&](const auto& area) {
std::ranges::find_if(memory_areas, [&](const auto& area) {
// Note: the region end check is inclusive because the user can pass in an address that // Note: the region end check is inclusive because the user can pass in an address that
// represents an open right bound // represents an open right bound
return address >= area.first && address <= area.first + area.second; return address >= area.first && address <= area.first + area.second;

View File

@ -14,11 +14,7 @@
namespace Settings { namespace Settings {
enum class GraphicsAPI { enum class GraphicsAPI { OpenGL = 0, OpenGLES = 1, Vulkan = 2 };
OpenGL = 0,
OpenGLES = 1,
Vulkan = 2
};
enum class InitClock { enum class InitClock {
SystemTime = 0, SystemTime = 0,

View File

@ -5,9 +5,9 @@
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <mutex> #include <mutex>
#include <numbers>
#include <thread> #include <thread>
#include <tuple> #include <tuple>
#include <numbers>
#include "common/math_util.h" #include "common/math_util.h"
#include "common/quaternion.h" #include "common/quaternion.h"
#include "common/thread.h" #include "common/thread.h"

View File

@ -8,13 +8,13 @@
#include <functional> #include <functional>
#include <iterator> #include <iterator>
#include <mutex> #include <mutex>
#include <numbers>
#include <string> #include <string>
#include <thread> #include <thread>
#include <tuple> #include <tuple>
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <numbers>
#include <SDL.h> #include <SDL.h>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/param_package.h" #include "common/param_package.h"

View File

@ -4,8 +4,8 @@
#include <limits> #include <limits>
#include "core/memory.h" #include "core/memory.h"
#include "video_core/video_core.h"
#include "video_core/rasterizer_accelerated.h" #include "video_core/rasterizer_accelerated.h"
#include "video_core/video_core.h"
namespace VideoCore { namespace VideoCore {
@ -53,21 +53,18 @@ void RasterizerAccelerated::UpdatePagesCachedCount(PAddr addr, u32 size, int del
cache_bytes += Memory::CITRA_PAGE_SIZE; cache_bytes += Memory::CITRA_PAGE_SIZE;
} else if (cache_bytes > 0) { } else if (cache_bytes > 0) {
VideoCore::g_memory->RasterizerMarkRegionCached(cache_start_addr, cache_bytes, VideoCore::g_memory->RasterizerMarkRegionCached(cache_start_addr, cache_bytes, true);
true);
cache_bytes = 0; cache_bytes = 0;
} }
} }
if (uncache_bytes > 0) { if (uncache_bytes > 0) {
VideoCore::g_memory->RasterizerMarkRegionCached(uncache_start_addr, uncache_bytes, VideoCore::g_memory->RasterizerMarkRegionCached(uncache_start_addr, uncache_bytes, false);
false);
} }
if (cache_bytes > 0) { if (cache_bytes > 0) {
VideoCore::g_memory->RasterizerMarkRegionCached(cache_start_addr, cache_bytes, VideoCore::g_memory->RasterizerMarkRegionCached(cache_start_addr, cache_bytes, true);
true);
} }
} }
@ -98,8 +95,7 @@ void RasterizerAccelerated::ClearAll(bool flush) {
} }
if (uncache_bytes > 0) { if (uncache_bytes > 0) {
VideoCore::g_memory->RasterizerMarkRegionCached(uncache_start_addr, uncache_bytes, VideoCore::g_memory->RasterizerMarkRegionCached(uncache_start_addr, uncache_bytes, false);
false);
} }
cached_pages = {}; cached_pages = {};

View File

@ -3,9 +3,9 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <span>
#include <bit>
#include <algorithm> #include <algorithm>
#include <bit>
#include <span>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/color.h" #include "common/color.h"
#include "video_core/rasterizer_cache/pixel_format.h" #include "video_core/rasterizer_cache/pixel_format.h"
@ -108,7 +108,8 @@ inline void EncodePixel(const std::byte* source, std::byte* dest) {
} }
template <bool morton_to_linear, PixelFormat format> template <bool morton_to_linear, PixelFormat format>
inline void MortonCopyTile(u32 stride, std::span<std::byte> tile_buffer, std::span<std::byte> linear_buffer) { inline void MortonCopyTile(u32 stride, std::span<std::byte> tile_buffer,
std::span<std::byte> linear_buffer) {
constexpr u32 bytes_per_pixel = GetFormatBpp(format) / 8; constexpr u32 bytes_per_pixel = GetFormatBpp(format) / 8;
constexpr u32 linear_bytes_per_pixel = GetBytesPerPixel(format); constexpr u32 linear_bytes_per_pixel = GetBytesPerPixel(format);
constexpr bool is_compressed = format == PixelFormat::ETC1 || format == PixelFormat::ETC1A4; constexpr bool is_compressed = format == PixelFormat::ETC1 || format == PixelFormat::ETC1A4;
@ -116,10 +117,10 @@ inline void MortonCopyTile(u32 stride, std::span<std::byte> tile_buffer, std::sp
for (u32 y = 0; y < 8; y++) { for (u32 y = 0; y < 8; y++) {
for (u32 x = 0; x < 8; x++) { for (u32 x = 0; x < 8; x++) {
const auto tiled_pixel = tile_buffer.subspan(VideoCore::MortonInterleave(x, y) * bytes_per_pixel, const auto tiled_pixel = tile_buffer.subspan(
bytes_per_pixel); VideoCore::MortonInterleave(x, y) * bytes_per_pixel, bytes_per_pixel);
const auto linear_pixel = linear_buffer.subspan(((7 - y) * stride + x) * linear_bytes_per_pixel, const auto linear_pixel = linear_buffer.subspan(
linear_bytes_per_pixel); ((7 - y) * stride + x) * linear_bytes_per_pixel, linear_bytes_per_pixel);
if constexpr (morton_to_linear) { if constexpr (morton_to_linear) {
if constexpr (is_compressed) { if constexpr (is_compressed) {
DecodePixelETC1<format>(x, y, tile_buffer.data(), linear_pixel.data()); DecodePixelETC1<format>(x, y, tile_buffer.data(), linear_pixel.data());
@ -138,24 +139,26 @@ inline void MortonCopyTile(u32 stride, std::span<std::byte> tile_buffer, std::sp
/** /**
* @brief Performs morton to/from linear convertions on the provided pixel data * @brief Performs morton to/from linear convertions on the provided pixel data
* @param width, height The dimentions of the rectangular region of pixels in linear_buffer * @param width, height The dimentions of the rectangular region of pixels in linear_buffer
* @param start_offset The number of bytes from the start of the first tile to the start of tiled_buffer * @param start_offset The number of bytes from the start of the first tile to the start of
* tiled_buffer
* @param end_offset The number of bytes from the start of the first tile to the end of tiled_buffer * @param end_offset The number of bytes from the start of the first tile to the end of tiled_buffer
* @param linear_buffer The linear pixel data * @param linear_buffer The linear pixel data
* @param tiled_buffer The tiled pixel data * @param tiled_buffer The tiled pixel data
* *
* The MortonCopy is at the heart of the PICA texture implementation, as it's responsible for converting between * The MortonCopy is at the heart of the PICA texture implementation, as it's responsible for
* linear and morton tiled layouts. The function handles both convertions but there are slightly different * converting between linear and morton tiled layouts. The function handles both convertions but
* paths and inputs for each: * there are slightly different paths and inputs for each:
* *
* Morton to Linear: * Morton to Linear:
* During uploads, tiled_buffer is always aligned to the tile or scanline boundary depending if the linear rectangle * During uploads, tiled_buffer is always aligned to the tile or scanline boundary depending if the
* spans multiple vertical tiles. linear_buffer does not reference the entire texture area, but rather the * linear rectangle spans multiple vertical tiles. linear_buffer does not reference the entire
* specific rectangle affected by the upload. * texture area, but rather the specific rectangle affected by the upload.
* *
* Linear to Morton: * Linear to Morton:
* This is similar to the other convertion but with some differences. In this case tiled_buffer is not required * This is similar to the other convertion but with some differences. In this case tiled_buffer is
* to be aligned to any specific boundary which requires special care. start_offset/end_offset are useful * not required to be aligned to any specific boundary which requires special care.
* here as they tell us exactly where the data should be placed in the linear_buffer. * start_offset/end_offset are useful here as they tell us exactly where the data should be placed
* in the linear_buffer.
*/ */
template <bool morton_to_linear, PixelFormat format> template <bool morton_to_linear, PixelFormat format>
static void MortonCopy(u32 width, u32 height, u32 start_offset, u32 end_offset, static void MortonCopy(u32 width, u32 height, u32 start_offset, u32 end_offset,
@ -170,7 +173,8 @@ static void MortonCopy(u32 width, u32 height, u32 start_offset, u32 end_offset,
const u32 aligned_start_offset = Common::AlignUp(start_offset, tile_size); const u32 aligned_start_offset = Common::AlignUp(start_offset, tile_size);
const u32 aligned_end_offset = Common::AlignDown(end_offset, tile_size); const u32 aligned_end_offset = Common::AlignDown(end_offset, tile_size);
ASSERT(!morton_to_linear || (aligned_start_offset == start_offset && aligned_end_offset == end_offset)); ASSERT(!morton_to_linear ||
(aligned_start_offset == start_offset && aligned_end_offset == end_offset));
// In OpenGL the texture origin is in the bottom left corner as opposed to other // In OpenGL the texture origin is in the bottom left corner as opposed to other
// APIs that have it at the top left. To avoid flipping texture coordinates in // APIs that have it at the top left. To avoid flipping texture coordinates in
@ -222,7 +226,8 @@ static void MortonCopy(u32 width, u32 height, u32 start_offset, u32 end_offset,
std::array<std::byte, tile_size> tmp_buf; std::array<std::byte, tile_size> tmp_buf;
auto linear_data = linear_buffer.subspan(linear_offset, linear_tile_stride); auto linear_data = linear_buffer.subspan(linear_offset, linear_tile_stride);
MortonCopyTile<morton_to_linear, format>(width, tmp_buf, linear_data); MortonCopyTile<morton_to_linear, format>(width, tmp_buf, linear_data);
std::memcpy(tiled_buffer.data() + tiled_offset, tmp_buf.data(), end_offset - aligned_end_offset); std::memcpy(tiled_buffer.data() + tiled_offset, tmp_buf.data(),
end_offset - aligned_end_offset);
} }
} }

View File

@ -6,9 +6,13 @@
namespace VideoCore { namespace VideoCore {
MICROPROFILE_DEFINE(RasterizerCache_BlitSurface, "RasterizerCache", "BlitSurface", MP_RGB(128, 192, 64)); MICROPROFILE_DEFINE(RasterizerCache_BlitSurface, "RasterizerCache", "BlitSurface",
MICROPROFILE_DEFINE(RasterizerCache_CopySurface, "RasterizerCache", "CopySurface", MP_RGB(128, 192, 64)); MP_RGB(128, 192, 64));
MICROPROFILE_DEFINE(RasterizerCache_SurfaceLoad, "RasterizerCache", "Surface Load", MP_RGB(128, 192, 64)); MICROPROFILE_DEFINE(RasterizerCache_CopySurface, "RasterizerCache", "CopySurface",
MICROPROFILE_DEFINE(RasterizerCache_SurfaceFlush, "RasterizerCache", "Surface Flush", MP_RGB(128, 192, 64)); MP_RGB(128, 192, 64));
MICROPROFILE_DEFINE(RasterizerCache_SurfaceLoad, "RasterizerCache", "Surface Load",
MP_RGB(128, 192, 64));
MICROPROFILE_DEFINE(RasterizerCache_SurfaceFlush, "RasterizerCache", "Surface Flush",
MP_RGB(128, 192, 64));
} // namespace VideoCore } // namespace VideoCore

View File

@ -4,8 +4,8 @@
#pragma once #pragma once
#include <algorithm> #include <algorithm>
#include <unordered_map>
#include <optional> #include <optional>
#include <unordered_map>
#include <vector> #include <vector>
#include <boost/range/iterator_range.hpp> #include <boost/range/iterator_range.hpp>
#include "common/alignment.h" #include "common/alignment.h"
@ -14,8 +14,8 @@
#include "video_core/pica_state.h" #include "video_core/pica_state.h"
#include "video_core/rasterizer_accelerated.h" #include "video_core/rasterizer_accelerated.h"
#include "video_core/rasterizer_cache/surface_base.h" #include "video_core/rasterizer_cache/surface_base.h"
#include "video_core/rasterizer_cache/utils.h"
#include "video_core/rasterizer_cache/surface_params.h" #include "video_core/rasterizer_cache/surface_params.h"
#include "video_core/rasterizer_cache/utils.h"
#include "video_core/texture/texture_decode.h" #include "video_core/texture/texture_decode.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
@ -54,15 +54,17 @@ public:
private: private:
/// Declare rasterizer interval types /// Declare rasterizer interval types
using SurfaceSet = std::set<Surface>; using SurfaceSet = std::set<Surface>;
using SurfaceMap = using SurfaceMap = boost::icl::interval_map<PAddr, Surface, boost::icl::partial_absorber,
boost::icl::interval_map<PAddr, Surface, boost::icl::partial_absorber, std::less, std::less, boost::icl::inplace_plus,
boost::icl::inplace_plus, boost::icl::inter_section, SurfaceInterval>; boost::icl::inter_section, SurfaceInterval>;
using SurfaceCache = using SurfaceCache = boost::icl::interval_map<PAddr, SurfaceSet, boost::icl::partial_absorber,
boost::icl::interval_map<PAddr, SurfaceSet, boost::icl::partial_absorber, std::less, std::less, boost::icl::inplace_plus,
boost::icl::inplace_plus, boost::icl::inter_section, SurfaceInterval>; boost::icl::inter_section, SurfaceInterval>;
static_assert(std::is_same<SurfaceRegions::interval_type, typename SurfaceCache::interval_type>() && static_assert(
std::is_same<typename SurfaceMap::interval_type, typename SurfaceCache::interval_type>(), std::is_same<SurfaceRegions::interval_type, typename SurfaceCache::interval_type>() &&
std::is_same<typename SurfaceMap::interval_type,
typename SurfaceCache::interval_type>(),
"Incorrect interval types"); "Incorrect interval types");
using SurfaceRect_Tuple = std::tuple<Surface, Common::Rectangle<u32>>; using SurfaceRect_Tuple = std::tuple<Surface, Common::Rectangle<u32>>;
@ -170,7 +172,8 @@ private:
}; };
template <class T> template <class T>
RasterizerCache<T>::RasterizerCache(VideoCore::RasterizerAccelerated& rasterizer, TextureRuntime& runtime) RasterizerCache<T>::RasterizerCache(VideoCore::RasterizerAccelerated& rasterizer,
TextureRuntime& runtime)
: rasterizer{rasterizer}, runtime{runtime} { : rasterizer{rasterizer}, runtime{runtime} {
resolution_scale_factor = VideoCore::GetResolutionScaleFactor(); resolution_scale_factor = VideoCore::GetResolutionScaleFactor();
} }
@ -271,8 +274,7 @@ bool RasterizerCache<T>::BlitSurfaces(const Surface& src_surface, Common::Rectan
const Surface& dst_surface, Common::Rectangle<u32> dst_rect) { const Surface& dst_surface, Common::Rectangle<u32> dst_rect) {
MICROPROFILE_SCOPE(RasterizerCache_BlitSurface); MICROPROFILE_SCOPE(RasterizerCache_BlitSurface);
if (!CheckFormatsBlittable(src_surface->pixel_format, if (!CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) [[unlikely]] {
dst_surface->pixel_format)) [[unlikely]] {
return false; return false;
} }
@ -282,28 +284,23 @@ bool RasterizerCache<T>::BlitSurfaces(const Surface& src_surface, Common::Rectan
// 1. No scaling (the dimentions of src and dest rect are the same) // 1. No scaling (the dimentions of src and dest rect are the same)
// 2. No flipping (if the bottom value is bigger than the top this indicates texture flip) // 2. No flipping (if the bottom value is bigger than the top this indicates texture flip)
if (src_rect.GetWidth() == dst_rect.GetWidth() && if (src_rect.GetWidth() == dst_rect.GetWidth() &&
src_rect.GetHeight() == dst_rect.GetHeight() && src_rect.GetHeight() == dst_rect.GetHeight() && src_rect.bottom < src_rect.top) {
src_rect.bottom < src_rect.top) { const TextureCopy texture_copy = {.src_level = 0,
const TextureCopy texture_copy = {
.src_level = 0,
.dst_level = 0, .dst_level = 0,
.src_layer = 0, .src_layer = 0,
.dst_layer = 0, .dst_layer = 0,
.src_offset = {src_rect.left, src_rect.bottom}, .src_offset = {src_rect.left, src_rect.bottom},
.dst_offset = {dst_rect.left, dst_rect.bottom}, .dst_offset = {dst_rect.left, dst_rect.bottom},
.extent = {src_rect.GetWidth(), src_rect.GetHeight()} .extent = {src_rect.GetWidth(), src_rect.GetHeight()}};
};
return runtime.CopyTextures(*src_surface, *dst_surface, texture_copy); return runtime.CopyTextures(*src_surface, *dst_surface, texture_copy);
} else { } else {
const TextureBlit texture_blit = { const TextureBlit texture_blit = {.src_level = 0,
.src_level = 0,
.dst_level = 0, .dst_level = 0,
.src_layer = 0, .src_layer = 0,
.dst_layer = 0, .dst_layer = 0,
.src_rect = src_rect, .src_rect = src_rect,
.dst_rect = dst_rect .dst_rect = dst_rect};
};
return runtime.BlitTextures(*src_surface, *dst_surface, texture_blit); return runtime.BlitTextures(*src_surface, *dst_surface, texture_blit);
} }
@ -332,23 +329,20 @@ void RasterizerCache<T>::CopySurface(const Surface& src_surface, const Surface&
const ClearValue clear_value = const ClearValue clear_value =
MakeClearValue(dst_surface->type, dst_surface->pixel_format, fill_buffer.data()); MakeClearValue(dst_surface->type, dst_surface->pixel_format, fill_buffer.data());
const TextureClear clear_rect = { const TextureClear clear_rect = {
.texture_level = 0, .texture_level = 0, .texture_rect = dst_surface->GetScaledSubRect(subrect_params)};
.texture_rect = dst_surface->GetScaledSubRect(subrect_params)
};
runtime.ClearTexture(*dst_surface, clear_rect, clear_value); runtime.ClearTexture(*dst_surface, clear_rect, clear_value);
return; return;
} }
if (src_surface->CanSubRect(subrect_params)) { if (src_surface->CanSubRect(subrect_params)) {
const TextureBlit texture_blit = { const TextureBlit texture_blit = {.src_level = 0,
.src_level = 0,
.dst_level = 0, .dst_level = 0,
.src_layer = 0, .src_layer = 0,
.dst_layer = 0, .dst_layer = 0,
.src_rect = src_surface->GetScaledSubRect(subrect_params), .src_rect = src_surface->GetScaledSubRect(subrect_params),
.dst_rect = dst_surface->GetScaledSubRect(subrect_params) .dst_rect =
}; dst_surface->GetScaledSubRect(subrect_params)};
runtime.BlitTextures(*src_surface, *dst_surface, texture_blit); runtime.BlitTextures(*src_surface, *dst_surface, texture_blit);
return; return;
@ -488,13 +482,15 @@ auto RasterizerCache<T>::GetSurfaceSubRect(const SurfaceParams& params, ScaleMat
} }
template <class T> template <class T>
auto RasterizerCache<T>::GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config) -> Surface { auto RasterizerCache<T>::GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config)
-> Surface {
const auto info = Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format); const auto info = Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format);
return GetTextureSurface(info, config.config.lod.max_level); return GetTextureSurface(info, config.config.lod.max_level);
} }
template <class T> template <class T>
auto RasterizerCache<T>::GetTextureSurface(const Pica::Texture::TextureInfo& info, u32 max_level) -> Surface { auto RasterizerCache<T>::GetTextureSurface(const Pica::Texture::TextureInfo& info, u32 max_level)
-> Surface {
if (info.physical_address == 0) [[unlikely]] { if (info.physical_address == 0) [[unlikely]] {
return nullptr; return nullptr;
} }
@ -573,14 +569,12 @@ auto RasterizerCache<T>::GetTextureSurface(const Pica::Texture::TextureInfo& inf
} }
if (/*texture_filterer->IsNull()*/ true) { if (/*texture_filterer->IsNull()*/ true) {
const TextureBlit texture_blit = { const TextureBlit texture_blit = {.src_level = 0,
.src_level = 0,
.dst_level = level, .dst_level = level,
.src_layer = 0, .src_layer = 0,
.dst_layer = 0, .dst_layer = 0,
.src_rect = level_surface->GetScaledRect(), .src_rect = level_surface->GetScaledRect(),
.dst_rect = surface_params.GetScaledRect() .dst_rect = surface_params.GetScaledRect()};
};
runtime.BlitTextures(*level_surface, *surface, texture_blit); runtime.BlitTextures(*level_surface, *surface, texture_blit);
} }
@ -597,15 +591,13 @@ template <class T>
auto RasterizerCache<T>::GetTextureCube(const TextureCubeConfig& config) -> const Surface& { auto RasterizerCache<T>::GetTextureCube(const TextureCubeConfig& config) -> const Surface& {
auto [it, new_surface] = texture_cube_cache.try_emplace(config); auto [it, new_surface] = texture_cube_cache.try_emplace(config);
if (new_surface) { if (new_surface) {
SurfaceParams cube_params = { SurfaceParams cube_params = {.addr = config.px,
.addr = config.px,
.width = config.width, .width = config.width,
.height = config.width, .height = config.width,
.stride = config.width, .stride = config.width,
.texture_type = TextureType::CubeMap, .texture_type = TextureType::CubeMap,
.pixel_format = PixelFormatFromTextureFormat(config.format), .pixel_format = PixelFormatFromTextureFormat(config.format),
.type = SurfaceType::Texture .type = SurfaceType::Texture};
};
it->second = CreateSurface(cube_params); it->second = CreateSurface(cube_params);
} }
@ -614,8 +606,7 @@ auto RasterizerCache<T>::GetTextureCube(const TextureCubeConfig& config) -> cons
// Update surface watchers // Update surface watchers
auto& watchers = cube->level_watchers; auto& watchers = cube->level_watchers;
const std::array addresses = {config.px, config.nx, config.py, const std::array addresses = {config.px, config.nx, config.py, config.ny, config.pz, config.nz};
config.ny, config.pz, config.nz};
for (std::size_t i = 0; i < addresses.size(); i++) { for (std::size_t i = 0; i < addresses.size(); i++) {
auto& watcher = watchers[i]; auto& watcher = watchers[i];
@ -650,14 +641,12 @@ auto RasterizerCache<T>::GetTextureCube(const TextureCubeConfig& config) -> cons
ValidateSurface(face, face->addr, face->size); ValidateSurface(face, face->addr, face->size);
} }
const TextureBlit texture_blit = { const TextureBlit texture_blit = {.src_level = 0,
.src_level = 0,
.dst_level = 0, .dst_level = 0,
.src_layer = 0, .src_layer = 0,
.dst_layer = static_cast<u32>(i), .dst_layer = static_cast<u32>(i),
.src_rect = face->GetScaledRect(), .src_rect = face->GetScaledRect(),
.dst_rect = Rect2D{0, scaled_size, scaled_size, 0} .dst_rect = Rect2D{0, scaled_size, scaled_size, 0}};
};
runtime.BlitTextures(*face, *cube, texture_blit); runtime.BlitTextures(*face, *cube, texture_blit);
watcher->Validate(); watcher->Validate();
@ -680,7 +669,8 @@ auto RasterizerCache<T>::GetFramebufferSurfaces(bool using_color_fb, bool using_
const bool texture_filter_changed = const bool texture_filter_changed =
/*VideoCore::g_texture_filter_update_requested.exchange(false) && /*VideoCore::g_texture_filter_update_requested.exchange(false) &&
texture_filterer->Reset(Settings::values.texture_filter_name, texture_filterer->Reset(Settings::values.texture_filter_name,
VideoCore::GetResolutionScaleFactor())*/false; VideoCore::GetResolutionScaleFactor())*/
false;
if (resolution_scale_changed || texture_filter_changed) [[unlikely]] { if (resolution_scale_changed || texture_filter_changed) [[unlikely]] {
resolution_scale_factor = VideoCore::GetResolutionScaleFactor(); resolution_scale_factor = VideoCore::GetResolutionScaleFactor();
@ -926,19 +916,18 @@ void RasterizerCache<T>::UploadSurface(const Surface& surface, SurfaceInterval i
const auto upload_data = source_ptr.GetWriteBytes(load_info.end - load_info.addr); const auto upload_data = source_ptr.GetWriteBytes(load_info.end - load_info.addr);
if (surface->is_tiled) { if (surface->is_tiled) {
std::vector<std::byte> unswizzled_data(load_info.width * load_info.height * GetBytesPerPixel(load_info.pixel_format)); std::vector<std::byte> unswizzled_data(load_info.width * load_info.height *
GetBytesPerPixel(load_info.pixel_format));
UnswizzleTexture(load_info, load_info.addr, load_info.end, upload_data, unswizzled_data); UnswizzleTexture(load_info, load_info.addr, load_info.end, upload_data, unswizzled_data);
runtime.FormatConvert(*surface, true, unswizzled_data, staging.mapped); runtime.FormatConvert(*surface, true, unswizzled_data, staging.mapped);
} else { } else {
runtime.FormatConvert(*surface, true, upload_data, staging.mapped); runtime.FormatConvert(*surface, true, upload_data, staging.mapped);
} }
const BufferTextureCopy upload = { const BufferTextureCopy upload = {.buffer_offset = 0,
.buffer_offset = 0,
.buffer_size = staging.size, .buffer_size = staging.size,
.texture_rect = surface->GetSubRect(load_info), .texture_rect = surface->GetSubRect(load_info),
.texture_level = 0 .texture_level = 0};
};
surface->Upload(upload, staging); surface->Upload(upload, staging);
} }
@ -953,16 +942,15 @@ void RasterizerCache<T>::DownloadSurface(const Surface& surface, SurfaceInterval
const auto& staging = runtime.FindStaging( const auto& staging = runtime.FindStaging(
flush_info.width * flush_info.height * surface->GetInternalBytesPerPixel(), false); flush_info.width * flush_info.height * surface->GetInternalBytesPerPixel(), false);
const BufferTextureCopy download = { const BufferTextureCopy download = {.buffer_offset = 0,
.buffer_offset = 0,
.buffer_size = staging.size, .buffer_size = staging.size,
.texture_rect = surface->GetSubRect(flush_info), .texture_rect = surface->GetSubRect(flush_info),
.texture_level = 0 .texture_level = 0};
};
surface->Download(download, staging); surface->Download(download, staging);
download_queue.push_back([this, surface, flush_start, flush_end, flush_info, mapped = staging.mapped]() { download_queue.push_back(
[this, surface, flush_start, flush_end, flush_info, mapped = staging.mapped]() {
MemoryRef dest_ptr = VideoCore::g_memory->GetPhysicalRef(flush_start); MemoryRef dest_ptr = VideoCore::g_memory->GetPhysicalRef(flush_start);
if (!dest_ptr) [[unlikely]] { if (!dest_ptr) [[unlikely]] {
return; return;
@ -971,7 +959,8 @@ void RasterizerCache<T>::DownloadSurface(const Surface& surface, SurfaceInterval
const auto download_dest = dest_ptr.GetWriteBytes(flush_end - flush_start); const auto download_dest = dest_ptr.GetWriteBytes(flush_end - flush_start);
if (surface->is_tiled) { if (surface->is_tiled) {
std::vector<std::byte> temp_data(flush_info.width * flush_info.height * GetBytesPerPixel(flush_info.pixel_format)); std::vector<std::byte> temp_data(flush_info.width * flush_info.height *
GetBytesPerPixel(flush_info.pixel_format));
runtime.FormatConvert(*surface, false, mapped, temp_data); runtime.FormatConvert(*surface, false, mapped, temp_data);
SwizzleTexture(flush_info, flush_start, flush_end, temp_data, download_dest); SwizzleTexture(flush_info, flush_start, flush_end, temp_data, download_dest);
} else { } else {
@ -992,7 +981,8 @@ void RasterizerCache<T>::DownloadFillSurface(const Surface& surface, SurfaceInte
} }
const u32 start_offset = flush_start - surface->addr; const u32 start_offset = flush_start - surface->addr;
const u32 download_size = std::clamp(flush_end - flush_start, 0u, static_cast<u32>(dest_ptr.GetSize())); const u32 download_size =
std::clamp(flush_end - flush_start, 0u, static_cast<u32>(dest_ptr.GetSize()));
const u32 coarse_start_offset = start_offset - (start_offset % surface->fill_size); const u32 coarse_start_offset = start_offset - (start_offset % surface->fill_size);
const u32 backup_bytes = start_offset % surface->fill_size; const u32 backup_bytes = start_offset % surface->fill_size;
@ -1012,7 +1002,8 @@ void RasterizerCache<T>::DownloadFillSurface(const Surface& surface, SurfaceInte
} }
template <class T> template <class T>
bool RasterizerCache<T>::NoUnimplementedReinterpretations(const Surface& surface, SurfaceParams& params, bool RasterizerCache<T>::NoUnimplementedReinterpretations(const Surface& surface,
SurfaceParams& params,
SurfaceInterval interval) { SurfaceInterval interval) {
static constexpr std::array all_formats = { static constexpr std::array all_formats = {
PixelFormat::RGBA8, PixelFormat::RGB8, PixelFormat::RGB5A1, PixelFormat::RGB565, PixelFormat::RGBA8, PixelFormat::RGB8, PixelFormat::RGB5A1, PixelFormat::RGB565,
@ -1043,13 +1034,13 @@ bool RasterizerCache<T>::NoUnimplementedReinterpretations(const Surface& surface
} }
template <class T> template <class T>
bool RasterizerCache<T>::IntervalHasInvalidPixelFormat(SurfaceParams& params, SurfaceInterval interval) { bool RasterizerCache<T>::IntervalHasInvalidPixelFormat(SurfaceParams& params,
SurfaceInterval interval) {
params.pixel_format = PixelFormat::Invalid; params.pixel_format = PixelFormat::Invalid;
for (const auto& set : RangeFromInterval(surface_cache, interval)) { for (const auto& set : RangeFromInterval(surface_cache, interval)) {
for (const auto& surface : set.second) { for (const auto& surface : set.second) {
if (surface->pixel_format == PixelFormat::Invalid) { if (surface->pixel_format == PixelFormat::Invalid) {
LOG_DEBUG(HW_GPU, "Surface {:#x} found with invalid pixel format", LOG_DEBUG(HW_GPU, "Surface {:#x} found with invalid pixel format", surface->addr);
surface->addr);
return true; return true;
} }
} }

View File

@ -46,6 +46,7 @@ public:
template <class S> template <class S>
class SurfaceBase : public SurfaceParams, public std::enable_shared_from_this<S> { class SurfaceBase : public SurfaceParams, public std::enable_shared_from_this<S> {
using Watcher = SurfaceWatcher<S>; using Watcher = SurfaceWatcher<S>;
public: public:
SurfaceBase(SurfaceParams& params) : SurfaceParams{params} {} SurfaceBase(SurfaceParams& params) : SurfaceParams{params} {}
virtual ~SurfaceBase() = default; virtual ~SurfaceBase() = default;
@ -53,7 +54,8 @@ public:
/// Returns true when this surface can be used to fill the fill_interval of dest_surface /// Returns true when this surface can be used to fill the fill_interval of dest_surface
bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const; bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const;
/// Returns true when copy_interval of dest_surface can be validated by copying from this surface /// Returns true when copy_interval of dest_surface can be validated by copying from this
/// surface
bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const; bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const;
/// Returns the region of the biggest valid rectange within interval /// Returns the region of the biggest valid rectange within interval
@ -93,7 +95,8 @@ public:
}; };
template <class S> template <class S>
bool SurfaceBase<S>::CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const { bool SurfaceBase<S>::CanFill(const SurfaceParams& dest_surface,
SurfaceInterval fill_interval) const {
if (type == SurfaceType::Fill && IsRegionValid(fill_interval) && if (type == SurfaceType::Fill && IsRegionValid(fill_interval) &&
boost::icl::first(fill_interval) >= addr && boost::icl::first(fill_interval) >= addr &&
boost::icl::last_next(fill_interval) <= end && // dest_surface is within our fill range boost::icl::last_next(fill_interval) <= end && // dest_surface is within our fill range
@ -139,13 +142,15 @@ template <class S>
SurfaceInterval SurfaceBase<S>::GetCopyableInterval(const SurfaceParams& params) const { SurfaceInterval SurfaceBase<S>::GetCopyableInterval(const SurfaceParams& params) const {
SurfaceInterval result{}; SurfaceInterval result{};
const u32 tile_align = params.BytesInPixels(params.is_tiled ? 8 * 8 : 1); const u32 tile_align = params.BytesInPixels(params.is_tiled ? 8 * 8 : 1);
const auto valid_regions = SurfaceRegions{params.GetInterval() & GetInterval()} - invalid_regions; const auto valid_regions =
SurfaceRegions{params.GetInterval() & GetInterval()} - invalid_regions;
for (auto& valid_interval : valid_regions) { for (auto& valid_interval : valid_regions) {
const SurfaceInterval aligned_interval{ const SurfaceInterval aligned_interval{
params.addr + Common::AlignUp(boost::icl::first(valid_interval) - params.addr, tile_align), params.addr +
params.addr + Common::AlignDown(boost::icl::last_next(valid_interval) - params.addr, tile_align) Common::AlignUp(boost::icl::first(valid_interval) - params.addr, tile_align),
}; params.addr +
Common::AlignDown(boost::icl::last_next(valid_interval) - params.addr, tile_align)};
if (params.BytesInPixels(tile_align) > boost::icl::length(valid_interval) || if (params.BytesInPixels(tile_align) > boost::icl::length(valid_interval) ||
boost::icl::length(aligned_interval) == 0) { boost::icl::length(aligned_interval) == 0) {
@ -155,8 +160,10 @@ SurfaceInterval SurfaceBase<S>::GetCopyableInterval(const SurfaceParams& params)
// Get the rectangle within aligned_interval // Get the rectangle within aligned_interval
const u32 stride_bytes = params.BytesInPixels(params.stride) * (params.is_tiled ? 8 : 1); const u32 stride_bytes = params.BytesInPixels(params.stride) * (params.is_tiled ? 8 : 1);
SurfaceInterval rect_interval{ SurfaceInterval rect_interval{
params.addr + Common::AlignUp(boost::icl::first(aligned_interval) - params.addr, stride_bytes), params.addr +
params.addr + Common::AlignDown(boost::icl::last_next(aligned_interval) - params.addr, stride_bytes), Common::AlignUp(boost::icl::first(aligned_interval) - params.addr, stride_bytes),
params.addr + Common::AlignDown(boost::icl::last_next(aligned_interval) - params.addr,
stride_bytes),
}; };
if (boost::icl::first(rect_interval) > boost::icl::last_next(rect_interval)) { if (boost::icl::first(rect_interval) > boost::icl::last_next(rect_interval)) {

View File

@ -15,10 +15,7 @@ namespace VideoCore {
using SurfaceInterval = boost::icl::right_open_interval<PAddr>; using SurfaceInterval = boost::icl::right_open_interval<PAddr>;
enum class TextureType { enum class TextureType { Texture2D = 0, CubeMap = 1 };
Texture2D = 0,
CubeMap = 1
};
class SurfaceParams { class SurfaceParams {
public: public:

View File

@ -3,10 +3,10 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/assert.h" #include "common/assert.h"
#include "video_core/texture/texture_decode.h"
#include "video_core/rasterizer_cache/morton_swizzle.h" #include "video_core/rasterizer_cache/morton_swizzle.h"
#include "video_core/rasterizer_cache/surface_params.h" #include "video_core/rasterizer_cache/surface_params.h"
#include "video_core/rasterizer_cache/utils.h" #include "video_core/rasterizer_cache/utils.h"
#include "video_core/texture/texture_decode.h"
namespace VideoCore { namespace VideoCore {
@ -51,18 +51,16 @@ void SwizzleTexture(const SurfaceParams& swizzle_info, PAddr start_addr, PAddr e
std::span<std::byte> source_linear, std::span<std::byte> dest_tiled) { std::span<std::byte> source_linear, std::span<std::byte> dest_tiled) {
const u32 func_index = static_cast<u32>(swizzle_info.pixel_format); const u32 func_index = static_cast<u32>(swizzle_info.pixel_format);
const MortonFunc SwizzleImpl = SWIZZLE_TABLE[func_index]; const MortonFunc SwizzleImpl = SWIZZLE_TABLE[func_index];
SwizzleImpl(swizzle_info.width, swizzle_info.height, SwizzleImpl(swizzle_info.width, swizzle_info.height, start_addr - swizzle_info.addr,
start_addr - swizzle_info.addr, end_addr - swizzle_info.addr, end_addr - swizzle_info.addr, source_linear, dest_tiled);
source_linear, dest_tiled);
} }
void UnswizzleTexture(const SurfaceParams& unswizzle_info, PAddr start_addr, PAddr end_addr, void UnswizzleTexture(const SurfaceParams& unswizzle_info, PAddr start_addr, PAddr end_addr,
std::span<std::byte> source_tiled, std::span<std::byte> dest_linear) { std::span<std::byte> source_tiled, std::span<std::byte> dest_linear) {
const u32 func_index = static_cast<u32>(unswizzle_info.pixel_format); const u32 func_index = static_cast<u32>(unswizzle_info.pixel_format);
const MortonFunc UnswizzleImpl = UNSWIZZLE_TABLE[func_index]; const MortonFunc UnswizzleImpl = UNSWIZZLE_TABLE[func_index];
UnswizzleImpl(unswizzle_info.width, unswizzle_info.height, UnswizzleImpl(unswizzle_info.width, unswizzle_info.height, start_addr - unswizzle_info.addr,
start_addr - unswizzle_info.addr, end_addr - unswizzle_info.addr, end_addr - unswizzle_info.addr, dest_linear, source_tiled);
dest_linear, source_tiled);
} }
} // namespace VideoCore } // namespace VideoCore

View File

@ -147,7 +147,6 @@ void Driver::FindBugs() {
if (vendor == Vendor::AMD || (vendor == Vendor::Intel && !is_linux)) { if (vendor == Vendor::AMD || (vendor == Vendor::Intel && !is_linux)) {
bugs |= DriverBug::BrokenTextureView; bugs |= DriverBug::BrokenTextureView;
} }
} }
} // namespace OpenGL } // namespace OpenGL

View File

@ -7,13 +7,7 @@
namespace OpenGL { namespace OpenGL {
enum class Vendor { enum class Vendor { Unknown = 0, AMD = 1, Nvidia = 2, Intel = 3, Generic = 4 };
Unknown = 0,
AMD = 1,
Nvidia = 2,
Intel = 3,
Generic = 4
};
enum class DriverBug { enum class DriverBug {
// AMD drivers sometimes freeze when one shader stage is changed but not the others. // AMD drivers sometimes freeze when one shader stage is changed but not the others.

View File

@ -46,8 +46,8 @@ void D24S8toRGBA8::Reinterpret(const Surface& source, VideoCore::Rect2D src_rect
if (use_texture_view) { if (use_texture_view) {
temp_tex.Create(); temp_tex.Create();
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glTextureView(temp_tex.handle, GL_TEXTURE_2D, source.texture.handle, GL_DEPTH24_STENCIL8, 0, 1, glTextureView(temp_tex.handle, GL_TEXTURE_2D, source.texture.handle, GL_DEPTH24_STENCIL8, 0,
0, 1); 1, 0, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} else { } else {
@ -70,8 +70,8 @@ void D24S8toRGBA8::Reinterpret(const Surface& source, VideoCore::Rect2D src_rect
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
if (!use_texture_view) { if (!use_texture_view) {
glCopyImageSubData(source.texture.handle, GL_TEXTURE_2D, 0, src_rect.left, src_rect.bottom, 0, glCopyImageSubData(source.texture.handle, GL_TEXTURE_2D, 0, src_rect.left, src_rect.bottom,
temp_tex.handle, GL_TEXTURE_2D, 0, src_rect.left, src_rect.bottom, 0, 0, temp_tex.handle, GL_TEXTURE_2D, 0, src_rect.left, src_rect.bottom, 0,
src_rect.GetWidth(), src_rect.GetHeight(), 1); src_rect.GetWidth(), src_rect.GetHeight(), 1);
} }
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
@ -154,8 +154,7 @@ void RGBA4toRGB5A1::Reinterpret(const Surface& source, VideoCore::Rect2D src_rec
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
dest.texture.handle, 0); dest.texture.handle, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
0);
glUniform2i(dst_size_loc, dst_rect.GetWidth(), dst_rect.GetHeight()); glUniform2i(dst_size_loc, dst_rect.GetWidth(), dst_rect.GetHeight());
glUniform2i(src_size_loc, src_rect.GetWidth(), src_rect.GetHeight()); glUniform2i(src_size_loc, src_rect.GetWidth(), src_rect.GetHeight());

View File

@ -16,8 +16,8 @@ public:
virtual ~FormatReinterpreterBase() = default; virtual ~FormatReinterpreterBase() = default;
virtual VideoCore::PixelFormat GetSourceFormat() const = 0; virtual VideoCore::PixelFormat GetSourceFormat() const = 0;
virtual void Reinterpret(const Surface& source, VideoCore::Rect2D src_rect, virtual void Reinterpret(const Surface& source, VideoCore::Rect2D src_rect, const Surface& dest,
const Surface& dest, VideoCore::Rect2D dst_rect) = 0; VideoCore::Rect2D dst_rect) = 0;
}; };
using ReinterpreterList = std::vector<std::unique_ptr<FormatReinterpreterBase>>; using ReinterpreterList = std::vector<std::unique_ptr<FormatReinterpreterBase>>;
@ -30,8 +30,8 @@ public:
return VideoCore::PixelFormat::D24S8; return VideoCore::PixelFormat::D24S8;
} }
void Reinterpret(const Surface& source, VideoCore::Rect2D src_rect, void Reinterpret(const Surface& source, VideoCore::Rect2D src_rect, const Surface& dest,
const Surface& dest, VideoCore::Rect2D dst_rect) override; VideoCore::Rect2D dst_rect) override;
private: private:
bool use_texture_view{}; bool use_texture_view{};
@ -49,8 +49,8 @@ public:
return VideoCore::PixelFormat::RGBA4; return VideoCore::PixelFormat::RGBA4;
} }
void Reinterpret(const Surface& source, VideoCore::Rect2D src_rect, void Reinterpret(const Surface& source, VideoCore::Rect2D src_rect, const Surface& dest,
const Surface& dest, VideoCore::Rect2D dst_rect) override; VideoCore::Rect2D dst_rect) override;
private: private:
OGLFramebuffer read_fbo; OGLFramebuffer read_fbo;

View File

@ -39,8 +39,8 @@ static bool IsVendorIntel() {
#endif #endif
RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window, Driver& driver) RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window, Driver& driver)
: driver{driver}, runtime{driver}, res_cache{*this, runtime}, : driver{driver}, runtime{driver}, res_cache{*this, runtime}, is_amd(IsVendorAmd()),
is_amd(IsVendorAmd()), vertex_buffer(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE, is_amd), vertex_buffer(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE, is_amd),
uniform_buffer(GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE, false), uniform_buffer(GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE, false),
index_buffer(GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE, false), index_buffer(GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE, false),
texture_buffer(GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE, false), texture_buffer(GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE, false),
@ -687,8 +687,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
.pz = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveZ), .pz = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveZ),
.nz = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ), .nz = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ),
.width = texture.config.width, .width = texture.config.width,
.format = texture.format .format = texture.format};
};
state.texture_cube_unit.texture_cube = state.texture_cube_unit.texture_cube =
res_cache.GetTextureCube(config)->texture.handle; res_cache.GetTextureCube(config)->texture.handle;
@ -729,7 +728,8 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
// Making a copy to sample from eliminates this issue and seems to be fairly cheap. // Making a copy to sample from eliminates this issue and seems to be fairly cheap.
OGLTexture temp_tex; OGLTexture temp_tex;
if (need_duplicate_texture) { if (need_duplicate_texture) {
temp_tex = runtime.Allocate(color_surface->GetScaledWidth(), color_surface->GetScaledHeight(), temp_tex =
runtime.Allocate(color_surface->GetScaledWidth(), color_surface->GetScaledHeight(),
color_surface->pixel_format, color_surface->texture_type); color_surface->pixel_format, color_surface->texture_type);
temp_tex.CopyFrom(color_surface->texture, GL_TEXTURE_2D, color_surface->max_level + 1, temp_tex.CopyFrom(color_surface->texture, GL_TEXTURE_2D, color_surface->max_level + 1,

View File

@ -9,10 +9,10 @@
#include "video_core/rasterizer_accelerated.h" #include "video_core/rasterizer_accelerated.h"
#include "video_core/regs_lighting.h" #include "video_core/regs_lighting.h"
#include "video_core/regs_texturing.h" #include "video_core/regs_texturing.h"
#include "video_core/renderer_opengl/gl_texture_runtime.h"
#include "video_core/renderer_opengl/gl_shader_manager.h" #include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_stream_buffer.h" #include "video_core/renderer_opengl/gl_stream_buffer.h"
#include "video_core/renderer_opengl/gl_texture_runtime.h"
#include "video_core/shader/shader.h" #include "video_core/shader/shader.h"
namespace Frontend { namespace Frontend {

View File

@ -4,8 +4,8 @@
#pragma once #pragma once
#include <utility>
#include <string_view> #include <string_view>
#include <utility>
#include <vector> #include <vector>
#include <glad/glad.h> #include <glad/glad.h>
#include "common/common_types.h" #include "common/common_types.h"

View File

@ -25,7 +25,8 @@ GLuint LoadShader(const char* source, GLenum type) {
#if defined(GL_EXT_clip_cull_distance) #if defined(GL_EXT_clip_cull_distance)
#extension GL_EXT_clip_cull_distance : enable #extension GL_EXT_clip_cull_distance : enable
#endif #endif
)" : "#version 430 core\n"; )"
: "#version 430 core\n";
const char* debug_type; const char* debug_type;
switch (type) { switch (type) {

View File

@ -4,10 +4,10 @@
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "video_core/rasterizer_cache/utils.h" #include "video_core/rasterizer_cache/utils.h"
#include "video_core/renderer_opengl/gl_texture_runtime.h"
#include "video_core/renderer_opengl/gl_driver.h" #include "video_core/renderer_opengl/gl_driver.h"
#include "video_core/renderer_opengl/gl_format_reinterpreter.h" #include "video_core/renderer_opengl/gl_format_reinterpreter.h"
#include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_texture_runtime.h"
namespace OpenGL { namespace OpenGL {
@ -15,8 +15,7 @@ constexpr FormatTuple DEFAULT_TUPLE = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
static constexpr std::array DEPTH_TUPLES = { static constexpr std::array DEPTH_TUPLES = {
FormatTuple{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16 FormatTuple{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16
FormatTuple{}, FormatTuple{}, FormatTuple{GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}, // D24
FormatTuple{GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}, // D24
FormatTuple{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24S8 FormatTuple{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24S8
}; };
@ -54,13 +53,14 @@ GLbitfield MakeBufferMask(VideoCore::SurfaceType type) {
} }
TextureRuntime::TextureRuntime(Driver& driver) TextureRuntime::TextureRuntime(Driver& driver)
: driver{driver}, downloader_es{false}, : driver{driver}, downloader_es{false}, filterer{Settings::values.texture_filter_name,
filterer{Settings::values.texture_filter_name, VideoCore::GetResolutionScaleFactor()}{ VideoCore::GetResolutionScaleFactor()} {
read_fbo.Create(); read_fbo.Create();
draw_fbo.Create(); draw_fbo.Create();
auto Register = [this](VideoCore::PixelFormat dest, std::unique_ptr<FormatReinterpreterBase>&& obj) { auto Register = [this](VideoCore::PixelFormat dest,
std::unique_ptr<FormatReinterpreterBase>&& obj) {
const u32 dst_index = static_cast<u32>(dest); const u32 dst_index = static_cast<u32>(dest);
return reinterpreters[dst_index].push_back(std::move(obj)); return reinterpreters[dst_index].push_back(std::move(obj));
}; };
@ -90,17 +90,19 @@ const StagingBuffer& TextureRuntime::FindStaging(u32 size, bool upload) {
// Allocate a new buffer and map the data to the host // Allocate a new buffer and map the data to the host
std::byte* data = nullptr; std::byte* data = nullptr;
if (driver.IsOpenGLES() && driver.HasExtBufferStorage()) { if (driver.IsOpenGLES() && driver.HasExtBufferStorage()) {
const GLbitfield storage = upload ? GL_MAP_WRITE_BIT : GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT_EXT; const GLbitfield storage =
glBufferStorageEXT(target, size, nullptr, storage | GL_MAP_PERSISTENT_BIT_EXT | upload ? GL_MAP_WRITE_BIT : GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT_EXT;
GL_MAP_COHERENT_BIT_EXT); glBufferStorageEXT(target, size, nullptr,
data = reinterpret_cast<std::byte*>(glMapBufferRange(target, 0, size, access | GL_MAP_PERSISTENT_BIT_EXT | storage | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
GL_MAP_COHERENT_BIT_EXT)); data = reinterpret_cast<std::byte*>(glMapBufferRange(
target, 0, size, access | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT));
} else if (driver.HasArbBufferStorage()) { } else if (driver.HasArbBufferStorage()) {
const GLbitfield storage = upload ? GL_MAP_WRITE_BIT : GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT; const GLbitfield storage =
glBufferStorage(target, size, nullptr, storage | GL_MAP_PERSISTENT_BIT | upload ? GL_MAP_WRITE_BIT : GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT;
GL_MAP_COHERENT_BIT); glBufferStorage(target, size, nullptr,
data = reinterpret_cast<std::byte*>(glMapBufferRange(target, 0, size, access | GL_MAP_PERSISTENT_BIT | storage | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
GL_MAP_COHERENT_BIT)); data = reinterpret_cast<std::byte*>(glMapBufferRange(
target, 0, size, access | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT));
} else { } else {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
@ -108,10 +110,7 @@ const StagingBuffer& TextureRuntime::FindStaging(u32 size, bool upload) {
glBindBuffer(target, 0); glBindBuffer(target, 0);
StagingBuffer staging = { StagingBuffer staging = {
.buffer = std::move(buffer), .buffer = std::move(buffer), .mapped = std::span{data, size}, .size = size};
.mapped = std::span{data, size},
.size = size
};
const auto& it = search.emplace(std::move(staging)); const auto& it = search.emplace(std::move(staging));
return *it; return *it;
@ -134,8 +133,8 @@ const FormatTuple& TextureRuntime::GetFormatTuple(VideoCore::PixelFormat pixel_f
return DEFAULT_TUPLE; return DEFAULT_TUPLE;
} }
void TextureRuntime::FormatConvert(const Surface& surface, bool upload, void TextureRuntime::FormatConvert(const Surface& surface, bool upload, std::span<std::byte> source,
std::span<std::byte> source, std::span<std::byte> dest) { std::span<std::byte> dest) {
const VideoCore::PixelFormat format = surface.pixel_format; const VideoCore::PixelFormat format = surface.pixel_format;
if (format == VideoCore::PixelFormat::RGBA8 && driver.IsOpenGLES()) { if (format == VideoCore::PixelFormat::RGBA8 && driver.IsOpenGLES()) {
return Pica::Texture::ConvertABGRToRGBA(source, dest); return Pica::Texture::ConvertABGRToRGBA(source, dest);
@ -153,11 +152,7 @@ OGLTexture TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
const GLenum target = const GLenum target =
type == VideoCore::TextureType::CubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; type == VideoCore::TextureType::CubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
const VideoCore::HostTextureTag key = { const VideoCore::HostTextureTag key = {
.format = format, .format = format, .width = width, .height = height, .layers = layers};
.width = width,
.height = height,
.layers = layers
};
// Attempt to recycle an unused texture // Attempt to recycle an unused texture
if (auto it = texture_recycler.find(key); it != texture_recycler.end()) { if (auto it = texture_recycler.find(key); it != texture_recycler.end()) {
@ -177,8 +172,8 @@ OGLTexture TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(target, texture.handle); glBindTexture(target, texture.handle);
glTexStorage2D(target, std::bit_width(std::max(width, height)), glTexStorage2D(target, std::bit_width(std::max(width, height)), tuple.internal_format, width,
tuple.internal_format, width, height); height);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -250,23 +245,22 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
return true; return true;
} }
bool TextureRuntime::CopyTextures(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy) { bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
const VideoCore::TextureCopy& copy) {
// Emulate texture copy with blit for now // Emulate texture copy with blit for now
const VideoCore::TextureBlit blit = { const VideoCore::TextureBlit blit = {
.src_level = copy.src_level, .src_level = copy.src_level,
.dst_level = copy.dst_level, .dst_level = copy.dst_level,
.src_layer = copy.src_layer, .src_layer = copy.src_layer,
.dst_layer = copy.dst_layer, .dst_layer = copy.dst_layer,
.src_rect = {copy.src_offset.x, copy.extent.height, .src_rect = {copy.src_offset.x, copy.extent.height, copy.extent.width, copy.src_offset.x},
copy.extent.width, copy.src_offset.x}, .dst_rect = {copy.dst_offset.x, copy.extent.height, copy.extent.width, copy.dst_offset.x}};
.dst_rect = {copy.dst_offset.x, copy.extent.height,
copy.extent.width, copy.dst_offset.x}
};
return BlitTextures(source, dest, blit); return BlitTextures(source, dest, blit);
} }
bool TextureRuntime::BlitTextures(Surface& source, Surface& dest, const VideoCore::TextureBlit& blit) { bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
const VideoCore::TextureBlit& blit) {
OpenGLState prev_state = OpenGLState::GetCurState(); OpenGLState prev_state = OpenGLState::GetCurState();
SCOPE_EXIT({ prev_state.Apply(); }); SCOPE_EXIT({ prev_state.Apply(); });
@ -275,12 +269,15 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest, const VideoCor
state.draw.draw_framebuffer = draw_fbo.handle; state.draw.draw_framebuffer = draw_fbo.handle;
state.Apply(); state.Apply();
const GLenum src_textarget = source.texture_type == VideoCore::TextureType::CubeMap ? const GLenum src_textarget = source.texture_type == VideoCore::TextureType::CubeMap
GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.src_layer : GL_TEXTURE_2D; ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.src_layer
BindFramebuffer(GL_READ_FRAMEBUFFER, blit.src_level, src_textarget, source.type, source.texture); : GL_TEXTURE_2D;
BindFramebuffer(GL_READ_FRAMEBUFFER, blit.src_level, src_textarget, source.type,
source.texture);
const GLenum dst_textarget = dest.texture_type == VideoCore::TextureType::CubeMap ? const GLenum dst_textarget = dest.texture_type == VideoCore::TextureType::CubeMap
GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.dst_layer : GL_TEXTURE_2D; ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.dst_layer
: GL_TEXTURE_2D;
BindFramebuffer(GL_DRAW_FRAMEBUFFER, blit.dst_level, dst_textarget, dest.type, dest.texture); BindFramebuffer(GL_DRAW_FRAMEBUFFER, blit.dst_level, dst_textarget, dest.type, dest.texture);
// TODO (wwylele): use GL_NEAREST for shadow map texture // TODO (wwylele): use GL_NEAREST for shadow map texture
@ -290,9 +287,9 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest, const VideoCor
// inconsistent scale. // inconsistent scale.
const GLbitfield buffer_mask = MakeBufferMask(source.type); const GLbitfield buffer_mask = MakeBufferMask(source.type);
const GLenum filter = buffer_mask == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST; const GLenum filter = buffer_mask == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST;
glBlitFramebuffer(blit.src_rect.left, blit.src_rect.bottom, blit.src_rect.right, blit.src_rect.top, glBlitFramebuffer(blit.src_rect.left, blit.src_rect.bottom, blit.src_rect.right,
blit.dst_rect.left, blit.dst_rect.bottom, blit.dst_rect.right, blit.dst_rect.top, blit.src_rect.top, blit.dst_rect.left, blit.dst_rect.bottom,
buffer_mask, filter); blit.dst_rect.right, blit.dst_rect.top, buffer_mask, filter);
return true; return true;
} }
@ -310,7 +307,8 @@ void TextureRuntime::GenerateMipmaps(Surface& surface, u32 max_level) {
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
} }
const ReinterpreterList& TextureRuntime::GetPossibleReinterpretations(VideoCore::PixelFormat dest_format) const { const ReinterpreterList& TextureRuntime::GetPossibleReinterpretations(
VideoCore::PixelFormat dest_format) const {
return reinterpreters[static_cast<u32>(dest_format)]; return reinterpreters[static_cast<u32>(dest_format)];
} }
@ -332,7 +330,8 @@ void TextureRuntime::BindFramebuffer(GLenum target, GLint level, GLenum textarge
break; break;
case VideoCore::SurfaceType::DepthStencil: case VideoCore::SurfaceType::DepthStencil:
glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0, textarget, 0, 0); glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0, textarget, 0, 0);
glFramebufferTexture2D(target, GL_DEPTH_STENCIL_ATTACHMENT, textarget, texture.handle, level); glFramebufferTexture2D(target, GL_DEPTH_STENCIL_ATTACHMENT, textarget, texture.handle,
level);
break; break;
default: default:
UNREACHABLE_MSG("Invalid surface type!"); UNREACHABLE_MSG("Invalid surface type!");
@ -342,7 +341,8 @@ void TextureRuntime::BindFramebuffer(GLenum target, GLint level, GLenum textarge
Surface::Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime) Surface::Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime)
: VideoCore::SurfaceBase<Surface>{params}, runtime{runtime}, driver{runtime.GetDriver()} { : VideoCore::SurfaceBase<Surface>{params}, runtime{runtime}, driver{runtime.GetDriver()} {
if (pixel_format != VideoCore::PixelFormat::Invalid) { if (pixel_format != VideoCore::PixelFormat::Invalid) {
texture = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), params.pixel_format, texture_type); texture = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), params.pixel_format,
texture_type);
} }
} }
@ -352,8 +352,7 @@ Surface::~Surface() {
.format = pixel_format, .format = pixel_format,
.width = GetScaledWidth(), .width = GetScaledWidth(),
.height = GetScaledHeight(), .height = GetScaledHeight(),
.layers = texture_type == VideoCore::TextureType::CubeMap ? 6u : 1u .layers = texture_type == VideoCore::TextureType::CubeMap ? 6u : 1u};
};
runtime.texture_recycler.emplace(tag, std::move(texture)); runtime.texture_recycler.emplace(tag, std::move(texture));
} }
@ -380,11 +379,9 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingBu
glBindTexture(GL_TEXTURE_2D, texture.handle); glBindTexture(GL_TEXTURE_2D, texture.handle);
const auto& tuple = runtime.GetFormatTuple(pixel_format); const auto& tuple = runtime.GetFormatTuple(pixel_format);
glTexSubImage2D(GL_TEXTURE_2D, upload.texture_level, glTexSubImage2D(GL_TEXTURE_2D, upload.texture_level, upload.texture_rect.left,
upload.texture_rect.left, upload.texture_rect.bottom, upload.texture_rect.bottom, upload.texture_rect.GetWidth(),
upload.texture_rect.GetWidth(), upload.texture_rect.GetHeight(), tuple.format, tuple.type, 0);
upload.texture_rect.GetHeight(),
tuple.format, tuple.type, 0);
} }
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
@ -412,7 +409,8 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
if (is_scaled) { if (is_scaled) {
ScaledDownload(download); ScaledDownload(download);
} else { } else {
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type, texture); runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type,
texture);
const auto& tuple = runtime.GetFormatTuple(pixel_format); const auto& tuple = runtime.GetFormatTuple(pixel_format);
glReadPixels(download.texture_rect.left, download.texture_rect.bottom, glReadPixels(download.texture_rect.left, download.texture_rect.bottom,
@ -429,15 +427,16 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download) {
const u32 rect_height = download.texture_rect.GetHeight(); const u32 rect_height = download.texture_rect.GetHeight();
// Allocate an unscaled texture that fits the download rectangle to use as a blit destination // Allocate an unscaled texture that fits the download rectangle to use as a blit destination
OGLTexture unscaled_tex = runtime.Allocate(rect_width, rect_height, pixel_format, OGLTexture unscaled_tex =
VideoCore::TextureType::Texture2D); runtime.Allocate(rect_width, rect_height, pixel_format, VideoCore::TextureType::Texture2D);
runtime.BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0, GL_TEXTURE_2D, type, unscaled_tex); runtime.BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0, GL_TEXTURE_2D, type, unscaled_tex);
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type, texture); runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type,
texture);
// Blit the scaled rectangle to the unscaled texture // Blit the scaled rectangle to the unscaled texture
const VideoCore::Rect2D scaled_rect = download.texture_rect * res_scale; const VideoCore::Rect2D scaled_rect = download.texture_rect * res_scale;
glBlitFramebuffer(scaled_rect.left, scaled_rect.bottom, scaled_rect.right, scaled_rect.top, glBlitFramebuffer(scaled_rect.left, scaled_rect.bottom, scaled_rect.right, scaled_rect.top, 0,
0, 0, rect_width, rect_height, MakeBufferMask(type), GL_LINEAR); 0, rect_width, rect_height, MakeBufferMask(type), GL_LINEAR);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, unscaled_tex.handle); glBindTexture(GL_TEXTURE_2D, unscaled_tex.handle);
@ -445,8 +444,8 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download) {
const auto& tuple = runtime.GetFormatTuple(pixel_format); const auto& tuple = runtime.GetFormatTuple(pixel_format);
if (driver.IsOpenGLES()) { if (driver.IsOpenGLES()) {
const auto& downloader_es = runtime.GetDownloaderES(); const auto& downloader_es = runtime.GetDownloaderES();
downloader_es.GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, downloader_es.GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, rect_height,
rect_height, rect_width, 0); rect_width, 0);
} else { } else {
glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, 0); glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, 0);
} }
@ -456,8 +455,8 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload) {
const u32 rect_width = upload.texture_rect.GetWidth(); const u32 rect_width = upload.texture_rect.GetWidth();
const u32 rect_height = upload.texture_rect.GetHeight(); const u32 rect_height = upload.texture_rect.GetHeight();
OGLTexture unscaled_tex = runtime.Allocate(rect_width, rect_height, pixel_format, OGLTexture unscaled_tex =
VideoCore::TextureType::Texture2D); runtime.Allocate(rect_width, rect_height, pixel_format, VideoCore::TextureType::Texture2D);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, unscaled_tex.handle); glBindTexture(GL_TEXTURE_2D, unscaled_tex.handle);
@ -470,13 +469,13 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload) {
const auto& filterer = runtime.GetFilterer(); const auto& filterer = runtime.GetFilterer();
if (!filterer.Filter(unscaled_tex, unscaled_rect, texture, scaled_rect, type)) { if (!filterer.Filter(unscaled_tex, unscaled_rect, texture, scaled_rect, type)) {
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, 0, GL_TEXTURE_2D, type, unscaled_tex); runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, 0, GL_TEXTURE_2D, type, unscaled_tex);
runtime.BindFramebuffer(GL_DRAW_FRAMEBUFFER, upload.texture_level, GL_TEXTURE_2D, type, texture); runtime.BindFramebuffer(GL_DRAW_FRAMEBUFFER, upload.texture_level, GL_TEXTURE_2D, type,
texture);
// If filtering fails, resort to normal blitting // If filtering fails, resort to normal blitting
glBlitFramebuffer(0, 0, rect_width, rect_height, glBlitFramebuffer(0, 0, rect_width, rect_height, upload.texture_rect.left,
upload.texture_rect.left, upload.texture_rect.bottom, upload.texture_rect.bottom, upload.texture_rect.right,
upload.texture_rect.right, upload.texture_rect.top, upload.texture_rect.top, MakeBufferMask(type), GL_LINEAR);
MakeBufferMask(type), GL_LINEAR);
} }
} }

View File

@ -3,13 +3,13 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <span>
#include <set> #include <set>
#include <span>
#include "video_core/rasterizer_cache/rasterizer_cache.h" #include "video_core/rasterizer_cache/rasterizer_cache.h"
#include "video_core/rasterizer_cache/surface_base.h" #include "video_core/rasterizer_cache/surface_base.h"
#include "video_core/renderer_opengl/gl_format_reinterpreter.h" #include "video_core/renderer_opengl/gl_format_reinterpreter.h"
#include "video_core/renderer_opengl/texture_filters/texture_filterer.h"
#include "video_core/renderer_opengl/texture_downloader_es.h" #include "video_core/renderer_opengl/texture_downloader_es.h"
#include "video_core/renderer_opengl/texture_filters/texture_filterer.h"
namespace OpenGL { namespace OpenGL {
@ -59,6 +59,7 @@ class Surface;
*/ */
class TextureRuntime { class TextureRuntime {
friend class Surface; friend class Surface;
public: public:
TextureRuntime(Driver& driver); TextureRuntime(Driver& driver);
~TextureRuntime() = default; ~TextureRuntime() = default;
@ -72,8 +73,8 @@ public:
void Finish() const {} void Finish() const {}
/// Performs required format convertions on the staging data /// Performs required format convertions on the staging data
void FormatConvert(const Surface& surface, bool upload, void FormatConvert(const Surface& surface, bool upload, std::span<std::byte> source,
std::span<std::byte> source, std::span<std::byte> dest); std::span<std::byte> dest);
/// Allocates an OpenGL texture with the specified dimentions and format /// Allocates an OpenGL texture with the specified dimentions and format
OGLTexture Allocate(u32 width, u32 height, VideoCore::PixelFormat format, OGLTexture Allocate(u32 width, u32 height, VideoCore::PixelFormat format,
@ -98,8 +99,8 @@ public:
private: private:
/// Returns the framebuffer used for texture downloads /// Returns the framebuffer used for texture downloads
void BindFramebuffer(GLenum target, GLint level, GLenum textarget, void BindFramebuffer(GLenum target, GLint level, GLenum textarget, VideoCore::SurfaceType type,
VideoCore::SurfaceType type, OGLTexture& texture) const; OGLTexture& texture) const;
/// Returns the OpenGL driver class /// Returns the OpenGL driver class
const Driver& GetDriver() const { const Driver& GetDriver() const {

View File

@ -7,8 +7,8 @@
#include <array> #include <array>
#include "core/hw/gpu.h" #include "core/hw/gpu.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "video_core/renderer_opengl/gl_driver.h"
#include "video_core/renderer_opengl/frame_dumper_opengl.h" #include "video_core/renderer_opengl/frame_dumper_opengl.h"
#include "video_core/renderer_opengl/gl_driver.h"
#include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_opengl/gl_state.h"

View File

@ -18,8 +18,7 @@ namespace OpenGL {
static constexpr std::array DEPTH_TUPLES_HACK = { static constexpr std::array DEPTH_TUPLES_HACK = {
FormatTuple{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16 FormatTuple{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16
FormatTuple{}, FormatTuple{}, FormatTuple{GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}, // D24
FormatTuple{GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}, // D24
FormatTuple{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24S8 FormatTuple{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24S8
}; };

View File

@ -12,6 +12,7 @@ class OpenGLState;
class TextureDownloaderES { class TextureDownloaderES {
static constexpr u16 MAX_SIZE = 1024; static constexpr u16 MAX_SIZE = 1024;
public: public:
TextureDownloaderES(bool enable_depth_stencil); TextureDownloaderES(bool enable_depth_stencil);
@ -22,16 +23,16 @@ public:
* Depth texture download assumes that the texture's format tuple matches what is found * Depth texture download assumes that the texture's format tuple matches what is found
* OpenGL::depth_format_tuples * OpenGL::depth_format_tuples
*/ */
void GetTexImage(GLenum target, GLuint level, GLenum format, const GLenum type, void GetTexImage(GLenum target, GLuint level, GLenum format, const GLenum type, GLint height,
GLint height, GLint width, void* pixels) const; GLint width, void* pixels) const;
private: private:
/** /**
* OpenGL ES does not support glReadBuffer for depth/stencil formats. * OpenGL ES does not support glReadBuffer for depth/stencil formats.
* This gets around it by converting to a Red surface before downloading * This gets around it by converting to a Red surface before downloading
*/ */
GLuint ConvertDepthToColor(GLuint level, GLenum& format, GLenum& type, GLuint ConvertDepthToColor(GLuint level, GLenum& format, GLenum& type, GLint height,
GLint height, GLint width) const; GLint width) const;
/// Self tests for the texture downloader /// Self tests for the texture downloader
void Test(); void Test();

View File

@ -63,7 +63,8 @@ bool TextureFilterer::Filter(const OGLTexture& src_tex, Common::Rectangle<u32> s
VideoCore::SurfaceType type) const { VideoCore::SurfaceType type) const {
// Depth/Stencil texture filtering is not supported for now // Depth/Stencil texture filtering is not supported for now
if (IsNull() || (type != VideoCore::SurfaceType::Color && type != VideoCore::SurfaceType::Texture)) { if (IsNull() ||
(type != VideoCore::SurfaceType::Color && type != VideoCore::SurfaceType::Texture)) {
return false; return false;
} }

View File

@ -19,15 +19,10 @@ struct FilterInfo {
}; };
inline FilterInfo TextureFilterMode(TextureFilter mag, TextureFilter min, TextureFilter mip) { inline FilterInfo TextureFilterMode(TextureFilter mag, TextureFilter min, TextureFilter mip) {
constexpr std::array filter_table = { constexpr std::array filter_table = {vk::Filter::eNearest, vk::Filter::eLinear};
vk::Filter::eNearest,
vk::Filter::eLinear
};
constexpr std::array mipmap_table = { constexpr std::array mipmap_table = {vk::SamplerMipmapMode::eNearest,
vk::SamplerMipmapMode::eNearest, vk::SamplerMipmapMode::eLinear};
vk::SamplerMipmapMode::eLinear
};
return FilterInfo{filter_table.at(mag), filter_table.at(min), mipmap_table.at(mip)}; return FilterInfo{filter_table.at(mag), filter_table.at(min), mipmap_table.at(mip)};
} }
@ -281,4 +276,4 @@ inline Common::Vec3f LightColor(const Pica::LightingRegs::LightColor& color) {
return Common::Vec3u{color.r, color.g, color.b} / 255.0f; return Common::Vec3u{color.r, color.g, color.b} / 255.0f;
} }
} // namespace PicaToGL } // namespace PicaToVK

View File

@ -140,12 +140,11 @@ void main() {
} }
)"; )";
/// Vertex structure that the drawn screen rectangles are composed of. /// Vertex structure that the drawn screen rectangles are composed of.
struct ScreenRectVertex { struct ScreenRectVertex {
ScreenRectVertex() = default; ScreenRectVertex() = default;
ScreenRectVertex(float x, float y, float u, float v) : ScreenRectVertex(float x, float y, float u, float v)
position{Common::MakeVec(x, y)}, tex_coord{Common::MakeVec(u, v)} {} : position{Common::MakeVec(x, y)}, tex_coord{Common::MakeVec(u, v)} {}
Common::Vec2f position; Common::Vec2f position;
Common::Vec2f tex_coord; Common::Vec2f tex_coord;
@ -154,11 +153,12 @@ struct ScreenRectVertex {
constexpr u32 VERTEX_BUFFER_SIZE = sizeof(ScreenRectVertex) * 8192; constexpr u32 VERTEX_BUFFER_SIZE = sizeof(ScreenRectVertex) * 8192;
RendererVulkan::RendererVulkan(Frontend::EmuWindow& window) RendererVulkan::RendererVulkan(Frontend::EmuWindow& window)
: RendererBase{window}, instance{window, Settings::values.physical_device, Settings::values.renderer_debug}, : RendererBase{window}, instance{window, Settings::values.physical_device,
scheduler{instance, *this}, Settings::values.renderer_debug},
renderpass_cache{instance, scheduler}, runtime{instance, scheduler, renderpass_cache}, scheduler{instance, *this}, renderpass_cache{instance, scheduler},
swapchain{instance, renderpass_cache}, runtime{instance, scheduler, renderpass_cache}, swapchain{instance, renderpass_cache},
vertex_buffer{instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}} { vertex_buffer{
instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}} {
auto& telemetry_session = Core::System::GetInstance().TelemetrySession(); auto& telemetry_session = Core::System::GetInstance().TelemetrySession();
constexpr auto user_system = Common::Telemetry::FieldType::UserSystem; constexpr auto user_system = Common::Telemetry::FieldType::UserSystem;
@ -192,8 +192,7 @@ RendererVulkan::~RendererVulkan() {
.format = VideoCore::PixelFormatFromGPUPixelFormat(info.texture.format), .format = VideoCore::PixelFormatFromGPUPixelFormat(info.texture.format),
.width = info.texture.width, .width = info.texture.width,
.height = info.texture.height, .height = info.texture.height,
.layers = 1 .layers = 1};
};
runtime.Recycle(tag, std::move(info.texture.alloc)); runtime.Recycle(tag, std::move(info.texture.alloc));
} }
@ -207,8 +206,8 @@ VideoCore::ResultStatus RendererVulkan::Init() {
BuildPipelines(); BuildPipelines();
// Create the rasterizer // Create the rasterizer
rasterizer = std::make_unique<RasterizerVulkan>(render_window, instance, scheduler, rasterizer = std::make_unique<RasterizerVulkan>(render_window, instance, scheduler, runtime,
runtime, renderpass_cache); renderpass_cache);
return VideoCore::ResultStatus::Success; return VideoCore::ResultStatus::Success;
} }
@ -237,13 +236,8 @@ void RendererVulkan::PrepareRendertarget() {
if (color_fill.is_enabled) { if (color_fill.is_enabled) {
const vk::ClearColorValue clear_color = { const vk::ClearColorValue clear_color = {
.float32 = std::array{ .float32 = std::array{color_fill.color_r / 255.0f, color_fill.color_g / 255.0f,
color_fill.color_r / 255.0f, color_fill.color_b / 255.0f, 1.0f}};
color_fill.color_g / 255.0f,
color_fill.color_b / 255.0f,
1.0f
}
};
const vk::ImageSubresourceRange range = { const vk::ImageSubresourceRange range = {
.aspectMask = vk::ImageAspectFlagBits::eColor, .aspectMask = vk::ImageAspectFlagBits::eColor,
@ -255,9 +249,10 @@ void RendererVulkan::PrepareRendertarget() {
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
TextureInfo& texture = screen_infos[i].texture; TextureInfo& texture = screen_infos[i].texture;
runtime.Transition(command_buffer, texture.alloc, vk::ImageLayout::eTransferDstOptimal, 0, texture.alloc.levels); runtime.Transition(command_buffer, texture.alloc, vk::ImageLayout::eTransferDstOptimal,
command_buffer.clearColorImage(texture.alloc.image, vk::ImageLayout::eTransferDstOptimal, 0, texture.alloc.levels);
clear_color, range); command_buffer.clearColorImage(
texture.alloc.image, vk::ImageLayout::eTransferDstOptimal, clear_color, range);
} else { } else {
TextureInfo& texture = screen_infos[i].texture; TextureInfo& texture = screen_infos[i].texture;
if (texture.width != framebuffer.width || texture.height != framebuffer.height || if (texture.width != framebuffer.width || texture.height != framebuffer.height ||
@ -280,7 +275,8 @@ void RendererVulkan::PrepareRendertarget() {
void RendererVulkan::BeginRendering() { void RendererVulkan::BeginRendering() {
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, present_pipelines[current_pipeline]); command_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics,
present_pipelines[current_pipeline]);
std::array<vk::DescriptorImageInfo, 4> present_textures; std::array<vk::DescriptorImageInfo, 4> present_textures;
for (std::size_t i = 0; i < screen_infos.size(); i++) { for (std::size_t i = 0; i < screen_infos.size(); i++) {
@ -288,38 +284,29 @@ void RendererVulkan::BeginRendering() {
present_textures[i] = vk::DescriptorImageInfo{ present_textures[i] = vk::DescriptorImageInfo{
.imageView = info.display_texture ? info.display_texture->image_view .imageView = info.display_texture ? info.display_texture->image_view
: info.texture.alloc.image_view, : info.texture.alloc.image_view,
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal .imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal};
};
} }
present_textures[3] = vk::DescriptorImageInfo{ present_textures[3] = vk::DescriptorImageInfo{.sampler = present_samplers[current_sampler]};
.sampler = present_samplers[current_sampler]
};
const vk::DescriptorSetAllocateInfo alloc_info = { const vk::DescriptorSetAllocateInfo alloc_info = {.descriptorPool =
.descriptorPool = scheduler.GetDescriptorPool(), scheduler.GetDescriptorPool(),
.descriptorSetCount = 1, .descriptorSetCount = 1,
.pSetLayouts = &present_descriptor_layout .pSetLayouts = &present_descriptor_layout};
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
vk::DescriptorSet set = device.allocateDescriptorSets(alloc_info)[0]; vk::DescriptorSet set = device.allocateDescriptorSets(alloc_info)[0];
device.updateDescriptorSetWithTemplate(set, present_update_template, present_textures[0]); device.updateDescriptorSetWithTemplate(set, present_update_template, present_textures[0]);
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, present_pipeline_layout, command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, present_pipeline_layout, 0,
0, 1, &set, 0, nullptr); 1, &set, 0, nullptr);
const vk::ClearValue clear_value = { const vk::ClearValue clear_value = {.color = clear_color};
.color = clear_color
};
const vk::RenderPassBeginInfo begin_info = { const vk::RenderPassBeginInfo begin_info = {
.renderPass = renderpass_cache.GetPresentRenderpass(), .renderPass = renderpass_cache.GetPresentRenderpass(),
.framebuffer = swapchain.GetFramebuffer(), .framebuffer = swapchain.GetFramebuffer(),
.renderArea = vk::Rect2D{ .renderArea = vk::Rect2D{.offset = {0, 0}, .extent = swapchain.GetExtent()},
.offset = {0, 0},
.extent = swapchain.GetExtent()
},
.clearValueCount = 1, .clearValueCount = 1,
.pClearValues = &clear_value, .pClearValues = &clear_value,
}; };
@ -352,7 +339,8 @@ void RendererVulkan::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
// only allows rows to have a memory alignement of 4. // only allows rows to have a memory alignement of 4.
ASSERT(pixel_stride % 4 == 0); ASSERT(pixel_stride % 4 == 0);
if (!rasterizer->AccelerateDisplay(framebuffer, framebuffer_addr, static_cast<u32>(pixel_stride), screen_info)) { if (!rasterizer->AccelerateDisplay(framebuffer, framebuffer_addr,
static_cast<u32>(pixel_stride), screen_info)) {
ASSERT(false); ASSERT(false);
// Reset the screen info's display texture to its own permanent texture // Reset the screen info's display texture to its own permanent texture
/*screen_info.display_texture = &screen_info.texture; /*screen_info.display_texture = &screen_info.texture;
@ -370,10 +358,10 @@ void RendererVulkan::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
void RendererVulkan::CompileShaders() { void RendererVulkan::CompileShaders() {
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
present_vertex_shader = Compile(vertex_shader, vk::ShaderStageFlagBits::eVertex, present_vertex_shader =
device, ShaderOptimization::Debug); Compile(vertex_shader, vk::ShaderStageFlagBits::eVertex, device, ShaderOptimization::Debug);
present_shaders[0] = Compile(fragment_shader, vk::ShaderStageFlagBits::eFragment, present_shaders[0] = Compile(fragment_shader, vk::ShaderStageFlagBits::eFragment, device,
device, ShaderOptimization::Debug); ShaderOptimization::Debug);
present_shaders[1] = Compile(fragment_shader_anaglyph, vk::ShaderStageFlagBits::eFragment, present_shaders[1] = Compile(fragment_shader_anaglyph, vk::ShaderStageFlagBits::eFragment,
device, ShaderOptimization::Debug); device, ShaderOptimization::Debug);
present_shaders[2] = Compile(fragment_shader_interlaced, vk::ShaderStageFlagBits::eFragment, present_shaders[2] = Compile(fragment_shader_interlaced, vk::ShaderStageFlagBits::eFragment,
@ -393,8 +381,7 @@ void RendererVulkan::CompileShaders() {
.compareEnable = false, .compareEnable = false,
.compareOp = vk::CompareOp::eAlways, .compareOp = vk::CompareOp::eAlways,
.borderColor = vk::BorderColor::eIntOpaqueBlack, .borderColor = vk::BorderColor::eIntOpaqueBlack,
.unnormalizedCoordinates = false .unnormalizedCoordinates = false};
};
present_samplers[i] = device.createSampler(sampler_info); present_samplers[i] = device.createSampler(sampler_info);
} }
@ -402,53 +389,41 @@ void RendererVulkan::CompileShaders() {
void RendererVulkan::BuildLayouts() { void RendererVulkan::BuildLayouts() {
const std::array present_layout_bindings = { const std::array present_layout_bindings = {
vk::DescriptorSetLayoutBinding{ vk::DescriptorSetLayoutBinding{.binding = 0,
.binding = 0,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.descriptorCount = 3, .descriptorCount = 3,
.stageFlags = vk::ShaderStageFlagBits::eFragment .stageFlags = vk::ShaderStageFlagBits::eFragment},
}, vk::DescriptorSetLayoutBinding{.binding = 1,
vk::DescriptorSetLayoutBinding{
.binding = 1,
.descriptorType = vk::DescriptorType::eSampler, .descriptorType = vk::DescriptorType::eSampler,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eFragment .stageFlags = vk::ShaderStageFlagBits::eFragment}};
}
};
const vk::DescriptorSetLayoutCreateInfo present_layout_info = { const vk::DescriptorSetLayoutCreateInfo present_layout_info = {
.bindingCount = static_cast<u32>(present_layout_bindings.size()), .bindingCount = static_cast<u32>(present_layout_bindings.size()),
.pBindings = present_layout_bindings.data() .pBindings = present_layout_bindings.data()};
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
present_descriptor_layout = device.createDescriptorSetLayout(present_layout_info); present_descriptor_layout = device.createDescriptorSetLayout(present_layout_info);
const std::array update_template_entries = { const std::array update_template_entries = {
vk::DescriptorUpdateTemplateEntry{ vk::DescriptorUpdateTemplateEntry{.dstBinding = 0,
.dstBinding = 0,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 3, .descriptorCount = 3,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.offset = 0, .offset = 0,
.stride = sizeof(vk::DescriptorImageInfo) .stride = sizeof(vk::DescriptorImageInfo)},
}, vk::DescriptorUpdateTemplateEntry{.dstBinding = 1,
vk::DescriptorUpdateTemplateEntry{
.dstBinding = 1,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampler, .descriptorType = vk::DescriptorType::eSampler,
.offset = 3 * sizeof(vk::DescriptorImageInfo), .offset = 3 * sizeof(vk::DescriptorImageInfo),
.stride = 0 .stride = 0}};
}
};
const vk::DescriptorUpdateTemplateCreateInfo template_info = { const vk::DescriptorUpdateTemplateCreateInfo template_info = {
.descriptorUpdateEntryCount = static_cast<u32>(update_template_entries.size()), .descriptorUpdateEntryCount = static_cast<u32>(update_template_entries.size()),
.pDescriptorUpdateEntries = update_template_entries.data(), .pDescriptorUpdateEntries = update_template_entries.data(),
.templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet, .templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet,
.descriptorSetLayout = present_descriptor_layout .descriptorSetLayout = present_descriptor_layout};
};
present_update_template = device.createDescriptorUpdateTemplate(template_info); present_update_template = device.createDescriptorUpdateTemplate(template_info);
@ -458,49 +433,37 @@ void RendererVulkan::BuildLayouts() {
.size = sizeof(PresentUniformData), .size = sizeof(PresentUniformData),
}; };
const vk::PipelineLayoutCreateInfo layout_info = { const vk::PipelineLayoutCreateInfo layout_info = {.setLayoutCount = 1,
.setLayoutCount = 1,
.pSetLayouts = &present_descriptor_layout, .pSetLayouts = &present_descriptor_layout,
.pushConstantRangeCount = 1, .pushConstantRangeCount = 1,
.pPushConstantRanges = &push_range .pPushConstantRanges = &push_range};
};
present_pipeline_layout = device.createPipelineLayout(layout_info); present_pipeline_layout = device.createPipelineLayout(layout_info);
} }
void RendererVulkan::BuildPipelines() { void RendererVulkan::BuildPipelines() {
const vk::VertexInputBindingDescription binding = { const vk::VertexInputBindingDescription binding = {.binding = 0,
.binding = 0,
.stride = sizeof(ScreenRectVertex), .stride = sizeof(ScreenRectVertex),
.inputRate = vk::VertexInputRate::eVertex .inputRate = vk::VertexInputRate::eVertex};
};
const std::array attributes = { const std::array attributes = {
vk::VertexInputAttributeDescription{ vk::VertexInputAttributeDescription{.location = 0,
.location = 0,
.binding = 0, .binding = 0,
.format = vk::Format::eR32G32Sfloat, .format = vk::Format::eR32G32Sfloat,
.offset = offsetof(ScreenRectVertex, position) .offset = offsetof(ScreenRectVertex, position)},
}, vk::VertexInputAttributeDescription{.location = 1,
vk::VertexInputAttributeDescription{
.location = 1,
.binding = 0, .binding = 0,
.format = vk::Format::eR32G32Sfloat, .format = vk::Format::eR32G32Sfloat,
.offset = offsetof(ScreenRectVertex, tex_coord) .offset = offsetof(ScreenRectVertex, tex_coord)}};
}
};
const vk::PipelineVertexInputStateCreateInfo vertex_input_info = { const vk::PipelineVertexInputStateCreateInfo vertex_input_info = {
.vertexBindingDescriptionCount = 1, .vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = &binding, .pVertexBindingDescriptions = &binding,
.vertexAttributeDescriptionCount = static_cast<u32>(attributes.size()), .vertexAttributeDescriptionCount = static_cast<u32>(attributes.size()),
.pVertexAttributeDescriptions = attributes.data() .pVertexAttributeDescriptions = attributes.data()};
};
const vk::PipelineInputAssemblyStateCreateInfo input_assembly = { const vk::PipelineInputAssemblyStateCreateInfo input_assembly = {
.topology = vk::PrimitiveTopology::eTriangleStrip, .topology = vk::PrimitiveTopology::eTriangleStrip, .primitiveRestartEnable = false};
.primitiveRestartEnable = false
};
const vk::PipelineRasterizationStateCreateInfo raster_state = { const vk::PipelineRasterizationStateCreateInfo raster_state = {
.depthClampEnable = false, .depthClampEnable = false,
@ -508,26 +471,21 @@ void RendererVulkan::BuildPipelines() {
.cullMode = vk::CullModeFlagBits::eNone, .cullMode = vk::CullModeFlagBits::eNone,
.frontFace = vk::FrontFace::eClockwise, .frontFace = vk::FrontFace::eClockwise,
.depthBiasEnable = false, .depthBiasEnable = false,
.lineWidth = 1.0f .lineWidth = 1.0f};
};
const vk::PipelineMultisampleStateCreateInfo multisampling = { const vk::PipelineMultisampleStateCreateInfo multisampling = {
.rasterizationSamples = vk::SampleCountFlagBits::e1, .rasterizationSamples = vk::SampleCountFlagBits::e1, .sampleShadingEnable = false};
.sampleShadingEnable = false
};
const vk::PipelineColorBlendAttachmentState colorblend_attachment = { const vk::PipelineColorBlendAttachmentState colorblend_attachment = {
.blendEnable = false, .blendEnable = false,
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA};
};
const vk::PipelineColorBlendStateCreateInfo color_blending = { const vk::PipelineColorBlendStateCreateInfo color_blending = {
.logicOpEnable = false, .logicOpEnable = false,
.attachmentCount = 1, .attachmentCount = 1,
.pAttachments = &colorblend_attachment, .pAttachments = &colorblend_attachment,
.blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f} .blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f}};
};
const vk::Viewport placeholder_viewport = vk::Viewport{0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; const vk::Viewport placeholder_viewport = vk::Viewport{0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
const vk::Rect2D placeholder_scissor = vk::Rect2D{{0, 0}, {1, 1}}; const vk::Rect2D placeholder_scissor = vk::Rect2D{{0, 0}, {1, 1}};
@ -538,36 +496,27 @@ void RendererVulkan::BuildPipelines() {
.pScissors = &placeholder_scissor, .pScissors = &placeholder_scissor,
}; };
const std::array dynamic_states = { const std::array dynamic_states = {vk::DynamicState::eViewport, vk::DynamicState::eScissor};
vk::DynamicState::eViewport,
vk::DynamicState::eScissor
};
const vk::PipelineDynamicStateCreateInfo dynamic_info = { const vk::PipelineDynamicStateCreateInfo dynamic_info = {
.dynamicStateCount = static_cast<u32>(dynamic_states.size()), .dynamicStateCount = static_cast<u32>(dynamic_states.size()),
.pDynamicStates = dynamic_states.data() .pDynamicStates = dynamic_states.data()};
};
const vk::PipelineDepthStencilStateCreateInfo depth_info = { const vk::PipelineDepthStencilStateCreateInfo depth_info = {.depthTestEnable = false,
.depthTestEnable = false,
.depthWriteEnable = false, .depthWriteEnable = false,
.depthCompareOp = vk::CompareOp::eAlways, .depthCompareOp =
vk::CompareOp::eAlways,
.depthBoundsTestEnable = false, .depthBoundsTestEnable = false,
.stencilTestEnable = false .stencilTestEnable = false};
};
for (u32 i = 0; i < PRESENT_PIPELINES; i++) { for (u32 i = 0; i < PRESENT_PIPELINES; i++) {
const std::array shader_stages = { const std::array shader_stages = {
vk::PipelineShaderStageCreateInfo{ vk::PipelineShaderStageCreateInfo{.stage = vk::ShaderStageFlagBits::eVertex,
.stage = vk::ShaderStageFlagBits::eVertex,
.module = present_vertex_shader, .module = present_vertex_shader,
.pName = "main" .pName = "main"},
}, vk::PipelineShaderStageCreateInfo{.stage = vk::ShaderStageFlagBits::eFragment,
vk::PipelineShaderStageCreateInfo{
.stage = vk::ShaderStageFlagBits::eFragment,
.module = present_shaders[i], .module = present_shaders[i],
.pName = "main" .pName = "main"},
},
}; };
const vk::GraphicsPipelineCreateInfo pipeline_info = { const vk::GraphicsPipelineCreateInfo pipeline_info = {
@ -582,8 +531,7 @@ void RendererVulkan::BuildPipelines() {
.pColorBlendState = &color_blending, .pColorBlendState = &color_blending,
.pDynamicState = &dynamic_info, .pDynamicState = &dynamic_info,
.layout = present_pipeline_layout, .layout = present_pipeline_layout,
.renderPass = renderpass_cache.GetPresentRenderpass() .renderPass = renderpass_cache.GetPresentRenderpass()};
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
if (const auto result = device.createGraphicsPipeline({}, pipeline_info); if (const auto result = device.createGraphicsPipeline({}, pipeline_info);
@ -596,10 +544,12 @@ void RendererVulkan::BuildPipelines() {
} }
} }
void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture, const GPU::Regs::FramebufferConfig& framebuffer) { void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture,
const GPU::Regs::FramebufferConfig& framebuffer) {
TextureInfo old_texture = texture; TextureInfo old_texture = texture;
texture = TextureInfo{ texture = TextureInfo{
.alloc = runtime.Allocate(framebuffer.width, framebuffer.height, .alloc =
runtime.Allocate(framebuffer.width, framebuffer.height,
VideoCore::PixelFormatFromGPUPixelFormat(framebuffer.color_format), VideoCore::PixelFormatFromGPUPixelFormat(framebuffer.color_format),
VideoCore::TextureType::Texture2D), VideoCore::TextureType::Texture2D),
.width = framebuffer.width, .width = framebuffer.width,
@ -607,14 +557,14 @@ void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture, const GPU
.format = framebuffer.color_format, .format = framebuffer.color_format,
}; };
// Recyle the old texture after allocation to avoid having duplicates of the same allocation in the recycler // Recyle the old texture after allocation to avoid having duplicates of the same allocation in
// the recycler
if (old_texture.width != 0 && old_texture.height != 0) { if (old_texture.width != 0 && old_texture.height != 0) {
const VideoCore::HostTextureTag tag = { const VideoCore::HostTextureTag tag = {
.format = VideoCore::PixelFormatFromGPUPixelFormat(old_texture.format), .format = VideoCore::PixelFormatFromGPUPixelFormat(old_texture.format),
.width = old_texture.width, .width = old_texture.width,
.height = old_texture.height, .height = old_texture.height,
.layers = 1 .layers = 1};
};
runtime.Recycle(tag, std::move(old_texture.alloc)); runtime.Recycle(tag, std::move(old_texture.alloc));
} }
@ -665,15 +615,16 @@ void RendererVulkan::DrawSingleScreenRotated(u32 screen_id, float x, float y, fl
const float width = static_cast<float>(screen_info.texture.width); const float width = static_cast<float>(screen_info.texture.width);
const float height = static_cast<float>(screen_info.texture.height); const float height = static_cast<float>(screen_info.texture.height);
draw_info.i_resolution = Common::Vec4f{width * scale_factor, height * scale_factor, draw_info.i_resolution =
1.0f / (width * scale_factor), Common::Vec4f{width * scale_factor, height * scale_factor, 1.0f / (width * scale_factor),
1.0f / (height * scale_factor)}; 1.0f / (height * scale_factor)};
draw_info.o_resolution = Common::Vec4f{h, w, 1.0f / h, 1.0f / w}; draw_info.o_resolution = Common::Vec4f{h, w, 1.0f / h, 1.0f / w};
draw_info.screen_id_l = screen_id; draw_info.screen_id_l = screen_id;
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.pushConstants(present_pipeline_layout, command_buffer.pushConstants(present_pipeline_layout,
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment |
vk::ShaderStageFlagBits::eVertex,
0, sizeof(draw_info), &draw_info); 0, sizeof(draw_info), &draw_info);
command_buffer.bindVertexBuffers(0, vertex_buffer.GetHandle(), {0}); command_buffer.bindVertexBuffers(0, vertex_buffer.GetHandle(), {0});
@ -701,20 +652,19 @@ void RendererVulkan::DrawSingleScreen(u32 screen_id, float x, float y, float w,
const float width = static_cast<float>(screen_info.texture.width); const float width = static_cast<float>(screen_info.texture.width);
const float height = static_cast<float>(screen_info.texture.height); const float height = static_cast<float>(screen_info.texture.height);
draw_info.i_resolution = Common::Vec4f{width * scale_factor, height * scale_factor, draw_info.i_resolution =
1.0f / (width * scale_factor), Common::Vec4f{width * scale_factor, height * scale_factor, 1.0f / (width * scale_factor),
1.0f / (height * scale_factor)}; 1.0f / (height * scale_factor)};
draw_info.o_resolution = Common::Vec4f{h, w, 1.0f / h, 1.0f / w}; draw_info.o_resolution = Common::Vec4f{h, w, 1.0f / h, 1.0f / w};
draw_info.screen_id_l = screen_id; draw_info.screen_id_l = screen_id;
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.pushConstants(present_pipeline_layout, command_buffer.pushConstants(present_pipeline_layout,
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment |
vk::ShaderStageFlagBits::eVertex,
0, sizeof(draw_info), &draw_info); 0, sizeof(draw_info), &draw_info);
const vk::ClearValue clear_value = { const vk::ClearValue clear_value = {.color = clear_color};
.color = clear_color
};
const vk::RenderPassBeginInfo begin_info = { const vk::RenderPassBeginInfo begin_info = {
.renderPass = renderpass_cache.GetPresentRenderpass(), .renderPass = renderpass_cache.GetPresentRenderpass(),
@ -729,20 +679,18 @@ void RendererVulkan::DrawSingleScreen(u32 screen_id, float x, float y, float w,
command_buffer.draw(4, 1, offset / sizeof(ScreenRectVertex), 0); command_buffer.draw(4, 1, offset / sizeof(ScreenRectVertex), 0);
} }
void RendererVulkan::DrawSingleScreenStereoRotated(u32 screen_id_l, u32 screen_id_r, void RendererVulkan::DrawSingleScreenStereoRotated(u32 screen_id_l, u32 screen_id_r, float x,
float x, float y, float w, float h) { float y, float w, float h) {
const ScreenInfo& screen_info_l = screen_infos[screen_id_l]; const ScreenInfo& screen_info_l = screen_infos[screen_id_l];
const auto& texcoords = screen_info_l.display_texcoords; const auto& texcoords = screen_info_l.display_texcoords;
u32 size = sizeof(ScreenRectVertex) * 4; u32 size = sizeof(ScreenRectVertex) * 4;
auto [ptr, offset, invalidate] = vertex_buffer.Map(size); auto [ptr, offset, invalidate] = vertex_buffer.Map(size);
const std::array vertices = { const std::array vertices = {ScreenRectVertex{x, y, texcoords.bottom, texcoords.left},
ScreenRectVertex{x, y, texcoords.bottom, texcoords.left},
ScreenRectVertex{x + w, y, texcoords.bottom, texcoords.right}, ScreenRectVertex{x + w, y, texcoords.bottom, texcoords.right},
ScreenRectVertex{x, y + h, texcoords.top, texcoords.left}, ScreenRectVertex{x, y + h, texcoords.top, texcoords.left},
ScreenRectVertex{x + w, y + h, texcoords.top, texcoords.right} ScreenRectVertex{x + w, y + h, texcoords.top, texcoords.right}};
};
std::memcpy(ptr, vertices.data(), size); std::memcpy(ptr, vertices.data(), size);
vertex_buffer.Commit(size); vertex_buffer.Commit(size);
@ -751,8 +699,8 @@ void RendererVulkan::DrawSingleScreenStereoRotated(u32 screen_id_l, u32 screen_i
const float width = static_cast<float>(screen_info_l.texture.width); const float width = static_cast<float>(screen_info_l.texture.width);
const float height = static_cast<float>(screen_info_l.texture.height); const float height = static_cast<float>(screen_info_l.texture.height);
draw_info.i_resolution = Common::Vec4f{width * scale_factor, height * scale_factor, draw_info.i_resolution =
1.0f / (width * scale_factor), Common::Vec4f{width * scale_factor, height * scale_factor, 1.0f / (width * scale_factor),
1.0f / (height * scale_factor)}; 1.0f / (height * scale_factor)};
draw_info.o_resolution = Common::Vec4f{h, w, 1.0f / h, 1.0f / w}; draw_info.o_resolution = Common::Vec4f{h, w, 1.0f / h, 1.0f / w};
@ -761,15 +709,16 @@ void RendererVulkan::DrawSingleScreenStereoRotated(u32 screen_id_l, u32 screen_i
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.pushConstants(present_pipeline_layout, command_buffer.pushConstants(present_pipeline_layout,
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment |
vk::ShaderStageFlagBits::eVertex,
0, sizeof(draw_info), &draw_info); 0, sizeof(draw_info), &draw_info);
command_buffer.bindVertexBuffers(0, vertex_buffer.GetHandle(), {0}); command_buffer.bindVertexBuffers(0, vertex_buffer.GetHandle(), {0});
command_buffer.draw(4, 1, offset / sizeof(ScreenRectVertex), 0); command_buffer.draw(4, 1, offset / sizeof(ScreenRectVertex), 0);
} }
void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, float x, float y,
float x, float y, float w, float h) { float w, float h) {
const ScreenInfo& screen_info_l = screen_infos[screen_id_l]; const ScreenInfo& screen_info_l = screen_infos[screen_id_l];
const auto& texcoords = screen_info_l.display_texcoords; const auto& texcoords = screen_info_l.display_texcoords;
@ -790,8 +739,8 @@ void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r,
const float width = static_cast<float>(screen_info_l.texture.width); const float width = static_cast<float>(screen_info_l.texture.width);
const float height = static_cast<float>(screen_info_l.texture.height); const float height = static_cast<float>(screen_info_l.texture.height);
draw_info.i_resolution = Common::Vec4f{width * scale_factor, height * scale_factor, draw_info.i_resolution =
1.0f / (width * scale_factor), Common::Vec4f{width * scale_factor, height * scale_factor, 1.0f / (width * scale_factor),
1.0f / (height * scale_factor)}; 1.0f / (height * scale_factor)};
draw_info.o_resolution = Common::Vec4f{w, h, 1.0f / w, 1.0f / h}; draw_info.o_resolution = Common::Vec4f{w, h, 1.0f / w, 1.0f / h};
@ -800,7 +749,8 @@ void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r,
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.pushConstants(present_pipeline_layout, command_buffer.pushConstants(present_pipeline_layout,
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment |
vk::ShaderStageFlagBits::eVertex,
0, sizeof(draw_info), &draw_info); 0, sizeof(draw_info), &draw_info);
command_buffer.bindVertexBuffers(0, vertex_buffer.GetHandle(), {0}); command_buffer.bindVertexBuffers(0, vertex_buffer.GetHandle(), {0});
@ -829,10 +779,10 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
// Set projection matrix // Set projection matrix
// draw_info.modelview = // draw_info.modelview =
// MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height), flipped); // MakeOrthographicMatrix(static_cast<float>(layout.width),
draw_info.modelview = glm::transpose(glm::ortho(0.f, static_cast<float>(layout.width), // static_cast<float>(layout.height), flipped);
static_cast<float>(layout.height), 0.0f, draw_info.modelview = glm::transpose(glm::ortho(
0.f, 1.f)); 0.f, static_cast<float>(layout.width), static_cast<float>(layout.height), 0.0f, 0.f, 1.f));
const bool stereo_single_screen = const bool stereo_single_screen =
Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph || Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph ||
@ -846,31 +796,29 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
if (layout.top_screen_enabled) { if (layout.top_screen_enabled) {
if (layout.is_rotated) { if (layout.is_rotated) {
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
DrawSingleScreenRotated(0, top_screen.left, DrawSingleScreenRotated(0, top_screen.left, top_screen.top, top_screen.GetWidth(),
top_screen.top, top_screen.GetWidth(),
top_screen.GetHeight()); top_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { } else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
DrawSingleScreenRotated(0, (float)top_screen.left / 2, DrawSingleScreenRotated(0, (float)top_screen.left / 2, (float)top_screen.top,
(float)top_screen.top, (float)top_screen.GetWidth() / 2, (float)top_screen.GetWidth() / 2,
(float)top_screen.GetHeight()); (float)top_screen.GetHeight());
draw_info.layer = 1; draw_info.layer = 1;
DrawSingleScreenRotated(1, DrawSingleScreenRotated(1, ((float)top_screen.left / 2) + ((float)layout.width / 2),
((float)top_screen.left / 2) + ((float)layout.width / 2),
(float)top_screen.top, (float)top_screen.GetWidth() / 2, (float)top_screen.top, (float)top_screen.GetWidth() / 2,
(float)top_screen.GetHeight()); (float)top_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { } else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
DrawSingleScreenRotated(0, layout.top_screen.left, DrawSingleScreenRotated(0, layout.top_screen.left, layout.top_screen.top,
layout.top_screen.top, layout.top_screen.GetWidth(), layout.top_screen.GetWidth(),
layout.top_screen.GetHeight()); layout.top_screen.GetHeight());
draw_info.layer = 1; draw_info.layer = 1;
DrawSingleScreenRotated(1, DrawSingleScreenRotated(
layout.cardboard.top_screen_right_eye + 1, layout.cardboard.top_screen_right_eye + ((float)layout.width / 2),
((float)layout.width / 2),
layout.top_screen.top, layout.top_screen.GetWidth(), layout.top_screen.top, layout.top_screen.GetWidth(),
layout.top_screen.GetHeight()); layout.top_screen.GetHeight());
} else if (stereo_single_screen) { } else if (stereo_single_screen) {
DrawSingleScreenStereoRotated(0, 1, (float)top_screen.left, (float)top_screen.top, DrawSingleScreenStereoRotated(0, 1, (float)top_screen.left, (float)top_screen.top,
(float)top_screen.GetWidth(), (float)top_screen.GetHeight()); (float)top_screen.GetWidth(),
(float)top_screen.GetHeight());
} }
} else { } else {
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
@ -880,8 +828,7 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
DrawSingleScreen(0, (float)top_screen.left / 2, (float)top_screen.top, DrawSingleScreen(0, (float)top_screen.left / 2, (float)top_screen.top,
(float)top_screen.GetWidth() / 2, (float)top_screen.GetHeight()); (float)top_screen.GetWidth() / 2, (float)top_screen.GetHeight());
draw_info.layer = 1; draw_info.layer = 1;
DrawSingleScreen(1, DrawSingleScreen(1, ((float)top_screen.left / 2) + ((float)layout.width / 2),
((float)top_screen.left / 2) + ((float)layout.width / 2),
(float)top_screen.top, (float)top_screen.GetWidth() / 2, (float)top_screen.top, (float)top_screen.GetWidth() / 2,
(float)top_screen.GetHeight()); (float)top_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { } else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
@ -893,9 +840,8 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
layout.top_screen.top, layout.top_screen.GetWidth(), layout.top_screen.top, layout.top_screen.GetWidth(),
layout.top_screen.GetHeight()); layout.top_screen.GetHeight());
} else if (stereo_single_screen) { } else if (stereo_single_screen) {
DrawSingleScreenStereo(0, 1, (float)top_screen.left, DrawSingleScreenStereo(0, 1, (float)top_screen.left, (float)top_screen.top,
(float)top_screen.top, (float)top_screen.GetWidth(), (float)top_screen.GetWidth(), (float)top_screen.GetHeight());
(float)top_screen.GetHeight());
} }
} }
} }
@ -904,60 +850,55 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
if (layout.bottom_screen_enabled) { if (layout.bottom_screen_enabled) {
if (layout.is_rotated) { if (layout.is_rotated) {
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
DrawSingleScreenRotated(2, (float)bottom_screen.left, DrawSingleScreenRotated(2, (float)bottom_screen.left, (float)bottom_screen.top,
(float)bottom_screen.top, (float)bottom_screen.GetWidth(), (float)bottom_screen.GetWidth(),
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { } else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
DrawSingleScreenRotated( DrawSingleScreenRotated(2, (float)bottom_screen.left / 2, (float)bottom_screen.top,
2, (float)bottom_screen.left / 2, (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
(float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
draw_info.layer = 1; draw_info.layer = 1;
DrawSingleScreenRotated( DrawSingleScreenRotated(
2, ((float)bottom_screen.left / 2) + ((float)layout.width / 2), 2, ((float)bottom_screen.left / 2) + ((float)layout.width / 2),
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { } else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
DrawSingleScreenRotated(2, layout.bottom_screen.left, DrawSingleScreenRotated(2, layout.bottom_screen.left, layout.bottom_screen.top,
layout.bottom_screen.top, layout.bottom_screen.GetWidth(), layout.bottom_screen.GetWidth(),
layout.bottom_screen.GetHeight()); layout.bottom_screen.GetHeight());
draw_info.layer = 1; draw_info.layer = 1;
DrawSingleScreenRotated(2, DrawSingleScreenRotated(
layout.cardboard.bottom_screen_right_eye + 2, layout.cardboard.bottom_screen_right_eye + ((float)layout.width / 2),
((float)layout.width / 2),
layout.bottom_screen.top, layout.bottom_screen.GetWidth(), layout.bottom_screen.top, layout.bottom_screen.GetWidth(),
layout.bottom_screen.GetHeight()); layout.bottom_screen.GetHeight());
} else if (stereo_single_screen) { } else if (stereo_single_screen) {
DrawSingleScreenStereoRotated(2, 2, (float)bottom_screen.left, (float)bottom_screen.top, DrawSingleScreenStereoRotated(
(float)bottom_screen.GetWidth(), 2, 2, (float)bottom_screen.left, (float)bottom_screen.top,
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetWidth(), (float)bottom_screen.GetHeight());
} }
} else { } else {
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
DrawSingleScreen(2, (float)bottom_screen.left, DrawSingleScreen(2, (float)bottom_screen.left, (float)bottom_screen.top,
(float)bottom_screen.top, (float)bottom_screen.GetWidth(), (float)bottom_screen.GetWidth(), (float)bottom_screen.GetHeight());
(float)bottom_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { } else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
DrawSingleScreen(2, (float)bottom_screen.left / 2, DrawSingleScreen(2, (float)bottom_screen.left / 2, (float)bottom_screen.top,
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetWidth() / 2,
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
draw_info.layer = 1; draw_info.layer = 1;
DrawSingleScreen(2, DrawSingleScreen(2, ((float)bottom_screen.left / 2) + ((float)layout.width / 2),
((float)bottom_screen.left / 2) + ((float)layout.width / 2),
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { } else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
DrawSingleScreen(2, layout.bottom_screen.left, DrawSingleScreen(2, layout.bottom_screen.left, layout.bottom_screen.top,
layout.bottom_screen.top, layout.bottom_screen.GetWidth(), layout.bottom_screen.GetWidth(), layout.bottom_screen.GetHeight());
layout.bottom_screen.GetHeight());
draw_info.layer = 1; draw_info.layer = 1;
DrawSingleScreen(2, DrawSingleScreen(
layout.cardboard.bottom_screen_right_eye + 2, layout.cardboard.bottom_screen_right_eye + ((float)layout.width / 2),
((float)layout.width / 2),
layout.bottom_screen.top, layout.bottom_screen.GetWidth(), layout.bottom_screen.top, layout.bottom_screen.GetWidth(),
layout.bottom_screen.GetHeight()); layout.bottom_screen.GetHeight());
} else if (stereo_single_screen) { } else if (stereo_single_screen) {
DrawSingleScreenStereo(2, 2, (float)bottom_screen.left, DrawSingleScreenStereo(2, 2, (float)bottom_screen.left, (float)bottom_screen.top,
(float)bottom_screen.top, (float)bottom_screen.GetWidth(), (float)bottom_screen.GetWidth(),
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
} }
} }
@ -980,19 +921,14 @@ void RendererVulkan::SwapBuffers() {
const vk::Semaphore present_ready = scheduler.GetPresentReadySemaphore(); const vk::Semaphore present_ready = scheduler.GetPresentReadySemaphore();
swapchain.AcquireNextImage(image_acquired); swapchain.AcquireNextImage(image_acquired);
const vk::Viewport viewport = { const vk::Viewport viewport = {.x = 0.0f,
.x = 0.0f,
.y = 0.0f, .y = 0.0f,
.width = static_cast<float>(layout.width), .width = static_cast<float>(layout.width),
.height = static_cast<float>(layout.height), .height = static_cast<float>(layout.height),
.minDepth = 0.0f, .minDepth = 0.0f,
.maxDepth = 1.0f .maxDepth = 1.0f};
};
const vk::Rect2D scissor = { const vk::Rect2D scissor = {.offset = {0, 0}, .extent = {layout.width, layout.height}};
.offset = {0, 0},
.extent = {layout.width, layout.height}
};
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.setViewport(0, viewport); command_buffer.setViewport(0, viewport);
@ -1002,7 +938,8 @@ void RendererVulkan::SwapBuffers() {
for (auto& info : screen_infos) { for (auto& info : screen_infos) {
auto alloc = info.display_texture ? info.display_texture : &info.texture.alloc; auto alloc = info.display_texture ? info.display_texture : &info.texture.alloc;
runtime.Transition(command_buffer, *alloc, vk::ImageLayout::eShaderReadOnlyOptimal, 0, alloc->levels); runtime.Transition(command_buffer, *alloc, vk::ImageLayout::eShaderReadOnlyOptimal, 0,
alloc->levels);
} }
DrawScreens(layout, false); DrawScreens(layout, false);

View File

@ -10,9 +10,9 @@
#include "common/math_util.h" #include "common/math_util.h"
#include "core/hw/gpu.h" #include "core/hw/gpu.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h" #include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
#include "video_core/renderer_vulkan/vk_texture_runtime.h" #include "video_core/renderer_vulkan/vk_texture_runtime.h"
namespace Layout { namespace Layout {
@ -81,7 +81,8 @@ private:
void CompileShaders(); void CompileShaders();
void BuildLayouts(); void BuildLayouts();
void BuildPipelines(); void BuildPipelines();
void ConfigureFramebufferTexture(TextureInfo& texture, const GPU::Regs::FramebufferConfig& framebuffer); void ConfigureFramebufferTexture(TextureInfo& texture,
const GPU::Regs::FramebufferConfig& framebuffer);
void ConfigureRenderPipeline(); void ConfigureRenderPipeline();
void PrepareRendertarget(); void PrepareRendertarget();
void BeginRendering(); void BeginRendering();
@ -89,8 +90,10 @@ private:
void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped); void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped);
void DrawSingleScreenRotated(u32 screen_id, float x, float y, float w, float h); void DrawSingleScreenRotated(u32 screen_id, float x, float y, float w, float h);
void DrawSingleScreen(u32 screen_id, float x, float y, float w, float h); void DrawSingleScreen(u32 screen_id, float x, float y, float w, float h);
void DrawSingleScreenStereoRotated(u32 screen_id_l, u32 screen_id_r, float x, float y, float w, float h); void DrawSingleScreenStereoRotated(u32 screen_id_l, u32 screen_id_r, float x, float y, float w,
void DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, float x, float y, float w, float h); float h);
void DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, float x, float y, float w,
float h);
void UpdateFramerate(); void UpdateFramerate();

View File

@ -41,25 +41,21 @@ constexpr vk::ImageAspectFlags GetImageAspect(vk::Format format) {
/// Returns a bit mask with the required usage of a format with a particular aspect /// Returns a bit mask with the required usage of a format with a particular aspect
constexpr vk::ImageUsageFlags GetImageUsage(vk::ImageAspectFlags aspect) { constexpr vk::ImageUsageFlags GetImageUsage(vk::ImageAspectFlags aspect) {
auto usage = vk::ImageUsageFlagBits::eSampled | auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst |
vk::ImageUsageFlagBits::eTransferDst |
vk::ImageUsageFlagBits::eTransferSrc; vk::ImageUsageFlagBits::eTransferSrc;
if (aspect & vk::ImageAspectFlagBits::eDepth) { if (aspect & vk::ImageAspectFlagBits::eDepth) {
return usage | vk::ImageUsageFlagBits::eDepthStencilAttachment; return usage | vk::ImageUsageFlagBits::eDepthStencilAttachment;
} else { } else {
return usage | vk::ImageUsageFlagBits::eStorage | return usage | vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eColorAttachment;
vk::ImageUsageFlagBits::eColorAttachment;
} }
} }
/// Returns a bit mask with the required features of a format with a particular aspect /// Returns a bit mask with the required features of a format with a particular aspect
constexpr vk::FormatFeatureFlags GetFormatFeatures(vk::ImageAspectFlags aspect) { constexpr vk::FormatFeatureFlags GetFormatFeatures(vk::ImageAspectFlags aspect) {
auto usage = vk::FormatFeatureFlagBits::eSampledImage | auto usage = vk::FormatFeatureFlagBits::eSampledImage |
vk::FormatFeatureFlagBits::eTransferDst | vk::FormatFeatureFlagBits::eTransferDst | vk::FormatFeatureFlagBits::eTransferSrc |
vk::FormatFeatureFlagBits::eTransferSrc | vk::FormatFeatureFlagBits::eBlitSrc | vk::FormatFeatureFlagBits::eBlitDst;
vk::FormatFeatureFlagBits::eBlitSrc |
vk::FormatFeatureFlagBits::eBlitDst;
if (aspect & vk::ImageAspectFlagBits::eDepth) { if (aspect & vk::ImageAspectFlagBits::eDepth) {
return usage | vk::FormatFeatureFlagBits::eDepthStencilAttachment; return usage | vk::FormatFeatureFlagBits::eDepthStencilAttachment;

View File

@ -4,12 +4,13 @@
#define VULKAN_HPP_NO_CONSTRUCTORS #define VULKAN_HPP_NO_CONSTRUCTORS
#include "video_core/renderer_vulkan/vk_format_reinterpreter.h" #include "video_core/renderer_vulkan/vk_format_reinterpreter.h"
#include "video_core/renderer_vulkan/vk_texture_runtime.h"
#include "video_core/renderer_vulkan/vk_shader.h" #include "video_core/renderer_vulkan/vk_shader.h"
#include "video_core/renderer_vulkan/vk_texture_runtime.h"
namespace Vulkan { namespace Vulkan {
D24S8toRGBA8::D24S8toRGBA8(const Instance& instance, TaskScheduler& scheduler, TextureRuntime& runtime) D24S8toRGBA8::D24S8toRGBA8(const Instance& instance, TaskScheduler& scheduler,
TextureRuntime& runtime)
: FormatReinterpreterBase{instance, scheduler, runtime}, device{instance.GetDevice()} { : FormatReinterpreterBase{instance, scheduler, runtime}, device{instance.GetDevice()} {
constexpr std::string_view cs_source = R"( constexpr std::string_view cs_source = R"(
#version 450 core #version 450 core
@ -35,70 +36,54 @@ void main() {
} }
)"; )";
compute_shader = Compile(cs_source, vk::ShaderStageFlagBits::eCompute, compute_shader =
device, ShaderOptimization::High); Compile(cs_source, vk::ShaderStageFlagBits::eCompute, device, ShaderOptimization::High);
const std::array compute_layout_bindings = { const std::array compute_layout_bindings = {
vk::DescriptorSetLayoutBinding{ vk::DescriptorSetLayoutBinding{.binding = 0,
.binding = 0,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eCompute .stageFlags = vk::ShaderStageFlagBits::eCompute},
}, vk::DescriptorSetLayoutBinding{.binding = 1,
vk::DescriptorSetLayoutBinding{
.binding = 1,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eCompute .stageFlags = vk::ShaderStageFlagBits::eCompute},
}, vk::DescriptorSetLayoutBinding{.binding = 2,
vk::DescriptorSetLayoutBinding{
.binding = 2,
.descriptorType = vk::DescriptorType::eStorageImage, .descriptorType = vk::DescriptorType::eStorageImage,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eCompute .stageFlags = vk::ShaderStageFlagBits::eCompute}};
}
};
const vk::DescriptorSetLayoutCreateInfo compute_layout_info = { const vk::DescriptorSetLayoutCreateInfo compute_layout_info = {
.bindingCount = static_cast<u32>(compute_layout_bindings.size()), .bindingCount = static_cast<u32>(compute_layout_bindings.size()),
.pBindings = compute_layout_bindings.data() .pBindings = compute_layout_bindings.data()};
};
descriptor_layout = device.createDescriptorSetLayout(compute_layout_info); descriptor_layout = device.createDescriptorSetLayout(compute_layout_info);
const std::array update_template_entries = { const std::array update_template_entries = {
vk::DescriptorUpdateTemplateEntry{ vk::DescriptorUpdateTemplateEntry{.dstBinding = 0,
.dstBinding = 0,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.offset = 0, .offset = 0,
.stride = sizeof(vk::DescriptorImageInfo) .stride = sizeof(vk::DescriptorImageInfo)},
}, vk::DescriptorUpdateTemplateEntry{.dstBinding = 1,
vk::DescriptorUpdateTemplateEntry{
.dstBinding = 1,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eSampledImage,
.offset = sizeof(vk::DescriptorImageInfo), .offset = sizeof(vk::DescriptorImageInfo),
.stride = 0 .stride = 0},
}, vk::DescriptorUpdateTemplateEntry{.dstBinding = 2,
vk::DescriptorUpdateTemplateEntry{
.dstBinding = 2,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eStorageImage, .descriptorType = vk::DescriptorType::eStorageImage,
.offset = 2 * sizeof(vk::DescriptorImageInfo), .offset = 2 * sizeof(vk::DescriptorImageInfo),
.stride = 0 .stride = 0}};
}
};
const vk::DescriptorUpdateTemplateCreateInfo template_info = { const vk::DescriptorUpdateTemplateCreateInfo template_info = {
.descriptorUpdateEntryCount = static_cast<u32>(update_template_entries.size()), .descriptorUpdateEntryCount = static_cast<u32>(update_template_entries.size()),
.pDescriptorUpdateEntries = update_template_entries.data(), .pDescriptorUpdateEntries = update_template_entries.data(),
.templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet, .templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet,
.descriptorSetLayout = descriptor_layout .descriptorSetLayout = descriptor_layout};
};
update_template = device.createDescriptorUpdateTemplate(template_info); update_template = device.createDescriptorUpdateTemplate(template_info);
@ -108,33 +93,25 @@ void main() {
.size = sizeof(Common::Vec2i), .size = sizeof(Common::Vec2i),
}; };
const vk::PipelineLayoutCreateInfo layout_info = { const vk::PipelineLayoutCreateInfo layout_info = {.setLayoutCount = 1,
.setLayoutCount = 1,
.pSetLayouts = &descriptor_layout, .pSetLayouts = &descriptor_layout,
.pushConstantRangeCount = 1, .pushConstantRangeCount = 1,
.pPushConstantRanges = &push_range .pPushConstantRanges = &push_range};
};
compute_pipeline_layout = device.createPipelineLayout(layout_info); compute_pipeline_layout = device.createPipelineLayout(layout_info);
const vk::DescriptorSetAllocateInfo alloc_info = { const vk::DescriptorSetAllocateInfo alloc_info = {.descriptorPool =
.descriptorPool = scheduler.GetPersistentDescriptorPool(), scheduler.GetPersistentDescriptorPool(),
.descriptorSetCount = 1, .descriptorSetCount = 1,
.pSetLayouts = &descriptor_layout .pSetLayouts = &descriptor_layout};
};
descriptor_set = device.allocateDescriptorSets(alloc_info)[0]; descriptor_set = device.allocateDescriptorSets(alloc_info)[0];
const vk::PipelineShaderStageCreateInfo compute_stage = { const vk::PipelineShaderStageCreateInfo compute_stage = {
.stage = vk::ShaderStageFlagBits::eCompute, .stage = vk::ShaderStageFlagBits::eCompute, .module = compute_shader, .pName = "main"};
.module = compute_shader,
.pName = "main"
};
const vk::ComputePipelineCreateInfo compute_info = { const vk::ComputePipelineCreateInfo compute_info = {.stage = compute_stage,
.stage = compute_stage, .layout = compute_pipeline_layout};
.layout = compute_pipeline_layout
};
if (const auto result = device.createComputePipeline({}, compute_info); if (const auto result = device.createComputePipeline({}, compute_info);
result.result == vk::Result::eSuccess) { result.result == vk::Result::eSuccess) {
@ -153,37 +130,30 @@ D24S8toRGBA8::~D24S8toRGBA8() {
device.destroyShaderModule(compute_shader); device.destroyShaderModule(compute_shader);
} }
void D24S8toRGBA8::Reinterpret(Surface& source, VideoCore::Rect2D src_rect, void D24S8toRGBA8::Reinterpret(Surface& source, VideoCore::Rect2D src_rect, Surface& dest,
Surface& dest, VideoCore::Rect2D dst_rect) { VideoCore::Rect2D dst_rect) {
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
runtime.Transition(command_buffer, source.alloc, vk::ImageLayout::eDepthStencilReadOnlyOptimal, runtime.Transition(command_buffer, source.alloc, vk::ImageLayout::eDepthStencilReadOnlyOptimal,
0, source.alloc.levels); 0, source.alloc.levels);
runtime.Transition(command_buffer, dest.alloc, vk::ImageLayout::eGeneral, 0, dest.alloc.levels); runtime.Transition(command_buffer, dest.alloc, vk::ImageLayout::eGeneral, 0, dest.alloc.levels);
const std::array textures = { const std::array textures = {
vk::DescriptorImageInfo{ vk::DescriptorImageInfo{.imageView = source.GetDepthView(),
.imageView = source.GetDepthView(), .imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal},
.imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal vk::DescriptorImageInfo{.imageView = source.GetStencilView(),
}, .imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal},
vk::DescriptorImageInfo{ vk::DescriptorImageInfo{.imageView = dest.GetImageView(),
.imageView = source.GetStencilView(), .imageLayout = vk::ImageLayout::eGeneral}};
.imageLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal
},
vk::DescriptorImageInfo{
.imageView = dest.GetImageView(),
.imageLayout = vk::ImageLayout::eGeneral
}
};
device.updateDescriptorSetWithTemplate(descriptor_set, update_template, textures[0]); device.updateDescriptorSetWithTemplate(descriptor_set, update_template, textures[0]);
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout, command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout, 0,
0, 1, &descriptor_set, 0, nullptr); 1, &descriptor_set, 0, nullptr);
command_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, compute_pipeline); command_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, compute_pipeline);
const auto src_offset = Common::MakeVec(src_rect.left, src_rect.bottom); const auto src_offset = Common::MakeVec(src_rect.left, src_rect.bottom);
command_buffer.pushConstants(compute_pipeline_layout, vk::ShaderStageFlagBits::eCompute, command_buffer.pushConstants(compute_pipeline_layout, vk::ShaderStageFlagBits::eCompute, 0,
0, sizeof(Common::Vec2i), src_offset.AsArray()); sizeof(Common::Vec2i), src_offset.AsArray());
command_buffer.dispatch(src_rect.GetWidth() / 32, src_rect.GetHeight() / 32, 1); command_buffer.dispatch(src_rect.GetWidth() / 32, src_rect.GetHeight() / 32, 1);
} }

View File

@ -16,13 +16,14 @@ class TextureRuntime;
class FormatReinterpreterBase { class FormatReinterpreterBase {
public: public:
FormatReinterpreterBase(const Instance& instance, TaskScheduler& scheduler, TextureRuntime& runtime) FormatReinterpreterBase(const Instance& instance, TaskScheduler& scheduler,
TextureRuntime& runtime)
: instance{instance}, scheduler{scheduler}, runtime{runtime} {} : instance{instance}, scheduler{scheduler}, runtime{runtime} {}
virtual ~FormatReinterpreterBase() = default; virtual ~FormatReinterpreterBase() = default;
virtual VideoCore::PixelFormat GetSourceFormat() const = 0; virtual VideoCore::PixelFormat GetSourceFormat() const = 0;
virtual void Reinterpret(Surface& source, VideoCore::Rect2D src_rect, virtual void Reinterpret(Surface& source, VideoCore::Rect2D src_rect, Surface& dest,
Surface& dest, VideoCore::Rect2D dst_rect) = 0; VideoCore::Rect2D dst_rect) = 0;
protected: protected:
const Instance& instance; const Instance& instance;
@ -41,8 +42,8 @@ public:
return VideoCore::PixelFormat::D24S8; return VideoCore::PixelFormat::D24S8;
} }
void Reinterpret(Surface& source, VideoCore::Rect2D src_rect, void Reinterpret(Surface& source, VideoCore::Rect2D src_rect, Surface& dest,
Surface& dest, VideoCore::Rect2D dst_rect) override; VideoCore::Rect2D dst_rect) override;
private: private:
vk::Device device; vk::Device device;

View File

@ -6,8 +6,8 @@
#include <span> #include <span>
#include "common/assert.h" #include "common/assert.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "video_core/renderer_vulkan/vk_platform.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_platform.h"
namespace Vulkan { namespace Vulkan {
@ -41,28 +41,25 @@ vk::Format ToVkFormat(VideoCore::PixelFormat format) {
Instance::Instance() { Instance::Instance() {
// Fetch instance independant function pointers // Fetch instance independant function pointers
vk::DynamicLoader dl; vk::DynamicLoader dl;
auto vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"); auto vkGetInstanceProcAddr =
dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
const vk::ApplicationInfo application_info = { const vk::ApplicationInfo application_info = {.pApplicationName = "Citra",
.pApplicationName = "Citra",
.applicationVersion = VK_MAKE_VERSION(1, 0, 0), .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
.pEngineName = "Citra Vulkan", .pEngineName = "Citra Vulkan",
.engineVersion = VK_MAKE_VERSION(1, 0, 0), .engineVersion = VK_MAKE_VERSION(1, 0, 0),
.apiVersion = VK_API_VERSION_1_0 .apiVersion = VK_API_VERSION_1_0};
};
const vk::InstanceCreateInfo instance_info = { const vk::InstanceCreateInfo instance_info = {.pApplicationInfo = &application_info};
.pApplicationInfo = &application_info
};
instance = vk::createInstance(instance_info); instance = vk::createInstance(instance_info);
// Load required function pointers for querying the physical device // Load required function pointers for querying the physical device
VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumeratePhysicalDevices = VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumeratePhysicalDevices = PFN_vkEnumeratePhysicalDevices(
PFN_vkEnumeratePhysicalDevices(vkGetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices")); vkGetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices"));
VULKAN_HPP_DEFAULT_DISPATCHER.vkGetPhysicalDeviceProperties = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetPhysicalDeviceProperties = PFN_vkGetPhysicalDeviceProperties(
PFN_vkGetPhysicalDeviceProperties(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties")); vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties"));
VULKAN_HPP_DEFAULT_DISPATCHER.vkDestroyInstance = VULKAN_HPP_DEFAULT_DISPATCHER.vkDestroyInstance =
PFN_vkDestroyInstance(vkGetInstanceProcAddr(instance, "vkDestroyInstance")); PFN_vkDestroyInstance(vkGetInstanceProcAddr(instance, "vkDestroyInstance"));
@ -74,7 +71,8 @@ Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index, bool
// Fetch instance independant function pointers // Fetch instance independant function pointers
vk::DynamicLoader dl; vk::DynamicLoader dl;
auto vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"); auto vkGetInstanceProcAddr =
dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
// Enable the instance extensions the backend uses // Enable the instance extensions the backend uses
@ -87,23 +85,20 @@ Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index, bool
return; return;
} }
const vk::ApplicationInfo application_info = { const vk::ApplicationInfo application_info = {.pApplicationName = "Citra",
.pApplicationName = "Citra",
.applicationVersion = VK_MAKE_VERSION(1, 0, 0), .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
.pEngineName = "Citra Vulkan", .pEngineName = "Citra Vulkan",
.engineVersion = VK_MAKE_VERSION(1, 0, 0), .engineVersion = VK_MAKE_VERSION(1, 0, 0),
.apiVersion = available_version .apiVersion = available_version};
};
const std::array layers = {"VK_LAYER_KHRONOS_validation"}; const std::array layers = {"VK_LAYER_KHRONOS_validation"};
const u32 layer_count = enable_validation ? 1u : 0u; const u32 layer_count = enable_validation ? 1u : 0u;
const vk::InstanceCreateInfo instance_info = { const vk::InstanceCreateInfo instance_info = {.pApplicationInfo = &application_info,
.pApplicationInfo = &application_info,
.enabledLayerCount = layer_count, .enabledLayerCount = layer_count,
.ppEnabledLayerNames = layers.data(), .ppEnabledLayerNames = layers.data(),
.enabledExtensionCount = static_cast<u32>(extensions.size()), .enabledExtensionCount =
.ppEnabledExtensionNames = extensions.data() static_cast<u32>(extensions.size()),
}; .ppEnabledExtensionNames = extensions.data()};
instance = vk::createInstance(instance_info); instance = vk::createInstance(instance_info);
surface = CreateSurface(instance, window); surface = CreateSurface(instance, window);
@ -112,7 +107,8 @@ Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index, bool
physical_devices = instance.enumeratePhysicalDevices(); physical_devices = instance.enumeratePhysicalDevices();
if (const u16 physical_device_count = static_cast<u16>(physical_devices.size()); if (const u16 physical_device_count = static_cast<u16>(physical_devices.size());
physical_device_index >= physical_devices.size()) { physical_device_index >= physical_devices.size()) {
LOG_CRITICAL(Render_Vulkan, "Invalid physical device index {} provided when only {} devices exist", LOG_CRITICAL(Render_Vulkan,
"Invalid physical device index {} provided when only {} devices exist",
physical_device_index, physical_device_count); physical_device_index, physical_device_count);
UNREACHABLE(); UNREACHABLE();
} }
@ -145,30 +141,20 @@ FormatTraits Instance::GetTraits(VideoCore::PixelFormat pixel_format) const {
void Instance::CreateFormatTable() { void Instance::CreateFormatTable() {
constexpr std::array pixel_formats = { constexpr std::array pixel_formats = {
VideoCore::PixelFormat::RGBA8, VideoCore::PixelFormat::RGBA8, VideoCore::PixelFormat::RGB8,
VideoCore::PixelFormat::RGB8, VideoCore::PixelFormat::RGB5A1, VideoCore::PixelFormat::RGB565,
VideoCore::PixelFormat::RGB5A1, VideoCore::PixelFormat::RGBA4, VideoCore::PixelFormat::IA8,
VideoCore::PixelFormat::RGB565, VideoCore::PixelFormat::RG8, VideoCore::PixelFormat::I8,
VideoCore::PixelFormat::RGBA4, VideoCore::PixelFormat::A8, VideoCore::PixelFormat::IA4,
VideoCore::PixelFormat::IA8, VideoCore::PixelFormat::I4, VideoCore::PixelFormat::A4,
VideoCore::PixelFormat::RG8, VideoCore::PixelFormat::ETC1, VideoCore::PixelFormat::ETC1A4,
VideoCore::PixelFormat::I8, VideoCore::PixelFormat::D16, VideoCore::PixelFormat::D24,
VideoCore::PixelFormat::A8, VideoCore::PixelFormat::D24S8};
VideoCore::PixelFormat::IA4,
VideoCore::PixelFormat::I4,
VideoCore::PixelFormat::A4,
VideoCore::PixelFormat::ETC1,
VideoCore::PixelFormat::ETC1A4,
VideoCore::PixelFormat::D16,
VideoCore::PixelFormat::D24,
VideoCore::PixelFormat::D24S8
};
const vk::FormatFeatureFlags storage_usage = vk::FormatFeatureFlagBits::eStorageImage; const vk::FormatFeatureFlags storage_usage = vk::FormatFeatureFlagBits::eStorageImage;
const vk::FormatFeatureFlags blit_usage = vk::FormatFeatureFlagBits::eSampledImage | const vk::FormatFeatureFlags blit_usage =
vk::FormatFeatureFlagBits::eTransferDst | vk::FormatFeatureFlagBits::eSampledImage | vk::FormatFeatureFlagBits::eTransferDst |
vk::FormatFeatureFlagBits::eTransferSrc | vk::FormatFeatureFlagBits::eTransferSrc | vk::FormatFeatureFlagBits::eBlitSrc |
vk::FormatFeatureFlagBits::eBlitSrc |
vk::FormatFeatureFlagBits::eBlitDst; vk::FormatFeatureFlagBits::eBlitDst;
for (const auto& pixel_format : pixel_formats) { for (const auto& pixel_format : pixel_formats) {
@ -176,12 +162,12 @@ void Instance::CreateFormatTable() {
const vk::FormatProperties properties = physical_device.getFormatProperties(format); const vk::FormatProperties properties = physical_device.getFormatProperties(format);
const vk::ImageAspectFlags aspect = GetImageAspect(format); const vk::ImageAspectFlags aspect = GetImageAspect(format);
const vk::FormatFeatureFlagBits attachment_usage = (aspect & vk::ImageAspectFlagBits::eDepth) ? const vk::FormatFeatureFlagBits attachment_usage =
vk::FormatFeatureFlagBits::eDepthStencilAttachment : (aspect & vk::ImageAspectFlagBits::eDepth)
vk::FormatFeatureFlagBits::eColorAttachment; ? vk::FormatFeatureFlagBits::eDepthStencilAttachment
: vk::FormatFeatureFlagBits::eColorAttachment;
const bool supports_blit = const bool supports_blit = (properties.optimalTilingFeatures & blit_usage) == blit_usage;
(properties.optimalTilingFeatures & blit_usage) == blit_usage;
const bool supports_attachment = const bool supports_attachment =
(properties.optimalTilingFeatures & attachment_usage) == attachment_usage; (properties.optimalTilingFeatures & attachment_usage) == attachment_usage;
const bool supports_storage = const bool supports_storage =
@ -190,14 +176,13 @@ void Instance::CreateFormatTable() {
// Find the most inclusive usage flags for this format // Find the most inclusive usage flags for this format
vk::ImageUsageFlags best_usage; vk::ImageUsageFlags best_usage;
if (supports_blit) { if (supports_blit) {
best_usage |= vk::ImageUsageFlagBits::eSampled | best_usage |= vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst |
vk::ImageUsageFlagBits::eTransferDst |
vk::ImageUsageFlagBits::eTransferSrc; vk::ImageUsageFlagBits::eTransferSrc;
} }
if (supports_attachment) { if (supports_attachment) {
best_usage |= (aspect & vk::ImageAspectFlagBits::eDepth) ? best_usage |= (aspect & vk::ImageAspectFlagBits::eDepth)
vk::ImageUsageFlagBits::eDepthStencilAttachment : ? vk::ImageUsageFlagBits::eDepthStencilAttachment
vk::ImageUsageFlagBits::eColorAttachment; : vk::ImageUsageFlagBits::eColorAttachment;
} }
if (supports_storage) { if (supports_storage) {
best_usage |= vk::ImageUsageFlagBits::eStorage; best_usage |= vk::ImageUsageFlagBits::eStorage;
@ -219,26 +204,26 @@ void Instance::CreateFormatTable() {
} }
const u32 index = static_cast<u32>(pixel_format); const u32 index = static_cast<u32>(pixel_format);
format_table[index] = FormatTraits{ format_table[index] = FormatTraits{.blit_support = supports_blit,
.blit_support = supports_blit,
.attachment_support = supports_attachment, .attachment_support = supports_attachment,
.storage_support = supports_storage, .storage_support = supports_storage,
.usage = best_usage, .usage = best_usage,
.native = format, .native = format,
.fallback = fallback .fallback = fallback};
};
} }
} }
bool Instance::CreateDevice() { bool Instance::CreateDevice() {
auto feature_chain = physical_device.getFeatures2<vk::PhysicalDeviceFeatures2, auto feature_chain =
physical_device.getFeatures2<vk::PhysicalDeviceFeatures2,
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT,
vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>(); vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>();
// Not having geometry shaders will cause issues with accelerated rendering. // Not having geometry shaders will cause issues with accelerated rendering.
const vk::PhysicalDeviceFeatures available = feature_chain.get().features; const vk::PhysicalDeviceFeatures available = feature_chain.get().features;
if (!available.geometryShader) { if (!available.geometryShader) {
LOG_WARNING(Render_Vulkan, "Geometry shaders not availabe! Accelerated rendering not possible!"); LOG_WARNING(Render_Vulkan,
"Geometry shaders not availabe! Accelerated rendering not possible!");
} }
auto extension_list = physical_device.enumerateDeviceExtensionProperties(); auto extension_list = physical_device.enumerateDeviceExtensionProperties();
@ -252,9 +237,9 @@ bool Instance::CreateDevice() {
u32 enabled_extension_count = 0; u32 enabled_extension_count = 0;
auto AddExtension = [&](std::string_view name) -> bool { auto AddExtension = [&](std::string_view name) -> bool {
auto result = std::find_if(extension_list.begin(), extension_list.end(), [&](const auto& prop) { auto result =
return name.compare(prop.extensionName.data()); std::find_if(extension_list.begin(), extension_list.end(),
}); [&](const auto& prop) { return name.compare(prop.extensionName.data()); });
if (result != extension_list.end()) { if (result != extension_list.end()) {
LOG_INFO(Render_Vulkan, "Enabling extension: {}", name); LOG_INFO(Render_Vulkan, "Enabling extension: {}", name);
@ -311,17 +296,12 @@ bool Instance::CreateDevice() {
static constexpr float queue_priorities[] = {1.0f}; static constexpr float queue_priorities[] = {1.0f};
const std::array queue_infos = { const std::array queue_infos = {
vk::DeviceQueueCreateInfo{ vk::DeviceQueueCreateInfo{.queueFamilyIndex = graphics_queue_family_index,
.queueFamilyIndex = graphics_queue_family_index,
.queueCount = 1, .queueCount = 1,
.pQueuePriorities = queue_priorities .pQueuePriorities = queue_priorities},
}, vk::DeviceQueueCreateInfo{.queueFamilyIndex = present_queue_family_index,
vk::DeviceQueueCreateInfo{
.queueFamilyIndex = present_queue_family_index,
.queueCount = 1, .queueCount = 1,
.pQueuePriorities = queue_priorities .pQueuePriorities = queue_priorities}};
}
};
const u32 queue_count = graphics_queue_family_index != present_queue_family_index ? 2u : 1u; const u32 queue_count = graphics_queue_family_index != present_queue_family_index ? 2u : 1u;
const vk::StructureChain device_chain = { const vk::StructureChain device_chain = {
@ -332,8 +312,7 @@ bool Instance::CreateDevice() {
.ppEnabledExtensionNames = enabled_extensions.data(), .ppEnabledExtensionNames = enabled_extensions.data(),
}, },
vk::PhysicalDeviceFeatures2{ vk::PhysicalDeviceFeatures2{
.features = { .features = {.robustBufferAccess = available.robustBufferAccess,
.robustBufferAccess = available.robustBufferAccess,
.geometryShader = available.geometryShader, .geometryShader = available.geometryShader,
.dualSrcBlend = available.dualSrcBlend, .dualSrcBlend = available.dualSrcBlend,
.logicOp = available.logicOp, .logicOp = available.logicOp,
@ -342,15 +321,10 @@ bool Instance::CreateDevice() {
.samplerAnisotropy = available.samplerAnisotropy, .samplerAnisotropy = available.samplerAnisotropy,
.fragmentStoresAndAtomics = available.fragmentStoresAndAtomics, .fragmentStoresAndAtomics = available.fragmentStoresAndAtomics,
.shaderStorageImageMultisample = available.shaderStorageImageMultisample, .shaderStorageImageMultisample = available.shaderStorageImageMultisample,
.shaderClipDistance = available.shaderClipDistance .shaderClipDistance = available.shaderClipDistance}},
} vk::PhysicalDeviceDepthClipControlFeaturesEXT{.depthClipControl = true},
},
vk::PhysicalDeviceDepthClipControlFeaturesEXT{
.depthClipControl = true
},
feature_chain.get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(), feature_chain.get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(),
feature_chain.get<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>() feature_chain.get<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>()};
};
// Create logical device // Create logical device
device = physical_device.createDevice(device_chain.get()); device = physical_device.createDevice(device_chain.get());
@ -367,16 +341,13 @@ bool Instance::CreateDevice() {
void Instance::CreateAllocator() { void Instance::CreateAllocator() {
const VmaVulkanFunctions functions = { const VmaVulkanFunctions functions = {
.vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr, .vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr,
.vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr .vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr};
};
const VmaAllocatorCreateInfo allocator_info = { const VmaAllocatorCreateInfo allocator_info = {.physicalDevice = physical_device,
.physicalDevice = physical_device,
.device = device, .device = device,
.pVulkanFunctions = &functions, .pVulkanFunctions = &functions,
.instance = instance, .instance = instance,
.vulkanApiVersion = VK_API_VERSION_1_1 .vulkanApiVersion = VK_API_VERSION_1_1};
};
if (VkResult result = vmaCreateAllocator(&allocator_info, &allocator); result != VK_SUCCESS) { if (VkResult result = vmaCreateAllocator(&allocator_info, &allocator); result != VK_SUCCESS) {
LOG_CRITICAL(Render_Vulkan, "Failed to initialize VMA with error {}", result); LOG_CRITICAL(Render_Vulkan, "Failed to initialize VMA with error {}", result);

View File

@ -8,8 +8,8 @@
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/renderer_vulkan/pica_to_vk.h" #include "video_core/renderer_vulkan/pica_to_vk.h"
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h" #include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_task_scheduler.h" #include "video_core/renderer_vulkan/vk_task_scheduler.h"
@ -22,51 +22,26 @@ struct Bindings {
constexpr u32 RASTERIZER_SET_COUNT = 4; constexpr u32 RASTERIZER_SET_COUNT = 4;
constexpr static std::array RASTERIZER_SETS = { constexpr static std::array RASTERIZER_SETS = {
Bindings{ Bindings{// Utility set
// Utility set .bindings = {vk::DescriptorType::eUniformBuffer, vk::DescriptorType::eUniformBuffer,
.bindings = {
vk::DescriptorType::eUniformBuffer,
vk::DescriptorType::eUniformBuffer,
vk::DescriptorType::eUniformTexelBuffer, vk::DescriptorType::eUniformTexelBuffer,
vk::DescriptorType::eUniformTexelBuffer, vk::DescriptorType::eUniformTexelBuffer,
vk::DescriptorType::eUniformTexelBuffer vk::DescriptorType::eUniformTexelBuffer},
}, .binding_count = 5},
.binding_count = 5 Bindings{// Texture set
}, .bindings = {vk::DescriptorType::eSampledImage, vk::DescriptorType::eSampledImage,
Bindings{ vk::DescriptorType::eSampledImage, vk::DescriptorType::eSampledImage},
// Texture set .binding_count = 4},
.bindings = { Bindings{// Sampler set
vk::DescriptorType::eSampledImage, .bindings = {vk::DescriptorType::eSampler, vk::DescriptorType::eSampler,
vk::DescriptorType::eSampledImage, vk::DescriptorType::eSampler, vk::DescriptorType::eSampler},
vk::DescriptorType::eSampledImage, .binding_count = 4},
vk::DescriptorType::eSampledImage Bindings{// Shadow set
}, .bindings = {vk::DescriptorType::eStorageImage, vk::DescriptorType::eStorageImage,
.binding_count = 4 vk::DescriptorType::eStorageImage, vk::DescriptorType::eStorageImage,
}, vk::DescriptorType::eStorageImage, vk::DescriptorType::eStorageImage,
Bindings{ vk::DescriptorType::eStorageImage},
// Sampler set .binding_count = 7}};
.bindings = {
vk::DescriptorType::eSampler,
vk::DescriptorType::eSampler,
vk::DescriptorType::eSampler,
vk::DescriptorType::eSampler
},
.binding_count = 4
},
Bindings {
// Shadow set
.bindings = {
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage
},
.binding_count = 7
}
};
constexpr vk::ShaderStageFlags ToVkStageFlags(vk::DescriptorType type) { constexpr vk::ShaderStageFlags ToVkStageFlags(vk::DescriptorType type) {
vk::ShaderStageFlags flags; vk::ShaderStageFlags flags;
@ -79,10 +54,8 @@ constexpr vk::ShaderStageFlags ToVkStageFlags(vk::DescriptorType type) {
break; break;
case vk::DescriptorType::eUniformBuffer: case vk::DescriptorType::eUniformBuffer:
case vk::DescriptorType::eUniformBufferDynamic: case vk::DescriptorType::eUniformBufferDynamic:
flags = vk::ShaderStageFlagBits::eFragment | flags = vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eVertex |
vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eGeometry | vk::ShaderStageFlagBits::eCompute;
vk::ShaderStageFlagBits::eGeometry |
vk::ShaderStageFlagBits::eCompute;
break; break;
default: default:
LOG_ERROR(Render_Vulkan, "Unknown descriptor type!"); LOG_ERROR(Render_Vulkan, "Unknown descriptor type!");
@ -109,10 +82,14 @@ vk::Format ToVkAttributeFormat(VertexAttribute attrib) {
switch (attrib.type) { switch (attrib.type) {
case AttribType::Float: case AttribType::Float:
switch (attrib.size) { switch (attrib.size) {
case 1: return vk::Format::eR32Sfloat; case 1:
case 2: return vk::Format::eR32G32Sfloat; return vk::Format::eR32Sfloat;
case 3: return vk::Format::eR32G32B32Sfloat; case 2:
case 4: return vk::Format::eR32G32B32A32Sfloat; return vk::Format::eR32G32Sfloat;
case 3:
return vk::Format::eR32G32B32Sfloat;
case 4:
return vk::Format::eR32G32B32A32Sfloat;
} }
default: default:
LOG_CRITICAL(Render_Vulkan, "Unimplemented vertex attribute format!"); LOG_CRITICAL(Render_Vulkan, "Unimplemented vertex attribute format!");
@ -124,9 +101,12 @@ vk::Format ToVkAttributeFormat(VertexAttribute attrib) {
vk::ShaderStageFlagBits ToVkShaderStage(std::size_t index) { vk::ShaderStageFlagBits ToVkShaderStage(std::size_t index) {
switch (index) { switch (index) {
case 0: return vk::ShaderStageFlagBits::eVertex; case 0:
case 1: return vk::ShaderStageFlagBits::eFragment; return vk::ShaderStageFlagBits::eVertex;
case 2: return vk::ShaderStageFlagBits::eGeometry; case 1:
return vk::ShaderStageFlagBits::eFragment;
case 2:
return vk::ShaderStageFlagBits::eGeometry;
default: default:
LOG_CRITICAL(Render_Vulkan, "Invalid shader stage index!"); LOG_CRITICAL(Render_Vulkan, "Invalid shader stage index!");
UNREACHABLE(); UNREACHABLE();
@ -135,7 +115,8 @@ vk::ShaderStageFlagBits ToVkShaderStage(std::size_t index) {
return vk::ShaderStageFlagBits::eVertex; return vk::ShaderStageFlagBits::eVertex;
} }
PipelineCache::PipelineCache(const Instance& instance, TaskScheduler& scheduler, RenderpassCache& renderpass_cache) PipelineCache::PipelineCache(const Instance& instance, TaskScheduler& scheduler,
RenderpassCache& renderpass_cache)
: instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache} { : instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache} {
descriptor_dirty.fill(true); descriptor_dirty.fill(true);
@ -185,9 +166,10 @@ void PipelineCache::BindPipeline(const PipelineInfo& info) {
shader_hash = Common::HashCombine(shader_hash, shader_hashes[i]); shader_hash = Common::HashCombine(shader_hash, shader_hashes[i]);
} }
const u64 info_hash_size = instance.IsExtendedDynamicStateSupported() ? const u64 info_hash_size = instance.IsExtendedDynamicStateSupported()
offsetof(PipelineInfo, rasterization) : ? offsetof(PipelineInfo, rasterization)
offsetof(PipelineInfo, depth_stencil) + offsetof(DepthStencilState, stencil_reference); : offsetof(PipelineInfo, depth_stencil) +
offsetof(DepthStencilState, stencil_reference);
u64 info_hash = Common::ComputeHash64(&info, info_hash_size); u64 info_hash = Common::ComputeHash64(&info, info_hash_size);
u64 pipeline_hash = Common::HashCombine(shader_hash, info_hash); u64 pipeline_hash = Common::HashCombine(shader_hash, info_hash);
@ -206,9 +188,11 @@ void PipelineCache::BindPipeline(const PipelineInfo& info) {
BindDescriptorSets(); BindDescriptorSets();
} }
bool PipelineCache::UseProgrammableVertexShader(const Pica::Regs& regs, Pica::Shader::ShaderSetup& setup) { bool PipelineCache::UseProgrammableVertexShader(const Pica::Regs& regs,
Pica::Shader::ShaderSetup& setup) {
const PicaVSConfig config{regs.vs, setup}; const PicaVSConfig config{regs.vs, setup};
auto [handle, result] = programmable_vertex_shaders.Get(config, setup, vk::ShaderStageFlagBits::eVertex, auto [handle, result] =
programmable_vertex_shaders.Get(config, setup, vk::ShaderStageFlagBits::eVertex,
instance.GetDevice(), ShaderOptimization::Debug); instance.GetDevice(), ShaderOptimization::Debug);
if (!handle) { if (!handle) {
return false; return false;
@ -247,48 +231,33 @@ void PipelineCache::UseFragmentShader(const Pica::Regs& regs) {
void PipelineCache::BindTexture(u32 binding, vk::ImageView image_view) { void PipelineCache::BindTexture(u32 binding, vk::ImageView image_view) {
const vk::DescriptorImageInfo image_info = { const vk::DescriptorImageInfo image_info = {
.imageView = image_view, .imageView = image_view, .imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal};
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal
};
SetBinding(1, binding, DescriptorData{image_info}); SetBinding(1, binding, DescriptorData{image_info});
} }
void PipelineCache::BindStorageImage(u32 binding, vk::ImageView image_view) { void PipelineCache::BindStorageImage(u32 binding, vk::ImageView image_view) {
const vk::DescriptorImageInfo image_info = { const vk::DescriptorImageInfo image_info = {.imageView = image_view,
.imageView = image_view, .imageLayout = vk::ImageLayout::eGeneral};
.imageLayout = vk::ImageLayout::eGeneral
};
SetBinding(3, binding, DescriptorData{image_info}); SetBinding(3, binding, DescriptorData{image_info});
} }
void PipelineCache::BindBuffer(u32 binding, vk::Buffer buffer, u32 offset, u32 size) { void PipelineCache::BindBuffer(u32 binding, vk::Buffer buffer, u32 offset, u32 size) {
const DescriptorData data = { const DescriptorData data = {
.buffer_info = vk::DescriptorBufferInfo{ .buffer_info = vk::DescriptorBufferInfo{.buffer = buffer, .offset = offset, .range = size}};
.buffer = buffer,
.offset = offset,
.range = size
}
};
SetBinding(0, binding, data); SetBinding(0, binding, data);
} }
void PipelineCache::BindTexelBuffer(u32 binding, vk::BufferView buffer_view) { void PipelineCache::BindTexelBuffer(u32 binding, vk::BufferView buffer_view) {
const DescriptorData data = { const DescriptorData data = {.buffer_view = buffer_view};
.buffer_view = buffer_view
};
SetBinding(0, binding, data); SetBinding(0, binding, data);
} }
void PipelineCache::BindSampler(u32 binding, vk::Sampler sampler) { void PipelineCache::BindSampler(u32 binding, vk::Sampler sampler) {
const DescriptorData data = { const DescriptorData data = {.image_info = vk::DescriptorImageInfo{.sampler = sampler}};
.image_info = vk::DescriptorImageInfo{
.sampler = sampler
}
};
SetBinding(2, binding, data); SetBinding(2, binding, data);
} }
@ -311,7 +280,8 @@ void PipelineCache::MarkDirty() {
void PipelineCache::ApplyDynamic(const PipelineInfo& info) { void PipelineCache::ApplyDynamic(const PipelineInfo& info) {
if (instance.IsExtendedDynamicStateSupported()) { if (instance.IsExtendedDynamicStateSupported()) {
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.setPrimitiveTopologyEXT(PicaToVK::PrimitiveTopology(info.rasterization.topology)); command_buffer.setPrimitiveTopologyEXT(
PicaToVK::PrimitiveTopology(info.rasterization.topology));
} }
} }
@ -331,27 +301,22 @@ void PipelineCache::BuildLayout() {
const auto& set = RASTERIZER_SETS[i]; const auto& set = RASTERIZER_SETS[i];
for (u32 j = 0; j < set.binding_count; j++) { for (u32 j = 0; j < set.binding_count; j++) {
vk::DescriptorType type = set.bindings[j]; vk::DescriptorType type = set.bindings[j];
set_bindings[j] = vk::DescriptorSetLayoutBinding{ set_bindings[j] = vk::DescriptorSetLayoutBinding{.binding = j,
.binding = j,
.descriptorType = type, .descriptorType = type,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = ToVkStageFlags(type) .stageFlags = ToVkStageFlags(type)};
};
update_entries[j] = vk::DescriptorUpdateTemplateEntry{ update_entries[j] =
.dstBinding = j, vk::DescriptorUpdateTemplateEntry{.dstBinding = j,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = type, .descriptorType = type,
.offset = j * sizeof(DescriptorData), .offset = j * sizeof(DescriptorData),
.stride = 0 .stride = 0};
};
} }
const vk::DescriptorSetLayoutCreateInfo layout_info = { const vk::DescriptorSetLayoutCreateInfo layout_info = {.bindingCount = set.binding_count,
.bindingCount = set.binding_count, .pBindings = set_bindings.data()};
.pBindings = set_bindings.data()
};
// Create descriptor set layout // Create descriptor set layout
descriptor_set_layouts[i] = device.createDescriptorSetLayout(layout_info); descriptor_set_layouts[i] = device.createDescriptorSetLayout(layout_info);
@ -360,19 +325,16 @@ void PipelineCache::BuildLayout() {
.descriptorUpdateEntryCount = set.binding_count, .descriptorUpdateEntryCount = set.binding_count,
.pDescriptorUpdateEntries = update_entries.data(), .pDescriptorUpdateEntries = update_entries.data(),
.templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet, .templateType = vk::DescriptorUpdateTemplateType::eDescriptorSet,
.descriptorSetLayout = descriptor_set_layouts[i] .descriptorSetLayout = descriptor_set_layouts[i]};
};
// Create descriptor set update template // Create descriptor set update template
update_templates[i] = device.createDescriptorUpdateTemplate(template_info); update_templates[i] = device.createDescriptorUpdateTemplate(template_info);
} }
const vk::PipelineLayoutCreateInfo layout_info = { const vk::PipelineLayoutCreateInfo layout_info = {.setLayoutCount = RASTERIZER_SET_COUNT,
.setLayoutCount = RASTERIZER_SET_COUNT,
.pSetLayouts = descriptor_set_layouts.data(), .pSetLayouts = descriptor_set_layouts.data(),
.pushConstantRangeCount = 0, .pushConstantRangeCount = 0,
.pPushConstantRanges = nullptr .pPushConstantRanges = nullptr};
};
layout = device.createPipelineLayout(layout_info); layout = device.createPipelineLayout(layout_info);
} }
@ -389,16 +351,14 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
} }
shader_stages[shader_count++] = vk::PipelineShaderStageCreateInfo{ shader_stages[shader_count++] = vk::PipelineShaderStageCreateInfo{
.stage = ToVkShaderStage(i), .stage = ToVkShaderStage(i), .module = shader, .pName = "main"};
.module = shader,
.pName = "main"
};
} }
/** /**
* Vulkan doesn't intuitively support fixed attributes. To avoid duplicating the data and increasing * Vulkan doesn't intuitively support fixed attributes. To avoid duplicating the data and
* data upload, when the fixed flag is true, we specify VK_VERTEX_INPUT_RATE_INSTANCE as the input rate. * increasing data upload, when the fixed flag is true, we specify VK_VERTEX_INPUT_RATE_INSTANCE
* Since one instance is all we render, the shader will always read the single attribute. * as the input rate. Since one instance is all we render, the shader will always read the
* single attribute.
*/ */
std::array<vk::VertexInputBindingDescription, MAX_VERTEX_BINDINGS> bindings; std::array<vk::VertexInputBindingDescription, MAX_VERTEX_BINDINGS> bindings;
for (u32 i = 0; i < info.vertex_layout.binding_count; i++) { for (u32 i = 0; i < info.vertex_layout.binding_count; i++) {
@ -407,33 +367,28 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.binding = binding.binding, .binding = binding.binding,
.stride = binding.stride, .stride = binding.stride,
.inputRate = binding.fixed.Value() ? vk::VertexInputRate::eInstance .inputRate = binding.fixed.Value() ? vk::VertexInputRate::eInstance
: vk::VertexInputRate::eVertex : vk::VertexInputRate::eVertex};
};
} }
// Populate vertex attribute structures // Populate vertex attribute structures
std::array<vk::VertexInputAttributeDescription, MAX_VERTEX_ATTRIBUTES> attributes; std::array<vk::VertexInputAttributeDescription, MAX_VERTEX_ATTRIBUTES> attributes;
for (u32 i = 0; i < info.vertex_layout.attribute_count; i++) { for (u32 i = 0; i < info.vertex_layout.attribute_count; i++) {
const auto& attr = info.vertex_layout.attributes[i]; const auto& attr = info.vertex_layout.attributes[i];
attributes[i] = vk::VertexInputAttributeDescription{ attributes[i] = vk::VertexInputAttributeDescription{.location = attr.location,
.location = attr.location,
.binding = attr.binding, .binding = attr.binding,
.format = ToVkAttributeFormat(attr), .format = ToVkAttributeFormat(attr),
.offset = attr.offset .offset = attr.offset};
};
} }
const vk::PipelineVertexInputStateCreateInfo vertex_input_info = { const vk::PipelineVertexInputStateCreateInfo vertex_input_info = {
.vertexBindingDescriptionCount = info.vertex_layout.binding_count, .vertexBindingDescriptionCount = info.vertex_layout.binding_count,
.pVertexBindingDescriptions = bindings.data(), .pVertexBindingDescriptions = bindings.data(),
.vertexAttributeDescriptionCount = info.vertex_layout.attribute_count, .vertexAttributeDescriptionCount = info.vertex_layout.attribute_count,
.pVertexAttributeDescriptions = attributes.data() .pVertexAttributeDescriptions = attributes.data()};
};
const vk::PipelineInputAssemblyStateCreateInfo input_assembly = { const vk::PipelineInputAssemblyStateCreateInfo input_assembly = {
.topology = PicaToVK::PrimitiveTopology(info.rasterization.topology), .topology = PicaToVK::PrimitiveTopology(info.rasterization.topology),
.primitiveRestartEnable = false .primitiveRestartEnable = false};
};
const vk::PipelineRasterizationStateCreateInfo raster_state = { const vk::PipelineRasterizationStateCreateInfo raster_state = {
.depthClampEnable = false, .depthClampEnable = false,
@ -441,13 +396,10 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.cullMode = PicaToVK::CullMode(info.rasterization.cull_mode), .cullMode = PicaToVK::CullMode(info.rasterization.cull_mode),
.frontFace = PicaToVK::FrontFace(info.rasterization.cull_mode), .frontFace = PicaToVK::FrontFace(info.rasterization.cull_mode),
.depthBiasEnable = false, .depthBiasEnable = false,
.lineWidth = 1.0f .lineWidth = 1.0f};
};
const vk::PipelineMultisampleStateCreateInfo multisampling = { const vk::PipelineMultisampleStateCreateInfo multisampling = {
.rasterizationSamples = vk::SampleCountFlagBits::e1, .rasterizationSamples = vk::SampleCountFlagBits::e1, .sampleShadingEnable = false};
.sampleShadingEnable = false
};
const vk::PipelineColorBlendAttachmentState colorblend_attachment = { const vk::PipelineColorBlendAttachmentState colorblend_attachment = {
.blendEnable = info.blending.blend_enable.Value(), .blendEnable = info.blending.blend_enable.Value(),
@ -458,34 +410,22 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.dstAlphaBlendFactor = PicaToVK::BlendFunc(info.blending.dst_alpha_blend_factor), .dstAlphaBlendFactor = PicaToVK::BlendFunc(info.blending.dst_alpha_blend_factor),
.alphaBlendOp = PicaToVK::BlendEquation(info.blending.alpha_blend_eq), .alphaBlendOp = PicaToVK::BlendEquation(info.blending.alpha_blend_eq),
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA};
};
const vk::PipelineColorBlendStateCreateInfo color_blending = { const vk::PipelineColorBlendStateCreateInfo color_blending = {
.logicOpEnable = info.blending.logic_op_enable.Value(), .logicOpEnable = info.blending.logic_op_enable.Value(),
.logicOp = PicaToVK::LogicOp(info.blending.logic_op), .logicOp = PicaToVK::LogicOp(info.blending.logic_op),
.attachmentCount = 1, .attachmentCount = 1,
.pAttachments = &colorblend_attachment, .pAttachments = &colorblend_attachment,
.blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f} .blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f}};
};
const vk::Viewport viewport = { const vk::Viewport viewport = {
.x = 0.0f, .x = 0.0f, .y = 0.0f, .width = 1.0f, .height = 1.0f, .minDepth = 0.0f, .maxDepth = 1.0f};
.y = 0.0f,
.width = 1.0f,
.height = 1.0f,
.minDepth = 0.0f,
.maxDepth = 1.0f
};
const vk::Rect2D scissor = { const vk::Rect2D scissor = {.offset = {0, 0}, .extent = {1, 1}};
.offset = {0, 0},
.extent = {1, 1}
};
vk::PipelineViewportDepthClipControlCreateInfoEXT depth_clip_control = { vk::PipelineViewportDepthClipControlCreateInfoEXT depth_clip_control = {.negativeOneToOne =
.negativeOneToOne = true true};
};
const vk::PipelineViewportStateCreateInfo viewport_info = { const vk::PipelineViewportStateCreateInfo viewport_info = {
.pNext = &depth_clip_control, .pNext = &depth_clip_control,
@ -515,17 +455,14 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
}; };
const vk::PipelineDynamicStateCreateInfo dynamic_info = { const vk::PipelineDynamicStateCreateInfo dynamic_info = {
.dynamicStateCount = .dynamicStateCount = extended_dynamic_states ? static_cast<u32>(dynamic_states.size()) : 6u,
extended_dynamic_states ? static_cast<u32>(dynamic_states.size()) : 6u, .pDynamicStates = dynamic_states.data()};
.pDynamicStates = dynamic_states.data()
};
const vk::StencilOpState stencil_op_state = { const vk::StencilOpState stencil_op_state = {
.failOp = PicaToVK::StencilOp(info.depth_stencil.stencil_fail_op), .failOp = PicaToVK::StencilOp(info.depth_stencil.stencil_fail_op),
.passOp = PicaToVK::StencilOp(info.depth_stencil.stencil_pass_op), .passOp = PicaToVK::StencilOp(info.depth_stencil.stencil_pass_op),
.depthFailOp = PicaToVK::StencilOp(info.depth_stencil.stencil_depth_fail_op), .depthFailOp = PicaToVK::StencilOp(info.depth_stencil.stencil_depth_fail_op),
.compareOp = PicaToVK::CompareFunc(info.depth_stencil.stencil_compare_op) .compareOp = PicaToVK::CompareFunc(info.depth_stencil.stencil_compare_op)};
};
const vk::PipelineDepthStencilStateCreateInfo depth_info = { const vk::PipelineDepthStencilStateCreateInfo depth_info = {
.depthTestEnable = static_cast<u32>(info.depth_stencil.depth_test_enable.Value()), .depthTestEnable = static_cast<u32>(info.depth_stencil.depth_test_enable.Value()),
@ -534,8 +471,7 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.depthBoundsTestEnable = false, .depthBoundsTestEnable = false,
.stencilTestEnable = static_cast<u32>(info.depth_stencil.stencil_test_enable.Value()), .stencilTestEnable = static_cast<u32>(info.depth_stencil.stencil_test_enable.Value()),
.front = stencil_op_state, .front = stencil_op_state,
.back = stencil_op_state .back = stencil_op_state};
};
const vk::GraphicsPipelineCreateInfo pipeline_info = { const vk::GraphicsPipelineCreateInfo pipeline_info = {
.stageCount = shader_count, .stageCount = shader_count,
@ -549,9 +485,8 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
.pColorBlendState = &color_blending, .pColorBlendState = &color_blending,
.pDynamicState = &dynamic_info, .pDynamicState = &dynamic_info,
.layout = layout, .layout = layout,
.renderPass = renderpass_cache.GetRenderpass(info.color_attachment, .renderPass =
info.depth_attachment, false) renderpass_cache.GetRenderpass(info.color_attachment, info.depth_attachment, false)};
};
if (const auto result = device.createGraphicsPipeline(pipeline_cache, pipeline_info); if (const auto result = device.createGraphicsPipeline(pipeline_cache, pipeline_info);
result.result == vk::Result::eSuccess) { result.result == vk::Result::eSuccess) {
@ -573,8 +508,7 @@ void PipelineCache::BindDescriptorSets() {
const vk::DescriptorSetAllocateInfo alloc_info = { const vk::DescriptorSetAllocateInfo alloc_info = {
.descriptorPool = scheduler.GetDescriptorPool(), .descriptorPool = scheduler.GetDescriptorPool(),
.descriptorSetCount = 1, .descriptorSetCount = 1,
.pSetLayouts = &descriptor_set_layouts[i] .pSetLayouts = &descriptor_set_layouts[i]};
};
vk::DescriptorSet set = device.allocateDescriptorSets(alloc_info)[0]; vk::DescriptorSet set = device.allocateDescriptorSets(alloc_info)[0];
device.updateDescriptorSetWithTemplate(set, update_templates[i], update_data[i][0]); device.updateDescriptorSetWithTemplate(set, update_templates[i], update_data[i][0]);
@ -586,8 +520,8 @@ void PipelineCache::BindDescriptorSets() {
// Bind the descriptor sets // Bind the descriptor sets
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0, RASTERIZER_SET_COUNT, command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0,
descriptor_sets.data(), 0, nullptr); RASTERIZER_SET_COUNT, descriptor_sets.data(), 0, nullptr);
} }
void PipelineCache::LoadDiskCache() { void PipelineCache::LoadDiskCache() {
@ -596,10 +530,7 @@ void PipelineCache::LoadDiskCache() {
} }
const std::string cache_file_path = GetPipelineCacheDir() + DIR_SEP "pipelines.bin"; const std::string cache_file_path = GetPipelineCacheDir() + DIR_SEP "pipelines.bin";
vk::PipelineCacheCreateInfo cache_info = { vk::PipelineCacheCreateInfo cache_info = {.initialDataSize = 0, .pInitialData = nullptr};
.initialDataSize = 0,
.pInitialData = nullptr
};
FileUtil::IOFile cache_file{cache_file_path, "r"}; FileUtil::IOFile cache_file{cache_file_path, "r"};
if (cache_file.IsOpen()) { if (cache_file.IsOpen()) {
@ -664,14 +595,16 @@ bool PipelineCache::IsCacheValid(const u8* data, u32 size) const {
} }
if (u32 vendor_id = instance.GetVendorID(); header.vendorID != vendor_id) { if (u32 vendor_id = instance.GetVendorID(); header.vendorID != vendor_id) {
LOG_ERROR(Render_Vulkan, LOG_ERROR(
Render_Vulkan,
"Pipeline cache failed validation: Incorrect vendor ID (file: {:#X}, device: {:#X})", "Pipeline cache failed validation: Incorrect vendor ID (file: {:#X}, device: {:#X})",
header.vendorID, vendor_id); header.vendorID, vendor_id);
return false; return false;
} }
if (u32 device_id = instance.GetDeviceID(); header.deviceID != device_id) { if (u32 device_id = instance.GetDeviceID(); header.deviceID != device_id) {
LOG_ERROR(Render_Vulkan, LOG_ERROR(
Render_Vulkan,
"Pipeline cache failed validation: Incorrect device ID (file: {:#X}, device: {:#X})", "Pipeline cache failed validation: Incorrect device ID (file: {:#X}, device: {:#X})",
header.deviceID, device_id); header.deviceID, device_id);
return false; return false;

View File

@ -8,11 +8,11 @@
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/hash.h" #include "common/hash.h"
#include "video_core/rasterizer_cache/pixel_format.h" #include "video_core/rasterizer_cache/pixel_format.h"
#include "video_core/regs.h"
#include "video_core/renderer_vulkan/vk_common.h" #include "video_core/renderer_vulkan/vk_common.h"
#include "video_core/renderer_vulkan/vk_shader.h" #include "video_core/renderer_vulkan/vk_shader.h"
#include "video_core/renderer_vulkan/vk_shader_gen.h" #include "video_core/renderer_vulkan/vk_shader_gen.h"
#include "video_core/shader/shader_cache.h" #include "video_core/shader/shader_cache.h"
#include "video_core/regs.h"
namespace Vulkan { namespace Vulkan {
@ -22,13 +22,7 @@ constexpr u32 MAX_VERTEX_BINDINGS = 16;
constexpr u32 MAX_DESCRIPTORS = 8; constexpr u32 MAX_DESCRIPTORS = 8;
constexpr u32 MAX_DESCRIPTOR_SETS = 6; constexpr u32 MAX_DESCRIPTOR_SETS = 6;
enum class AttribType : u32 { enum class AttribType : u32 { Float = 0, Int = 1, Short = 2, Byte = 3, Ubyte = 4 };
Float = 0,
Int = 1,
Short = 2,
Byte = 3,
Ubyte = 4
};
/** /**
* The pipeline state is tightly packed with bitfields to reduce * The pipeline state is tightly packed with bitfields to reduce
@ -111,8 +105,8 @@ struct PipelineInfo {
const bool has_stencil = depth_attachment == VideoCore::PixelFormat::D24S8; const bool has_stencil = depth_attachment == VideoCore::PixelFormat::D24S8;
const bool depth_write = const bool depth_write =
depth_stencil.depth_test_enable && depth_stencil.depth_write_enable; depth_stencil.depth_test_enable && depth_stencil.depth_write_enable;
const bool stencil_write = const bool stencil_write = has_stencil && depth_stencil.stencil_test_enable &&
has_stencil && depth_stencil.stencil_test_enable && depth_stencil.stencil_write_mask != 0; depth_stencil.stencil_write_mask != 0;
return depth_write || stencil_write; return depth_write || stencil_write;
} }
@ -133,16 +127,15 @@ using DescriptorSetData = std::array<DescriptorData, MAX_DESCRIPTORS>;
/** /**
* Vulkan specialized PICA shader caches * Vulkan specialized PICA shader caches
*/ */
using ProgrammableVertexShaders = using ProgrammableVertexShaders = Pica::Shader::ShaderDoubleCache<PicaVSConfig, vk::ShaderModule,
Pica::Shader::ShaderDoubleCache<PicaVSConfig, vk::ShaderModule, &Compile, &GenerateVertexShader>; &Compile, &GenerateVertexShader>;
using FixedGeometryShaders = using FixedGeometryShaders = Pica::Shader::ShaderCache<PicaFixedGSConfig, vk::ShaderModule,
Pica::Shader::ShaderCache<PicaFixedGSConfig, vk::ShaderModule, &Compile, &GenerateFixedGeometryShader>; &Compile, &GenerateFixedGeometryShader>;
using FragmentShaders = using FragmentShaders =
Pica::Shader::ShaderCache<PicaFSConfig, vk::ShaderModule, &Compile, &GenerateFragmentShader>; Pica::Shader::ShaderCache<PicaFSConfig, vk::ShaderModule, &Compile, &GenerateFragmentShader>;
class Instance; class Instance;
class TaskScheduler; class TaskScheduler;
class RenderpassCache; class RenderpassCache;
@ -153,7 +146,8 @@ class RenderpassCache;
*/ */
class PipelineCache { class PipelineCache {
public: public:
PipelineCache(const Instance& instance, TaskScheduler& scheduler, RenderpassCache& renderpass_cache); PipelineCache(const Instance& instance, TaskScheduler& scheduler,
RenderpassCache& renderpass_cache);
~PipelineCache(); ~PipelineCache();
/// Binds a pipeline using the provided information /// Binds a pipeline using the provided information
@ -250,11 +244,7 @@ private:
std::array<vk::DescriptorSet, MAX_DESCRIPTOR_SETS> descriptor_sets; std::array<vk::DescriptorSet, MAX_DESCRIPTOR_SETS> descriptor_sets;
// Bound shader modules // Bound shader modules
enum ProgramType : u32 { enum ProgramType : u32 { VS = 0, GS = 2, FS = 1 };
VS = 0,
GS = 2,
FS = 1
};
std::array<vk::ShaderModule, MAX_SHADER_STAGES> current_shaders; std::array<vk::ShaderModule, MAX_SHADER_STAGES> current_shaders;
std::array<u64, MAX_SHADER_STAGES> shader_hashes; std::array<u64, MAX_SHADER_STAGES> shader_hashes;

View File

@ -33,9 +33,7 @@ vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& e
#if defined(VK_USE_PLATFORM_WIN32_KHR) #if defined(VK_USE_PLATFORM_WIN32_KHR)
if (window_info.type == Frontend::WindowSystemType::Windows) { if (window_info.type == Frontend::WindowSystemType::Windows) {
const vk::Win32SurfaceCreateInfoKHR win32_ci = { const vk::Win32SurfaceCreateInfoKHR win32_ci = {
.hinstance = nullptr, .hinstance = nullptr, .hwnd = static_cast<HWND>(window_info.render_surface)};
.hwnd = static_cast<HWND>(window_info.render_surface)
};
if (instance.createWin32SurfaceKHR(&win32_ci, nullptr, &surface) != vk::Result::eSuccess) { if (instance.createWin32SurfaceKHR(&win32_ci, nullptr, &surface) != vk::Result::eSuccess) {
LOG_CRITICAL(Render_Vulkan, "Failed to initialize Win32 surface"); LOG_CRITICAL(Render_Vulkan, "Failed to initialize Win32 surface");
@ -46,8 +44,7 @@ vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& e
if (window_info.type == Frontend::WindowSystemType::X11) { if (window_info.type == Frontend::WindowSystemType::X11) {
const vk::XlibSurfaceCreateInfoKHR xlib_ci = { const vk::XlibSurfaceCreateInfoKHR xlib_ci = {
.dpy = static_cast<Display*>(window_info.display_connection), .dpy = static_cast<Display*>(window_info.display_connection),
.window = reinterpret_cast<Window>(window_info.render_surface) .window = reinterpret_cast<Window>(window_info.render_surface)};
};
if (instance.createXlibSurfaceKHR(&xlib_ci, nullptr, &surface) != vk::Result::eSuccess) { if (instance.createXlibSurfaceKHR(&xlib_ci, nullptr, &surface) != vk::Result::eSuccess) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface"); LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface");
@ -58,10 +55,10 @@ vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& e
if (window_info.type == Frontend::WindowSystemType::Wayland) { if (window_info.type == Frontend::WindowSystemType::Wayland) {
const vk::WaylandSurfaceCreateInfoKHR wayland_ci = { const vk::WaylandSurfaceCreateInfoKHR wayland_ci = {
.display = static_cast<wl_display*>(window_info.display_connection), .display = static_cast<wl_display*>(window_info.display_connection),
.surface = static_cast<wl_surface*>(window_info.render_surface) .surface = static_cast<wl_surface*>(window_info.render_surface)};
};
if (instance.createWaylandSurfaceKHR(&wayland_ci, nullptr, &surface) != vk::Result::eSuccess) { if (instance.createWaylandSurfaceKHR(&wayland_ci, nullptr, &surface) !=
vk::Result::eSuccess) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface"); LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface");
UNREACHABLE(); UNREACHABLE();
} }
@ -75,7 +72,8 @@ vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& e
return surface; return surface;
} }
std::vector<const char*> GetInstanceExtensions(Frontend::WindowSystemType window_type, bool enable_debug_utils) { std::vector<const char*> GetInstanceExtensions(Frontend::WindowSystemType window_type,
bool enable_debug_utils) {
const auto properties = vk::enumerateInstanceExtensionProperties(); const auto properties = vk::enumerateInstanceExtensionProperties();
if (properties.empty()) { if (properties.empty()) {
LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); LOG_ERROR(Render_Vulkan, "Failed to query extension properties");

View File

@ -11,11 +11,12 @@
namespace Frontend { namespace Frontend {
class EmuWindow; class EmuWindow;
enum class WindowSystemType : u8; enum class WindowSystemType : u8;
} } // namespace Frontend
namespace Vulkan { namespace Vulkan {
std::vector<const char*> GetInstanceExtensions(Frontend::WindowSystemType window_type, bool enable_debug_utils); std::vector<const char*> GetInstanceExtensions(Frontend::WindowSystemType window_type,
bool enable_debug_utils);
vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& emu_window); vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& emu_window);

View File

@ -12,8 +12,8 @@
#include "video_core/regs_rasterizer.h" #include "video_core/regs_rasterizer.h"
#include "video_core/renderer_vulkan/pica_to_vk.h" #include "video_core/renderer_vulkan/pica_to_vk.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h"
#include "video_core/renderer_vulkan/vk_task_scheduler.h" #include "video_core/renderer_vulkan/vk_task_scheduler.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
@ -26,7 +26,8 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
RasterizerVulkan::HardwareVertex::HardwareVertex(const Pica::Shader::OutputVertex& v, bool flip_quaternion) { RasterizerVulkan::HardwareVertex::HardwareVertex(const Pica::Shader::OutputVertex& v,
bool flip_quaternion) {
position[0] = v.pos.x.ToFloat32(); position[0] = v.pos.x.ToFloat32();
position[1] = v.pos.y.ToFloat32(); position[1] = v.pos.y.ToFloat32();
position[2] = v.pos.z.ToFloat32(); position[2] = v.pos.z.ToFloat32();
@ -98,31 +99,31 @@ constexpr u32 INDEX_BUFFER_SIZE = 8 * 1024 * 1024;
constexpr u32 UNIFORM_BUFFER_SIZE = 16 * 1024 * 1024; constexpr u32 UNIFORM_BUFFER_SIZE = 16 * 1024 * 1024;
constexpr u32 TEXTURE_BUFFER_SIZE = 16 * 1024 * 1024; constexpr u32 TEXTURE_BUFFER_SIZE = 16 * 1024 * 1024;
constexpr std::array TEXTURE_BUFFER_LF_FORMATS = { constexpr std::array TEXTURE_BUFFER_LF_FORMATS = {vk::Format::eR32G32Sfloat};
vk::Format::eR32G32Sfloat
};
constexpr std::array TEXTURE_BUFFER_FORMATS = { constexpr std::array TEXTURE_BUFFER_FORMATS = {vk::Format::eR32G32Sfloat,
vk::Format::eR32G32Sfloat, vk::Format::eR32G32B32A32Sfloat};
vk::Format::eR32G32B32A32Sfloat
};
RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instance& instance, RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instance& instance,
TaskScheduler& scheduler, TextureRuntime& runtime, TaskScheduler& scheduler, TextureRuntime& runtime,
RenderpassCache& renderpass_cache) RenderpassCache& renderpass_cache)
: instance{instance}, scheduler{scheduler}, runtime{runtime}, renderpass_cache{renderpass_cache}, : instance{instance}, scheduler{scheduler}, runtime{runtime},
res_cache{*this, runtime}, pipeline_cache{instance, scheduler, renderpass_cache}, renderpass_cache{renderpass_cache}, res_cache{*this, runtime},
vertex_buffer{instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}}, pipeline_cache{instance, scheduler, renderpass_cache},
uniform_buffer{instance, scheduler, UNIFORM_BUFFER_SIZE, vk::BufferUsageFlagBits::eUniformBuffer, {}}, vertex_buffer{
index_buffer{instance, scheduler, INDEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eIndexBuffer, {}}, instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}},
texture_buffer{instance, scheduler, TEXTURE_BUFFER_SIZE, vk::BufferUsageFlagBits::eUniformTexelBuffer, uniform_buffer{
TEXTURE_BUFFER_FORMATS}, instance, scheduler, UNIFORM_BUFFER_SIZE, vk::BufferUsageFlagBits::eUniformBuffer, {}},
texture_lf_buffer{instance, scheduler, TEXTURE_BUFFER_SIZE, vk::BufferUsageFlagBits::eUniformTexelBuffer, index_buffer{
TEXTURE_BUFFER_LF_FORMATS} { instance, scheduler, INDEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eIndexBuffer, {}},
texture_buffer{instance, scheduler, TEXTURE_BUFFER_SIZE,
vk::BufferUsageFlagBits::eUniformTexelBuffer, TEXTURE_BUFFER_FORMATS},
texture_lf_buffer{instance, scheduler, TEXTURE_BUFFER_SIZE,
vk::BufferUsageFlagBits::eUniformTexelBuffer, TEXTURE_BUFFER_LF_FORMATS} {
// Create a 1x1 clear texture to use in the NULL case, // Create a 1x1 clear texture to use in the NULL case,
default_texture = runtime.Allocate(1, 1, VideoCore::PixelFormat::RGBA8, default_texture =
VideoCore::TextureType::Texture2D); runtime.Allocate(1, 1, VideoCore::PixelFormat::RGBA8, VideoCore::TextureType::Texture2D);
runtime.Transition(scheduler.GetUploadCommandBuffer(), default_texture, runtime.Transition(scheduler.GetUploadCommandBuffer(), default_texture,
vk::ImageLayout::eShaderReadOnlyOptimal, 0, 1); vk::ImageLayout::eShaderReadOnlyOptimal, 0, 1);
@ -142,8 +143,7 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instan
.min_filter = Pica::TexturingRegs::TextureConfig::TextureFilter::Linear, .min_filter = Pica::TexturingRegs::TextureConfig::TextureFilter::Linear,
.mip_filter = Pica::TexturingRegs::TextureConfig::TextureFilter::Linear, .mip_filter = Pica::TexturingRegs::TextureConfig::TextureFilter::Linear,
.wrap_s = Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder, .wrap_s = Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder,
.wrap_t = Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder .wrap_t = Pica::TexturingRegs::TextureConfig::WrapMode::ClampToBorder};
};
default_sampler = CreateSampler(default_sampler_info); default_sampler = CreateSampler(default_sampler_info);
@ -327,7 +327,8 @@ RasterizerVulkan::VertexArrayInfo RasterizerVulkan::AnalyzeVertexArray(bool is_i
return {vertex_min, vertex_max, vs_input_size}; return {vertex_min, vertex_max, vs_input_size};
} }
void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_min, u32 vs_input_index_max) { void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_min,
u32 vs_input_index_max) {
auto [array_ptr, array_offset, _] = vertex_buffer.Map(vs_input_size, 4); auto [array_ptr, array_offset, _] = vertex_buffer.Map(vs_input_size, 4);
/** /**
@ -358,10 +359,12 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
u32 attribute_index = loader.GetComponent(comp); u32 attribute_index = loader.GetComponent(comp);
if (attribute_index < 12) { if (attribute_index < 12) {
if (u32 size = vertex_attributes.GetNumElements(attribute_index); size != 0) { if (u32 size = vertex_attributes.GetNumElements(attribute_index); size != 0) {
offset = Common::AlignUp(offset, vertex_attributes.GetElementSizeInBytes(attribute_index)); offset = Common::AlignUp(
offset, vertex_attributes.GetElementSizeInBytes(attribute_index));
const u32 input_reg = regs.vs.GetRegisterForAttribute(attribute_index); const u32 input_reg = regs.vs.GetRegisterForAttribute(attribute_index);
const u32 attrib_format = static_cast<u32>(vertex_attributes.GetFormat(attribute_index)); const u32 attrib_format =
static_cast<u32>(vertex_attributes.GetFormat(attribute_index));
const AttribType type = vs_attrib_types[attrib_format]; const AttribType type = vs_attrib_types[attrib_format];
// Define the attribute // Define the attribute
@ -377,13 +380,15 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
} }
} else { } else {
// Attribute ids 12, 13, 14 and 15 signify 4, 8, 12 and 16-byte paddings respectively // Attribute ids 12, 13, 14 and 15 signify 4, 8, 12 and 16-byte paddings
// respectively
offset = Common::AlignUp(offset, 4); offset = Common::AlignUp(offset, 4);
offset += (attribute_index - 11) * 4; offset += (attribute_index - 11) * 4;
} }
} }
const PAddr data_addr = base_address + loader.data_offset + (vs_input_index_min * loader.byte_count); const PAddr data_addr =
base_address + loader.data_offset + (vs_input_index_min * loader.byte_count);
const u32 vertex_num = vs_input_index_max - vs_input_index_min + 1; const u32 vertex_num = vs_input_index_max - vs_input_index_min + 1;
const u32 data_size = loader.byte_count * vertex_num; const u32 data_size = loader.byte_count * vertex_num;
@ -409,12 +414,8 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
const u32 reg = regs.vs.GetRegisterForAttribute(i); const u32 reg = regs.vs.GetRegisterForAttribute(i);
if (!enable_attributes[reg]) { if (!enable_attributes[reg]) {
const auto& attr = Pica::g_state.input_default_attributes.attr[i]; const auto& attr = Pica::g_state.input_default_attributes.attr[i];
const std::array data = { const std::array data = {attr.x.ToFloat32(), attr.y.ToFloat32(), attr.z.ToFloat32(),
attr.x.ToFloat32(), attr.w.ToFloat32()};
attr.y.ToFloat32(),
attr.z.ToFloat32(),
attr.w.ToFloat32()
};
// Copy the data to the end of the buffer // Copy the data to the end of the buffer
const u32 data_size = sizeof(float) * static_cast<u32>(data.size()); const u32 data_size = sizeof(float) * static_cast<u32>(data.size());
@ -448,7 +449,8 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
// Bind the vertex buffers with all the bindings // Bind the vertex buffers with all the bindings
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.bindVertexBuffers(0, layout.binding_count, buffers.data(), binding_offsets.data()); command_buffer.bindVertexBuffers(0, layout.binding_count, buffers.data(),
binding_offsets.data());
} }
bool RasterizerVulkan::SetupVertexShader() { bool RasterizerVulkan::SetupVertexShader() {
@ -596,8 +598,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
surfaces_rect.left, surfaces_rect.right)), // Right surfaces_rect.left, surfaces_rect.right)), // Right
static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) +
viewport_rect_unscaled.bottom * res_scale, viewport_rect_unscaled.bottom * res_scale,
surfaces_rect.bottom, surfaces_rect.top)) surfaces_rect.bottom, surfaces_rect.top))};
};
if (uniform_block_data.data.framebuffer_scale != res_scale) { if (uniform_block_data.data.framebuffer_scale != res_scale) {
uniform_block_data.data.framebuffer_scale = res_scale; uniform_block_data.data.framebuffer_scale = res_scale;
@ -606,13 +607,17 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
// Scissor checks are window-, not viewport-relative, which means that if the cached texture // Scissor checks are window-, not viewport-relative, which means that if the cached texture
// sub-rect changes, the scissor bounds also need to be updated. // sub-rect changes, the scissor bounds also need to be updated.
int scissor_x1 = static_cast<int>(surfaces_rect.left + regs.rasterizer.scissor_test.x1 * res_scale); int scissor_x1 =
int scissor_y1 = static_cast<int>(surfaces_rect.bottom + regs.rasterizer.scissor_test.y1 * res_scale); static_cast<int>(surfaces_rect.left + regs.rasterizer.scissor_test.x1 * res_scale);
int scissor_y1 =
static_cast<int>(surfaces_rect.bottom + regs.rasterizer.scissor_test.y1 * res_scale);
// x2, y2 have +1 added to cover the entire pixel area, otherwise you might get cracks when // x2, y2 have +1 added to cover the entire pixel area, otherwise you might get cracks when
// scaling or doing multisampling. // scaling or doing multisampling.
int scissor_x2 = static_cast<int>(surfaces_rect.left + (regs.rasterizer.scissor_test.x2 + 1) * res_scale); int scissor_x2 =
int scissor_y2 = static_cast<int>(surfaces_rect.bottom + (regs.rasterizer.scissor_test.y2 + 1) * res_scale); static_cast<int>(surfaces_rect.left + (regs.rasterizer.scissor_test.x2 + 1) * res_scale);
int scissor_y2 =
static_cast<int>(surfaces_rect.bottom + (regs.rasterizer.scissor_test.y2 + 1) * res_scale);
if (uniform_block_data.data.scissor_x1 != scissor_x1 || if (uniform_block_data.data.scissor_x1 != scissor_x1 ||
uniform_block_data.data.scissor_x2 != scissor_x2 || uniform_block_data.data.scissor_x2 != scissor_x2 ||
@ -626,7 +631,8 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
uniform_block_data.dirty = true; uniform_block_data.dirty = true;
} }
auto CheckBarrier = [this, &color_surface = color_surface](vk::ImageView image_view, u32 texture_index) { auto CheckBarrier = [this, &color_surface = color_surface](vk::ImageView image_view,
u32 texture_index) {
if (color_surface && color_surface->alloc.image_view == image_view) { if (color_surface && color_surface->alloc.image_view == image_view) {
// auto temp_tex = backend->CreateTexture(texture->GetInfo()); // auto temp_tex = backend->CreateTexture(texture->GetInfo());
// temp_tex->CopyFrom(texture); // temp_tex->CopyFrom(texture);
@ -651,15 +657,14 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
const auto BindSampler = [&](u32 binding, SamplerInfo& info, const auto BindSampler = [&](u32 binding, SamplerInfo& info,
const Pica::TexturingRegs::TextureConfig& config) { const Pica::TexturingRegs::TextureConfig& config) {
// TODO(GPUCode): Cubemaps don't contain any mipmaps for now, so sampling from them returns nothing // TODO(GPUCode): Cubemaps don't contain any mipmaps for now, so sampling from them returns
// Always sample from the base level until mipmaps for texture cubes are implemented // nothing Always sample from the base level until mipmaps for texture cubes are implemented
// NOTE: There are no Vulkan filter modes that directly correspond to OpenGL minification filters // NOTE: There are no Vulkan filter modes that directly correspond to OpenGL minification
// GL_LINEAR/GL_NEAREST so emulate them by setting // filters GL_LINEAR/GL_NEAREST so emulate them by setting minLod = 0, and maxLod = 0.25,
// minLod = 0, and maxLod = 0.25, and using minFilter = VK_FILTER_LINEAR or minFilter = VK_FILTER_NEAREST // and using minFilter = VK_FILTER_LINEAR or minFilter = VK_FILTER_NEAREST
const bool skip_mipmap = const bool skip_mipmap = config.type == Pica::TexturingRegs::TextureConfig::TextureCube;
config.type == Pica::TexturingRegs::TextureConfig::TextureCube; info =
info = SamplerInfo{ SamplerInfo{.mag_filter = config.mag_filter,
.mag_filter = config.mag_filter,
.min_filter = config.min_filter, .min_filter = config.min_filter,
.mip_filter = config.mip_filter, .mip_filter = config.mip_filter,
.wrap_s = config.wrap_s, .wrap_s = config.wrap_s,
@ -667,8 +672,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
.border_color = config.border_color.raw, .border_color = config.border_color.raw,
.lod_min = skip_mipmap ? 0.f : static_cast<float>(config.lod.min_level), .lod_min = skip_mipmap ? 0.f : static_cast<float>(config.lod.min_level),
.lod_max = skip_mipmap ? 0.25f : static_cast<float>(config.lod.max_level), .lod_max = skip_mipmap ? 0.25f : static_cast<float>(config.lod.max_level),
.lod_bias = static_cast<float>(config.lod.bias) .lod_bias = static_cast<float>(config.lod.bias)};
};
// Search the cache and bind the appropriate sampler // Search the cache and bind the appropriate sampler
if (auto it = samplers.find(info); it != samplers.end()) { if (auto it = samplers.find(info); it != samplers.end()) {
@ -722,14 +726,13 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
.pz = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveZ), .pz = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveZ),
.nz = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ), .nz = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ),
.width = texture.config.width, .width = texture.config.width,
.format = texture.format .format = texture.format};
};
auto surface = res_cache.GetTextureCube(config); auto surface = res_cache.GetTextureCube(config);
if (surface != nullptr) { if (surface != nullptr) {
runtime.Transition(scheduler.GetRenderCommandBuffer(), surface->alloc, runtime.Transition(scheduler.GetRenderCommandBuffer(), surface->alloc,
vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, 0,
0, surface->alloc.levels, 0, 6); surface->alloc.levels, 0, 6);
pipeline_cache.BindTexture(3, surface->alloc.image_view); pipeline_cache.BindTexture(3, surface->alloc.image_view);
} else { } else {
pipeline_cache.BindTexture(3, default_texture.image_view); pipeline_cache.BindTexture(3, default_texture.image_view);
@ -749,8 +752,8 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
auto surface = res_cache.GetTextureSurface(texture); auto surface = res_cache.GetTextureSurface(texture);
if (surface != nullptr) { if (surface != nullptr) {
runtime.Transition(scheduler.GetRenderCommandBuffer(), surface->alloc, runtime.Transition(scheduler.GetRenderCommandBuffer(), surface->alloc,
vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, 0,
0, surface->alloc.levels); surface->alloc.levels);
CheckBarrier(surface->alloc.image_view, texture_index); CheckBarrier(surface->alloc.image_view, texture_index);
} else { } else {
// Can occur when texture addr is null or its memory is unmapped/invalid // Can occur when texture addr is null or its memory is unmapped/invalid
@ -769,8 +772,8 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
} }
} }
// NOTE: From here onwards its a safe zone to set the draw state, doing that any earlier will cause // NOTE: From here onwards its a safe zone to set the draw state, doing that any earlier will
// issues as the rasterizer cache might cause a scheduler switch and invalidate our state // cause issues as the rasterizer cache might cause a scheduler switch and invalidate our state
// Sync the viewport // Sync the viewport
pipeline_cache.SetViewport(surfaces_rect.left + viewport_rect_unscaled.left * res_scale, pipeline_cache.SetViewport(surfaces_rect.left + viewport_rect_unscaled.left * res_scale,
@ -793,7 +796,8 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
// Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect.
// Enable scissor test to prevent drawing outside of the framebuffer region // Enable scissor test to prevent drawing outside of the framebuffer region
pipeline_cache.SetScissor(draw_rect.left, draw_rect.bottom, draw_rect.GetWidth(), draw_rect.GetHeight()); pipeline_cache.SetScissor(draw_rect.left, draw_rect.bottom, draw_rect.GetWidth(),
draw_rect.GetHeight());
auto valid_surface = color_surface ? color_surface : depth_surface; auto valid_surface = color_surface ? color_surface : depth_surface;
const FramebufferInfo framebuffer_info = { const FramebufferInfo framebuffer_info = {
@ -802,8 +806,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
.renderpass = renderpass_cache.GetRenderpass(pipeline_info.color_attachment, .renderpass = renderpass_cache.GetRenderpass(pipeline_info.color_attachment,
pipeline_info.depth_attachment, false), pipeline_info.depth_attachment, false),
.width = valid_surface->GetScaledWidth(), .width = valid_surface->GetScaledWidth(),
.height = valid_surface->GetScaledHeight() .height = valid_surface->GetScaledHeight()};
};
auto [it, new_framebuffer] = framebuffers.try_emplace(framebuffer_info, vk::Framebuffer{}); auto [it, new_framebuffer] = framebuffers.try_emplace(framebuffer_info, vk::Framebuffer{});
if (new_framebuffer) { if (new_framebuffer) {
@ -813,29 +816,26 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
if (color_surface) { if (color_surface) {
runtime.Transition(command_buffer, color_surface->alloc, runtime.Transition(command_buffer, color_surface->alloc,
vk::ImageLayout::eColorAttachmentOptimal, vk::ImageLayout::eColorAttachmentOptimal, 0,
0, color_surface->alloc.levels); color_surface->alloc.levels);
} }
if (depth_surface) { if (depth_surface) {
runtime.Transition(command_buffer, depth_surface->alloc, runtime.Transition(command_buffer, depth_surface->alloc,
vk::ImageLayout::eDepthStencilAttachmentOptimal, vk::ImageLayout::eDepthStencilAttachmentOptimal, 0,
0, depth_surface->alloc.levels); depth_surface->alloc.levels);
} }
const vk::RenderPassBeginInfo renderpass_begin = { const vk::RenderPassBeginInfo renderpass_begin = {
.renderPass = .renderPass = renderpass_cache.GetRenderpass(pipeline_info.color_attachment,
renderpass_cache.GetRenderpass(pipeline_info.color_attachment,
pipeline_info.depth_attachment, false), pipeline_info.depth_attachment, false),
.framebuffer = it->second, .framebuffer = it->second,
.renderArea = vk::Rect2D{ .renderArea = vk::Rect2D{.offset = {static_cast<s32>(draw_rect.left),
.offset = {static_cast<s32>(draw_rect.left), static_cast<s32>(draw_rect.bottom)}, static_cast<s32>(draw_rect.bottom)},
.extent = {draw_rect.GetWidth(), draw_rect.GetHeight()} .extent = {draw_rect.GetWidth(), draw_rect.GetHeight()}},
},
.clearValueCount = 0, .clearValueCount = 0,
.pClearValues = nullptr .pClearValues = nullptr};
};
renderpass_cache.EnterRenderpass(renderpass_begin); renderpass_cache.EnterRenderpass(renderpass_begin);
@ -853,7 +853,8 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
// that when base_vertex is zero the GPU will start drawing from the current mapped // that when base_vertex is zero the GPU will start drawing from the current mapped
// offset not the start of the buffer. // offset not the start of the buffer.
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.bindVertexBuffers(0, vertex_buffer.GetHandle(), vertex_buffer.GetBufferOffset()); command_buffer.bindVertexBuffers(0, vertex_buffer.GetHandle(),
vertex_buffer.GetBufferOffset());
const u32 max_vertices = VERTEX_BUFFER_SIZE / sizeof(HardwareVertex); const u32 max_vertices = VERTEX_BUFFER_SIZE / sizeof(HardwareVertex);
const u32 batch_size = static_cast<u32>(vertex_batch.size()); const u32 batch_size = static_cast<u32>(vertex_batch.size());
@ -874,11 +875,8 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
// Mark framebuffer surfaces as dirty // Mark framebuffer surfaces as dirty
const VideoCore::Rect2D draw_rect_unscaled = { const VideoCore::Rect2D draw_rect_unscaled = {
draw_rect.left / res_scale, draw_rect.left / res_scale, draw_rect.top / res_scale, draw_rect.right / res_scale,
draw_rect.top / res_scale, draw_rect.bottom / res_scale};
draw_rect.right / res_scale,
draw_rect.bottom / res_scale
};
if (color_surface != nullptr && write_color_fb) { if (color_surface != nullptr && write_color_fb) {
auto interval = color_surface->GetSubRectInterval(draw_rect_unscaled); auto interval = color_surface->GetSubRectInterval(draw_rect_unscaled);
@ -1590,8 +1588,7 @@ vk::Sampler RasterizerVulkan::CreateSampler(const SamplerInfo& info) {
.minLod = info.lod_min, .minLod = info.lod_min,
.maxLod = info.lod_max, .maxLod = info.lod_max,
.borderColor = vk::BorderColor::eIntOpaqueBlack, .borderColor = vk::BorderColor::eIntOpaqueBlack,
.unnormalizedCoordinates = false .unnormalizedCoordinates = false};
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
return device.createSampler(sampler_info); return device.createSampler(sampler_info);
@ -1609,14 +1606,12 @@ vk::Framebuffer RasterizerVulkan::CreateFramebuffer(const FramebufferInfo& info)
attachments[attachment_count++] = info.depth; attachments[attachment_count++] = info.depth;
} }
const vk::FramebufferCreateInfo framebuffer_info = { const vk::FramebufferCreateInfo framebuffer_info = {.renderPass = info.renderpass,
.renderPass = info.renderpass,
.attachmentCount = attachment_count, .attachmentCount = attachment_count,
.pAttachments = attachments.data(), .pAttachments = attachments.data(),
.width = info.width, .width = info.width,
.height = info.height, .height = info.height,
.layers = 1 .layers = 1};
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
return device.createFramebuffer(framebuffer_info); return device.createFramebuffer(framebuffer_info);
@ -1660,7 +1655,8 @@ void RasterizerVulkan::SyncCullMode() {
} }
void RasterizerVulkan::SyncDepthScale() { void RasterizerVulkan::SyncDepthScale() {
float depth_scale = Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_range).ToFloat32(); float depth_scale =
Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_range).ToFloat32();
if (depth_scale != uniform_block_data.data.depth_scale) { if (depth_scale != uniform_block_data.data.depth_scale) {
uniform_block_data.data.depth_scale = depth_scale; uniform_block_data.data.depth_scale = depth_scale;
@ -1669,7 +1665,8 @@ void RasterizerVulkan::SyncDepthScale() {
} }
void RasterizerVulkan::SyncDepthOffset() { void RasterizerVulkan::SyncDepthOffset() {
float depth_offset = Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_near_plane).ToFloat32(); float depth_offset =
Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_near_plane).ToFloat32();
if (depth_offset != uniform_block_data.data.depth_offset) { if (depth_offset != uniform_block_data.data.depth_offset) {
uniform_block_data.data.depth_offset = depth_offset; uniform_block_data.data.depth_offset = depth_offset;
@ -1678,18 +1675,25 @@ void RasterizerVulkan::SyncDepthOffset() {
} }
void RasterizerVulkan::SyncBlendEnabled() { void RasterizerVulkan::SyncBlendEnabled() {
pipeline_info.blending.blend_enable.Assign(Pica::g_state.regs.framebuffer.output_merger.alphablend_enable); pipeline_info.blending.blend_enable.Assign(
Pica::g_state.regs.framebuffer.output_merger.alphablend_enable);
} }
void RasterizerVulkan::SyncBlendFuncs() { void RasterizerVulkan::SyncBlendFuncs() {
const auto& regs = Pica::g_state.regs; const auto& regs = Pica::g_state.regs;
pipeline_info.blending.color_blend_eq.Assign(regs.framebuffer.output_merger.alpha_blending.blend_equation_rgb); pipeline_info.blending.color_blend_eq.Assign(
pipeline_info.blending.alpha_blend_eq.Assign(regs.framebuffer.output_merger.alpha_blending.blend_equation_a); regs.framebuffer.output_merger.alpha_blending.blend_equation_rgb);
pipeline_info.blending.src_color_blend_factor.Assign(regs.framebuffer.output_merger.alpha_blending.factor_source_rgb); pipeline_info.blending.alpha_blend_eq.Assign(
pipeline_info.blending.dst_color_blend_factor.Assign(regs.framebuffer.output_merger.alpha_blending.factor_dest_rgb); regs.framebuffer.output_merger.alpha_blending.blend_equation_a);
pipeline_info.blending.src_alpha_blend_factor.Assign(regs.framebuffer.output_merger.alpha_blending.factor_source_a); pipeline_info.blending.src_color_blend_factor.Assign(
pipeline_info.blending.dst_alpha_blend_factor.Assign(regs.framebuffer.output_merger.alpha_blending.factor_dest_a); regs.framebuffer.output_merger.alpha_blending.factor_source_rgb);
pipeline_info.blending.dst_color_blend_factor.Assign(
regs.framebuffer.output_merger.alpha_blending.factor_dest_rgb);
pipeline_info.blending.src_alpha_blend_factor.Assign(
regs.framebuffer.output_merger.alpha_blending.factor_source_a);
pipeline_info.blending.dst_alpha_blend_factor.Assign(
regs.framebuffer.output_merger.alpha_blending.factor_dest_a);
} }
void RasterizerVulkan::SyncBlendColor() { void RasterizerVulkan::SyncBlendColor() {
@ -1764,7 +1768,8 @@ void RasterizerVulkan::SyncStencilWriteMask() {
: 0; : 0;
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.setStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack, pipeline_info.depth_stencil.stencil_write_mask); command_buffer.setStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack,
pipeline_info.depth_stencil.stencil_write_mask);
} }
void RasterizerVulkan::SyncDepthWriteMask() { void RasterizerVulkan::SyncDepthWriteMask() {
@ -1784,13 +1789,16 @@ void RasterizerVulkan::SyncDepthWriteMask() {
void RasterizerVulkan::SyncStencilTest() { void RasterizerVulkan::SyncStencilTest() {
const auto& regs = Pica::g_state.regs; const auto& regs = Pica::g_state.regs;
const bool test_enable = regs.framebuffer.output_merger.stencil_test.enable && const bool test_enable =
regs.framebuffer.output_merger.stencil_test.enable &&
regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8; regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8;
const auto& stencil_test = regs.framebuffer.output_merger.stencil_test; const auto& stencil_test = regs.framebuffer.output_merger.stencil_test;
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack, stencil_test.input_mask); command_buffer.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack,
command_buffer.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack, stencil_test.reference_value); stencil_test.input_mask);
command_buffer.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
stencil_test.reference_value);
if (instance.IsExtendedDynamicStateSupported()) { if (instance.IsExtendedDynamicStateSupported()) {
command_buffer.setStencilTestEnableEXT(test_enable); command_buffer.setStencilTestEnableEXT(test_enable);
@ -1830,7 +1838,8 @@ void RasterizerVulkan::SyncDepthTest() {
} }
void RasterizerVulkan::SyncCombinerColor() { void RasterizerVulkan::SyncCombinerColor() {
auto combiner_color = PicaToVK::ColorRGBA8(Pica::g_state.regs.texturing.tev_combiner_buffer_color.raw); auto combiner_color =
PicaToVK::ColorRGBA8(Pica::g_state.regs.texturing.tev_combiner_buffer_color.raw);
if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) { if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
uniform_block_data.data.tev_combiner_buffer_color = combiner_color; uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
uniform_block_data.dirty = true; uniform_block_data.dirty = true;
@ -1893,8 +1902,7 @@ void RasterizerVulkan::SyncLightPosition(int light_index) {
const Common::Vec3f position = { const Common::Vec3f position = {
Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].x).ToFloat32(), Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].x).ToFloat32(),
Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].y).ToFloat32(), Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].y).ToFloat32(),
Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32() Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32()};
};
if (position != uniform_block_data.data.light_src[light_index].position) { if (position != uniform_block_data.data.light_src[light_index].position) {
uniform_block_data.data.light_src[light_index].position = position; uniform_block_data.data.light_src[light_index].position = position;
@ -1913,7 +1921,8 @@ void RasterizerVulkan::SyncLightSpotDirection(int light_index) {
} }
void RasterizerVulkan::SyncLightDistanceAttenuationBias(int light_index) { void RasterizerVulkan::SyncLightDistanceAttenuationBias(int light_index) {
float dist_atten_bias = Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_bias) float dist_atten_bias =
Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_bias)
.ToFloat32(); .ToFloat32();
if (dist_atten_bias != uniform_block_data.data.light_src[light_index].dist_atten_bias) { if (dist_atten_bias != uniform_block_data.data.light_src[light_index].dist_atten_bias) {
@ -1923,7 +1932,8 @@ void RasterizerVulkan::SyncLightDistanceAttenuationBias(int light_index) {
} }
void RasterizerVulkan::SyncLightDistanceAttenuationScale(int light_index) { void RasterizerVulkan::SyncLightDistanceAttenuationScale(int light_index) {
float dist_atten_scale = Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_scale) float dist_atten_scale =
Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_scale)
.ToFloat32(); .ToFloat32();
if (dist_atten_scale != uniform_block_data.data.light_src[light_index].dist_atten_scale) { if (dist_atten_scale != uniform_block_data.data.light_src[light_index].dist_atten_scale) {
@ -2032,8 +2042,9 @@ void RasterizerVulkan::SyncAndUploadLUTs() {
auto [buffer, offset, invalidate] = texture_buffer.Map(max_size, sizeof(Common::Vec4f)); auto [buffer, offset, invalidate] = texture_buffer.Map(max_size, sizeof(Common::Vec4f));
// helper function for SyncProcTexNoiseLUT/ColorMap/AlphaMap // helper function for SyncProcTexNoiseLUT/ColorMap/AlphaMap
auto SyncProcTexValueLUT = [this, &buffer = buffer, &offset = offset, &invalidate = invalidate, &bytes_used]( auto SyncProcTexValueLUT =
const std::array<Pica::State::ProcTex::ValueEntry, 128>& lut, [this, &buffer = buffer, &offset = offset, &invalidate = invalidate,
&bytes_used](const std::array<Pica::State::ProcTex::ValueEntry, 128>& lut,
std::array<Common::Vec2f, 128>& lut_data, int& lut_offset) { std::array<Common::Vec2f, 128>& lut_data, int& lut_offset) {
std::array<Common::Vec2f, 128> new_data; std::array<Common::Vec2f, 128> new_data;
std::transform(lut.begin(), lut.end(), new_data.begin(), [](const auto& entry) { std::transform(lut.begin(), lut.end(), new_data.begin(), [](const auto& entry) {
@ -2130,20 +2141,22 @@ void RasterizerVulkan::UploadUniforms(bool accelerate_draw) {
u32 used_bytes = 0; u32 used_bytes = 0;
const u32 uniform_size = static_cast<u32>(uniform_size_aligned_vs + uniform_size_aligned_fs); const u32 uniform_size = static_cast<u32>(uniform_size_aligned_vs + uniform_size_aligned_fs);
auto [uniforms, offset, invalidate] = uniform_buffer.Map(uniform_size, auto [uniforms, offset, invalidate] =
static_cast<u32>(uniform_buffer_alignment)); uniform_buffer.Map(uniform_size, static_cast<u32>(uniform_buffer_alignment));
if (sync_vs) { if (sync_vs) {
Pica::Shader::VSUniformData vs_uniforms; Pica::Shader::VSUniformData vs_uniforms;
vs_uniforms.uniforms.SetFromRegs(Pica::g_state.regs.vs, Pica::g_state.vs); vs_uniforms.uniforms.SetFromRegs(Pica::g_state.regs.vs, Pica::g_state.vs);
std::memcpy(uniforms + used_bytes, &vs_uniforms, sizeof(vs_uniforms)); std::memcpy(uniforms + used_bytes, &vs_uniforms, sizeof(vs_uniforms));
pipeline_cache.BindBuffer(0, uniform_buffer.GetHandle(), offset + used_bytes, sizeof(vs_uniforms)); pipeline_cache.BindBuffer(0, uniform_buffer.GetHandle(), offset + used_bytes,
sizeof(vs_uniforms));
used_bytes += static_cast<u32>(uniform_size_aligned_vs); used_bytes += static_cast<u32>(uniform_size_aligned_vs);
} }
if (sync_fs || invalidate) { if (sync_fs || invalidate) {
std::memcpy(uniforms + used_bytes, &uniform_block_data.data, sizeof(Pica::Shader::UniformData)); std::memcpy(uniforms + used_bytes, &uniform_block_data.data,
sizeof(Pica::Shader::UniformData));
pipeline_cache.BindBuffer(1, uniform_buffer.GetHandle(), offset + used_bytes, pipeline_cache.BindBuffer(1, uniform_buffer.GetHandle(), offset + used_bytes,
sizeof(uniform_block_data.data)); sizeof(uniform_block_data.data));

View File

@ -9,8 +9,8 @@
#include "video_core/rasterizer_accelerated.h" #include "video_core/rasterizer_accelerated.h"
#include "video_core/regs_lighting.h" #include "video_core/regs_lighting.h"
#include "video_core/regs_texturing.h" #include "video_core/regs_texturing.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/vk_pipeline_cache.h" #include "video_core/renderer_vulkan/vk_pipeline_cache.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/vk_texture_runtime.h" #include "video_core/renderer_vulkan/vk_texture_runtime.h"
#include "video_core/shader/shader.h" #include "video_core/shader/shader.h"
#include "video_core/shader/shader_uniforms.h" #include "video_core/shader/shader_uniforms.h"
@ -55,7 +55,7 @@ struct FramebufferInfo {
auto operator<=>(const FramebufferInfo&) const noexcept = default; auto operator<=>(const FramebufferInfo&) const noexcept = default;
}; };
} } // namespace Vulkan
namespace std { namespace std {
template <> template <>
@ -77,9 +77,11 @@ namespace Vulkan {
class RasterizerVulkan : public VideoCore::RasterizerAccelerated { class RasterizerVulkan : public VideoCore::RasterizerAccelerated {
friend class RendererVulkan; friend class RendererVulkan;
public: public:
explicit RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instance& instance, TaskScheduler& scheduler, explicit RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instance& instance,
TextureRuntime& runtime, RenderpassCache& renderpass_cache); TaskScheduler& scheduler, TextureRuntime& runtime,
RenderpassCache& renderpass_cache);
~RasterizerVulkan() override; ~RasterizerVulkan() override;
void LoadDiskResources(const std::atomic_bool& stop_loading, void LoadDiskResources(const std::atomic_bool& stop_loading,

View File

@ -4,29 +4,39 @@
#define VULKAN_HPP_NO_CONSTRUCTORS #define VULKAN_HPP_NO_CONSTRUCTORS
#include "common/assert.h" #include "common/assert.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_task_scheduler.h" #include "video_core/renderer_vulkan/vk_task_scheduler.h"
namespace Vulkan { namespace Vulkan {
VideoCore::PixelFormat ToFormatColor(u32 index) { VideoCore::PixelFormat ToFormatColor(u32 index) {
switch (index) { switch (index) {
case 0: return VideoCore::PixelFormat::RGBA8; case 0:
case 1: return VideoCore::PixelFormat::RGB8; return VideoCore::PixelFormat::RGBA8;
case 2: return VideoCore::PixelFormat::RGB5A1; case 1:
case 3: return VideoCore::PixelFormat::RGB565; return VideoCore::PixelFormat::RGB8;
case 4: return VideoCore::PixelFormat::RGBA4; case 2:
default: return VideoCore::PixelFormat::Invalid; return VideoCore::PixelFormat::RGB5A1;
case 3:
return VideoCore::PixelFormat::RGB565;
case 4:
return VideoCore::PixelFormat::RGBA4;
default:
return VideoCore::PixelFormat::Invalid;
} }
} }
VideoCore::PixelFormat ToFormatDepth(u32 index) { VideoCore::PixelFormat ToFormatDepth(u32 index) {
switch (index) { switch (index) {
case 0: return VideoCore::PixelFormat::D16; case 0:
case 1: return VideoCore::PixelFormat::D24; return VideoCore::PixelFormat::D16;
case 3: return VideoCore::PixelFormat::D24S8; case 1:
default: return VideoCore::PixelFormat::Invalid; return VideoCore::PixelFormat::D24;
case 3:
return VideoCore::PixelFormat::D24S8;
default:
return VideoCore::PixelFormat::Invalid;
} }
} }
@ -47,14 +57,12 @@ RenderpassCache::RenderpassCache(const Instance& instance, TaskScheduler& schedu
continue; continue;
} }
cached_renderpasses[color][depth][0] = CreateRenderPass(color_format, depth_format, cached_renderpasses[color][depth][0] = CreateRenderPass(
vk::AttachmentLoadOp::eLoad, color_format, depth_format, vk::AttachmentLoadOp::eLoad,
vk::ImageLayout::eColorAttachmentOptimal, vk::ImageLayout::eColorAttachmentOptimal, vk::ImageLayout::eColorAttachmentOptimal);
vk::ImageLayout::eColorAttachmentOptimal); cached_renderpasses[color][depth][1] = CreateRenderPass(
cached_renderpasses[color][depth][1] = CreateRenderPass(color_format, depth_format, color_format, depth_format, vk::AttachmentLoadOp::eClear,
vk::AttachmentLoadOp::eClear, vk::ImageLayout::eColorAttachmentOptimal, vk::ImageLayout::eColorAttachmentOptimal);
vk::ImageLayout::eColorAttachmentOptimal,
vk::ImageLayout::eColorAttachmentOptimal);
} }
} }
} }
@ -102,26 +110,28 @@ void RenderpassCache::ExitRenderpass() {
void RenderpassCache::CreatePresentRenderpass(vk::Format format) { void RenderpassCache::CreatePresentRenderpass(vk::Format format) {
if (!present_renderpass) { if (!present_renderpass) {
present_renderpass = CreateRenderPass(format, vk::Format::eUndefined, present_renderpass =
vk::AttachmentLoadOp::eClear, CreateRenderPass(format, vk::Format::eUndefined, vk::AttachmentLoadOp::eClear,
vk::ImageLayout::eUndefined, vk::ImageLayout::eUndefined, vk::ImageLayout::ePresentSrcKHR);
vk::ImageLayout::ePresentSrcKHR);
} }
} }
vk::RenderPass RenderpassCache::GetRenderpass(VideoCore::PixelFormat color, VideoCore::PixelFormat depth, vk::RenderPass RenderpassCache::GetRenderpass(VideoCore::PixelFormat color,
bool is_clear) const { VideoCore::PixelFormat depth, bool is_clear) const {
const u32 color_index = const u32 color_index =
color == VideoCore::PixelFormat::Invalid ? MAX_COLOR_FORMATS : static_cast<u32>(color); color == VideoCore::PixelFormat::Invalid ? MAX_COLOR_FORMATS : static_cast<u32>(color);
const u32 depth_index = const u32 depth_index = depth == VideoCore::PixelFormat::Invalid
depth == VideoCore::PixelFormat::Invalid ? MAX_DEPTH_FORMATS : (static_cast<u32>(depth) - 14); ? MAX_DEPTH_FORMATS
: (static_cast<u32>(depth) - 14);
ASSERT(color_index <= MAX_COLOR_FORMATS && depth_index <= MAX_DEPTH_FORMATS); ASSERT(color_index <= MAX_COLOR_FORMATS && depth_index <= MAX_DEPTH_FORMATS);
return cached_renderpasses[color_index][depth_index][is_clear]; return cached_renderpasses[color_index][depth_index][is_clear];
} }
vk::RenderPass RenderpassCache::CreateRenderPass(vk::Format color, vk::Format depth, vk::AttachmentLoadOp load_op, vk::RenderPass RenderpassCache::CreateRenderPass(vk::Format color, vk::Format depth,
vk::ImageLayout initial_layout, vk::ImageLayout final_layout) const { vk::AttachmentLoadOp load_op,
vk::ImageLayout initial_layout,
vk::ImageLayout final_layout) const {
// Define attachments // Define attachments
u32 attachment_count = 0; u32 attachment_count = 0;
std::array<vk::AttachmentDescription, 2> attachments; std::array<vk::AttachmentDescription, 2> attachments;
@ -132,20 +142,17 @@ vk::RenderPass RenderpassCache::CreateRenderPass(vk::Format color, vk::Format de
vk::AttachmentReference depth_attachment_ref{}; vk::AttachmentReference depth_attachment_ref{};
if (color != vk::Format::eUndefined) { if (color != vk::Format::eUndefined) {
attachments[attachment_count] = vk::AttachmentDescription{ attachments[attachment_count] =
.format = color, vk::AttachmentDescription{.format = color,
.loadOp = load_op, .loadOp = load_op,
.storeOp = vk::AttachmentStoreOp::eStore, .storeOp = vk::AttachmentStoreOp::eStore,
.stencilLoadOp = vk::AttachmentLoadOp::eDontCare, .stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
.stencilStoreOp = vk::AttachmentStoreOp::eDontCare, .stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
.initialLayout = initial_layout, .initialLayout = initial_layout,
.finalLayout = final_layout .finalLayout = final_layout};
};
color_attachment_ref = vk::AttachmentReference{ color_attachment_ref = vk::AttachmentReference{
.attachment = attachment_count++, .attachment = attachment_count++, .layout = vk::ImageLayout::eColorAttachmentOptimal};
.layout = vk::ImageLayout::eColorAttachmentOptimal
};
use_color = true; use_color = true;
} }
@ -158,40 +165,35 @@ vk::RenderPass RenderpassCache::CreateRenderPass(vk::Format color, vk::Format de
.stencilLoadOp = vk::AttachmentLoadOp::eLoad, .stencilLoadOp = vk::AttachmentLoadOp::eLoad,
.stencilStoreOp = vk::AttachmentStoreOp::eStore, .stencilStoreOp = vk::AttachmentStoreOp::eStore,
.initialLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal, .initialLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal,
.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal .finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal};
};
depth_attachment_ref = vk::AttachmentReference{ depth_attachment_ref =
.attachment = attachment_count++, vk::AttachmentReference{.attachment = attachment_count++,
.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal .layout = vk::ImageLayout::eDepthStencilAttachmentOptimal};
};
use_depth = true; use_depth = true;
} }
// We also require only one subpass // We also require only one subpass
const vk::SubpassDescription subpass = { const vk::SubpassDescription subpass = {.pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
.pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
.inputAttachmentCount = 0, .inputAttachmentCount = 0,
.pInputAttachments = nullptr, .pInputAttachments = nullptr,
.colorAttachmentCount = use_color ? 1u : 0u, .colorAttachmentCount = use_color ? 1u : 0u,
.pColorAttachments = &color_attachment_ref, .pColorAttachments = &color_attachment_ref,
.pResolveAttachments = 0, .pResolveAttachments = 0,
.pDepthStencilAttachment = use_depth ? &depth_attachment_ref : nullptr .pDepthStencilAttachment =
}; use_depth ? &depth_attachment_ref : nullptr};
const vk::RenderPassCreateInfo renderpass_info = { const vk::RenderPassCreateInfo renderpass_info = {.attachmentCount = attachment_count,
.attachmentCount = attachment_count,
.pAttachments = attachments.data(), .pAttachments = attachments.data(),
.subpassCount = 1, .subpassCount = 1,
.pSubpasses = &subpass, .pSubpasses = &subpass,
.dependencyCount = 0, .dependencyCount = 0,
.pDependencies = nullptr .pDependencies = nullptr};
};
// Create the renderpass // Create the renderpass
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
return device.createRenderPass(renderpass_info); return device.createRenderPass(renderpass_info);
} }
} // namespace VideoCore::Vulkan } // namespace Vulkan

View File

@ -30,8 +30,8 @@ public:
void CreatePresentRenderpass(vk::Format format); void CreatePresentRenderpass(vk::Format format);
/// Returns the renderpass associated with the color-depth format pair /// Returns the renderpass associated with the color-depth format pair
[[nodiscard]] vk::RenderPass GetRenderpass(VideoCore::PixelFormat color, VideoCore::PixelFormat depth, [[nodiscard]] vk::RenderPass GetRenderpass(VideoCore::PixelFormat color,
bool is_clear) const; VideoCore::PixelFormat depth, bool is_clear) const;
/// Returns the swapchain clear renderpass /// Returns the swapchain clear renderpass
[[nodiscard]] vk::RenderPass GetPresentRenderpass() const { [[nodiscard]] vk::RenderPass GetPresentRenderpass() const {
return present_renderpass; return present_renderpass;
@ -44,8 +44,9 @@ public:
private: private:
/// Creates a renderpass configured appropriately and stores it in cached_renderpasses /// Creates a renderpass configured appropriately and stores it in cached_renderpasses
vk::RenderPass CreateRenderPass(vk::Format color, vk::Format depth, vk::AttachmentLoadOp load_op, vk::RenderPass CreateRenderPass(vk::Format color, vk::Format depth,
vk::ImageLayout initial_layout, vk::ImageLayout final_layout) const; vk::AttachmentLoadOp load_op, vk::ImageLayout initial_layout,
vk::ImageLayout final_layout) const;
private: private:
const Instance& instance; const Instance& instance;

View File

@ -3,17 +3,16 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#define VULKAN_HPP_NO_CONSTRUCTORS #define VULKAN_HPP_NO_CONSTRUCTORS
#include <SPIRV/GlslangToSpv.h>
#include <glslang/Include/ResourceLimits.h>
#include <glslang/Public/ShaderLang.h>
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/renderer_vulkan/vk_shader.h" #include "video_core/renderer_vulkan/vk_shader.h"
#include <glslang/Public/ShaderLang.h>
#include <glslang/Include/ResourceLimits.h>
#include <SPIRV/GlslangToSpv.h>
namespace Vulkan { namespace Vulkan {
constexpr TBuiltInResource DefaultTBuiltInResource = { constexpr TBuiltInResource DefaultTBuiltInResource = {.maxLights = 32,
.maxLights = 32,
.maxClipPlanes = 6, .maxClipPlanes = 6,
.maxTextureUnits = 32, .maxTextureUnits = 32,
.maxTextureCoords = 32, .maxTextureCoords = 32,
@ -92,7 +91,8 @@ constexpr TBuiltInResource DefaultTBuiltInResource = {
.maxCombinedAtomicCounterBuffers = 1, .maxCombinedAtomicCounterBuffers = 1,
.maxAtomicCounterBufferSize = 16384, .maxAtomicCounterBufferSize = 16384,
.maxTransformFeedbackBuffers = 4, .maxTransformFeedbackBuffers = 4,
.maxTransformFeedbackInterleavedComponents = 64, .maxTransformFeedbackInterleavedComponents =
64,
.maxCullDistances = 8, .maxCullDistances = 8,
.maxCombinedClipAndCullDistances = 8, .maxCombinedClipAndCullDistances = 8,
.maxSamples = 4, .maxSamples = 4,
@ -116,8 +116,7 @@ constexpr TBuiltInResource DefaultTBuiltInResource = {
.generalSamplerIndexing = 1, .generalSamplerIndexing = 1,
.generalVariableIndexing = 1, .generalVariableIndexing = 1,
.generalConstantMatrixVectorIndexing = 1, .generalConstantMatrixVectorIndexing = 1,
} }};
};
EShLanguage ToEshShaderStage(vk::ShaderStageFlagBits stage) { EShLanguage ToEshShaderStage(vk::ShaderStageFlagBits stage) {
switch (stage) { switch (stage) {
@ -162,7 +161,8 @@ vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, v
} }
EProfile profile = ECoreProfile; EProfile profile = ECoreProfile;
EShMessages messages = static_cast<EShMessages>(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules); EShMessages messages =
static_cast<EShMessages>(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules);
EShLanguage lang = ToEshShaderStage(stage); EShLanguage lang = ToEshShaderStage(stage);
int default_version = 450; int default_version = 450;
@ -170,12 +170,15 @@ vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, v
int pass_source_code_length = static_cast<int>(code.size()); int pass_source_code_length = static_cast<int>(code.size());
auto shader = std::make_unique<glslang::TShader>(lang); auto shader = std::make_unique<glslang::TShader>(lang);
shader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetLanguageVersion::EShTargetSpv_1_3); shader->setEnvTarget(glslang::EShTargetSpv,
glslang::EShTargetLanguageVersion::EShTargetSpv_1_3);
shader->setStringsWithLengths(&pass_source_code, &pass_source_code_length, 1); shader->setStringsWithLengths(&pass_source_code, &pass_source_code_length, 1);
glslang::TShader::ForbidIncluder includer; glslang::TShader::ForbidIncluder includer;
if (!shader->parse(&DefaultTBuiltInResource, default_version, profile, false, true, messages, includer)) { if (!shader->parse(&DefaultTBuiltInResource, default_version, profile, false, true, messages,
LOG_CRITICAL(Render_Vulkan, "Shader Info Log:\n{}\n{}", shader->getInfoLog(), shader->getInfoDebugLog()); includer)) {
LOG_CRITICAL(Render_Vulkan, "Shader Info Log:\n{}\n{}", shader->getInfoLog(),
shader->getInfoDebugLog());
return VK_NULL_HANDLE; return VK_NULL_HANDLE;
} }
@ -183,7 +186,8 @@ vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, v
auto program = std::make_unique<glslang::TProgram>(); auto program = std::make_unique<glslang::TProgram>();
program->addShader(shader.get()); program->addShader(shader.get());
if (!program->link(messages)) { if (!program->link(messages)) {
LOG_CRITICAL(Render_Vulkan, "Program Info Log:\n{}\n{}", program->getInfoLog(), program->getInfoDebugLog()); LOG_CRITICAL(Render_Vulkan, "Program Info Log:\n{}\n{}", program->getInfoLog(),
program->getInfoDebugLog());
return VK_NULL_HANDLE; return VK_NULL_HANDLE;
} }
@ -212,10 +216,8 @@ vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, v
LOG_INFO(Render_Vulkan, "SPIR-V conversion messages: {}", spv_messages); LOG_INFO(Render_Vulkan, "SPIR-V conversion messages: {}", spv_messages);
} }
const vk::ShaderModuleCreateInfo shader_info = { const vk::ShaderModuleCreateInfo shader_info = {.codeSize = out_code.size() * sizeof(u32),
.codeSize = out_code.size() * sizeof(u32), .pCode = out_code.data()};
.pCode = out_code.data()
};
return device.createShaderModule(shader_info); return device.createShaderModule(shader_info);
} }

View File

@ -8,12 +8,9 @@
namespace Vulkan { namespace Vulkan {
enum class ShaderOptimization { enum class ShaderOptimization { High = 0, Debug = 1 };
High = 0,
Debug = 1
};
vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, vk::Device device,
vk::Device device, ShaderOptimization level); ShaderOptimization level);
} // namespace Vulkan } // namespace Vulkan

View File

@ -293,7 +293,8 @@ static std::string SampleTexture(const PicaFSConfig& config, unsigned texture_un
// Only unit 0 respects the texturing type // Only unit 0 respects the texturing type
switch (state.texture0_type) { switch (state.texture0_type) {
case TexturingRegs::TextureConfig::Texture2D: case TexturingRegs::TextureConfig::Texture2D:
return "textureLod(sampler2D(tex0, tex0_sampler), texcoord0, getLod(texcoord0 * vec2(textureSize(sampler2D(tex0, tex0_sampler), 0))))"; return "textureLod(sampler2D(tex0, tex0_sampler), texcoord0, getLod(texcoord0 * "
"vec2(textureSize(sampler2D(tex0, tex0_sampler), 0))))";
case TexturingRegs::TextureConfig::Projection2D: case TexturingRegs::TextureConfig::Projection2D:
// TODO (wwylele): find the exact LOD formula for projection texture // TODO (wwylele): find the exact LOD formula for projection texture
return "textureProj(sampler2D(tex0, tex0_sampler), vec3(texcoord0, texcoord0_w))"; return "textureProj(sampler2D(tex0, tex0_sampler), vec3(texcoord0, texcoord0_w))";
@ -311,12 +312,15 @@ static std::string SampleTexture(const PicaFSConfig& config, unsigned texture_un
return "texture(sampler2D(tex0, tex0_sampler), texcoord0)"; return "texture(sampler2D(tex0, tex0_sampler), texcoord0)";
} }
case 1: case 1:
return "textureLod(sampler2D(tex1, tex1_sampler), texcoord1, getLod(texcoord1 * vec2(textureSize(sampler2D(tex1, tex1_sampler), 0))))"; return "textureLod(sampler2D(tex1, tex1_sampler), texcoord1, getLod(texcoord1 * "
"vec2(textureSize(sampler2D(tex1, tex1_sampler), 0))))";
case 2: case 2:
if (state.texture2_use_coord1) if (state.texture2_use_coord1)
return "textureLod(sampler2D(tex2, tex2_sampler), texcoord1, getLod(texcoord1 * vec2(textureSize(sampler2D(tex2, tex2_sampler), 0))))"; return "textureLod(sampler2D(tex2, tex2_sampler), texcoord1, getLod(texcoord1 * "
"vec2(textureSize(sampler2D(tex2, tex2_sampler), 0))))";
else else
return "textureLod(sampler2D(tex2, tex2_sampler), texcoord2, getLod(texcoord2 * vec2(textureSize(sampler2D(tex2, tex2_sampler), 0))))"; return "textureLod(sampler2D(tex2, tex2_sampler), texcoord2, getLod(texcoord2 * "
"vec2(textureSize(sampler2D(tex2, tex2_sampler), 0))))";
case 3: case 3:
if (state.proctex.enable) { if (state.proctex.enable) {
return "ProcTex()"; return "ProcTex()";
@ -1580,8 +1584,8 @@ void main() {
return out; return out;
} }
std::optional<std::string> GenerateVertexShader( std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& setup,
const Pica::Shader::ShaderSetup& setup, const PicaVSConfig& config) { const PicaVSConfig& config) {
/*std::string out = "#extension GL_ARB_separate_shader_objects : enable\n"; /*std::string out = "#extension GL_ARB_separate_shader_objects : enable\n";
out += ShaderDecompiler::GetCommonDeclarations(); out += ShaderDecompiler::GetCommonDeclarations();
@ -1626,7 +1630,8 @@ layout (std140) uniform vs_config {
// output attributes declaration // output attributes declaration
for (u32 i = 0; i < config.state.num_outputs; ++i) { for (u32 i = 0; i < config.state.num_outputs; ++i) {
out += "layout(location = " + std::to_string(i) + ") out vec4 vs_out_attr" + std::to_string(i) + ";\n"; out += "layout(location = " + std::to_string(i) + ") out vec4 vs_out_attr" +
std::to_string(i) + ";\n";
} }
out += "\nvoid main() {\n"; out += "\nvoid main() {\n";
@ -1648,7 +1653,8 @@ static std::string GetGSCommonSource(const PicaGSConfigCommonRaw& config) {
out += '\n'; out += '\n';
for (u32 i = 0; i < config.vs_output_attributes; ++i) { for (u32 i = 0; i < config.vs_output_attributes; ++i) {
out += ("layout(location = " + std::to_string(i) + ") in vec4 vs_out_attr" + std::to_string(i) + "[];\n"; out += ("layout(location = " + std::to_string(i) + ") in vec4 vs_out_attr" +
std::to_string(i) + "[];\n";
} }
out += R"( out += R"(

View File

@ -203,8 +203,8 @@ std::string GenerateTrivialVertexShader();
* Generates the GLSL vertex shader program source code for the given VS program * Generates the GLSL vertex shader program source code for the given VS program
* @returns String of the shader source code; boost::none on failure * @returns String of the shader source code; boost::none on failure
*/ */
std::optional<std::string> GenerateVertexShader( std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& setup,
const Pica::Shader::ShaderSetup& setup, const PicaVSConfig& config); const PicaVSConfig& config);
/** /**
* Generates the GLSL fixed geometry shader program source code for non-GS PICA pipeline * Generates the GLSL fixed geometry shader program source code for non-GS PICA pipeline

View File

@ -7,9 +7,9 @@
#include "common/alignment.h" #include "common/alignment.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/vk_task_scheduler.h" #include "video_core/renderer_vulkan/vk_task_scheduler.h"
#include "video_core/renderer_vulkan/vk_instance.h"
namespace Vulkan { namespace Vulkan {
@ -21,8 +21,8 @@ inline auto ToVkAccessStageFlags(vk::BufferUsageFlagBits usage) {
vk::PipelineStageFlagBits::eVertexInput); vk::PipelineStageFlagBits::eVertexInput);
break; break;
case vk::BufferUsageFlagBits::eIndexBuffer: case vk::BufferUsageFlagBits::eIndexBuffer:
result = std::make_pair(vk::AccessFlagBits::eIndexRead, result =
vk::PipelineStageFlagBits::eVertexInput); std::make_pair(vk::AccessFlagBits::eIndexRead, vk::PipelineStageFlagBits::eVertexInput);
case vk::BufferUsageFlagBits::eUniformBuffer: case vk::BufferUsageFlagBits::eUniformBuffer:
result = std::make_pair(vk::AccessFlagBits::eUniformRead, result = std::make_pair(vk::AccessFlagBits::eUniformRead,
vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eVertexShader |
@ -41,24 +41,20 @@ inline auto ToVkAccessStageFlags(vk::BufferUsageFlagBits usage) {
StagingBuffer::StagingBuffer(const Instance& instance, u32 size, vk::BufferUsageFlags usage) StagingBuffer::StagingBuffer(const Instance& instance, u32 size, vk::BufferUsageFlags usage)
: instance{instance} { : instance{instance} {
const vk::BufferCreateInfo buffer_info = { const vk::BufferCreateInfo buffer_info = {.size = size, .usage = usage};
.size = size,
.usage = usage
};
const VmaAllocationCreateInfo alloc_create_info = { const VmaAllocationCreateInfo alloc_create_info = {
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | .flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
VMA_ALLOCATION_CREATE_MAPPED_BIT, VMA_ALLOCATION_CREATE_MAPPED_BIT,
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST .usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST};
};
VkBuffer unsafe_buffer = VK_NULL_HANDLE; VkBuffer unsafe_buffer = VK_NULL_HANDLE;
VkBufferCreateInfo unsafe_buffer_info = static_cast<VkBufferCreateInfo>(buffer_info); VkBufferCreateInfo unsafe_buffer_info = static_cast<VkBufferCreateInfo>(buffer_info);
VmaAllocationInfo alloc_info; VmaAllocationInfo alloc_info;
VmaAllocator allocator = instance.GetAllocator(); VmaAllocator allocator = instance.GetAllocator();
vmaCreateBuffer(allocator, &unsafe_buffer_info, &alloc_create_info, vmaCreateBuffer(allocator, &unsafe_buffer_info, &alloc_create_info, &unsafe_buffer, &allocation,
&unsafe_buffer, &allocation, &alloc_info); &alloc_info);
buffer = vk::Buffer{unsafe_buffer}; buffer = vk::Buffer{unsafe_buffer};
mapped = std::span{reinterpret_cast<std::byte*>(alloc_info.pMappedData), size}; mapped = std::span{reinterpret_cast<std::byte*>(alloc_info.pMappedData), size};
@ -68,27 +64,25 @@ StagingBuffer::~StagingBuffer() {
vmaDestroyBuffer(instance.GetAllocator(), static_cast<VkBuffer>(buffer), allocation); vmaDestroyBuffer(instance.GetAllocator(), static_cast<VkBuffer>(buffer), allocation);
} }
StreamBuffer::StreamBuffer(const Instance& instance, TaskScheduler& scheduler, StreamBuffer::StreamBuffer(const Instance& instance, TaskScheduler& scheduler, u32 size,
u32 size, vk::BufferUsageFlagBits usage, std::span<const vk::Format> view_formats) vk::BufferUsageFlagBits usage, std::span<const vk::Format> view_formats)
: instance{instance}, scheduler{scheduler}, staging{instance, size, vk::BufferUsageFlagBits::eTransferSrc}, : instance{instance}, scheduler{scheduler}, staging{instance, size,
vk::BufferUsageFlagBits::eTransferSrc},
usage{usage}, total_size{size} { usage{usage}, total_size{size} {
const vk::BufferCreateInfo buffer_info = { const vk::BufferCreateInfo buffer_info = {
.size = total_size, .size = total_size, .usage = usage | vk::BufferUsageFlagBits::eTransferDst};
.usage = usage | vk::BufferUsageFlagBits::eTransferDst
};
const VmaAllocationCreateInfo alloc_create_info = { const VmaAllocationCreateInfo alloc_create_info = {.usage =
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE};
};
VkBuffer unsafe_buffer = VK_NULL_HANDLE; VkBuffer unsafe_buffer = VK_NULL_HANDLE;
VkBufferCreateInfo unsafe_buffer_info = static_cast<VkBufferCreateInfo>(buffer_info); VkBufferCreateInfo unsafe_buffer_info = static_cast<VkBufferCreateInfo>(buffer_info);
VmaAllocationInfo alloc_info; VmaAllocationInfo alloc_info;
VmaAllocator allocator = instance.GetAllocator(); VmaAllocator allocator = instance.GetAllocator();
vmaCreateBuffer(allocator, &unsafe_buffer_info, &alloc_create_info, vmaCreateBuffer(allocator, &unsafe_buffer_info, &alloc_create_info, &unsafe_buffer, &allocation,
&unsafe_buffer, &allocation, &alloc_info); &alloc_info);
buffer = vk::Buffer{unsafe_buffer}; buffer = vk::Buffer{unsafe_buffer};
@ -97,11 +91,7 @@ StreamBuffer::StreamBuffer(const Instance& instance, TaskScheduler& scheduler,
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
for (std::size_t i = 0; i < view_formats.size(); i++) { for (std::size_t i = 0; i < view_formats.size(); i++) {
const vk::BufferViewCreateInfo view_info = { const vk::BufferViewCreateInfo view_info = {
.buffer = buffer, .buffer = buffer, .format = view_formats[i], .offset = 0, .range = total_size};
.format = view_formats[i],
.offset = 0,
.range = total_size
};
views[i] = device.createBufferView(view_info); views[i] = device.createBufferView(view_info);
} }
@ -138,7 +128,6 @@ std::tuple<u8*, u32, bool> StreamBuffer::Map(u32 size, u32 alignment) {
const u32 buffer_offset = current_bucket * bucket_size + bucket.offset; const u32 buffer_offset = current_bucket * bucket_size + bucket.offset;
u8* mapped = reinterpret_cast<u8*>(staging.mapped.data() + buffer_offset); u8* mapped = reinterpret_cast<u8*>(staging.mapped.data() + buffer_offset);
return std::make_tuple(mapped, buffer_offset, invalidate); return std::make_tuple(mapped, buffer_offset, invalidate);
} }
void StreamBuffer::Commit(u32 size) { void StreamBuffer::Commit(u32 size) {
@ -156,10 +145,7 @@ void StreamBuffer::Flush() {
const u32 flush_start = current_bucket * bucket_size; const u32 flush_start = current_bucket * bucket_size;
const vk::BufferCopy copy_region = { const vk::BufferCopy copy_region = {
.srcOffset = flush_start, .srcOffset = flush_start, .dstOffset = flush_start, .size = flush_size};
.dstOffset = flush_start,
.size = flush_size
};
vmaFlushAllocation(allocator, allocation, flush_start, flush_size); vmaFlushAllocation(allocator, allocation, flush_start, flush_size);
command_buffer.copyBuffer(staging.buffer, buffer, copy_region); command_buffer.copyBuffer(staging.buffer, buffer, copy_region);
@ -173,8 +159,7 @@ void StreamBuffer::Flush() {
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = buffer, .buffer = buffer,
.offset = flush_start, .offset = flush_start,
.size = flush_size .size = flush_size};
};
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, stage_mask, command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, stage_mask,
vk::DependencyFlagBits::eByRegion, {}, buffer_barrier, {}); vk::DependencyFlagBits::eByRegion, {}, buffer_barrier, {});

View File

@ -33,8 +33,8 @@ struct StagingBuffer {
class StreamBuffer { class StreamBuffer {
public: public:
StreamBuffer(const Instance& instance, TaskScheduler& scheduler, StreamBuffer(const Instance& instance, TaskScheduler& scheduler, u32 size,
u32 size, vk::BufferUsageFlagBits usage, std::span<const vk::Format> views); vk::BufferUsageFlagBits usage, std::span<const vk::Format> views);
~StreamBuffer(); ~StreamBuffer();
std::tuple<u8*, u32, bool> Map(u32 size, u32 alignment = 0); std::tuple<u8*, u32, bool> Map(u32 size, u32 alignment = 0);

View File

@ -5,9 +5,9 @@
#define VULKAN_HPP_NO_CONSTRUCTORS #define VULKAN_HPP_NO_CONSTRUCTORS
#include <algorithm> #include <algorithm>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h" #include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
namespace Vulkan { namespace Vulkan {
@ -59,8 +59,7 @@ void Swapchain::Create(u32 width, u32 height, bool vsync_enabled) {
.preTransform = transform, .preTransform = transform,
.presentMode = present_mode, .presentMode = present_mode,
.clipped = true, .clipped = true,
.oldSwapchain = swapchain .oldSwapchain = swapchain};
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
vk::SwapchainKHR new_swapchain = device.createSwapchainKHR(swapchain_info); vk::SwapchainKHR new_swapchain = device.createSwapchainKHR(swapchain_info);
@ -87,34 +86,25 @@ void Swapchain::Create(u32 width, u32 height, bool vsync_enabled) {
.image = image, .image = image,
.viewType = vk::ImageViewType::e2D, .viewType = vk::ImageViewType::e2D,
.format = surface_format.format, .format = surface_format.format,
.subresourceRange = { .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor,
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1 .layerCount = 1}};
}
};
vk::ImageView image_view = device.createImageView(view_info); vk::ImageView image_view = device.createImageView(view_info);
const std::array attachments{image_view}; const std::array attachments{image_view};
const vk::FramebufferCreateInfo framebuffer_info = { const vk::FramebufferCreateInfo framebuffer_info = {.renderPass = present_renderpass,
.renderPass = present_renderpass,
.attachmentCount = 1, .attachmentCount = 1,
.pAttachments = attachments.data(), .pAttachments = attachments.data(),
.width = extent.width, .width = extent.width,
.height = extent.height, .height = extent.height,
.layers = 1 .layers = 1};
};
vk::Framebuffer framebuffer = device.createFramebuffer(framebuffer_info); vk::Framebuffer framebuffer = device.createFramebuffer(framebuffer_info);
return Image{ return Image{.image = image, .image_view = image_view, .framebuffer = framebuffer};
.image = image,
.image_view = image_view,
.framebuffer = framebuffer
};
}); });
} }
@ -141,13 +131,11 @@ void Swapchain::AcquireNextImage(vk::Semaphore signal_acquired) {
} }
void Swapchain::Present(vk::Semaphore wait_for_present) { void Swapchain::Present(vk::Semaphore wait_for_present) {
const vk::PresentInfoKHR present_info = { const vk::PresentInfoKHR present_info = {.waitSemaphoreCount = 1,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &wait_for_present, .pWaitSemaphores = &wait_for_present,
.swapchainCount = 1, .swapchainCount = 1,
.pSwapchains = &swapchain, .pSwapchains = &swapchain,
.pImageIndices = &current_image .pImageIndices = &current_image};
};
vk::Queue present_queue = instance.GetPresentQueue(); vk::Queue present_queue = instance.GetPresentQueue();
vk::Result result = present_queue.presentKHR(present_info); vk::Result result = present_queue.presentKHR(present_info);
@ -196,9 +184,8 @@ void Swapchain::Configure(u32 width, u32 height) {
// FIFO is guaranteed by the Vulkan standard to be available // FIFO is guaranteed by the Vulkan standard to be available
present_mode = vk::PresentModeKHR::eFifo; present_mode = vk::PresentModeKHR::eFifo;
auto iter = std::ranges::find_if(modes, [](vk::PresentModeKHR mode) { auto iter = std::ranges::find_if(
return vk::PresentModeKHR::eMailbox == mode; modes, [](vk::PresentModeKHR mode) { return vk::PresentModeKHR::eMailbox == mode; });
});
// Prefer Mailbox if present for lowest latency // Prefer Mailbox if present for lowest latency
if (iter != modes.end()) { if (iter != modes.end()) {
@ -210,8 +197,8 @@ void Swapchain::Configure(u32 width, u32 height) {
extent = capabilities.currentExtent; extent = capabilities.currentExtent;
if (capabilities.currentExtent.width == std::numeric_limits<u32>::max()) { if (capabilities.currentExtent.width == std::numeric_limits<u32>::max()) {
extent.width = std::clamp(width, capabilities.minImageExtent.width, extent.width =
capabilities.maxImageExtent.width); std::clamp(width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height = std::clamp(height, capabilities.minImageExtent.height, extent.height = std::clamp(height, capabilities.minImageExtent.height,
capabilities.maxImageExtent.height); capabilities.maxImageExtent.height);
} }

View File

@ -6,8 +6,8 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "video_core/renderer_vulkan/vk_task_scheduler.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_task_scheduler.h"
namespace Vulkan { namespace Vulkan {
@ -16,8 +16,7 @@ TaskScheduler::TaskScheduler(const Instance& instance, RendererVulkan& renderer)
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
const vk::CommandPoolCreateInfo command_pool_info = { const vk::CommandPoolCreateInfo command_pool_info = {
.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer, .flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
.queueFamilyIndex = instance.GetGraphicsQueueFamilyIndex() .queueFamilyIndex = instance.GetGraphicsQueueFamilyIndex()};
};
command_pool = device.createCommandPool(command_pool_info); command_pool = device.createCommandPool(command_pool_info);
@ -25,11 +24,8 @@ TaskScheduler::TaskScheduler(const Instance& instance, RendererVulkan& renderer)
if (instance.IsTimelineSemaphoreSupported()) { if (instance.IsTimelineSemaphoreSupported()) {
const vk::StructureChain timeline_info = { const vk::StructureChain timeline_info = {
vk::SemaphoreCreateInfo{}, vk::SemaphoreCreateInfo{},
vk::SemaphoreTypeCreateInfo{ vk::SemaphoreTypeCreateInfo{.semaphoreType = vk::SemaphoreType::eTimeline,
.semaphoreType = vk::SemaphoreType::eTimeline, .initialValue = 0}};
.initialValue = 0
}
};
timeline = device.createSemaphore(timeline_info.get()); timeline = device.createSemaphore(timeline_info.get());
} }
@ -40,22 +36,19 @@ TaskScheduler::TaskScheduler(const Instance& instance, RendererVulkan& renderer)
vk::DescriptorPoolSize{vk::DescriptorType::eSampledImage, 2048}, vk::DescriptorPoolSize{vk::DescriptorType::eSampledImage, 2048},
vk::DescriptorPoolSize{vk::DescriptorType::eCombinedImageSampler, 512}, vk::DescriptorPoolSize{vk::DescriptorType::eCombinedImageSampler, 512},
vk::DescriptorPoolSize{vk::DescriptorType::eSampler, 2048}, vk::DescriptorPoolSize{vk::DescriptorType::eSampler, 2048},
vk::DescriptorPoolSize{vk::DescriptorType::eUniformTexelBuffer, 1024} vk::DescriptorPoolSize{vk::DescriptorType::eUniformTexelBuffer, 1024}};
};
const vk::DescriptorPoolCreateInfo descriptor_pool_info = { const vk::DescriptorPoolCreateInfo descriptor_pool_info = {
.maxSets = 2048, .maxSets = 2048,
.poolSizeCount = static_cast<u32>(pool_sizes.size()), .poolSizeCount = static_cast<u32>(pool_sizes.size()),
.pPoolSizes = pool_sizes.data() .pPoolSizes = pool_sizes.data()};
};
persistent_descriptor_pool = device.createDescriptorPool(descriptor_pool_info); persistent_descriptor_pool = device.createDescriptorPool(descriptor_pool_info);
const vk::CommandBufferAllocateInfo buffer_info = { const vk::CommandBufferAllocateInfo buffer_info = {.commandPool = command_pool,
.commandPool = command_pool,
.level = vk::CommandBufferLevel::ePrimary, .level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = 2 * SCHEDULER_COMMAND_COUNT .commandBufferCount =
}; 2 * SCHEDULER_COMMAND_COUNT};
const auto command_buffers = device.allocateCommandBuffers(buffer_info); const auto command_buffers = device.allocateCommandBuffers(buffer_info);
for (std::size_t i = 0; i < commands.size(); i++) { for (std::size_t i = 0; i < commands.size(); i++) {
@ -70,8 +63,7 @@ TaskScheduler::TaskScheduler(const Instance& instance, RendererVulkan& renderer)
} }
const vk::CommandBufferBeginInfo begin_info = { const vk::CommandBufferBeginInfo begin_info = {
.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
};
// Begin first command // Begin first command
auto& command = commands[current_command]; auto& command = commands[current_command];
@ -106,13 +98,11 @@ void TaskScheduler::Synchronize(u32 slot) {
if (command.fence_counter > completed_counter) { if (command.fence_counter > completed_counter) {
if (instance.IsTimelineSemaphoreSupported()) { if (instance.IsTimelineSemaphoreSupported()) {
const vk::SemaphoreWaitInfo wait_info = { const vk::SemaphoreWaitInfo wait_info = {
.semaphoreCount = 1, .semaphoreCount = 1, .pSemaphores = &timeline, .pValues = &command.fence_counter};
.pSemaphores = &timeline,
.pValues = &command.fence_counter
};
if (device.waitSemaphores(wait_info, UINT64_MAX) != vk::Result::eSuccess) { if (device.waitSemaphores(wait_info, UINT64_MAX) != vk::Result::eSuccess) {
LOG_ERROR(Render_Vulkan, "Waiting for fence counter {} failed!", command.fence_counter); LOG_ERROR(Render_Vulkan, "Waiting for fence counter {} failed!",
command.fence_counter);
UNREACHABLE(); UNREACHABLE();
} }
@ -161,8 +151,7 @@ void TaskScheduler::Submit(SubmitMode mode) {
.waitSemaphoreValueCount = wait_semaphore_count, .waitSemaphoreValueCount = wait_semaphore_count,
.pWaitSemaphoreValues = wait_values.data(), .pWaitSemaphoreValues = wait_values.data(),
.signalSemaphoreValueCount = signal_semaphore_count, .signalSemaphoreValueCount = signal_semaphore_count,
.pSignalSemaphoreValues = signal_values.data() .pSignalSemaphoreValues = signal_values.data()};
};
const std::array<vk::PipelineStageFlags, 2> wait_stage_masks = { const std::array<vk::PipelineStageFlags, 2> wait_stage_masks = {
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
@ -228,8 +217,7 @@ vk::CommandBuffer TaskScheduler::GetUploadCommandBuffer() {
auto& command = commands[current_command]; auto& command = commands[current_command];
if (!command.use_upload_buffer) { if (!command.use_upload_buffer) {
const vk::CommandBufferBeginInfo begin_info = { const vk::CommandBufferBeginInfo begin_info = {
.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
};
command.upload_command_buffer.begin(begin_info); command.upload_command_buffer.begin(begin_info);
command.use_upload_buffer = true; command.use_upload_buffer = true;
@ -246,8 +234,7 @@ void TaskScheduler::SwitchSlot() {
Synchronize(current_command); Synchronize(current_command);
const vk::CommandBufferBeginInfo begin_info = { const vk::CommandBufferBeginInfo begin_info = {
.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
};
// Begin the next command buffer. // Begin the next command buffer.
command.render_command_buffer.begin(begin_info); command.render_command_buffer.begin(begin_info);

View File

@ -4,11 +4,11 @@
#pragma once #pragma once
#include <memory>
#include <array> #include <array>
#include <functional> #include <functional>
#include "common/common_types.h" #include <memory>
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h"
#include "video_core/renderer_vulkan/vk_common.h" #include "video_core/renderer_vulkan/vk_common.h"
namespace Vulkan { namespace Vulkan {

View File

@ -42,12 +42,14 @@ TextureRuntime::TextureRuntime(const Instance& instance, TaskScheduler& schedule
vk::BufferUsageFlagBits::eTransferDst); vk::BufferUsageFlagBits::eTransferDst);
} }
auto Register = [this](VideoCore::PixelFormat dest, std::unique_ptr<FormatReinterpreterBase>&& obj) { auto Register = [this](VideoCore::PixelFormat dest,
std::unique_ptr<FormatReinterpreterBase>&& obj) {
const u32 dst_index = static_cast<u32>(dest); const u32 dst_index = static_cast<u32>(dest);
return reinterpreters[dst_index].push_back(std::move(obj)); return reinterpreters[dst_index].push_back(std::move(obj));
}; };
Register(VideoCore::PixelFormat::RGBA8, std::make_unique<D24S8toRGBA8>(instance, scheduler, *this)); Register(VideoCore::PixelFormat::RGBA8,
std::make_unique<D24S8toRGBA8>(instance, scheduler, *this));
} }
TextureRuntime::~TextureRuntime() { TextureRuntime::~TextureRuntime() {
@ -81,12 +83,10 @@ StagingData TextureRuntime::FindStaging(u32 size, bool upload) {
} }
const auto& buffer = staging_buffers[current_slot]; const auto& buffer = staging_buffers[current_slot];
return StagingData{ return StagingData{.buffer = buffer->buffer,
.buffer = buffer->buffer,
.size = size, .size = size,
.mapped = buffer->mapped.subspan(offset, size), .mapped = buffer->mapped.subspan(offset, size),
.buffer_offset = offset .buffer_offset = offset};
};
} }
void TextureRuntime::Finish() { void TextureRuntime::Finish() {
@ -102,11 +102,7 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
const u32 layers = type == VideoCore::TextureType::CubeMap ? 6 : 1; const u32 layers = type == VideoCore::TextureType::CubeMap ? 6 : 1;
const VideoCore::HostTextureTag key = { const VideoCore::HostTextureTag key = {
.format = format, .format = format, .width = width, .height = height, .layers = layers};
.width = width,
.height = height,
.layers = layers
};
// Attempt to recycle an unused allocation // Attempt to recycle an unused allocation
if (auto it = texture_recycler.find(key); it != texture_recycler.end()) { if (auto it = texture_recycler.find(key); it != texture_recycler.end()) {
@ -123,22 +119,18 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
const vk::ImageUsageFlags vk_usage = is_suitable ? traits.usage : GetImageUsage(aspect); const vk::ImageUsageFlags vk_usage = is_suitable ? traits.usage : GetImageUsage(aspect);
const u32 levels = std::bit_width(std::max(width, height)); const u32 levels = std::bit_width(std::max(width, height));
const vk::ImageCreateInfo image_info = { const vk::ImageCreateInfo image_info = {.flags = type == VideoCore::TextureType::CubeMap
.flags = type == VideoCore::TextureType::CubeMap ? ? vk::ImageCreateFlagBits::eCubeCompatible
vk::ImageCreateFlagBits::eCubeCompatible : : vk::ImageCreateFlags{},
vk::ImageCreateFlags{},
.imageType = vk::ImageType::e2D, .imageType = vk::ImageType::e2D,
.format = vk_format, .format = vk_format,
.extent = {width, height, 1}, .extent = {width, height, 1},
.mipLevels = levels, .mipLevels = levels,
.arrayLayers = layers, .arrayLayers = layers,
.samples = vk::SampleCountFlagBits::e1, .samples = vk::SampleCountFlagBits::e1,
.usage = vk_usage .usage = vk_usage};
};
const VmaAllocationCreateInfo alloc_info = { const VmaAllocationCreateInfo alloc_info = {.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE};
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE
};
VkImage unsafe_image{}; VkImage unsafe_image{};
VkImageCreateInfo unsafe_image_info = static_cast<VkImageCreateInfo>(image_info); VkImageCreateInfo unsafe_image_info = static_cast<VkImageCreateInfo>(image_info);
@ -152,36 +144,28 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
} }
vk::Image image = vk::Image{unsafe_image}; vk::Image image = vk::Image{unsafe_image};
const vk::ImageViewCreateInfo view_info = { const vk::ImageViewCreateInfo view_info = {.image = image,
.image = image, .viewType = type == VideoCore::TextureType::CubeMap
.viewType = type == VideoCore::TextureType::CubeMap ? ? vk::ImageViewType::eCube
vk::ImageViewType::eCube : : vk::ImageViewType::e2D,
vk::ImageViewType::e2D,
.format = vk_format, .format = vk_format,
.subresourceRange = { .subresourceRange = {.aspectMask = aspect,
.aspectMask = aspect,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = levels, .levelCount = levels,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = layers .layerCount = layers}};
}
};
// Also create a base mip view in case this is used as an attachment // Also create a base mip view in case this is used as an attachment
const vk::ImageViewCreateInfo base_view_info = { const vk::ImageViewCreateInfo base_view_info = {
.image = image, .image = image,
.viewType = type == VideoCore::TextureType::CubeMap ? .viewType = type == VideoCore::TextureType::CubeMap ? vk::ImageViewType::eCube
vk::ImageViewType::eCube : : vk::ImageViewType::e2D,
vk::ImageViewType::e2D,
.format = vk_format, .format = vk_format,
.subresourceRange = { .subresourceRange = {.aspectMask = aspect,
.aspectMask = aspect,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = layers .layerCount = layers}};
}
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
vk::ImageView image_view = device.createImageView(view_info); vk::ImageView image_view = device.createImageView(view_info);
@ -193,26 +177,21 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
if (format == VideoCore::PixelFormat::D24S8) { if (format == VideoCore::PixelFormat::D24S8) {
vk::ImageViewCreateInfo view_info = { vk::ImageViewCreateInfo view_info = {
.image = image, .image = image,
.viewType = type == VideoCore::TextureType::CubeMap ? .viewType = type == VideoCore::TextureType::CubeMap ? vk::ImageViewType::eCube
vk::ImageViewType::eCube : : vk::ImageViewType::e2D,
vk::ImageViewType::e2D,
.format = vk_format, .format = vk_format,
.subresourceRange = { .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eDepth,
.aspectMask = vk::ImageAspectFlagBits::eDepth,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = levels, .levelCount = levels,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = layers .layerCount = layers}};
}
};
depth_view = device.createImageView(view_info); depth_view = device.createImageView(view_info);
view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eStencil; view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eStencil;
stencil_view = device.createImageView(view_info); stencil_view = device.createImageView(view_info);
} }
return ImageAlloc{ return ImageAlloc{.image = image,
.image = image,
.image_view = image_view, .image_view = image_view,
.base_view = base_view, .base_view = base_view,
.depth_view = depth_view, .depth_view = depth_view,
@ -221,16 +200,15 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
.format = vk_format, .format = vk_format,
.aspect = aspect, .aspect = aspect,
.levels = levels, .levels = levels,
.layers = layers .layers = layers};
};
} }
void TextureRuntime::Recycle(const VideoCore::HostTextureTag tag, ImageAlloc&& alloc) { void TextureRuntime::Recycle(const VideoCore::HostTextureTag tag, ImageAlloc&& alloc) {
texture_recycler.emplace(tag, std::move(alloc)); texture_recycler.emplace(tag, std::move(alloc));
} }
void TextureRuntime::FormatConvert(const Surface& surface, bool upload, void TextureRuntime::FormatConvert(const Surface& surface, bool upload, std::span<std::byte> source,
std::span<std::byte> source, std::span<std::byte> dest) { std::span<std::byte> dest) {
if (!surface.NeedsConvert()) { if (!surface.NeedsConvert()) {
std::memcpy(dest.data(), source.data(), source.size()); std::memcpy(dest.data(), source.data(), source.size());
return; return;
@ -267,7 +245,8 @@ void TextureRuntime::FormatConvert(const Surface& surface, bool upload,
} }
LOG_WARNING(Render_Vulkan, "Missing format convertion: {} {} {}", LOG_WARNING(Render_Vulkan, "Missing format convertion: {} {} {}",
vk::to_string(surface.traits.native), upload ? "->" : "<-", vk::to_string(surface.alloc.format)); vk::to_string(surface.traits.native), upload ? "->" : "<-",
vk::to_string(surface.alloc.format));
} }
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear, bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear,
@ -276,36 +255,37 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
Transition(command_buffer, surface.alloc, vk::ImageLayout::eTransferDstOptimal, Transition(command_buffer, surface.alloc, vk::ImageLayout::eTransferDstOptimal, 0,
0, surface.alloc.levels, 0, surface.texture_type == VideoCore::TextureType::CubeMap ? 6 : 1); surface.alloc.levels, 0,
surface.texture_type == VideoCore::TextureType::CubeMap ? 6 : 1);
vk::ClearValue clear_value{}; vk::ClearValue clear_value{};
if (aspect & vk::ImageAspectFlagBits::eColor) { if (aspect & vk::ImageAspectFlagBits::eColor) {
clear_value.color = vk::ClearColorValue{ clear_value.color = vk::ClearColorValue{
.float32 = std::to_array({value.color[0], value.color[1], value.color[2], value.color[3]}) .float32 =
}; std::to_array({value.color[0], value.color[1], value.color[2], value.color[3]})};
} else if (aspect & vk::ImageAspectFlagBits::eDepth || aspect & vk::ImageAspectFlagBits::eStencil) { } else if (aspect & vk::ImageAspectFlagBits::eDepth ||
clear_value.depthStencil = vk::ClearDepthStencilValue{ aspect & vk::ImageAspectFlagBits::eStencil) {
.depth = value.depth, clear_value.depthStencil =
.stencil = value.stencil vk::ClearDepthStencilValue{.depth = value.depth, .stencil = value.stencil};
};
} }
// For full clears we can use vkCmdClearColorImage/vkCmdClearDepthStencilImage // For full clears we can use vkCmdClearColorImage/vkCmdClearDepthStencilImage
if (clear.texture_rect == surface.GetScaledRect()) { if (clear.texture_rect == surface.GetScaledRect()) {
const vk::ImageSubresourceRange range = { const vk::ImageSubresourceRange range = {.aspectMask = aspect,
.aspectMask = aspect,
.baseMipLevel = clear.texture_level, .baseMipLevel = clear.texture_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1 .layerCount = 1};
};
if (aspect & vk::ImageAspectFlagBits::eColor) { if (aspect & vk::ImageAspectFlagBits::eColor) {
command_buffer.clearColorImage(surface.alloc.image, vk::ImageLayout::eTransferDstOptimal, command_buffer.clearColorImage(surface.alloc.image,
clear_value.color, range); vk::ImageLayout::eTransferDstOptimal, clear_value.color,
} else if (aspect & vk::ImageAspectFlagBits::eDepth || aspect & vk::ImageAspectFlagBits::eStencil) { range);
command_buffer.clearDepthStencilImage(surface.alloc.image, vk::ImageLayout::eTransferDstOptimal, } else if (aspect & vk::ImageAspectFlagBits::eDepth ||
aspect & vk::ImageAspectFlagBits::eStencil) {
command_buffer.clearDepthStencilImage(surface.alloc.image,
vk::ImageLayout::eTransferDstOptimal,
clear_value.depthStencil, range); clear_value.depthStencil, range);
} }
} else { } else {
@ -313,26 +293,28 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
vk::RenderPass clear_renderpass{}; vk::RenderPass clear_renderpass{};
ImageAlloc& alloc = surface.alloc; ImageAlloc& alloc = surface.alloc;
if (aspect & vk::ImageAspectFlagBits::eColor) { if (aspect & vk::ImageAspectFlagBits::eColor) {
clear_renderpass = renderpass_cache.GetRenderpass(surface.pixel_format, clear_renderpass = renderpass_cache.GetRenderpass(
VideoCore::PixelFormat::Invalid, true); surface.pixel_format, VideoCore::PixelFormat::Invalid, true);
Transition(command_buffer, alloc, vk::ImageLayout::eColorAttachmentOptimal, 0, alloc.levels); Transition(command_buffer, alloc, vk::ImageLayout::eColorAttachmentOptimal, 0,
} else if (aspect & vk::ImageAspectFlagBits::eDepth || aspect & vk::ImageAspectFlagBits::eStencil) { alloc.levels);
} else if (aspect & vk::ImageAspectFlagBits::eDepth ||
aspect & vk::ImageAspectFlagBits::eStencil) {
clear_renderpass = renderpass_cache.GetRenderpass(VideoCore::PixelFormat::Invalid, clear_renderpass = renderpass_cache.GetRenderpass(VideoCore::PixelFormat::Invalid,
surface.pixel_format, true); surface.pixel_format, true);
Transition(command_buffer, alloc, vk::ImageLayout::eDepthStencilAttachmentOptimal, 0, alloc.levels); Transition(command_buffer, alloc, vk::ImageLayout::eDepthStencilAttachmentOptimal, 0,
alloc.levels);
} }
auto [it, new_framebuffer] = clear_framebuffers.try_emplace(alloc.image_view, vk::Framebuffer{}); auto [it, new_framebuffer] =
if (new_framebuffer) {\ clear_framebuffers.try_emplace(alloc.image_view, vk::Framebuffer{});
if (new_framebuffer) {
const vk::ImageView framebuffer_view = surface.GetFramebufferView(); const vk::ImageView framebuffer_view = surface.GetFramebufferView();
const vk::FramebufferCreateInfo framebuffer_info = { const vk::FramebufferCreateInfo framebuffer_info = {.renderPass = clear_renderpass,
.renderPass = clear_renderpass,
.attachmentCount = 1, .attachmentCount = 1,
.pAttachments = &framebuffer_view, .pAttachments = &framebuffer_view,
.width = surface.GetScaledWidth(), .width = surface.GetScaledWidth(),
.height = surface.GetScaledHeight(), .height = surface.GetScaledHeight(),
.layers = 1 .layers = 1};
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
it->second = device.createFramebuffer(framebuffer_info); it->second = device.createFramebuffer(framebuffer_info);
@ -341,13 +323,12 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
const vk::RenderPassBeginInfo clear_begin_info = { const vk::RenderPassBeginInfo clear_begin_info = {
.renderPass = clear_renderpass, .renderPass = clear_renderpass,
.framebuffer = it->second, .framebuffer = it->second,
.renderArea = vk::Rect2D{ .renderArea = vk::Rect2D{.offset = {static_cast<s32>(clear.texture_rect.left),
.offset = {static_cast<s32>(clear.texture_rect.left), static_cast<s32>(clear.texture_rect.bottom)}, static_cast<s32>(clear.texture_rect.bottom)},
.extent = {clear.texture_rect.GetWidth(), clear.texture_rect.GetHeight()} .extent = {clear.texture_rect.GetWidth(),
}, clear.texture_rect.GetHeight()}},
.clearValueCount = 1, .clearValueCount = 1,
.pClearValues = &clear_value .pClearValues = &clear_value};
};
renderpass_cache.EnterRenderpass(clear_begin_info); renderpass_cache.EnterRenderpass(clear_begin_info);
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
@ -356,30 +337,28 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
return true; return true;
} }
bool TextureRuntime::CopyTextures(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy) { bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
const VideoCore::TextureCopy& copy) {
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
const vk::ImageCopy image_copy = { const vk::ImageCopy image_copy = {
.srcSubresource = { .srcSubresource = {.aspectMask = ToVkAspect(source.type),
.aspectMask = ToVkAspect(source.type),
.mipLevel = copy.src_level, .mipLevel = copy.src_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1 .layerCount = 1},
},
.srcOffset = {static_cast<s32>(copy.src_offset.x), static_cast<s32>(copy.src_offset.y), 0}, .srcOffset = {static_cast<s32>(copy.src_offset.x), static_cast<s32>(copy.src_offset.y), 0},
.dstSubresource = { .dstSubresource = {.aspectMask = ToVkAspect(dest.type),
.aspectMask = ToVkAspect(dest.type),
.mipLevel = copy.dst_level, .mipLevel = copy.dst_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1 .layerCount = 1},
},
.dstOffset = {static_cast<s32>(copy.dst_offset.x), static_cast<s32>(copy.dst_offset.y), 0}, .dstOffset = {static_cast<s32>(copy.dst_offset.x), static_cast<s32>(copy.dst_offset.y), 0},
.extent = {copy.extent.width, copy.extent.height, 1} .extent = {copy.extent.width, copy.extent.height, 1}};
};
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
Transition(command_buffer, source.alloc, vk::ImageLayout::eTransferSrcOptimal, 0, source.alloc.levels); Transition(command_buffer, source.alloc, vk::ImageLayout::eTransferSrcOptimal, 0,
Transition(command_buffer, dest.alloc, vk::ImageLayout::eTransferDstOptimal, 0, dest.alloc.levels); source.alloc.levels);
Transition(command_buffer, dest.alloc, vk::ImageLayout::eTransferDstOptimal, 0,
dest.alloc.levels);
command_buffer.copyImage(source.alloc.image, vk::ImageLayout::eTransferSrcOptimal, command_buffer.copyImage(source.alloc.image, vk::ImageLayout::eTransferSrcOptimal,
dest.alloc.image, vk::ImageLayout::eTransferDstOptimal, image_copy); dest.alloc.image, vk::ImageLayout::eTransferDstOptimal, image_copy);
@ -387,45 +366,41 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest, const VideoCor
return true; return true;
} }
bool TextureRuntime::BlitTextures(Surface& source, Surface& dest, const VideoCore::TextureBlit& blit) { bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
const VideoCore::TextureBlit& blit) {
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
Transition(command_buffer, source.alloc, vk::ImageLayout::eTransferSrcOptimal, Transition(command_buffer, source.alloc, vk::ImageLayout::eTransferSrcOptimal, 0,
0, source.alloc.levels, 0, source.texture_type == VideoCore::TextureType::CubeMap ? 6 : 1); source.alloc.levels, 0,
Transition(command_buffer, dest.alloc, vk::ImageLayout::eTransferDstOptimal, source.texture_type == VideoCore::TextureType::CubeMap ? 6 : 1);
0, dest.alloc.levels, 0, dest.texture_type == VideoCore::TextureType::CubeMap ? 6 : 1); Transition(command_buffer, dest.alloc, vk::ImageLayout::eTransferDstOptimal, 0,
dest.alloc.levels, 0, dest.texture_type == VideoCore::TextureType::CubeMap ? 6 : 1);
const std::array source_offsets = { const std::array source_offsets = {vk::Offset3D{static_cast<s32>(blit.src_rect.left),
vk::Offset3D{static_cast<s32>(blit.src_rect.left), static_cast<s32>(blit.src_rect.bottom), 0}, static_cast<s32>(blit.src_rect.bottom), 0},
vk::Offset3D{static_cast<s32>(blit.src_rect.right), static_cast<s32>(blit.src_rect.top), 1} vk::Offset3D{static_cast<s32>(blit.src_rect.right),
}; static_cast<s32>(blit.src_rect.top), 1}};
const std::array dest_offsets = { const std::array dest_offsets = {vk::Offset3D{static_cast<s32>(blit.dst_rect.left),
vk::Offset3D{static_cast<s32>(blit.dst_rect.left), static_cast<s32>(blit.dst_rect.bottom), 0}, static_cast<s32>(blit.dst_rect.bottom), 0},
vk::Offset3D{static_cast<s32>(blit.dst_rect.right), static_cast<s32>(blit.dst_rect.top), 1} vk::Offset3D{static_cast<s32>(blit.dst_rect.right),
}; static_cast<s32>(blit.dst_rect.top), 1}};
const vk::ImageBlit blit_area = { const vk::ImageBlit blit_area = {.srcSubresource = {.aspectMask = ToVkAspect(source.type),
.srcSubresource = {
.aspectMask = ToVkAspect(source.type),
.mipLevel = blit.src_level, .mipLevel = blit.src_level,
.baseArrayLayer = blit.src_layer, .baseArrayLayer = blit.src_layer,
.layerCount = 1 .layerCount = 1},
},
.srcOffsets = source_offsets, .srcOffsets = source_offsets,
.dstSubresource = { .dstSubresource = {.aspectMask = ToVkAspect(dest.type),
.aspectMask = ToVkAspect(dest.type),
.mipLevel = blit.dst_level, .mipLevel = blit.dst_level,
.baseArrayLayer = blit.dst_layer, .baseArrayLayer = blit.dst_layer,
.layerCount = 1 .layerCount = 1},
}, .dstOffsets = dest_offsets};
.dstOffsets = dest_offsets
};
command_buffer.blitImage(source.alloc.image, vk::ImageLayout::eTransferSrcOptimal, command_buffer.blitImage(source.alloc.image, vk::ImageLayout::eTransferSrcOptimal,
dest.alloc.image, vk::ImageLayout::eTransferDstOptimal, dest.alloc.image, vk::ImageLayout::eTransferDstOptimal, blit_area,
blit_area, vk::Filter::eNearest); vk::Filter::eNearest);
return true; return true;
} }
@ -444,33 +419,23 @@ void TextureRuntime::GenerateMipmaps(Surface& surface, u32 max_level) {
Transition(command_buffer, surface.alloc, vk::ImageLayout::eTransferSrcOptimal, i - 1, 1); Transition(command_buffer, surface.alloc, vk::ImageLayout::eTransferSrcOptimal, i - 1, 1);
Transition(command_buffer, surface.alloc, vk::ImageLayout::eTransferDstOptimal, i, 1); Transition(command_buffer, surface.alloc, vk::ImageLayout::eTransferDstOptimal, i, 1);
const std::array source_offsets = { const std::array source_offsets = {vk::Offset3D{0, 0, 0},
vk::Offset3D{0, 0, 0}, vk::Offset3D{current_width, current_height, 1}};
vk::Offset3D{current_width, current_height, 1}
};
const std::array dest_offsets = { const std::array dest_offsets = {
vk::Offset3D{0, 0, 0}, vk::Offset3D{0, 0, 0}, vk::Offset3D{current_width > 1 ? current_width / 2 : 1,
vk::Offset3D{current_width > 1 ? current_width / 2 : 1, current_height > 1 ? current_height / 2 : 1, 1}};
current_height > 1 ? current_height / 2 : 1, 1}
};
const vk::ImageBlit blit_area = { const vk::ImageBlit blit_area = {.srcSubresource = {.aspectMask = aspect,
.srcSubresource = {
.aspectMask = aspect,
.mipLevel = i - 1, .mipLevel = i - 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1 .layerCount = 1},
},
.srcOffsets = source_offsets, .srcOffsets = source_offsets,
.dstSubresource = { .dstSubresource = {.aspectMask = aspect,
.aspectMask = aspect,
.mipLevel = i, .mipLevel = i,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1 .layerCount = 1},
}, .dstOffsets = dest_offsets};
.dstOffsets = dest_offsets
};
command_buffer.blitImage(surface.alloc.image, vk::ImageLayout::eTransferSrcOptimal, command_buffer.blitImage(surface.alloc.image, vk::ImageLayout::eTransferSrcOptimal,
surface.alloc.image, vk::ImageLayout::eTransferDstOptimal, surface.alloc.image, vk::ImageLayout::eTransferDstOptimal,
@ -478,13 +443,14 @@ void TextureRuntime::GenerateMipmaps(Surface& surface, u32 max_level) {
} }
} }
const ReinterpreterList& TextureRuntime::GetPossibleReinterpretations(VideoCore::PixelFormat dest_format) const { const ReinterpreterList& TextureRuntime::GetPossibleReinterpretations(
VideoCore::PixelFormat dest_format) const {
return reinterpreters[static_cast<u32>(dest_format)]; return reinterpreters[static_cast<u32>(dest_format)];
} }
void TextureRuntime::Transition(vk::CommandBuffer command_buffer, ImageAlloc& alloc, void TextureRuntime::Transition(vk::CommandBuffer command_buffer, ImageAlloc& alloc,
vk::ImageLayout new_layout, u32 level, u32 level_count, vk::ImageLayout new_layout, u32 level, u32 level_count, u32 layer,
u32 layer, u32 layer_count) { u32 layer_count) {
if (new_layout == alloc.layout || !alloc.image) { if (new_layout == alloc.layout || !alloc.image) {
return; return;
} }
@ -515,7 +481,8 @@ void TextureRuntime::Transition(vk::CommandBuffer command_buffer, ImageAlloc& al
info.stage = vk::PipelineStageFlagBits::eColorAttachmentOutput; info.stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
break; break;
case vk::ImageLayout::eDepthStencilAttachmentOptimal: case vk::ImageLayout::eDepthStencilAttachmentOptimal:
// Image was being used as a depthstencil attachment, so ensure all writes have completed. // Image was being used as a depthstencil attachment, so ensure all writes have
// completed.
info.access = vk::AccessFlagBits::eDepthStencilAttachmentRead | info.access = vk::AccessFlagBits::eDepthStencilAttachmentRead |
vk::AccessFlagBits::eDepthStencilAttachmentWrite; vk::AccessFlagBits::eDepthStencilAttachmentWrite;
info.stage = vk::PipelineStageFlagBits::eEarlyFragmentTests | info.stage = vk::PipelineStageFlagBits::eEarlyFragmentTests |
@ -568,18 +535,14 @@ void TextureRuntime::Transition(vk::CommandBuffer command_buffer, ImageAlloc& al
.oldLayout = alloc.layout, .oldLayout = alloc.layout,
.newLayout = new_layout, .newLayout = new_layout,
.image = alloc.image, .image = alloc.image,
.subresourceRange = { .subresourceRange = {.aspectMask = alloc.aspect,
.aspectMask = alloc.aspect,
.baseMipLevel = /*level*/ 0, .baseMipLevel = /*level*/ 0,
.levelCount = /*level_count*/ alloc.levels, .levelCount = /*level_count*/ alloc.levels,
.baseArrayLayer = layer, .baseArrayLayer = layer,
.layerCount = layer_count .layerCount = layer_count}};
}
};
command_buffer.pipelineBarrier(source.stage, dest.stage, command_buffer.pipelineBarrier(source.stage, dest.stage, vk::DependencyFlagBits::eByRegion, {},
vk::DependencyFlagBits::eByRegion, {}, barrier);
{}, {}, barrier);
alloc.layout = new_layout; alloc.layout = new_layout;
} }
@ -589,7 +552,8 @@ Surface::Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime)
scheduler{runtime.GetScheduler()}, traits{instance.GetTraits(pixel_format)} { scheduler{runtime.GetScheduler()}, traits{instance.GetTraits(pixel_format)} {
if (pixel_format != VideoCore::PixelFormat::Invalid) { if (pixel_format != VideoCore::PixelFormat::Invalid) {
alloc = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), params.pixel_format, texture_type); alloc = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), params.pixel_format,
texture_type);
} }
} }
@ -599,8 +563,7 @@ Surface::~Surface() {
.format = pixel_format, .format = pixel_format,
.width = GetScaledWidth(), .width = GetScaledWidth(),
.height = GetScaledHeight(), .height = GetScaledHeight(),
.layers = texture_type == VideoCore::TextureType::CubeMap ? 6u : 1u .layers = texture_type == VideoCore::TextureType::CubeMap ? 6u : 1u};
};
runtime.Recycle(tag, std::move(alloc)); runtime.Recycle(tag, std::move(alloc));
} }
@ -622,21 +585,18 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
.bufferOffset = staging.buffer_offset, .bufferOffset = staging.buffer_offset,
.bufferRowLength = rect.GetWidth(), .bufferRowLength = rect.GetWidth(),
.bufferImageHeight = rect.GetHeight(), .bufferImageHeight = rect.GetHeight(),
.imageSubresource = { .imageSubresource = {.aspectMask = alloc.aspect,
.aspectMask = alloc.aspect,
.mipLevel = upload.texture_level, .mipLevel = upload.texture_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1 .layerCount = 1},
},
.imageOffset = {static_cast<s32>(rect.left), static_cast<s32>(rect.bottom), 0}, .imageOffset = {static_cast<s32>(rect.left), static_cast<s32>(rect.bottom), 0},
.imageExtent = {rect.GetWidth(), rect.GetHeight(), 1} .imageExtent = {rect.GetWidth(), rect.GetHeight(), 1}};
};
runtime.Transition(command_buffer, alloc, vk::ImageLayout::eTransferDstOptimal, 0, alloc.levels, runtime.Transition(command_buffer, alloc, vk::ImageLayout::eTransferDstOptimal, 0,
0, texture_type == VideoCore::TextureType::CubeMap ? 6 : 1); alloc.levels, 0,
texture_type == VideoCore::TextureType::CubeMap ? 6 : 1);
command_buffer.copyBufferToImage(staging.buffer, alloc.image, command_buffer.copyBufferToImage(staging.buffer, alloc.image,
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferDstOptimal, copy_region);
copy_region);
} }
InvalidateAllWatcher(); InvalidateAllWatcher();
@ -665,15 +625,12 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
.bufferOffset = staging.buffer_offset + download.buffer_offset, .bufferOffset = staging.buffer_offset + download.buffer_offset,
.bufferRowLength = rect.GetWidth(), .bufferRowLength = rect.GetWidth(),
.bufferImageHeight = rect.GetHeight(), .bufferImageHeight = rect.GetHeight(),
.imageSubresource = { .imageSubresource = {.aspectMask = alloc.aspect,
.aspectMask = alloc.aspect,
.mipLevel = download.texture_level, .mipLevel = download.texture_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1 .layerCount = 1},
},
.imageOffset = {static_cast<s32>(rect.left), static_cast<s32>(rect.bottom), 0}, .imageOffset = {static_cast<s32>(rect.left), static_cast<s32>(rect.bottom), 0},
.imageExtent = {rect.GetWidth(), rect.GetHeight(), 1} .imageExtent = {rect.GetWidth(), rect.GetHeight(), 1}};
};
if (alloc.aspect & vk::ImageAspectFlagBits::eColor) { if (alloc.aspect & vk::ImageAspectFlagBits::eColor) {
copy_regions[region_count++] = copy_region; copy_regions[region_count++] = copy_region;
@ -688,7 +645,8 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
} }
} }
runtime.Transition(command_buffer, alloc, vk::ImageLayout::eTransferSrcOptimal, 0, alloc.levels); runtime.Transition(command_buffer, alloc, vk::ImageLayout::eTransferSrcOptimal, 0,
alloc.levels);
// Copy pixel data to the staging buffer // Copy pixel data to the staging buffer
command_buffer.copyImageToBuffer(alloc.image, vk::ImageLayout::eTransferSrcOptimal, command_buffer.copyImageToBuffer(alloc.image, vk::ImageLayout::eTransferSrcOptimal,
@ -703,8 +661,7 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
bool Surface::NeedsConvert() const { bool Surface::NeedsConvert() const {
// RGBA8 needs a byteswap since R8G8B8A8UnormPack32 does not exist // RGBA8 needs a byteswap since R8G8B8A8UnormPack32 does not exist
// D24S8 always needs an interleave pass even if natively supported // D24S8 always needs an interleave pass even if natively supported
return alloc.format != traits.native || return alloc.format != traits.native || pixel_format == VideoCore::PixelFormat::RGBA8 ||
pixel_format == VideoCore::PixelFormat::RGBA8 ||
pixel_format == VideoCore::PixelFormat::D24S8; pixel_format == VideoCore::PixelFormat::D24S8;
} }
@ -720,7 +677,8 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download) {
const ImageAlloc unscaled_tex = runtime.Allocate(rect_width, rect_height, pixel_format, const ImageAlloc unscaled_tex = runtime.Allocate(rect_width, rect_height, pixel_format,
VideoCore::TextureType::Texture2D); VideoCore::TextureType::Texture2D);
runtime.BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0, GL_TEXTURE_2D, type, unscaled_tex); runtime.BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0, GL_TEXTURE_2D, type, unscaled_tex);
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type, texture); runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type,
texture);
// Blit the scaled rectangle to the unscaled texture // Blit the scaled rectangle to the unscaled texture
const VideoCore::Rect2D scaled_rect = download.texture_rect * res_scale; const VideoCore::Rect2D scaled_rect = download.texture_rect * res_scale;
@ -759,7 +717,8 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload) {
const auto& filterer = runtime.GetFilterer(); const auto& filterer = runtime.GetFilterer();
if (!filterer.Filter(unscaled_tex, unscaled_rect, texture, scaled_rect, type)) { if (!filterer.Filter(unscaled_tex, unscaled_rect, texture, scaled_rect, type)) {
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, 0, GL_TEXTURE_2D, type, unscaled_tex); runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, 0, GL_TEXTURE_2D, type, unscaled_tex);
runtime.BindFramebuffer(GL_DRAW_FRAMEBUFFER, upload.texture_level, GL_TEXTURE_2D, type, texture); runtime.BindFramebuffer(GL_DRAW_FRAMEBUFFER, upload.texture_level, GL_TEXTURE_2D, type,
texture);
// If filtering fails, resort to normal blitting // If filtering fails, resort to normal blitting
glBlitFramebuffer(0, 0, rect_width, rect_height, glBlitFramebuffer(0, 0, rect_width, rect_height,

View File

@ -3,14 +3,14 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <span>
#include <set> #include <set>
#include <span>
#include <vulkan/vulkan_hash.hpp> #include <vulkan/vulkan_hash.hpp>
#include "video_core/rasterizer_cache/rasterizer_cache.h" #include "video_core/rasterizer_cache/rasterizer_cache.h"
#include "video_core/rasterizer_cache/surface_base.h" #include "video_core/rasterizer_cache/surface_base.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/vk_format_reinterpreter.h" #include "video_core/renderer_vulkan/vk_format_reinterpreter.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/vk_task_scheduler.h" #include "video_core/renderer_vulkan/vk_task_scheduler.h"
namespace Vulkan { namespace Vulkan {
@ -47,6 +47,7 @@ class Surface;
*/ */
class TextureRuntime { class TextureRuntime {
friend class Surface; friend class Surface;
public: public:
TextureRuntime(const Instance& instance, TaskScheduler& scheduler, TextureRuntime(const Instance& instance, TaskScheduler& scheduler,
RenderpassCache& renderpass_cache); RenderpassCache& renderpass_cache);
@ -66,13 +67,12 @@ public:
void Recycle(const VideoCore::HostTextureTag tag, ImageAlloc&& alloc); void Recycle(const VideoCore::HostTextureTag tag, ImageAlloc&& alloc);
/// Performs required format convertions on the staging data /// Performs required format convertions on the staging data
void FormatConvert(const Surface& surface, bool upload, void FormatConvert(const Surface& surface, bool upload, std::span<std::byte> source,
std::span<std::byte> source, std::span<std::byte> dest); std::span<std::byte> dest);
/// Transitions the mip level range of the surface to new_layout /// Transitions the mip level range of the surface to new_layout
void Transition(vk::CommandBuffer command_buffer, ImageAlloc& alloc, void Transition(vk::CommandBuffer command_buffer, ImageAlloc& alloc, vk::ImageLayout new_layout,
vk::ImageLayout new_layout, u32 level, u32 level_count, u32 level, u32 level_count, u32 layer = 0, u32 layer_count = 1);
u32 layer = 0, u32 layer_count = 1);
/// Fills the rectangle of the texture with the clear value provided /// Fills the rectangle of the texture with the clear value provided
bool ClearTexture(Surface& surface, const VideoCore::TextureClear& clear, bool ClearTexture(Surface& surface, const VideoCore::TextureClear& clear,
@ -120,6 +120,7 @@ private:
class Surface : public VideoCore::SurfaceBase<Surface> { class Surface : public VideoCore::SurfaceBase<Surface> {
friend class TextureRuntime; friend class TextureRuntime;
friend class RasterizerVulkan; friend class RasterizerVulkan;
public: public:
Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime); Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime);
~Surface() override; ~Surface() override;

View File

@ -5,8 +5,8 @@
#pragma once #pragma once
#include <optional> #include <optional>
#include <unordered_map>
#include <tuple> #include <tuple>
#include <unordered_map>
#include "video_core/shader/shader.h" #include "video_core/shader/shader.h"
namespace Pica::Shader { namespace Pica::Shader {
@ -52,14 +52,16 @@ public:
* different config values from the same shader program. * different config values from the same shader program.
*/ */
template <typename KeyType, typename ShaderType, auto ModuleCompiler, template <typename KeyType, typename ShaderType, auto ModuleCompiler,
std::optional<std::string>(*CodeGenerator)(const Pica::Shader::ShaderSetup&, const KeyType&)> std::optional<std::string> (*CodeGenerator)(const Pica::Shader::ShaderSetup&,
const KeyType&)>
class ShaderDoubleCache { class ShaderDoubleCache {
public: public:
ShaderDoubleCache() = default; ShaderDoubleCache() = default;
~ShaderDoubleCache() = default; ~ShaderDoubleCache() = default;
template <typename... Args> template <typename... Args>
auto Get(const KeyType& key, const Pica::Shader::ShaderSetup& setup, Args&&... args) -> ShaderCacheResult<ShaderType> { auto Get(const KeyType& key, const Pica::Shader::ShaderSetup& setup, Args&&... args)
-> ShaderCacheResult<ShaderType> {
if (auto map_iter = shader_map.find(key); map_iter == shader_map.end()) { if (auto map_iter = shader_map.find(key); map_iter == shader_map.end()) {
auto code = CodeGenerator(setup, key); auto code = CodeGenerator(setup, key);
if (!code) { if (!code) {

View File

@ -8,7 +8,8 @@
namespace Pica::Shader { namespace Pica::Shader {
void PicaUniformsData::SetFromRegs(const Pica::ShaderRegs& regs, const Pica::Shader::ShaderSetup& setup) { void PicaUniformsData::SetFromRegs(const Pica::ShaderRegs& regs,
const Pica::Shader::ShaderSetup& setup) {
std::transform(std::begin(setup.uniforms.b), std::end(setup.uniforms.b), std::begin(bools), std::transform(std::begin(setup.uniforms.b), std::end(setup.uniforms.b), std::begin(bools),
[](bool value) -> BoolAligned { return {value ? 1 : 0}; }); [](bool value) -> BoolAligned { return {value ? 1 : 0}; });
std::transform(std::begin(regs.int_uniforms), std::end(regs.int_uniforms), std::begin(i), std::transform(std::begin(regs.int_uniforms), std::end(regs.int_uniforms), std::begin(i),

View File

@ -95,5 +95,4 @@ static_assert(sizeof(VSUniformData) == 1856,
static_assert(sizeof(VSUniformData) < 16384, static_assert(sizeof(VSUniformData) < 16384,
"VSUniformData structure must be less than 16kb as per the OpenGL spec"); "VSUniformData structure must be less than 16kb as per the OpenGL spec");
} // namespace Pica::Shader } // namespace Pica::Shader

View File

@ -71,7 +71,6 @@ void ConvertBGRToRGB(std::span<const std::byte> source, std::span<std::byte> des
*/ */
void ConvertBGRToRGBA(std::span<const std::byte> source, std::span<std::byte> dest); void ConvertBGRToRGBA(std::span<const std::byte> source, std::span<std::byte> dest);
/** /**
* Converts pixel data encoded in ABGR format to RGBA * Converts pixel data encoded in ABGR format to RGBA
* *

View File

@ -47,11 +47,7 @@ extern Layout::FramebufferLayout g_screenshot_framebuffer_layout;
extern Memory::MemorySystem* g_memory; extern Memory::MemorySystem* g_memory;
enum class ResultStatus { enum class ResultStatus { Success, ErrorRendererInit, ErrorGenericDrivers };
Success,
ErrorRendererInit,
ErrorGenericDrivers
};
/// Initialize the video core /// Initialize the video core
ResultStatus Init(Frontend::EmuWindow& emu_window, Memory::MemorySystem& memory); ResultStatus Init(Frontend::EmuWindow& emu_window, Memory::MemorySystem& memory);

View File

@ -3,8 +3,8 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <system_error> #include <system_error>
#include "common/logging/log.h"
#include <jwt/jwt.hpp> #include <jwt/jwt.hpp>
#include "common/logging/log.h"
#include "common/web_result.h" #include "common/web_result.h"
#include "web_service/verify_user_jwt.h" #include "web_service/verify_user_jwt.h"
#include "web_service/web_backend.h" #include "web_service/web_backend.h"