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 <thread>
// 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/emu_window/emu_window_sdl2.h"
#include "citra/lodepng_image_interface.h"
@ -17,6 +16,7 @@
#include "common/file_util.h"
#include "common/logging/backend.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/scope_exit.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->system_camera,
qOverload<int>(&QComboBox::currentIndexChanged), this,
connect(ui->system_camera, qOverload<int>(&QComboBox::currentIndexChanged), this,
[this] { StopPreviewing(); });
connect(ui->camera_flip, qOverload<int>(&QComboBox::currentIndexChanged), this,
[this] { StopPreviewing(); });
connect(ui->camera_flip, qOverload<int>(&QComboBox::currentIndexChanged),
this, [this] { StopPreviewing(); });
}
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_disk_shader_cache = ui->toggle_disk_shader_cache->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());
}

View File

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

View File

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

View File

@ -407,7 +407,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
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_layout = new QVBoxLayout;
@ -514,7 +515,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
int num_attributes = shader_config.max_input_attribute_index + 1;
for (auto pattern : shader_setup.swizzle_data) {
const nihstro::SwizzleInfo swizzle_info = { .pattern = nihstro::SwizzlePattern{pattern} };
const nihstro::SwizzleInfo swizzle_info = {.pattern = nihstro::SwizzlePattern{pattern}};
info.swizzle_info.push_back(swizzle_info);
}

View File

@ -160,7 +160,8 @@ void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* 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();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -63,7 +63,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index) {
return inst_base;
}
static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) {
static ARM_INST_PTR INTERPRETER_TRANSLATE (and)(unsigned int inst, int index) {
arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst));
and_inst* inst_cream = (and_inst*)inst_base->component;

View File

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

View File

@ -26,47 +26,66 @@ struct AppletTitleData {
static constexpr std::size_t NumApplets = 29;
static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{
{{AppletId::HomeMenu, AppletId::None}, {0x4003000008202, 0x4003000008F02, 0x4003000009802,
0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102}},
{{AppletId::AlternateMenu, AppletId::None}, {0x4003000008102, 0x4003000008102, 0x4003000008102,
0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102}},
{{AppletId::Camera, AppletId::None}, {0x4003000008402, 0x4003000009002, 0x4003000009902,
0x4003000008402, 0x400300000A202, 0x400300000AA02, 0x400300000B202}},
{{AppletId::FriendList, AppletId::None}, {0x4003000008D02, 0x4003000009602, 0x4003000009F02,
0x4003000008D02, 0x400300000A702, 0x400300000AF02, 0x400300000B702}},
{{AppletId::GameNotes, AppletId::None}, {0x4003000008702, 0x4003000009302, 0x4003000009C02,
0x4003000008702, 0x400300000A502, 0x400300000AD02, 0x400300000B502}},
{{AppletId::InternetBrowser, AppletId::None}, {0x4003000008802, 0x4003000009402, 0x4003000009D02,
0x4003000008802, 0x400300000A602, 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}},
{{AppletId::HomeMenu, AppletId::None},
{0x4003000008202, 0x4003000008F02, 0x4003000009802, 0x4003000008202, 0x400300000A102,
0x400300000A902, 0x400300000B102}},
{{AppletId::AlternateMenu, AppletId::None},
{0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102,
0x4003000008102, 0x4003000008102}},
{{AppletId::Camera, AppletId::None},
{0x4003000008402, 0x4003000009002, 0x4003000009902, 0x4003000008402, 0x400300000A202,
0x400300000AA02, 0x400300000B202}},
{{AppletId::FriendList, AppletId::None},
{0x4003000008D02, 0x4003000009602, 0x4003000009F02, 0x4003000008D02, 0x400300000A702,
0x400300000AF02, 0x400300000B702}},
{{AppletId::GameNotes, AppletId::None},
{0x4003000008702, 0x4003000009302, 0x4003000009C02, 0x4003000008702, 0x400300000A502,
0x400300000AD02, 0x400300000B502}},
{{AppletId::InternetBrowser, AppletId::None},
{0x4003000008802, 0x4003000009402, 0x4003000009D02, 0x4003000008802, 0x400300000A602,
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
{{AppletId::MiiversePost, AppletId::None}, {0x400300000BA02, 0x400300000BA02, 0x400300000BA02,
0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02}},
{{AppletId::MiiversePost, AppletId::None},
{0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02,
0x400300000BA02, 0x400300000BA02}},
// {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02,
// 0x4003000008302, 0x0, 0x0, 0x0},
{{AppletId::AmiiboSettings, AppletId::None}, {0x4003000009502, 0x4003000009E02, 0x400300000B902,
0x4003000009502, 0x0, 0x4003000008C02, 0x400300000BF02}},
{{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2}, {0x400300000C002, 0x400300000C802,
0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402}},
{{AppletId::Ed1, AppletId::Ed2}, {0x400300000C102, 0x400300000C902, 0x400300000D102,
0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502}},
{{AppletId::PnoteApp, AppletId::PnoteApp2}, {0x400300000C302, 0x400300000CB02, 0x400300000D302,
0x400300000C302, 0x400300000DB02, 0x400300000E102, 0x400300000E702}},
{{AppletId::SnoteApp, AppletId::SnoteApp2}, {0x400300000C402, 0x400300000CC02, 0x400300000D402,
0x400300000C402, 0x400300000DC02, 0x400300000E202, 0x400300000E802}},
{{AppletId::Error, AppletId::Error2}, {0x400300000C502, 0x400300000C502, 0x400300000C502,
0x400300000C502, 0x400300000CF02, 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}},
{{AppletId::AmiiboSettings, AppletId::None},
{0x4003000009502, 0x4003000009E02, 0x400300000B902, 0x4003000009502, 0x0, 0x4003000008C02,
0x400300000BF02}},
{{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2},
{0x400300000C002, 0x400300000C802, 0x400300000D002, 0x400300000C002, 0x400300000D802,
0x400300000DE02, 0x400300000E402}},
{{AppletId::Ed1, AppletId::Ed2},
{0x400300000C102, 0x400300000C902, 0x400300000D102, 0x400300000C102, 0x400300000D902,
0x400300000DF02, 0x400300000E502}},
{{AppletId::PnoteApp, AppletId::PnoteApp2},
{0x400300000C302, 0x400300000CB02, 0x400300000D302, 0x400300000C302, 0x400300000DB02,
0x400300000E102, 0x400300000E702}},
{{AppletId::SnoteApp, AppletId::SnoteApp2},
{0x400300000C402, 0x400300000CC02, 0x400300000D402, 0x400300000C402, 0x400300000DC02,
0x400300000E202, 0x400300000E802}},
{{AppletId::Error, AppletId::Error2},
{0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000CF02,
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
}};

View File

@ -111,7 +111,8 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
codeset->RODataSegment().offset + codeset->RODataSegment().size;
codeset->DataSegment().addr = overlay_ncch->exheader_header.codeset_info.data.address;
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;
// 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,
PageType type) {
LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), base * CITRA_PAGE_SIZE,
(base + size) * CITRA_PAGE_SIZE);
LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(),
base * CITRA_PAGE_SIZE, (base + size) * CITRA_PAGE_SIZE);
RasterizerFlushVirtualRegion(base << CITRA_PAGE_BITS, size * CITRA_PAGE_SIZE,
FlushMode::FlushAndInvalidate);
@ -256,7 +256,8 @@ void MemorySystem::MapIoRegion(PageTable& page_table, VAddr base, u32 size,
MMIORegionPointer mmio_handler) {
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);
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});
}
@ -264,7 +265,8 @@ void MemorySystem::MapIoRegion(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((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 {
@ -494,8 +496,7 @@ MemoryRef MemorySystem::GetPhysicalRef(PAddr address) const {
std::make_pair(N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE),
};
const auto area =
std::ranges::find_if(memory_areas, [&](const auto& area) {
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
// represents an open right bound
return address >= area.first && address <= area.first + area.second;

View File

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

View File

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

View File

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

View File

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

View File

@ -3,9 +3,9 @@
// Refer to the license.txt file included.
#pragma once
#include <span>
#include <bit>
#include <algorithm>
#include <bit>
#include <span>
#include "common/alignment.h"
#include "common/color.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>
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 linear_bytes_per_pixel = GetBytesPerPixel(format);
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 x = 0; x < 8; x++) {
const auto tiled_pixel = tile_buffer.subspan(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,
linear_bytes_per_pixel);
const auto tiled_pixel = tile_buffer.subspan(
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, linear_bytes_per_pixel);
if constexpr (morton_to_linear) {
if constexpr (is_compressed) {
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
* @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 linear_buffer The linear 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
* linear and morton tiled layouts. The function handles both convertions but there are slightly different
* paths and inputs for each:
* The MortonCopy is at the heart of the PICA texture implementation, as it's responsible for
* converting between linear and morton tiled layouts. The function handles both convertions but
* there are slightly different paths and inputs for each:
*
* Morton to Linear:
* During uploads, tiled_buffer is always aligned to the tile or scanline boundary depending if the linear rectangle
* spans multiple vertical tiles. linear_buffer does not reference the entire texture area, but rather the
* specific rectangle affected by the upload.
* During uploads, tiled_buffer is always aligned to the tile or scanline boundary depending if the
* linear rectangle spans multiple vertical tiles. linear_buffer does not reference the entire
* texture area, but rather the specific rectangle affected by the upload.
*
* Linear to Morton:
* This is similar to the other convertion but with some differences. In this case tiled_buffer is not required
* to be aligned to any specific boundary which requires special care. start_offset/end_offset are useful
* here as they tell us exactly where the data should be placed in the linear_buffer.
* This is similar to the other convertion but with some differences. In this case tiled_buffer is
* not required to be aligned to any specific boundary which requires special care.
* 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>
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_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
// 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;
auto linear_data = linear_buffer.subspan(linear_offset, linear_tile_stride);
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 {
MICROPROFILE_DEFINE(RasterizerCache_BlitSurface, "RasterizerCache", "BlitSurface", MP_RGB(128, 192, 64));
MICROPROFILE_DEFINE(RasterizerCache_CopySurface, "RasterizerCache", "CopySurface", 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));
MICROPROFILE_DEFINE(RasterizerCache_BlitSurface, "RasterizerCache", "BlitSurface",
MP_RGB(128, 192, 64));
MICROPROFILE_DEFINE(RasterizerCache_CopySurface, "RasterizerCache", "CopySurface",
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

View File

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

View File

@ -46,6 +46,7 @@ public:
template <class S>
class SurfaceBase : public SurfaceParams, public std::enable_shared_from_this<S> {
using Watcher = SurfaceWatcher<S>;
public:
SurfaceBase(SurfaceParams& params) : SurfaceParams{params} {}
virtual ~SurfaceBase() = default;
@ -53,7 +54,8 @@ public:
/// 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;
/// 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;
/// Returns the region of the biggest valid rectange within interval
@ -93,7 +95,8 @@ public:
};
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) &&
boost::icl::first(fill_interval) >= addr &&
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 result{};
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) {
const SurfaceInterval aligned_interval{
params.addr + 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)
};
params.addr +
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) ||
boost::icl::length(aligned_interval) == 0) {
@ -155,8 +160,10 @@ SurfaceInterval SurfaceBase<S>::GetCopyableInterval(const SurfaceParams& params)
// Get the rectangle within aligned_interval
const u32 stride_bytes = params.BytesInPixels(params.stride) * (params.is_tiled ? 8 : 1);
SurfaceInterval rect_interval{
params.addr + 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),
params.addr +
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)) {

View File

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

View File

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

View File

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

View File

@ -7,13 +7,7 @@
namespace OpenGL {
enum class Vendor {
Unknown = 0,
AMD = 1,
Nvidia = 2,
Intel = 3,
Generic = 4
};
enum class Vendor { Unknown = 0, AMD = 1, Nvidia = 2, Intel = 3, Generic = 4 };
enum class DriverBug {
// 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) {
temp_tex.Create();
glActiveTexture(GL_TEXTURE1);
glTextureView(temp_tex.handle, GL_TEXTURE_2D, source.texture.handle, GL_DEPTH24_STENCIL8, 0, 1,
0, 1);
glTextureView(temp_tex.handle, GL_TEXTURE_2D, source.texture.handle, GL_DEPTH24_STENCIL8, 0,
1, 0, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} else {
@ -70,8 +70,8 @@ void D24S8toRGBA8::Reinterpret(const Surface& source, VideoCore::Rect2D src_rect
glActiveTexture(GL_TEXTURE1);
if (!use_texture_view) {
glCopyImageSubData(source.texture.handle, GL_TEXTURE_2D, 0, src_rect.left, src_rect.bottom, 0,
temp_tex.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,
0, temp_tex.handle, GL_TEXTURE_2D, 0, src_rect.left, src_rect.bottom, 0,
src_rect.GetWidth(), src_rect.GetHeight(), 1);
}
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,
dest.texture.handle, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
glUniform2i(dst_size_loc, dst_rect.GetWidth(), dst_rect.GetHeight());
glUniform2i(src_size_loc, src_rect.GetWidth(), src_rect.GetHeight());

View File

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

View File

@ -39,8 +39,8 @@ static bool IsVendorIntel() {
#endif
RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window, Driver& driver)
: driver{driver}, runtime{driver}, res_cache{*this, runtime},
is_amd(IsVendorAmd()), vertex_buffer(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE, is_amd),
: driver{driver}, runtime{driver}, res_cache{*this, runtime}, is_amd(IsVendorAmd()),
vertex_buffer(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE, is_amd),
uniform_buffer(GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE, false),
index_buffer(GL_ELEMENT_ARRAY_BUFFER, INDEX_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),
.nz = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ),
.width = texture.config.width,
.format = texture.format
};
.format = texture.format};
state.texture_cube_unit.texture_cube =
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.
OGLTexture temp_tex;
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);
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/regs_lighting.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_state.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"
namespace Frontend {

View File

@ -4,8 +4,8 @@
#pragma once
#include <utility>
#include <string_view>
#include <utility>
#include <vector>
#include <glad/glad.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)
#extension GL_EXT_clip_cull_distance : enable
#endif
)" : "#version 430 core\n";
)"
: "#version 430 core\n";
const char* debug_type;
switch (type) {

View File

@ -4,10 +4,10 @@
#include "common/scope_exit.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_format_reinterpreter.h"
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_texture_runtime.h"
namespace OpenGL {
@ -15,8 +15,7 @@ constexpr FormatTuple DEFAULT_TUPLE = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
static constexpr std::array DEPTH_TUPLES = {
FormatTuple{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16
FormatTuple{},
FormatTuple{GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}, // D24
FormatTuple{}, FormatTuple{GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}, // D24
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)
: driver{driver}, downloader_es{false},
filterer{Settings::values.texture_filter_name, VideoCore::GetResolutionScaleFactor()}{
: driver{driver}, downloader_es{false}, filterer{Settings::values.texture_filter_name,
VideoCore::GetResolutionScaleFactor()} {
read_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);
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
std::byte* data = nullptr;
if (driver.IsOpenGLES() && driver.HasExtBufferStorage()) {
const GLbitfield storage = upload ? GL_MAP_WRITE_BIT : GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT_EXT;
glBufferStorageEXT(target, size, nullptr, storage | GL_MAP_PERSISTENT_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));
const GLbitfield storage =
upload ? GL_MAP_WRITE_BIT : GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT_EXT;
glBufferStorageEXT(target, size, nullptr,
storage | GL_MAP_PERSISTENT_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()) {
const GLbitfield storage = upload ? GL_MAP_WRITE_BIT : GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT;
glBufferStorage(target, size, nullptr, storage | GL_MAP_PERSISTENT_BIT |
GL_MAP_COHERENT_BIT);
data = reinterpret_cast<std::byte*>(glMapBufferRange(target, 0, size, access | GL_MAP_PERSISTENT_BIT |
GL_MAP_COHERENT_BIT));
const GLbitfield storage =
upload ? GL_MAP_WRITE_BIT : GL_MAP_READ_BIT | GL_CLIENT_STORAGE_BIT;
glBufferStorage(target, size, nullptr,
storage | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
data = reinterpret_cast<std::byte*>(glMapBufferRange(
target, 0, size, access | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT));
} else {
UNIMPLEMENTED();
}
@ -108,10 +110,7 @@ const StagingBuffer& TextureRuntime::FindStaging(u32 size, bool upload) {
glBindBuffer(target, 0);
StagingBuffer staging = {
.buffer = std::move(buffer),
.mapped = std::span{data, size},
.size = size
};
.buffer = std::move(buffer), .mapped = std::span{data, size}, .size = size};
const auto& it = search.emplace(std::move(staging));
return *it;
@ -134,8 +133,8 @@ const FormatTuple& TextureRuntime::GetFormatTuple(VideoCore::PixelFormat pixel_f
return DEFAULT_TUPLE;
}
void TextureRuntime::FormatConvert(const Surface& surface, bool upload,
std::span<std::byte> source, std::span<std::byte> dest) {
void TextureRuntime::FormatConvert(const Surface& surface, bool upload, std::span<std::byte> source,
std::span<std::byte> dest) {
const VideoCore::PixelFormat format = surface.pixel_format;
if (format == VideoCore::PixelFormat::RGBA8 && driver.IsOpenGLES()) {
return Pica::Texture::ConvertABGRToRGBA(source, dest);
@ -153,11 +152,7 @@ OGLTexture TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
const GLenum target =
type == VideoCore::TextureType::CubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
const VideoCore::HostTextureTag key = {
.format = format,
.width = width,
.height = height,
.layers = layers
};
.format = format, .width = width, .height = height, .layers = layers};
// Attempt to recycle an unused texture
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);
glBindTexture(target, texture.handle);
glTexStorage2D(target, std::bit_width(std::max(width, height)),
tuple.internal_format, width, height);
glTexStorage2D(target, std::bit_width(std::max(width, height)), tuple.internal_format, width,
height);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -250,23 +245,22 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
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
const VideoCore::TextureBlit blit = {
.src_level = copy.src_level,
.dst_level = copy.dst_level,
.src_layer = copy.src_layer,
.dst_layer = copy.dst_layer,
.src_rect = {copy.src_offset.x, copy.extent.height,
copy.extent.width, copy.src_offset.x},
.dst_rect = {copy.dst_offset.x, copy.extent.height,
copy.extent.width, copy.dst_offset.x}
};
.src_rect = {copy.src_offset.x, copy.extent.height, copy.extent.width, copy.src_offset.x},
.dst_rect = {copy.dst_offset.x, copy.extent.height, copy.extent.width, copy.dst_offset.x}};
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();
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.Apply();
const GLenum src_textarget = source.texture_type == VideoCore::TextureType::CubeMap ?
GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.src_layer : GL_TEXTURE_2D;
BindFramebuffer(GL_READ_FRAMEBUFFER, blit.src_level, src_textarget, source.type, source.texture);
const GLenum src_textarget = source.texture_type == VideoCore::TextureType::CubeMap
? GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.src_layer
: 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 ?
GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.dst_layer : GL_TEXTURE_2D;
const GLenum dst_textarget = dest.texture_type == VideoCore::TextureType::CubeMap
? 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);
// TODO (wwylele): use GL_NEAREST for shadow map texture
@ -290,9 +287,9 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest, const VideoCor
// inconsistent scale.
const GLbitfield buffer_mask = MakeBufferMask(source.type);
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,
blit.dst_rect.left, blit.dst_rect.bottom, blit.dst_rect.right, blit.dst_rect.top,
buffer_mask, filter);
glBlitFramebuffer(blit.src_rect.left, blit.src_rect.bottom, blit.src_rect.right,
blit.src_rect.top, blit.dst_rect.left, blit.dst_rect.bottom,
blit.dst_rect.right, blit.dst_rect.top, buffer_mask, filter);
return true;
}
@ -310,7 +307,8 @@ void TextureRuntime::GenerateMipmaps(Surface& surface, u32 max_level) {
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)];
}
@ -332,7 +330,8 @@ void TextureRuntime::BindFramebuffer(GLenum target, GLint level, GLenum textarge
break;
case VideoCore::SurfaceType::DepthStencil:
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;
default:
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)
: VideoCore::SurfaceBase<Surface>{params}, runtime{runtime}, driver{runtime.GetDriver()} {
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,
.width = GetScaledWidth(),
.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));
}
@ -380,11 +379,9 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingBu
glBindTexture(GL_TEXTURE_2D, texture.handle);
const auto& tuple = runtime.GetFormatTuple(pixel_format);
glTexSubImage2D(GL_TEXTURE_2D, upload.texture_level,
upload.texture_rect.left, upload.texture_rect.bottom,
upload.texture_rect.GetWidth(),
upload.texture_rect.GetHeight(),
tuple.format, tuple.type, 0);
glTexSubImage2D(GL_TEXTURE_2D, upload.texture_level, upload.texture_rect.left,
upload.texture_rect.bottom, upload.texture_rect.GetWidth(),
upload.texture_rect.GetHeight(), tuple.format, tuple.type, 0);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
@ -412,7 +409,8 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
if (is_scaled) {
ScaledDownload(download);
} 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);
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();
// 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,
VideoCore::TextureType::Texture2D);
OGLTexture unscaled_tex =
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_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
const VideoCore::Rect2D scaled_rect = download.texture_rect * res_scale;
glBlitFramebuffer(scaled_rect.left, scaled_rect.bottom, scaled_rect.right, scaled_rect.top,
0, 0, rect_width, rect_height, MakeBufferMask(type), GL_LINEAR);
glBlitFramebuffer(scaled_rect.left, scaled_rect.bottom, scaled_rect.right, scaled_rect.top, 0,
0, rect_width, rect_height, MakeBufferMask(type), GL_LINEAR);
glActiveTexture(GL_TEXTURE0);
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);
if (driver.IsOpenGLES()) {
const auto& downloader_es = runtime.GetDownloaderES();
downloader_es.GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type,
rect_height, rect_width, 0);
downloader_es.GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, rect_height,
rect_width, 0);
} else {
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_height = upload.texture_rect.GetHeight();
OGLTexture unscaled_tex = runtime.Allocate(rect_width, rect_height, pixel_format,
VideoCore::TextureType::Texture2D);
OGLTexture unscaled_tex =
runtime.Allocate(rect_width, rect_height, pixel_format, VideoCore::TextureType::Texture2D);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, unscaled_tex.handle);
@ -470,13 +469,13 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload) {
const auto& filterer = runtime.GetFilterer();
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_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
glBlitFramebuffer(0, 0, rect_width, rect_height,
upload.texture_rect.left, upload.texture_rect.bottom,
upload.texture_rect.right, upload.texture_rect.top,
MakeBufferMask(type), GL_LINEAR);
glBlitFramebuffer(0, 0, rect_width, rect_height, upload.texture_rect.left,
upload.texture_rect.bottom, upload.texture_rect.right,
upload.texture_rect.top, MakeBufferMask(type), GL_LINEAR);
}
}

View File

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

View File

@ -7,8 +7,8 @@
#include <array>
#include "core/hw/gpu.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/gl_driver.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_state.h"

View File

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

View File

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

View File

@ -63,7 +63,8 @@ bool TextureFilterer::Filter(const OGLTexture& src_tex, Common::Rectangle<u32> s
VideoCore::SurfaceType type) const {
// 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;
}

View File

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

View File

@ -10,9 +10,9 @@
#include "common/math_util.h"
#include "core/hw/gpu.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_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
#include "video_core/renderer_vulkan/vk_texture_runtime.h"
namespace Layout {
@ -81,7 +81,8 @@ private:
void CompileShaders();
void BuildLayouts();
void BuildPipelines();
void ConfigureFramebufferTexture(TextureInfo& texture, const GPU::Regs::FramebufferConfig& framebuffer);
void ConfigureFramebufferTexture(TextureInfo& texture,
const GPU::Regs::FramebufferConfig& framebuffer);
void ConfigureRenderPipeline();
void PrepareRendertarget();
void BeginRendering();
@ -89,8 +90,10 @@ private:
void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped);
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 DrawSingleScreenStereoRotated(u32 screen_id_l, u32 screen_id_r, float x, float y, float w, float h);
void DrawSingleScreenStereo(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,
float h);
void DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, float x, float y, float w,
float h);
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
constexpr vk::ImageUsageFlags GetImageUsage(vk::ImageAspectFlags aspect) {
auto usage = vk::ImageUsageFlagBits::eSampled |
vk::ImageUsageFlagBits::eTransferDst |
auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst |
vk::ImageUsageFlagBits::eTransferSrc;
if (aspect & vk::ImageAspectFlagBits::eDepth) {
return usage | vk::ImageUsageFlagBits::eDepthStencilAttachment;
} else {
return usage | vk::ImageUsageFlagBits::eStorage |
vk::ImageUsageFlagBits::eColorAttachment;
return usage | vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eColorAttachment;
}
}
/// Returns a bit mask with the required features of a format with a particular aspect
constexpr vk::FormatFeatureFlags GetFormatFeatures(vk::ImageAspectFlags aspect) {
auto usage = vk::FormatFeatureFlagBits::eSampledImage |
vk::FormatFeatureFlagBits::eTransferDst |
vk::FormatFeatureFlagBits::eTransferSrc |
vk::FormatFeatureFlagBits::eBlitSrc |
vk::FormatFeatureFlagBits::eBlitDst;
vk::FormatFeatureFlagBits::eTransferDst | vk::FormatFeatureFlagBits::eTransferSrc |
vk::FormatFeatureFlagBits::eBlitSrc | vk::FormatFeatureFlagBits::eBlitDst;
if (aspect & vk::ImageAspectFlagBits::eDepth) {
return usage | vk::FormatFeatureFlagBits::eDepthStencilAttachment;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,16 +3,16 @@
// Refer to the license.txt file included.
// Include the vulkan platform specific header
#if defined(ANDROID) || defined (__ANDROID__)
#define VK_USE_PLATFORM_ANDROID_KHR
#if defined(ANDROID) || defined(__ANDROID__)
#define VK_USE_PLATFORM_ANDROID_KHR
#elif defined(_WIN32)
#define VK_USE_PLATFORM_WIN32_KHR
#define VK_USE_PLATFORM_WIN32_KHR
#elif defined(__APPLE__)
#define VK_USE_PLATFORM_MACOS_MVK
#define VK_USE_PLATFORM_METAL_EXT
#define VK_USE_PLATFORM_MACOS_MVK
#define VK_USE_PLATFORM_METAL_EXT
#else
#define VK_USE_PLATFORM_WAYLAND_KHR
#define VK_USE_PLATFORM_XLIB_KHR
#define VK_USE_PLATFORM_WAYLAND_KHR
#define VK_USE_PLATFORM_XLIB_KHR
#endif
#define VULKAN_HPP_NO_CONSTRUCTORS
@ -33,9 +33,7 @@ vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& e
#if defined(VK_USE_PLATFORM_WIN32_KHR)
if (window_info.type == Frontend::WindowSystemType::Windows) {
const vk::Win32SurfaceCreateInfoKHR win32_ci = {
.hinstance = nullptr,
.hwnd = static_cast<HWND>(window_info.render_surface)
};
.hinstance = nullptr, .hwnd = static_cast<HWND>(window_info.render_surface)};
if (instance.createWin32SurfaceKHR(&win32_ci, nullptr, &surface) != vk::Result::eSuccess) {
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) {
const vk::XlibSurfaceCreateInfoKHR xlib_ci = {
.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) {
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) {
const vk::WaylandSurfaceCreateInfoKHR wayland_ci = {
.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");
UNREACHABLE();
}
@ -75,7 +72,8 @@ vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& e
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();
if (properties.empty()) {
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");

View File

@ -11,11 +11,12 @@
namespace Frontend {
class EmuWindow;
enum class WindowSystemType : u8;
}
} // namespace Frontend
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);

View File

@ -12,8 +12,8 @@
#include "video_core/regs_rasterizer.h"
#include "video_core/renderer_vulkan/pica_to_vk.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_rasterizer.h"
#include "video_core/renderer_vulkan/vk_task_scheduler.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_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[1] = v.pos.y.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 TEXTURE_BUFFER_SIZE = 16 * 1024 * 1024;
constexpr std::array TEXTURE_BUFFER_LF_FORMATS = {
vk::Format::eR32G32Sfloat
};
constexpr std::array TEXTURE_BUFFER_LF_FORMATS = {vk::Format::eR32G32Sfloat};
constexpr std::array TEXTURE_BUFFER_FORMATS = {
vk::Format::eR32G32Sfloat,
vk::Format::eR32G32B32A32Sfloat
};
constexpr std::array TEXTURE_BUFFER_FORMATS = {vk::Format::eR32G32Sfloat,
vk::Format::eR32G32B32A32Sfloat};
RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instance& instance,
TaskScheduler& scheduler, TextureRuntime& runtime,
RenderpassCache& renderpass_cache)
: instance{instance}, scheduler{scheduler}, runtime{runtime}, renderpass_cache{renderpass_cache},
res_cache{*this, runtime}, pipeline_cache{instance, scheduler, renderpass_cache},
vertex_buffer{instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}},
uniform_buffer{instance, scheduler, UNIFORM_BUFFER_SIZE, vk::BufferUsageFlagBits::eUniformBuffer, {}},
index_buffer{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} {
: instance{instance}, scheduler{scheduler}, runtime{runtime},
renderpass_cache{renderpass_cache}, res_cache{*this, runtime},
pipeline_cache{instance, scheduler, renderpass_cache},
vertex_buffer{
instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}},
uniform_buffer{
instance, scheduler, UNIFORM_BUFFER_SIZE, vk::BufferUsageFlagBits::eUniformBuffer, {}},
index_buffer{
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,
default_texture = runtime.Allocate(1, 1, VideoCore::PixelFormat::RGBA8,
VideoCore::TextureType::Texture2D);
default_texture =
runtime.Allocate(1, 1, VideoCore::PixelFormat::RGBA8, VideoCore::TextureType::Texture2D);
runtime.Transition(scheduler.GetUploadCommandBuffer(), default_texture,
vk::ImageLayout::eShaderReadOnlyOptimal, 0, 1);
@ -142,8 +143,7 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window, const Instan
.min_filter = Pica::TexturingRegs::TextureConfig::TextureFilter::Linear,
.mip_filter = Pica::TexturingRegs::TextureConfig::TextureFilter::Linear,
.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);
@ -194,7 +194,7 @@ RasterizerVulkan::~RasterizerVulkan() {
void RasterizerVulkan::LoadDiskResources(const std::atomic_bool& stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) {
//shader_program_manager->LoadDiskCache(stop_loading, callback);
// shader_program_manager->LoadDiskCache(stop_loading, callback);
}
void RasterizerVulkan::SyncEntireState() {
@ -327,7 +327,8 @@ RasterizerVulkan::VertexArrayInfo RasterizerVulkan::AnalyzeVertexArray(bool is_i
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);
/**
@ -358,10 +359,12 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
u32 attribute_index = loader.GetComponent(comp);
if (attribute_index < 12) {
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 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];
// Define the attribute
@ -377,13 +380,15 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
}
} 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 += (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 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);
if (!enable_attributes[reg]) {
const auto& attr = Pica::g_state.input_default_attributes.attr[i];
const std::array data = {
attr.x.ToFloat32(),
attr.y.ToFloat32(),
attr.z.ToFloat32(),
attr.w.ToFloat32()
};
const std::array data = {attr.x.ToFloat32(), attr.y.ToFloat32(), attr.z.ToFloat32(),
attr.w.ToFloat32()};
// Copy the data to the end of the buffer
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
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() {
@ -596,8 +598,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
surfaces_rect.left, surfaces_rect.right)), // Right
static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) +
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) {
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
// 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_y1 = static_cast<int>(surfaces_rect.bottom + regs.rasterizer.scissor_test.y1 * res_scale);
int scissor_x1 =
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
// scaling or doing multisampling.
int scissor_x2 = 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);
int scissor_x2 =
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 ||
uniform_block_data.data.scissor_x2 != scissor_x2 ||
@ -626,10 +631,11 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
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) {
//auto temp_tex = backend->CreateTexture(texture->GetInfo());
//temp_tex->CopyFrom(texture);
// auto temp_tex = backend->CreateTexture(texture->GetInfo());
// temp_tex->CopyFrom(texture);
pipeline_cache.BindTexture(texture_index, image_view);
} else {
pipeline_cache.BindTexture(texture_index, image_view);
@ -651,15 +657,14 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
const auto BindSampler = [&](u32 binding, SamplerInfo& info,
const Pica::TexturingRegs::TextureConfig& config) {
// TODO(GPUCode): Cubemaps don't contain any mipmaps for now, so sampling from them returns 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
// GL_LINEAR/GL_NEAREST so emulate them by setting
// minLod = 0, and maxLod = 0.25, and using minFilter = VK_FILTER_LINEAR or minFilter = VK_FILTER_NEAREST
const bool skip_mipmap =
config.type == Pica::TexturingRegs::TextureConfig::TextureCube;
info = SamplerInfo{
.mag_filter = config.mag_filter,
// TODO(GPUCode): Cubemaps don't contain any mipmaps for now, so sampling from them returns
// 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 GL_LINEAR/GL_NEAREST so emulate them by setting minLod = 0, and maxLod = 0.25,
// and using minFilter = VK_FILTER_LINEAR or minFilter = VK_FILTER_NEAREST
const bool skip_mipmap = config.type == Pica::TexturingRegs::TextureConfig::TextureCube;
info =
SamplerInfo{.mag_filter = config.mag_filter,
.min_filter = config.min_filter,
.mip_filter = config.mip_filter,
.wrap_s = config.wrap_s,
@ -667,8 +672,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
.border_color = config.border_color.raw,
.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_bias = static_cast<float>(config.lod.bias)
};
.lod_bias = static_cast<float>(config.lod.bias)};
// Search the cache and bind the appropriate sampler
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),
.nz = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ),
.width = texture.config.width,
.format = texture.format
};
.format = texture.format};
auto surface = res_cache.GetTextureCube(config);
if (surface != nullptr) {
runtime.Transition(scheduler.GetRenderCommandBuffer(), surface->alloc,
vk::ImageLayout::eShaderReadOnlyOptimal,
0, surface->alloc.levels, 0, 6);
vk::ImageLayout::eShaderReadOnlyOptimal, 0,
surface->alloc.levels, 0, 6);
pipeline_cache.BindTexture(3, surface->alloc.image_view);
} else {
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);
if (surface != nullptr) {
runtime.Transition(scheduler.GetRenderCommandBuffer(), surface->alloc,
vk::ImageLayout::eShaderReadOnlyOptimal,
0, surface->alloc.levels);
vk::ImageLayout::eShaderReadOnlyOptimal, 0,
surface->alloc.levels);
CheckBarrier(surface->alloc.image_view, texture_index);
} else {
// Can occur when texture addr is null or its memory is unmapped/invalid
@ -760,7 +763,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
// the geometry in question.
// For example: a bug in Pokemon X/Y causes NULL-texture squares to be drawn
// on the male character's face, which in the OpenGL default appear black.
//state.texture_units[texture_index].texture_2d = default_texture;
// state.texture_units[texture_index].texture_2d = default_texture;
pipeline_cache.BindTexture(texture_index, default_texture.image_view);
}
} else {
@ -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
// issues as the rasterizer cache might cause a scheduler switch and invalidate our state
// NOTE: From here onwards its a safe zone to set the draw state, doing that any earlier will
// cause issues as the rasterizer cache might cause a scheduler switch and invalidate our state
// Sync the viewport
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.
// 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;
const FramebufferInfo framebuffer_info = {
@ -802,8 +806,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
.renderpass = renderpass_cache.GetRenderpass(pipeline_info.color_attachment,
pipeline_info.depth_attachment, false),
.width = valid_surface->GetScaledWidth(),
.height = valid_surface->GetScaledHeight()
};
.height = valid_surface->GetScaledHeight()};
auto [it, new_framebuffer] = framebuffers.try_emplace(framebuffer_info, vk::Framebuffer{});
if (new_framebuffer) {
@ -813,29 +816,26 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
if (color_surface) {
runtime.Transition(command_buffer, color_surface->alloc,
vk::ImageLayout::eColorAttachmentOptimal,
0, color_surface->alloc.levels);
vk::ImageLayout::eColorAttachmentOptimal, 0,
color_surface->alloc.levels);
}
if (depth_surface) {
runtime.Transition(command_buffer, depth_surface->alloc,
vk::ImageLayout::eDepthStencilAttachmentOptimal,
0, depth_surface->alloc.levels);
vk::ImageLayout::eDepthStencilAttachmentOptimal, 0,
depth_surface->alloc.levels);
}
const vk::RenderPassBeginInfo renderpass_begin = {
.renderPass =
renderpass_cache.GetRenderpass(pipeline_info.color_attachment,
.renderPass = renderpass_cache.GetRenderpass(pipeline_info.color_attachment,
pipeline_info.depth_attachment, false),
.framebuffer = it->second,
.renderArea = vk::Rect2D{
.offset = {static_cast<s32>(draw_rect.left), static_cast<s32>(draw_rect.bottom)},
.extent = {draw_rect.GetWidth(), draw_rect.GetHeight()}
},
.renderArea = vk::Rect2D{.offset = {static_cast<s32>(draw_rect.left),
static_cast<s32>(draw_rect.bottom)},
.extent = {draw_rect.GetWidth(), draw_rect.GetHeight()}},
.clearValueCount = 0,
.pClearValues = nullptr
};
.pClearValues = nullptr};
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
// offset not the start of the buffer.
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 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
const VideoCore::Rect2D draw_rect_unscaled = {
draw_rect.left / res_scale,
draw_rect.top / res_scale,
draw_rect.right / res_scale,
draw_rect.bottom / res_scale
};
draw_rect.left / res_scale, draw_rect.top / res_scale, draw_rect.right / res_scale,
draw_rect.bottom / res_scale};
if (color_surface != nullptr && write_color_fb) {
auto interval = color_surface->GetSubRectInterval(draw_rect_unscaled);
@ -1590,8 +1588,7 @@ vk::Sampler RasterizerVulkan::CreateSampler(const SamplerInfo& info) {
.minLod = info.lod_min,
.maxLod = info.lod_max,
.borderColor = vk::BorderColor::eIntOpaqueBlack,
.unnormalizedCoordinates = false
};
.unnormalizedCoordinates = false};
vk::Device device = instance.GetDevice();
return device.createSampler(sampler_info);
@ -1609,14 +1606,12 @@ vk::Framebuffer RasterizerVulkan::CreateFramebuffer(const FramebufferInfo& info)
attachments[attachment_count++] = info.depth;
}
const vk::FramebufferCreateInfo framebuffer_info = {
.renderPass = info.renderpass,
const vk::FramebufferCreateInfo framebuffer_info = {.renderPass = info.renderpass,
.attachmentCount = attachment_count,
.pAttachments = attachments.data(),
.width = info.width,
.height = info.height,
.layers = 1
};
.layers = 1};
vk::Device device = instance.GetDevice();
return device.createFramebuffer(framebuffer_info);
@ -1660,7 +1655,8 @@ void RasterizerVulkan::SyncCullMode() {
}
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) {
uniform_block_data.data.depth_scale = depth_scale;
@ -1669,7 +1665,8 @@ void RasterizerVulkan::SyncDepthScale() {
}
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) {
uniform_block_data.data.depth_offset = depth_offset;
@ -1678,18 +1675,25 @@ void RasterizerVulkan::SyncDepthOffset() {
}
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() {
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.alpha_blend_eq.Assign(regs.framebuffer.output_merger.alpha_blending.blend_equation_a);
pipeline_info.blending.src_color_blend_factor.Assign(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);
pipeline_info.blending.color_blend_eq.Assign(
regs.framebuffer.output_merger.alpha_blending.blend_equation_rgb);
pipeline_info.blending.alpha_blend_eq.Assign(
regs.framebuffer.output_merger.alpha_blending.blend_equation_a);
pipeline_info.blending.src_color_blend_factor.Assign(
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() {
@ -1764,7 +1768,8 @@ void RasterizerVulkan::SyncStencilWriteMask() {
: 0;
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() {
@ -1784,13 +1789,16 @@ void RasterizerVulkan::SyncDepthWriteMask() {
void RasterizerVulkan::SyncStencilTest() {
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;
const auto& stencil_test = regs.framebuffer.output_merger.stencil_test;
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack, stencil_test.input_mask);
command_buffer.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack, stencil_test.reference_value);
command_buffer.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack,
stencil_test.input_mask);
command_buffer.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
stencil_test.reference_value);
if (instance.IsExtendedDynamicStateSupported()) {
command_buffer.setStencilTestEnableEXT(test_enable);
@ -1830,7 +1838,8 @@ void RasterizerVulkan::SyncDepthTest() {
}
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) {
uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
uniform_block_data.dirty = true;
@ -1893,8 +1902,7 @@ void RasterizerVulkan::SyncLightPosition(int light_index) {
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].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) {
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) {
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();
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) {
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();
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));
// helper function for SyncProcTexNoiseLUT/ColorMap/AlphaMap
auto SyncProcTexValueLUT = [this, &buffer = buffer, &offset = offset, &invalidate = invalidate, &bytes_used](
const std::array<Pica::State::ProcTex::ValueEntry, 128>& lut,
auto SyncProcTexValueLUT =
[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> new_data;
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;
const u32 uniform_size = static_cast<u32>(uniform_size_aligned_vs + uniform_size_aligned_fs);
auto [uniforms, offset, invalidate] = uniform_buffer.Map(uniform_size,
static_cast<u32>(uniform_buffer_alignment));
auto [uniforms, offset, invalidate] =
uniform_buffer.Map(uniform_size, static_cast<u32>(uniform_buffer_alignment));
if (sync_vs) {
Pica::Shader::VSUniformData vs_uniforms;
vs_uniforms.uniforms.SetFromRegs(Pica::g_state.regs.vs, Pica::g_state.vs);
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);
}
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,
sizeof(uniform_block_data.data));

View File

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

View File

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

View File

@ -30,8 +30,8 @@ public:
void CreatePresentRenderpass(vk::Format format);
/// Returns the renderpass associated with the color-depth format pair
[[nodiscard]] vk::RenderPass GetRenderpass(VideoCore::PixelFormat color, VideoCore::PixelFormat depth,
bool is_clear) const;
[[nodiscard]] vk::RenderPass GetRenderpass(VideoCore::PixelFormat color,
VideoCore::PixelFormat depth, bool is_clear) const;
/// Returns the swapchain clear renderpass
[[nodiscard]] vk::RenderPass GetPresentRenderpass() const {
return present_renderpass;
@ -44,8 +44,9 @@ public:
private:
/// 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::ImageLayout initial_layout, vk::ImageLayout final_layout) const;
vk::RenderPass CreateRenderPass(vk::Format color, vk::Format depth,
vk::AttachmentLoadOp load_op, vk::ImageLayout initial_layout,
vk::ImageLayout final_layout) const;
private:
const Instance& instance;
@ -53,7 +54,7 @@ private:
vk::RenderPass active_renderpass = VK_NULL_HANDLE;
vk::RenderPass present_renderpass{};
vk::RenderPass cached_renderpasses[MAX_COLOR_FORMATS+1][MAX_DEPTH_FORMATS+1][2];
vk::RenderPass cached_renderpasses[MAX_COLOR_FORMATS + 1][MAX_DEPTH_FORMATS + 1][2];
};
} // namespace Vulkan

View File

@ -3,17 +3,16 @@
// Refer to the license.txt file included.
#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/logging/log.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 {
constexpr TBuiltInResource DefaultTBuiltInResource = {
.maxLights = 32,
constexpr TBuiltInResource DefaultTBuiltInResource = {.maxLights = 32,
.maxClipPlanes = 6,
.maxTextureUnits = 32,
.maxTextureCoords = 32,
@ -92,7 +91,8 @@ constexpr TBuiltInResource DefaultTBuiltInResource = {
.maxCombinedAtomicCounterBuffers = 1,
.maxAtomicCounterBufferSize = 16384,
.maxTransformFeedbackBuffers = 4,
.maxTransformFeedbackInterleavedComponents = 64,
.maxTransformFeedbackInterleavedComponents =
64,
.maxCullDistances = 8,
.maxCombinedClipAndCullDistances = 8,
.maxSamples = 4,
@ -116,8 +116,7 @@ constexpr TBuiltInResource DefaultTBuiltInResource = {
.generalSamplerIndexing = 1,
.generalVariableIndexing = 1,
.generalConstantMatrixVectorIndexing = 1,
}
};
}};
EShLanguage ToEshShaderStage(vk::ShaderStageFlagBits stage) {
switch (stage) {
@ -162,7 +161,8 @@ vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, v
}
EProfile profile = ECoreProfile;
EShMessages messages = static_cast<EShMessages>(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules);
EShMessages messages =
static_cast<EShMessages>(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules);
EShLanguage lang = ToEshShaderStage(stage);
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());
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);
glslang::TShader::ForbidIncluder includer;
if (!shader->parse(&DefaultTBuiltInResource, default_version, profile, false, true, messages, includer)) {
LOG_CRITICAL(Render_Vulkan, "Shader Info Log:\n{}\n{}", shader->getInfoLog(), shader->getInfoDebugLog());
if (!shader->parse(&DefaultTBuiltInResource, default_version, profile, false, true, messages,
includer)) {
LOG_CRITICAL(Render_Vulkan, "Shader Info Log:\n{}\n{}", shader->getInfoLog(),
shader->getInfoDebugLog());
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>();
program->addShader(shader.get());
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;
}
@ -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);
}
const vk::ShaderModuleCreateInfo shader_info = {
.codeSize = out_code.size() * sizeof(u32),
.pCode = out_code.data()
};
const vk::ShaderModuleCreateInfo shader_info = {.codeSize = out_code.size() * sizeof(u32),
.pCode = out_code.data()};
return device.createShaderModule(shader_info);
}

View File

@ -8,12 +8,9 @@
namespace Vulkan {
enum class ShaderOptimization {
High = 0,
Debug = 1
};
enum class ShaderOptimization { High = 0, Debug = 1 };
vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage,
vk::Device device, ShaderOptimization level);
vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, vk::Device device,
ShaderOptimization level);
} // 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
switch (state.texture0_type) {
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:
// TODO (wwylele): find the exact LOD formula for projection texture
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)";
}
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:
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
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:
if (state.proctex.enable) {
return "ProcTex()";
@ -1580,8 +1584,8 @@ void main() {
return out;
}
std::optional<std::string> GenerateVertexShader(
const Pica::Shader::ShaderSetup& setup, const PicaVSConfig& config) {
std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& setup,
const PicaVSConfig& config) {
/*std::string out = "#extension GL_ARB_separate_shader_objects : enable\n";
out += ShaderDecompiler::GetCommonDeclarations();
@ -1626,7 +1630,8 @@ layout (std140) uniform vs_config {
// output attributes declaration
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";
@ -1648,7 +1653,8 @@ static std::string GetGSCommonSource(const PicaGSConfigCommonRaw& config) {
out += '\n';
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"(

View File

@ -203,8 +203,8 @@ std::string GenerateTrivialVertexShader();
* Generates the GLSL vertex shader program source code for the given VS program
* @returns String of the shader source code; boost::none on failure
*/
std::optional<std::string> GenerateVertexShader(
const Pica::Shader::ShaderSetup& setup, const PicaVSConfig& config);
std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& setup,
const PicaVSConfig& config);
/**
* 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/assert.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_task_scheduler.h"
#include "video_core/renderer_vulkan/vk_instance.h"
namespace Vulkan {
@ -21,8 +21,8 @@ inline auto ToVkAccessStageFlags(vk::BufferUsageFlagBits usage) {
vk::PipelineStageFlagBits::eVertexInput);
break;
case vk::BufferUsageFlagBits::eIndexBuffer:
result = std::make_pair(vk::AccessFlagBits::eIndexRead,
vk::PipelineStageFlagBits::eVertexInput);
result =
std::make_pair(vk::AccessFlagBits::eIndexRead, vk::PipelineStageFlagBits::eVertexInput);
case vk::BufferUsageFlagBits::eUniformBuffer:
result = std::make_pair(vk::AccessFlagBits::eUniformRead,
vk::PipelineStageFlagBits::eVertexShader |
@ -41,24 +41,20 @@ inline auto ToVkAccessStageFlags(vk::BufferUsageFlagBits usage) {
StagingBuffer::StagingBuffer(const Instance& instance, u32 size, vk::BufferUsageFlags usage)
: instance{instance} {
const vk::BufferCreateInfo buffer_info = {
.size = size,
.usage = usage
};
const vk::BufferCreateInfo buffer_info = {.size = size, .usage = usage};
const VmaAllocationCreateInfo alloc_create_info = {
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_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;
VkBufferCreateInfo unsafe_buffer_info = static_cast<VkBufferCreateInfo>(buffer_info);
VmaAllocationInfo alloc_info;
VmaAllocator allocator = instance.GetAllocator();
vmaCreateBuffer(allocator, &unsafe_buffer_info, &alloc_create_info,
&unsafe_buffer, &allocation, &alloc_info);
vmaCreateBuffer(allocator, &unsafe_buffer_info, &alloc_create_info, &unsafe_buffer, &allocation,
&alloc_info);
buffer = vk::Buffer{unsafe_buffer};
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);
}
StreamBuffer::StreamBuffer(const Instance& instance, TaskScheduler& scheduler,
u32 size, vk::BufferUsageFlagBits usage, std::span<const vk::Format> view_formats)
: instance{instance}, scheduler{scheduler}, staging{instance, size, vk::BufferUsageFlagBits::eTransferSrc},
StreamBuffer::StreamBuffer(const Instance& instance, TaskScheduler& scheduler, u32 size,
vk::BufferUsageFlagBits usage, std::span<const vk::Format> view_formats)
: instance{instance}, scheduler{scheduler}, staging{instance, size,
vk::BufferUsageFlagBits::eTransferSrc},
usage{usage}, total_size{size} {
const vk::BufferCreateInfo buffer_info = {
.size = total_size,
.usage = usage | vk::BufferUsageFlagBits::eTransferDst
};
.size = total_size, .usage = usage | vk::BufferUsageFlagBits::eTransferDst};
const VmaAllocationCreateInfo alloc_create_info = {
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE
};
const VmaAllocationCreateInfo alloc_create_info = {.usage =
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE};
VkBuffer unsafe_buffer = VK_NULL_HANDLE;
VkBufferCreateInfo unsafe_buffer_info = static_cast<VkBufferCreateInfo>(buffer_info);
VmaAllocationInfo alloc_info;
VmaAllocator allocator = instance.GetAllocator();
vmaCreateBuffer(allocator, &unsafe_buffer_info, &alloc_create_info,
&unsafe_buffer, &allocation, &alloc_info);
vmaCreateBuffer(allocator, &unsafe_buffer_info, &alloc_create_info, &unsafe_buffer, &allocation,
&alloc_info);
buffer = vk::Buffer{unsafe_buffer};
@ -97,11 +91,7 @@ StreamBuffer::StreamBuffer(const Instance& instance, TaskScheduler& scheduler,
vk::Device device = instance.GetDevice();
for (std::size_t i = 0; i < view_formats.size(); i++) {
const vk::BufferViewCreateInfo view_info = {
.buffer = buffer,
.format = view_formats[i],
.offset = 0,
.range = total_size
};
.buffer = buffer, .format = view_formats[i], .offset = 0, .range = total_size};
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;
u8* mapped = reinterpret_cast<u8*>(staging.mapped.data() + buffer_offset);
return std::make_tuple(mapped, buffer_offset, invalidate);
}
void StreamBuffer::Commit(u32 size) {
@ -156,10 +145,7 @@ void StreamBuffer::Flush() {
const u32 flush_start = current_bucket * bucket_size;
const vk::BufferCopy copy_region = {
.srcOffset = flush_start,
.dstOffset = flush_start,
.size = flush_size
};
.srcOffset = flush_start, .dstOffset = flush_start, .size = flush_size};
vmaFlushAllocation(allocator, allocation, flush_start, flush_size);
command_buffer.copyBuffer(staging.buffer, buffer, copy_region);
@ -173,8 +159,7 @@ void StreamBuffer::Flush() {
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = buffer,
.offset = flush_start,
.size = flush_size
};
.size = flush_size};
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, stage_mask,
vk::DependencyFlagBits::eByRegion, {}, buffer_barrier, {});

View File

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

View File

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

View File

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

View File

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

View File

@ -42,12 +42,14 @@ TextureRuntime::TextureRuntime(const Instance& instance, TaskScheduler& schedule
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);
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() {
@ -81,12 +83,10 @@ StagingData TextureRuntime::FindStaging(u32 size, bool upload) {
}
const auto& buffer = staging_buffers[current_slot];
return StagingData{
.buffer = buffer->buffer,
return StagingData{.buffer = buffer->buffer,
.size = size,
.mapped = buffer->mapped.subspan(offset, size),
.buffer_offset = offset
};
.buffer_offset = offset};
}
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 VideoCore::HostTextureTag key = {
.format = format,
.width = width,
.height = height,
.layers = layers
};
.format = format, .width = width, .height = height, .layers = layers};
// Attempt to recycle an unused allocation
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 u32 levels = std::bit_width(std::max(width, height));
const vk::ImageCreateInfo image_info = {
.flags = type == VideoCore::TextureType::CubeMap ?
vk::ImageCreateFlagBits::eCubeCompatible :
vk::ImageCreateFlags{},
const vk::ImageCreateInfo image_info = {.flags = type == VideoCore::TextureType::CubeMap
? vk::ImageCreateFlagBits::eCubeCompatible
: vk::ImageCreateFlags{},
.imageType = vk::ImageType::e2D,
.format = vk_format,
.extent = {width, height, 1},
.mipLevels = levels,
.arrayLayers = layers,
.samples = vk::SampleCountFlagBits::e1,
.usage = vk_usage
};
.usage = vk_usage};
const VmaAllocationCreateInfo alloc_info = {
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE
};
const VmaAllocationCreateInfo alloc_info = {.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE};
VkImage unsafe_image{};
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};
const vk::ImageViewCreateInfo view_info = {
.image = image,
.viewType = type == VideoCore::TextureType::CubeMap ?
vk::ImageViewType::eCube :
vk::ImageViewType::e2D,
const vk::ImageViewCreateInfo view_info = {.image = image,
.viewType = type == VideoCore::TextureType::CubeMap
? vk::ImageViewType::eCube
: vk::ImageViewType::e2D,
.format = vk_format,
.subresourceRange = {
.aspectMask = aspect,
.subresourceRange = {.aspectMask = aspect,
.baseMipLevel = 0,
.levelCount = levels,
.baseArrayLayer = 0,
.layerCount = layers
}
};
.layerCount = layers}};
// Also create a base mip view in case this is used as an attachment
const vk::ImageViewCreateInfo base_view_info = {
.image = image,
.viewType = type == VideoCore::TextureType::CubeMap ?
vk::ImageViewType::eCube :
vk::ImageViewType::e2D,
.viewType = type == VideoCore::TextureType::CubeMap ? vk::ImageViewType::eCube
: vk::ImageViewType::e2D,
.format = vk_format,
.subresourceRange = {
.aspectMask = aspect,
.subresourceRange = {.aspectMask = aspect,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = layers
}
};
.layerCount = layers}};
vk::Device device = instance.GetDevice();
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) {
vk::ImageViewCreateInfo view_info = {
.image = image,
.viewType = type == VideoCore::TextureType::CubeMap ?
vk::ImageViewType::eCube :
vk::ImageViewType::e2D,
.viewType = type == VideoCore::TextureType::CubeMap ? vk::ImageViewType::eCube
: vk::ImageViewType::e2D,
.format = vk_format,
.subresourceRange = {
.aspectMask = vk::ImageAspectFlagBits::eDepth,
.subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eDepth,
.baseMipLevel = 0,
.levelCount = levels,
.baseArrayLayer = 0,
.layerCount = layers
}
};
.layerCount = layers}};
depth_view = device.createImageView(view_info);
view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eStencil;
stencil_view = device.createImageView(view_info);
}
return ImageAlloc{
.image = image,
return ImageAlloc{.image = image,
.image_view = image_view,
.base_view = base_view,
.depth_view = depth_view,
@ -221,16 +200,15 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
.format = vk_format,
.aspect = aspect,
.levels = levels,
.layers = layers
};
.layers = layers};
}
void TextureRuntime::Recycle(const VideoCore::HostTextureTag tag, ImageAlloc&& alloc) {
texture_recycler.emplace(tag, std::move(alloc));
}
void TextureRuntime::FormatConvert(const Surface& surface, bool upload,
std::span<std::byte> source, std::span<std::byte> dest) {
void TextureRuntime::FormatConvert(const Surface& surface, bool upload, std::span<std::byte> source,
std::span<std::byte> dest) {
if (!surface.NeedsConvert()) {
std::memcpy(dest.data(), source.data(), source.size());
return;
@ -267,7 +245,8 @@ void TextureRuntime::FormatConvert(const Surface& surface, bool upload,
}
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,
@ -276,36 +255,37 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
renderpass_cache.ExitRenderpass();
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
Transition(command_buffer, surface.alloc, vk::ImageLayout::eTransferDstOptimal,
0, surface.alloc.levels, 0, surface.texture_type == VideoCore::TextureType::CubeMap ? 6 : 1);
Transition(command_buffer, surface.alloc, vk::ImageLayout::eTransferDstOptimal, 0,
surface.alloc.levels, 0,
surface.texture_type == VideoCore::TextureType::CubeMap ? 6 : 1);
vk::ClearValue clear_value{};
if (aspect & vk::ImageAspectFlagBits::eColor) {
clear_value.color = vk::ClearColorValue{
.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) {
clear_value.depthStencil = vk::ClearDepthStencilValue{
.depth = value.depth,
.stencil = value.stencil
};
.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) {
clear_value.depthStencil =
vk::ClearDepthStencilValue{.depth = value.depth, .stencil = value.stencil};
}
// For full clears we can use vkCmdClearColorImage/vkCmdClearDepthStencilImage
if (clear.texture_rect == surface.GetScaledRect()) {
const vk::ImageSubresourceRange range = {
.aspectMask = aspect,
const vk::ImageSubresourceRange range = {.aspectMask = aspect,
.baseMipLevel = clear.texture_level,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1
};
.layerCount = 1};
if (aspect & vk::ImageAspectFlagBits::eColor) {
command_buffer.clearColorImage(surface.alloc.image, vk::ImageLayout::eTransferDstOptimal,
clear_value.color, range);
} else if (aspect & vk::ImageAspectFlagBits::eDepth || aspect & vk::ImageAspectFlagBits::eStencil) {
command_buffer.clearDepthStencilImage(surface.alloc.image, vk::ImageLayout::eTransferDstOptimal,
command_buffer.clearColorImage(surface.alloc.image,
vk::ImageLayout::eTransferDstOptimal, clear_value.color,
range);
} else if (aspect & vk::ImageAspectFlagBits::eDepth ||
aspect & vk::ImageAspectFlagBits::eStencil) {
command_buffer.clearDepthStencilImage(surface.alloc.image,
vk::ImageLayout::eTransferDstOptimal,
clear_value.depthStencil, range);
}
} else {
@ -313,26 +293,28 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
vk::RenderPass clear_renderpass{};
ImageAlloc& alloc = surface.alloc;
if (aspect & vk::ImageAspectFlagBits::eColor) {
clear_renderpass = renderpass_cache.GetRenderpass(surface.pixel_format,
VideoCore::PixelFormat::Invalid, true);
Transition(command_buffer, alloc, vk::ImageLayout::eColorAttachmentOptimal, 0, alloc.levels);
} else if (aspect & vk::ImageAspectFlagBits::eDepth || aspect & vk::ImageAspectFlagBits::eStencil) {
clear_renderpass = renderpass_cache.GetRenderpass(
surface.pixel_format, VideoCore::PixelFormat::Invalid, true);
Transition(command_buffer, alloc, vk::ImageLayout::eColorAttachmentOptimal, 0,
alloc.levels);
} else if (aspect & vk::ImageAspectFlagBits::eDepth ||
aspect & vk::ImageAspectFlagBits::eStencil) {
clear_renderpass = renderpass_cache.GetRenderpass(VideoCore::PixelFormat::Invalid,
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{});
if (new_framebuffer) {\
auto [it, new_framebuffer] =
clear_framebuffers.try_emplace(alloc.image_view, vk::Framebuffer{});
if (new_framebuffer) {
const vk::ImageView framebuffer_view = surface.GetFramebufferView();
const vk::FramebufferCreateInfo framebuffer_info = {
.renderPass = clear_renderpass,
const vk::FramebufferCreateInfo framebuffer_info = {.renderPass = clear_renderpass,
.attachmentCount = 1,
.pAttachments = &framebuffer_view,
.width = surface.GetScaledWidth(),
.height = surface.GetScaledHeight(),
.layers = 1
};
.layers = 1};
vk::Device device = instance.GetDevice();
it->second = device.createFramebuffer(framebuffer_info);
@ -341,13 +323,12 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
const vk::RenderPassBeginInfo clear_begin_info = {
.renderPass = clear_renderpass,
.framebuffer = it->second,
.renderArea = vk::Rect2D{
.offset = {static_cast<s32>(clear.texture_rect.left), static_cast<s32>(clear.texture_rect.bottom)},
.extent = {clear.texture_rect.GetWidth(), clear.texture_rect.GetHeight()}
},
.renderArea = vk::Rect2D{.offset = {static_cast<s32>(clear.texture_rect.left),
static_cast<s32>(clear.texture_rect.bottom)},
.extent = {clear.texture_rect.GetWidth(),
clear.texture_rect.GetHeight()}},
.clearValueCount = 1,
.pClearValues = &clear_value
};
.pClearValues = &clear_value};
renderpass_cache.EnterRenderpass(clear_begin_info);
renderpass_cache.ExitRenderpass();
@ -356,30 +337,28 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
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();
const vk::ImageCopy image_copy = {
.srcSubresource = {
.aspectMask = ToVkAspect(source.type),
.srcSubresource = {.aspectMask = ToVkAspect(source.type),
.mipLevel = copy.src_level,
.baseArrayLayer = 0,
.layerCount = 1
},
.layerCount = 1},
.srcOffset = {static_cast<s32>(copy.src_offset.x), static_cast<s32>(copy.src_offset.y), 0},
.dstSubresource = {
.aspectMask = ToVkAspect(dest.type),
.dstSubresource = {.aspectMask = ToVkAspect(dest.type),
.mipLevel = copy.dst_level,
.baseArrayLayer = 0,
.layerCount = 1
},
.layerCount = 1},
.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();
Transition(command_buffer, source.alloc, vk::ImageLayout::eTransferSrcOptimal, 0, source.alloc.levels);
Transition(command_buffer, dest.alloc, vk::ImageLayout::eTransferDstOptimal, 0, dest.alloc.levels);
Transition(command_buffer, source.alloc, vk::ImageLayout::eTransferSrcOptimal, 0,
source.alloc.levels);
Transition(command_buffer, dest.alloc, vk::ImageLayout::eTransferDstOptimal, 0,
dest.alloc.levels);
command_buffer.copyImage(source.alloc.image, vk::ImageLayout::eTransferSrcOptimal,
dest.alloc.image, vk::ImageLayout::eTransferDstOptimal, image_copy);
@ -387,45 +366,41 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest, const VideoCor
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();
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
Transition(command_buffer, source.alloc, vk::ImageLayout::eTransferSrcOptimal,
0, source.alloc.levels, 0, source.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);
Transition(command_buffer, source.alloc, vk::ImageLayout::eTransferSrcOptimal, 0,
source.alloc.levels, 0,
source.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 = {
vk::Offset3D{static_cast<s32>(blit.src_rect.left), 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}
};
const std::array source_offsets = {vk::Offset3D{static_cast<s32>(blit.src_rect.left),
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}};
const std::array dest_offsets = {
vk::Offset3D{static_cast<s32>(blit.dst_rect.left), 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}
};
const std::array dest_offsets = {vk::Offset3D{static_cast<s32>(blit.dst_rect.left),
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}};
const vk::ImageBlit blit_area = {
.srcSubresource = {
.aspectMask = ToVkAspect(source.type),
const vk::ImageBlit blit_area = {.srcSubresource = {.aspectMask = ToVkAspect(source.type),
.mipLevel = blit.src_level,
.baseArrayLayer = blit.src_layer,
.layerCount = 1
},
.layerCount = 1},
.srcOffsets = source_offsets,
.dstSubresource = {
.aspectMask = ToVkAspect(dest.type),
.dstSubresource = {.aspectMask = ToVkAspect(dest.type),
.mipLevel = blit.dst_level,
.baseArrayLayer = blit.dst_layer,
.layerCount = 1
},
.dstOffsets = dest_offsets
};
.layerCount = 1},
.dstOffsets = dest_offsets};
command_buffer.blitImage(source.alloc.image, vk::ImageLayout::eTransferSrcOptimal,
dest.alloc.image, vk::ImageLayout::eTransferDstOptimal,
blit_area, vk::Filter::eNearest);
dest.alloc.image, vk::ImageLayout::eTransferDstOptimal, blit_area,
vk::Filter::eNearest);
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::eTransferDstOptimal, i, 1);
const std::array source_offsets = {
vk::Offset3D{0, 0, 0},
vk::Offset3D{current_width, current_height, 1}
};
const std::array source_offsets = {vk::Offset3D{0, 0, 0},
vk::Offset3D{current_width, current_height, 1}};
const std::array dest_offsets = {
vk::Offset3D{0, 0, 0},
vk::Offset3D{current_width > 1 ? current_width / 2 : 1,
current_height > 1 ? current_height / 2 : 1, 1}
};
vk::Offset3D{0, 0, 0}, vk::Offset3D{current_width > 1 ? current_width / 2 : 1,
current_height > 1 ? current_height / 2 : 1, 1}};
const vk::ImageBlit blit_area = {
.srcSubresource = {
.aspectMask = aspect,
const vk::ImageBlit blit_area = {.srcSubresource = {.aspectMask = aspect,
.mipLevel = i - 1,
.baseArrayLayer = 0,
.layerCount = 1
},
.layerCount = 1},
.srcOffsets = source_offsets,
.dstSubresource = {
.aspectMask = aspect,
.dstSubresource = {.aspectMask = aspect,
.mipLevel = i,
.baseArrayLayer = 0,
.layerCount = 1
},
.dstOffsets = dest_offsets
};
.layerCount = 1},
.dstOffsets = dest_offsets};
command_buffer.blitImage(surface.alloc.image, vk::ImageLayout::eTransferSrcOptimal,
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)];
}
void TextureRuntime::Transition(vk::CommandBuffer command_buffer, ImageAlloc& alloc,
vk::ImageLayout new_layout, u32 level, u32 level_count,
u32 layer, u32 layer_count) {
vk::ImageLayout new_layout, u32 level, u32 level_count, u32 layer,
u32 layer_count) {
if (new_layout == alloc.layout || !alloc.image) {
return;
}
@ -515,7 +481,8 @@ void TextureRuntime::Transition(vk::CommandBuffer command_buffer, ImageAlloc& al
info.stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
break;
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 |
vk::AccessFlagBits::eDepthStencilAttachmentWrite;
info.stage = vk::PipelineStageFlagBits::eEarlyFragmentTests |
@ -568,18 +535,14 @@ void TextureRuntime::Transition(vk::CommandBuffer command_buffer, ImageAlloc& al
.oldLayout = alloc.layout,
.newLayout = new_layout,
.image = alloc.image,
.subresourceRange = {
.aspectMask = alloc.aspect,
.baseMipLevel = /*level*/0,
.levelCount = /*level_count*/alloc.levels,
.subresourceRange = {.aspectMask = alloc.aspect,
.baseMipLevel = /*level*/ 0,
.levelCount = /*level_count*/ alloc.levels,
.baseArrayLayer = layer,
.layerCount = layer_count
}
};
.layerCount = layer_count}};
command_buffer.pipelineBarrier(source.stage, dest.stage,
vk::DependencyFlagBits::eByRegion,
{}, {}, barrier);
command_buffer.pipelineBarrier(source.stage, dest.stage, vk::DependencyFlagBits::eByRegion, {},
{}, barrier);
alloc.layout = new_layout;
}
@ -589,7 +552,8 @@ Surface::Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime)
scheduler{runtime.GetScheduler()}, traits{instance.GetTraits(pixel_format)} {
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,
.width = GetScaledWidth(),
.height = GetScaledHeight(),
.layers = texture_type == VideoCore::TextureType::CubeMap ? 6u : 1u
};
.layers = texture_type == VideoCore::TextureType::CubeMap ? 6u : 1u};
runtime.Recycle(tag, std::move(alloc));
}
@ -622,21 +585,18 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
.bufferOffset = staging.buffer_offset,
.bufferRowLength = rect.GetWidth(),
.bufferImageHeight = rect.GetHeight(),
.imageSubresource = {
.aspectMask = alloc.aspect,
.imageSubresource = {.aspectMask = alloc.aspect,
.mipLevel = upload.texture_level,
.baseArrayLayer = 0,
.layerCount = 1
},
.layerCount = 1},
.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,
0, texture_type == VideoCore::TextureType::CubeMap ? 6 : 1);
runtime.Transition(command_buffer, alloc, vk::ImageLayout::eTransferDstOptimal, 0,
alloc.levels, 0,
texture_type == VideoCore::TextureType::CubeMap ? 6 : 1);
command_buffer.copyBufferToImage(staging.buffer, alloc.image,
vk::ImageLayout::eTransferDstOptimal,
copy_region);
vk::ImageLayout::eTransferDstOptimal, copy_region);
}
InvalidateAllWatcher();
@ -665,15 +625,12 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
.bufferOffset = staging.buffer_offset + download.buffer_offset,
.bufferRowLength = rect.GetWidth(),
.bufferImageHeight = rect.GetHeight(),
.imageSubresource = {
.aspectMask = alloc.aspect,
.imageSubresource = {.aspectMask = alloc.aspect,
.mipLevel = download.texture_level,
.baseArrayLayer = 0,
.layerCount = 1
},
.layerCount = 1},
.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) {
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
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 {
// RGBA8 needs a byteswap since R8G8B8A8UnormPack32 does not exist
// D24S8 always needs an interleave pass even if natively supported
return alloc.format != traits.native ||
pixel_format == VideoCore::PixelFormat::RGBA8 ||
return alloc.format != traits.native || pixel_format == VideoCore::PixelFormat::RGBA8 ||
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,
VideoCore::TextureType::Texture2D);
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
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();
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_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
glBlitFramebuffer(0, 0, rect_width, rect_height,

View File

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

View File

@ -5,8 +5,8 @@
#pragma once
#include <optional>
#include <unordered_map>
#include <tuple>
#include <unordered_map>
#include "video_core/shader/shader.h"
namespace Pica::Shader {
@ -15,7 +15,7 @@ template <typename ShaderType>
using ShaderCacheResult = std::pair<ShaderType, std::optional<std::string>>;
template <typename KeyType, typename ShaderType, auto ModuleCompiler,
std::string(*CodeGenerator)(const KeyType&)>
std::string (*CodeGenerator)(const KeyType&)>
class ShaderCache {
public:
ShaderCache() {}
@ -52,14 +52,16 @@ public:
* different config values from the same shader program.
*/
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 {
public:
ShaderDoubleCache() = default;
~ShaderDoubleCache() = default;
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()) {
auto code = CodeGenerator(setup, key);
if (!code) {

View File

@ -8,7 +8,8 @@
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),
[](bool value) -> BoolAligned { return {value ? 1 : 0}; });
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,
"VSUniformData structure must be less than 16kb as per the OpenGL spec");
} // 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);
/**
* 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;
enum class ResultStatus {
Success,
ErrorRendererInit,
ErrorGenericDrivers
};
enum class ResultStatus { Success, ErrorRendererInit, ErrorGenericDrivers };
/// Initialize the video core
ResultStatus Init(Frontend::EmuWindow& emu_window, Memory::MemorySystem& memory);

View File

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