renderer_vulkan: Port per-game to vulkan renderer

This commit is contained in:
GPUCode
2022-12-25 23:06:30 +02:00
parent 33bf2b7c2d
commit b8583f9af3
43 changed files with 692 additions and 606 deletions

View File

@ -137,7 +137,8 @@ void EmuWindow_SDL2::Fullscreen() {
EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen, bool is_secondary) : EmuWindow(is_secondary) { EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen, bool is_secondary) : EmuWindow(is_secondary) {
// Initialize the window // Initialize the window
const bool is_opengles = Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES; const bool is_opengles =
Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::OpenGLES;
if (is_opengles) { if (is_opengles) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

View File

@ -148,7 +148,7 @@ public:
// disable vsync for any shared contexts // disable vsync for any shared contexts
auto format = share_context->format(); auto format = share_context->format();
format.setSwapInterval(main_surface ? Settings::values.use_vsync_new : 0); format.setSwapInterval(main_surface ? Settings::values.use_vsync_new.GetValue() : 0);
context = std::make_unique<QOpenGLContext>(); context = std::make_unique<QOpenGLContext>();
context->setShareContext(share_context); context->setShareContext(share_context);
@ -281,8 +281,8 @@ private:
class OpenGLRenderWidget : public RenderWidget { class OpenGLRenderWidget : public RenderWidget {
public: public:
explicit OpenGLRenderWidget(GRenderWindow* parent, bool is_secondary) : explicit OpenGLRenderWidget(GRenderWindow* parent, bool is_secondary)
RenderWidget(parent), is_secondary(is_secondary) { : RenderWidget(parent), is_secondary(is_secondary) {
windowHandle()->setSurfaceType(QWindow::OpenGLSurface); windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
} }
@ -341,7 +341,9 @@ static Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window
#if defined(WIN32) #if defined(WIN32)
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr; wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
#elif defined(__APPLE__) #elif defined(__APPLE__)
wsi.render_surface = window ? AppleSurfaceHelper::GetSurfaceLayer(reinterpret_cast<void*>(window->winId())) : nullptr; wsi.render_surface =
window ? AppleSurfaceHelper::GetSurfaceLayer(reinterpret_cast<void*>(window->winId()))
: nullptr;
#else #else
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
wsi.display_connection = pni->nativeResourceForWindow("display", window); wsi.display_connection = pni->nativeResourceForWindow("display", window);
@ -552,7 +554,7 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
} }
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const { std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api; const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api.GetValue();
if (graphics_api == Settings::GraphicsAPI::OpenGL || if (graphics_api == Settings::GraphicsAPI::OpenGL ||
graphics_api == Settings::GraphicsAPI::OpenGLES) { graphics_api == Settings::GraphicsAPI::OpenGLES) {
auto c = static_cast<OpenGLSharedContext*>(main_context.get()); auto c = static_cast<OpenGLSharedContext*>(main_context.get());
@ -576,7 +578,7 @@ bool GRenderWindow::InitRenderTarget() {
first_frame = false; first_frame = false;
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api; const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api.GetValue();
switch (graphics_api) { switch (graphics_api) {
case Settings::GraphicsAPI::OpenGL: case Settings::GraphicsAPI::OpenGL:
case Settings::GraphicsAPI::OpenGLES: case Settings::GraphicsAPI::OpenGLES:

View File

@ -3,8 +3,8 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <QDesktopServices> #include <QDesktopServices>
#include <QUrl>
#include <QMessageBox> #include <QMessageBox>
#include <QUrl>
#include "citra_qt/configuration/configure_debug.h" #include "citra_qt/configuration/configure_debug.h"
#include "citra_qt/debugger/console.h" #include "citra_qt/debugger/console.h"
#include "citra_qt/uisettings.h" #include "citra_qt/uisettings.h"
@ -27,31 +27,31 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
}); });
connect(ui->toggle_renderer_debug, &QCheckBox::clicked, this, [this](bool checked) { connect(ui->toggle_renderer_debug, &QCheckBox::clicked, this, [this](bool checked) {
if (checked && Settings::values.graphics_api == Settings::GraphicsAPI::Vulkan) { if (checked && Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::Vulkan) {
try { try {
Vulkan::Instance debug_inst{true}; Vulkan::Instance debug_inst{true};
} catch (vk::LayerNotPresentError&) { } catch (vk::LayerNotPresentError&) {
ui->toggle_renderer_debug->toggle(); ui->toggle_renderer_debug->toggle();
QMessageBox::warning( QMessageBox::warning(this, tr("Validation layer not available"),
this, tr("Validation layer not available"),
tr("Unable to enable debug renderer because the layer " tr("Unable to enable debug renderer because the layer "
"<strong>VK_LAYER_KHRONOS_validation</strong> is missing. " "<strong>VK_LAYER_KHRONOS_validation</strong> is missing. "
"Please install the Vulkan SDK or the appropriate package of your distribution")); "Please install the Vulkan SDK or the appropriate package "
"of your distribution"));
} }
} }
}); });
connect(ui->toggle_dump_command_buffers, &QCheckBox::clicked, this, [this](bool checked) { connect(ui->toggle_dump_command_buffers, &QCheckBox::clicked, this, [this](bool checked) {
if (checked && Settings::values.graphics_api == Settings::GraphicsAPI::Vulkan) { if (checked && Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::Vulkan) {
try { try {
Vulkan::Instance debug_inst{false, true}; Vulkan::Instance debug_inst{false, true};
} catch (vk::LayerNotPresentError&) { } catch (vk::LayerNotPresentError&) {
ui->toggle_dump_command_buffers->toggle(); ui->toggle_dump_command_buffers->toggle();
QMessageBox::warning( QMessageBox::warning(this, tr("Command buffer dumping not available"),
this, tr("Command buffer dumping not available"),
tr("Unable to enable command buffer dumping because the layer " tr("Unable to enable command buffer dumping because the layer "
"<strong>VK_LAYER_LUNARG_api_dump</strong> is missing. " "<strong>VK_LAYER_LUNARG_api_dump</strong> is missing. "
"Please install the Vulkan SDK or the appropriate package of your distribution")); "Please install the Vulkan SDK or the appropriate package "
"of your distribution"));
} }
} }
}); });

View File

@ -83,8 +83,10 @@ void ConfigureGraphics::SetConfiguration() {
ui->toggle_accurate_mul->setChecked(Settings::values.shaders_accurate_mul.GetValue()); ui->toggle_accurate_mul->setChecked(Settings::values.shaders_accurate_mul.GetValue());
ui->toggle_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue()); ui->toggle_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
ui->toggle_vsync_new->setChecked(Settings::values.use_vsync_new.GetValue()); ui->toggle_vsync_new->setChecked(Settings::values.use_vsync_new.GetValue());
ui->graphics_api_combo->setCurrentIndex(static_cast<int>(Settings::values.graphics_api.GetValue())); ui->graphics_api_combo->setCurrentIndex(
ui->physical_device_combo->setCurrentIndex(static_cast<int>(Settings::values.physical_device.GetValue())); static_cast<int>(Settings::values.graphics_api.GetValue()));
ui->physical_device_combo->setCurrentIndex(
static_cast<int>(Settings::values.physical_device.GetValue()));
ui->toggle_async_recording->setChecked(Settings::values.async_command_recording.GetValue()); ui->toggle_async_recording->setChecked(Settings::values.async_command_recording.GetValue());
ui->spirv_shader_gen->setChecked(Settings::values.spirv_shader_gen.GetValue()); ui->spirv_shader_gen->setChecked(Settings::values.spirv_shader_gen.GetValue());
@ -106,12 +108,14 @@ void ConfigureGraphics::ApplyConfiguration() {
ui->toggle_disk_shader_cache, use_disk_shader_cache); ui->toggle_disk_shader_cache, use_disk_shader_cache);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync_new, ui->toggle_vsync_new, ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync_new, ui->toggle_vsync_new,
use_vsync_new); use_vsync_new);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api, ui->graphics_api_combo); ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api,
ConfigurationShared::ApplyPerGameSetting(&Settings::values.physical_device, ui->physical_device_combo); ui->graphics_api_combo);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_command_recording, ui->toggle_async_recording, ConfigurationShared::ApplyPerGameSetting(&Settings::values.physical_device,
async_command_recording); ui->physical_device_combo);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.spirv_shader_gen, ui->spirv_shader_gen, ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_command_recording,
spirv_shader_gen); ui->toggle_async_recording, async_command_recording);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.spirv_shader_gen,
ui->spirv_shader_gen, spirv_shader_gen);
if (Settings::IsConfiguringGlobal()) { if (Settings::IsConfiguringGlobal()) {
Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked(); Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked();
@ -168,9 +172,5 @@ void ConfigureGraphics::SetPhysicalDeviceComboVisibility(int index) {
const bool is_visible = graphics_api == Settings::GraphicsAPI::Vulkan; const bool is_visible = graphics_api == Settings::GraphicsAPI::Vulkan;
ui->physical_device_label->setVisible(is_visible); ui->physical_device_label->setVisible(is_visible);
ui->physical_device_combo->setVisible(is_visible); ui->physical_device_combo->setVisible(is_visible);
<<<<<<< HEAD
}
=======
ui->spirv_shader_gen->setVisible(is_visible); ui->spirv_shader_gen->setVisible(is_visible);
} }
>>>>>>> 25502ebc8 (citra_qt: Add SPIR-V shader option)

View File

@ -2255,7 +2255,7 @@ void GMainWindow::UpdateAPIIndicator(bool override) {
static std::array graphics_api_colors = {QStringLiteral("#00ccdd"), QStringLiteral("#ba2a8d"), static std::array graphics_api_colors = {QStringLiteral("#00ccdd"), QStringLiteral("#ba2a8d"),
QStringLiteral("#91242a")}; QStringLiteral("#91242a")};
u32 api_index = static_cast<u32>(Settings::values.graphics_api); u32 api_index = static_cast<u32>(Settings::values.graphics_api.GetValue());
if (override) { if (override) {
api_index = (api_index + 1) % graphics_apis.size(); 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);

View File

@ -4,8 +4,8 @@
#include <limits> #include <limits>
#include "core/memory.h" #include "core/memory.h"
#include "video_core/rasterizer_accelerated.h"
#include "video_core/pica_state.h" #include "video_core/pica_state.h"
#include "video_core/rasterizer_accelerated.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
namespace VideoCore { namespace VideoCore {
@ -711,16 +711,15 @@ void RasterizerAccelerated::SyncAlphaTest() {
} }
void RasterizerAccelerated::SyncCombinerColor() { void RasterizerAccelerated::SyncCombinerColor() {
auto combiner_color = auto combiner_color = ColorRGBA8(Pica::g_state.regs.texturing.tev_combiner_buffer_color.raw);
ColorRGBA8(Pica::g_state.regs.texturing.tev_combiner_buffer_color.raw);
if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) { if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
uniform_block_data.data.tev_combiner_buffer_color = combiner_color; uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
uniform_block_data.dirty = true; uniform_block_data.dirty = true;
} }
} }
void RasterizerAccelerated::SyncTevConstColor(std::size_t stage_index, void RasterizerAccelerated::SyncTevConstColor(
const Pica::TexturingRegs::TevStageConfig& tev_stage) { std::size_t stage_index, const Pica::TexturingRegs::TevStageConfig& tev_stage) {
const auto const_color = ColorRGBA8(tev_stage.const_color); const auto const_color = ColorRGBA8(tev_stage.const_color);
if (const_color == uniform_block_data.data.const_color[stage_index]) { if (const_color == uniform_block_data.data.const_color[stage_index]) {
@ -785,7 +784,8 @@ void RasterizerAccelerated::SyncLightPosition(int light_index) {
void RasterizerAccelerated::SyncLightSpotDirection(int light_index) { void RasterizerAccelerated::SyncLightSpotDirection(int light_index) {
const auto& light = Pica::g_state.regs.lighting.light[light_index]; const auto& light = Pica::g_state.regs.lighting.light[light_index];
const auto spot_direction = Common::Vec3f{light.spot_x / 2047.0f, light.spot_y / 2047.0f, light.spot_z / 2047.0f}; const auto spot_direction =
Common::Vec3f{light.spot_x / 2047.0f, light.spot_y / 2047.0f, light.spot_z / 2047.0f};
if (spot_direction != uniform_block_data.data.light_src[light_index].spot_direction) { if (spot_direction != uniform_block_data.data.light_src[light_index].spot_direction) {
uniform_block_data.data.light_src[light_index].spot_direction = spot_direction; uniform_block_data.data.light_src[light_index].spot_direction = spot_direction;

View File

@ -16,8 +16,7 @@ public:
RasterizerAccelerated(); RasterizerAccelerated();
virtual ~RasterizerAccelerated() = default; virtual ~RasterizerAccelerated() = default;
void AddTriangle(const Pica::Shader::OutputVertex& v0, void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1,
const Pica::Shader::OutputVertex& v1,
const Pica::Shader::OutputVertex& v2) override; const Pica::Shader::OutputVertex& v2) override;
void UpdatePagesCachedCount(PAddr addr, u32 size, int delta) override; void UpdatePagesCachedCount(PAddr addr, u32 size, int delta) override;

View File

@ -5,8 +5,8 @@
#pragma once #pragma once
#include <array> #include <array>
#include "common/math_util.h"
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/math_util.h"
#include "common/vector_math.h" #include "common/vector_math.h"
#include "video_core/pica_types.h" #include "video_core/pica_types.h"

View File

@ -28,10 +28,10 @@ constexpr std::size_t TEXTURE_BUFFER_SIZE = 1 * 1024 * 1024;
RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window, Driver& driver) RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window, Driver& driver)
: driver{driver}, runtime{driver}, res_cache{*this, runtime}, : driver{driver}, runtime{driver}, res_cache{*this, runtime},
shader_program_manager{emu_window, driver, !driver.IsOpenGLES()}, shader_program_manager{emu_window, driver, !driver.IsOpenGLES()},
vertex_buffer{GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE}, vertex_buffer{GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE}, uniform_buffer{GL_UNIFORM_BUFFER,
uniform_buffer{GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE}, UNIFORM_BUFFER_SIZE},
index_buffer{GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE}, index_buffer{GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE}, texture_buffer{GL_TEXTURE_BUFFER,
texture_buffer{GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE}, TEXTURE_BUFFER_SIZE},
texture_lf_buffer{GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE} { texture_lf_buffer{GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE} {
// Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0 // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
@ -268,8 +268,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset,
MICROPROFILE_DEFINE(OpenGL_VS, "OpenGL", "Vertex Shader Setup", MP_RGB(192, 128, 128)); MICROPROFILE_DEFINE(OpenGL_VS, "OpenGL", "Vertex Shader Setup", MP_RGB(192, 128, 128));
bool RasterizerOpenGL::SetupVertexShader() { bool RasterizerOpenGL::SetupVertexShader() {
MICROPROFILE_SCOPE(OpenGL_VS); MICROPROFILE_SCOPE(OpenGL_VS);
return shader_program_manager.UseProgrammableVertexShader(Pica::g_state.regs, return shader_program_manager.UseProgrammableVertexShader(Pica::g_state.regs, Pica::g_state.vs);
Pica::g_state.vs);
} }
MICROPROFILE_DEFINE(OpenGL_GS, "OpenGL", "Geometry Shader Setup", MP_RGB(128, 192, 128)); MICROPROFILE_DEFINE(OpenGL_GS, "OpenGL", "Geometry Shader Setup", MP_RGB(128, 192, 128));

View File

@ -7,11 +7,11 @@
#include <thread> #include <thread>
#include <unordered_map> #include <unordered_map>
#include <boost/variant.hpp> #include <boost/variant.hpp>
#include "video_core/renderer_opengl/gl_driver.h"
#include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_shader_disk_cache.h" #include "video_core/renderer_opengl/gl_shader_disk_cache.h"
#include "video_core/renderer_opengl/gl_shader_manager.h" #include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_driver.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
namespace OpenGL { namespace OpenGL {
@ -374,7 +374,8 @@ public:
ShaderDiskCache disk_cache; ShaderDiskCache disk_cache;
}; };
ShaderProgramManager::ShaderProgramManager(Frontend::EmuWindow& emu_window_, Driver& driver, bool separable) ShaderProgramManager::ShaderProgramManager(Frontend::EmuWindow& emu_window_, Driver& driver,
bool separable)
: impl(std::make_unique<Impl>(separable)), emu_window{emu_window_}, driver{driver} {} : impl(std::make_unique<Impl>(separable)), emu_window{emu_window_}, driver{driver} {}
ShaderProgramManager::~ShaderProgramManager() = default; ShaderProgramManager::~ShaderProgramManager() = default;

View File

@ -12,7 +12,8 @@ MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
namespace OpenGL { namespace OpenGL {
OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool readback, bool prefer_coherent) OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool readback,
bool prefer_coherent)
: gl_target(target), buffer_size(size) { : gl_target(target), buffer_size(size) {
gl_buffer.Create(); gl_buffer.Create();
glBindBuffer(gl_target, gl_buffer.handle); glBindBuffer(gl_target, gl_buffer.handle);
@ -20,11 +21,12 @@ OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool readback,
if (GLAD_GL_ARB_buffer_storage) { if (GLAD_GL_ARB_buffer_storage) {
persistent = true; persistent = true;
coherent = prefer_coherent; coherent = prefer_coherent;
GLbitfield flags = GLbitfield flags = (readback ? GL_MAP_READ_BIT : GL_MAP_WRITE_BIT) | GL_MAP_PERSISTENT_BIT |
(readback ? GL_MAP_READ_BIT : GL_MAP_WRITE_BIT) | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0); (coherent ? GL_MAP_COHERENT_BIT : 0);
glBufferStorage(gl_target, size, nullptr, flags); glBufferStorage(gl_target, size, nullptr, flags);
mapped_ptr = static_cast<u8*>(glMapBufferRange( mapped_ptr = static_cast<u8*>(
gl_target, 0, buffer_size, flags | (!coherent && !readback ? GL_MAP_FLUSH_EXPLICIT_BIT : 0))); glMapBufferRange(gl_target, 0, buffer_size,
flags | (!coherent && !readback ? GL_MAP_FLUSH_EXPLICIT_BIT : 0)));
} else { } else {
glBufferData(gl_target, size, nullptr, GL_STREAM_DRAW); glBufferData(gl_target, size, nullptr, GL_STREAM_DRAW);
} }
@ -67,8 +69,10 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
if (invalidate || !persistent) { if (invalidate || !persistent) {
MICROPROFILE_SCOPE(OpenGL_StreamBuffer); MICROPROFILE_SCOPE(OpenGL_StreamBuffer);
GLbitfield flags = (readback ? GL_MAP_READ_BIT : GL_MAP_WRITE_BIT) | (persistent ? GL_MAP_PERSISTENT_BIT : 0) | GLbitfield flags = (readback ? GL_MAP_READ_BIT : GL_MAP_WRITE_BIT) |
(coherent ? GL_MAP_COHERENT_BIT : 0) | (!coherent && !readback ? GL_MAP_FLUSH_EXPLICIT_BIT : 0) | (persistent ? GL_MAP_PERSISTENT_BIT : 0) |
(coherent ? GL_MAP_COHERENT_BIT : 0) |
(!coherent && !readback ? GL_MAP_FLUSH_EXPLICIT_BIT : 0) |
(invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT); (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT);
mapped_ptr = static_cast<u8*>( mapped_ptr = static_cast<u8*>(
glMapBufferRange(gl_target, buffer_pos, buffer_size - buffer_pos, flags)); glMapBufferRange(gl_target, buffer_pos, buffer_size - buffer_pos, flags));

View File

@ -10,7 +10,8 @@ namespace OpenGL {
class OGLStreamBuffer : private NonCopyable { class OGLStreamBuffer : private NonCopyable {
public: public:
explicit OGLStreamBuffer(GLenum target, GLsizeiptr size, bool readback = false, bool prefer_coherent = false); explicit OGLStreamBuffer(GLenum target, GLsizeiptr size, bool readback = false,
bool prefer_coherent = false);
~OGLStreamBuffer(); ~OGLStreamBuffer();
GLuint GetHandle() const; GLuint GetHandle() const;

View File

@ -57,7 +57,8 @@ constexpr u32 UPLOAD_BUFFER_SIZE = 32 * 1024 * 1024;
constexpr u32 DOWNLOAD_BUFFER_SIZE = 32 * 1024 * 1024; constexpr u32 DOWNLOAD_BUFFER_SIZE = 32 * 1024 * 1024;
TextureRuntime::TextureRuntime(Driver& driver) TextureRuntime::TextureRuntime(Driver& driver)
: driver{driver}, filterer{Settings::values.texture_filter_name, VideoCore::GetResolutionScaleFactor()}, : driver{driver}, filterer{Settings::values.texture_filter_name.GetValue(),
VideoCore::GetResolutionScaleFactor()},
downloader_es{false}, upload_buffer{GL_PIXEL_UNPACK_BUFFER, UPLOAD_BUFFER_SIZE}, downloader_es{false}, upload_buffer{GL_PIXEL_UNPACK_BUFFER, UPLOAD_BUFFER_SIZE},
download_buffer{GL_PIXEL_PACK_BUFFER, DOWNLOAD_BUFFER_SIZE, true} { download_buffer{GL_PIXEL_PACK_BUFFER, DOWNLOAD_BUFFER_SIZE, true} {
@ -394,8 +395,7 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
const auto& tuple = runtime.GetFormatTuple(pixel_format); const auto& tuple = runtime.GetFormatTuple(pixel_format);
glReadPixels(download.texture_rect.left, download.texture_rect.bottom, glReadPixels(download.texture_rect.left, download.texture_rect.bottom,
download.texture_rect.GetWidth(), download.texture_rect.GetHeight(), download.texture_rect.GetWidth(), download.texture_rect.GetHeight(),
tuple.format, tuple.type, tuple.format, tuple.type, reinterpret_cast<void*>(staging.buffer_offset));
reinterpret_cast<void*>(staging.buffer_offset));
runtime.download_buffer.Unmap(staging.size); runtime.download_buffer.Unmap(staging.size);
} }
@ -403,8 +403,7 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_ROW_LENGTH, 0);
} }
void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging) {
const StagingData& staging) {
const u32 rect_width = upload.texture_rect.GetWidth(); const u32 rect_width = upload.texture_rect.GetWidth();
const u32 rect_height = upload.texture_rect.GetHeight(); const u32 rect_height = upload.texture_rect.GetHeight();
const auto scaled_rect = upload.texture_rect * res_scale; const auto scaled_rect = upload.texture_rect * res_scale;
@ -437,7 +436,8 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload,
} }
} }
void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download, const StagingData& staging) { void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download,
const StagingData& staging) {
const u32 rect_width = download.texture_rect.GetWidth(); const u32 rect_width = download.texture_rect.GetWidth();
const u32 rect_height = download.texture_rect.GetHeight(); const u32 rect_height = download.texture_rect.GetHeight();
const VideoCore::Rect2D scaled_rect = download.texture_rect * res_scale; const VideoCore::Rect2D scaled_rect = download.texture_rect * res_scale;
@ -467,8 +467,8 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download, const
const auto& tuple = runtime.GetFormatTuple(pixel_format); const auto& tuple = runtime.GetFormatTuple(pixel_format);
if (driver.IsOpenGLES()) { if (driver.IsOpenGLES()) {
const auto& downloader_es = runtime.GetDownloaderES(); const auto& downloader_es = runtime.GetDownloaderES();
downloader_es.GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, rect_height, rect_width, downloader_es.GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, rect_height,
reinterpret_cast<void*>(staging.buffer_offset)); rect_width, reinterpret_cast<void*>(staging.buffer_offset));
} else { } else {
glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type,
reinterpret_cast<void*>(staging.buffer_offset)); reinterpret_cast<void*>(staging.buffer_offset));

View File

@ -353,8 +353,9 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
} }
RendererOpenGL::RendererOpenGL(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window) RendererOpenGL::RendererOpenGL(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window)
: RendererBase{window, secondary_window}, driver{Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES, : RendererBase{window, secondary_window}, driver{Settings::values.graphics_api.GetValue() ==
Settings::values.renderer_debug}, Settings::GraphicsAPI::OpenGLES,
Settings::values.renderer_debug.GetValue()},
frame_dumper(Core::System::GetInstance().VideoDumper(), window) { frame_dumper(Core::System::GetInstance().VideoDumper(), window) {
window.mailbox = std::make_unique<OGLTextureMailbox>(); window.mailbox = std::make_unique<OGLTextureMailbox>();
if (secondary_window) { if (secondary_window) {

View File

@ -6,13 +6,13 @@
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/frontend/framebuffer_layout.h" #include "core/frontend/framebuffer_layout.h"
#include "core/hw/gpu.h" #include "core/hw/gpu.h"
#include "core/hw/hw.h" #include "core/hw/hw.h"
#include "core/hw/lcd.h" #include "core/hw/lcd.h"
#include "core/settings.h"
#include "core/tracer/recorder.h" #include "core/tracer/recorder.h"
#include "video_core/debug_utils/debug_utils.h" #include "video_core/debug_utils/debug_utils.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/renderer_vulkan.h"
@ -226,13 +226,16 @@ std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_ext
} // Anonymous namespace } // Anonymous namespace
RendererVulkan::RendererVulkan(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window) RendererVulkan::RendererVulkan(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window)
: RendererBase{window, secondary_window}, telemetry_session{Core::System::GetInstance().TelemetrySession()}, : RendererBase{window, secondary_window},
instance{window, Settings::values.physical_device}, telemetry_session{Core::System::GetInstance().TelemetrySession()},
scheduler{instance, renderpass_cache, *this}, instance{window, Settings::values.physical_device.GetValue()}, scheduler{instance,
renderpass_cache,
*this},
renderpass_cache{instance, scheduler}, desc_manager{instance, scheduler}, renderpass_cache{instance, scheduler}, desc_manager{instance, scheduler},
runtime{instance, scheduler, renderpass_cache, desc_manager}, runtime{instance, scheduler, renderpass_cache, desc_manager}, swapchain{instance, scheduler,
swapchain{instance, scheduler, renderpass_cache}, renderpass_cache},
vertex_buffer{instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}}, vertex_buffer{
instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}},
rasterizer{render_window, instance, scheduler, desc_manager, runtime, renderpass_cache} { rasterizer{render_window, instance, scheduler, desc_manager, runtime, renderpass_cache} {
Report(); Report();
window.mailbox = nullptr; window.mailbox = nullptr;
@ -296,8 +299,8 @@ void RendererVulkan::PrepareRendertarget() {
if (color_fill.is_enabled) { if (color_fill.is_enabled) {
TextureInfo& texture = screen_infos[i].texture; TextureInfo& texture = screen_infos[i].texture;
runtime.Transition(texture.alloc, vk::ImageLayout::eTransferDstOptimal, runtime.Transition(texture.alloc, vk::ImageLayout::eTransferDstOptimal, 0,
0, texture.alloc.levels); texture.alloc.levels);
scheduler.Record([image = texture.alloc.image, scheduler.Record([image = texture.alloc.image,
color_fill](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { color_fill](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
@ -313,7 +316,8 @@ void RendererVulkan::PrepareRendertarget() {
.layerCount = 1, .layerCount = 1,
}; };
render_cmdbuf.clearColorImage(image, vk::ImageLayout::eTransferDstOptimal, clear_color, range); render_cmdbuf.clearColorImage(image, vk::ImageLayout::eTransferDstOptimal,
clear_color, range);
}); });
} else { } else {
TextureInfo& texture = screen_infos[i].texture; TextureInfo& texture = screen_infos[i].texture;
@ -352,19 +356,20 @@ void RendererVulkan::BeginRendering() {
vk::DescriptorSet set = desc_manager.AllocateSet(present_descriptor_layout); vk::DescriptorSet set = desc_manager.AllocateSet(present_descriptor_layout);
device.updateDescriptorSetWithTemplate(set, present_update_template, present_textures[0]); device.updateDescriptorSetWithTemplate(set, present_update_template, present_textures[0]);
scheduler.Record([this, set, pipeline_index = current_pipeline](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { scheduler.Record([this, set, pipeline_index = current_pipeline](vk::CommandBuffer render_cmdbuf,
vk::CommandBuffer) {
render_cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, render_cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics,
present_pipelines[pipeline_index]); present_pipelines[pipeline_index]);
render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, present_pipeline_layout, 0, set, {}); render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, present_pipeline_layout,
0, set, {});
}); });
const RenderpassState renderpass_info = { const RenderpassState renderpass_info = {
.renderpass = renderpass_cache.GetPresentRenderpass(), .renderpass = renderpass_cache.GetPresentRenderpass(),
.framebuffer = swapchain.GetFramebuffer(), .framebuffer = swapchain.GetFramebuffer(),
.render_area = vk::Rect2D{.offset = {0, 0}, .extent = swapchain.GetExtent()}, .render_area = vk::Rect2D{.offset = {0, 0}, .extent = swapchain.GetExtent()},
.clear = vk::ClearValue{.color = clear_color} .clear = vk::ClearValue{.color = clear_color}};
};
renderpass_cache.EnterRenderpass(renderpass_info); renderpass_cache.EnterRenderpass(renderpass_info);
} }
@ -394,8 +399,8 @@ void RendererVulkan::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
// only allows rows to have a memory alignement of 4. // only allows rows to have a memory alignement of 4.
ASSERT(pixel_stride % 4 == 0); ASSERT(pixel_stride % 4 == 0);
if (!rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, if (!rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, static_cast<u32>(pixel_stride),
static_cast<u32>(pixel_stride), screen_info)) { screen_info)) {
ASSERT(false); ASSERT(false);
// Reset the screen info's display texture to its own permanent texture // Reset the screen info's display texture to its own permanent texture
/*screen_info.display_texture = &screen_info.texture; /*screen_info.display_texture = &screen_info.texture;
@ -622,19 +627,19 @@ void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture,
} }
void RendererVulkan::ReloadSampler() { void RendererVulkan::ReloadSampler() {
current_sampler = !Settings::values.filter_mode; current_sampler = !Settings::values.filter_mode.GetValue();
} }
void RendererVulkan::ReloadPipeline() { void RendererVulkan::ReloadPipeline() {
switch (Settings::values.render_3d) { const Settings::StereoRenderOption render_3d = Settings::values.render_3d.GetValue();
switch (render_3d) {
case Settings::StereoRenderOption::Anaglyph: case Settings::StereoRenderOption::Anaglyph:
current_pipeline = 1; current_pipeline = 1;
break; break;
case Settings::StereoRenderOption::Interlaced: case Settings::StereoRenderOption::Interlaced:
case Settings::StereoRenderOption::ReverseInterlaced: case Settings::StereoRenderOption::ReverseInterlaced:
current_pipeline = 2; current_pipeline = 2;
draw_info.reverse_interlaced = draw_info.reverse_interlaced = render_3d == Settings::StereoRenderOption::ReverseInterlaced;
Settings::values.render_3d == Settings::StereoRenderOption::ReverseInterlaced;
break; break;
default: default:
current_pipeline = 0; current_pipeline = 0;
@ -672,8 +677,8 @@ void RendererVulkan::DrawSingleScreenRotated(u32 screen_id, float x, float y, fl
draw_info.o_resolution = Common::Vec4f{h, w, 1.0f / h, 1.0f / w}; draw_info.o_resolution = Common::Vec4f{h, w, 1.0f / h, 1.0f / w};
draw_info.screen_id_l = screen_id; draw_info.screen_id_l = screen_id;
scheduler.Record([this, offset = offset, scheduler.Record([this, offset = offset, info = draw_info](vk::CommandBuffer render_cmdbuf,
info = draw_info](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { vk::CommandBuffer) {
render_cmdbuf.pushConstants(present_pipeline_layout, render_cmdbuf.pushConstants(present_pipeline_layout,
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eFragment |
vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eVertex,
@ -711,8 +716,8 @@ void RendererVulkan::DrawSingleScreen(u32 screen_id, float x, float y, float w,
draw_info.o_resolution = Common::Vec4f{h, w, 1.0f / h, 1.0f / w}; draw_info.o_resolution = Common::Vec4f{h, w, 1.0f / h, 1.0f / w};
draw_info.screen_id_l = screen_id; draw_info.screen_id_l = screen_id;
scheduler.Record([this, offset = offset, scheduler.Record([this, offset = offset, info = draw_info](vk::CommandBuffer render_cmdbuf,
info = draw_info](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { vk::CommandBuffer) {
render_cmdbuf.pushConstants(present_pipeline_layout, render_cmdbuf.pushConstants(present_pipeline_layout,
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eFragment |
vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eVertex,
@ -751,8 +756,8 @@ void RendererVulkan::DrawSingleScreenStereoRotated(u32 screen_id_l, u32 screen_i
draw_info.screen_id_l = screen_id_l; draw_info.screen_id_l = screen_id_l;
draw_info.screen_id_r = screen_id_r; draw_info.screen_id_r = screen_id_r;
scheduler.Record([this, offset = offset, scheduler.Record([this, offset = offset, info = draw_info](vk::CommandBuffer render_cmdbuf,
info = draw_info](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { vk::CommandBuffer) {
render_cmdbuf.pushConstants(present_pipeline_layout, render_cmdbuf.pushConstants(present_pipeline_layout,
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eFragment |
vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eVertex,
@ -793,8 +798,8 @@ void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, fl
draw_info.screen_id_l = screen_id_l; draw_info.screen_id_l = screen_id_l;
draw_info.screen_id_r = screen_id_r; draw_info.screen_id_r = screen_id_r;
scheduler.Record([this, offset = offset, scheduler.Record([this, offset = offset, info = draw_info](vk::CommandBuffer render_cmdbuf,
info = draw_info](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { vk::CommandBuffer) {
render_cmdbuf.pushConstants(present_pipeline_layout, render_cmdbuf.pushConstants(present_pipeline_layout,
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eFragment |
vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eVertex,
@ -808,9 +813,9 @@ void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, fl
void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool flipped) { void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool flipped) {
if (VideoCore::g_renderer_bg_color_update_requested.exchange(false)) { if (VideoCore::g_renderer_bg_color_update_requested.exchange(false)) {
// Update background color before drawing // Update background color before drawing
clear_color.float32[0] = Settings::values.bg_red; clear_color.float32[0] = Settings::values.bg_red.GetValue();
clear_color.float32[1] = Settings::values.bg_green; clear_color.float32[1] = Settings::values.bg_green.GetValue();
clear_color.float32[2] = Settings::values.bg_blue; clear_color.float32[2] = Settings::values.bg_blue.GetValue();
} }
if (VideoCore::g_renderer_sampler_update_requested.exchange(false)) { if (VideoCore::g_renderer_sampler_update_requested.exchange(false)) {
@ -832,10 +837,10 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
draw_info.modelview = glm::transpose(glm::ortho( 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)); 0.f, static_cast<float>(layout.width), static_cast<float>(layout.height), 0.0f, 0.f, 1.f));
const bool stereo_single_screen = const Settings::StereoRenderOption render_3d = Settings::values.render_3d.GetValue();
Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph || const bool stereo_single_screen = render_3d == Settings::StereoRenderOption::Anaglyph ||
Settings::values.render_3d == Settings::StereoRenderOption::Interlaced || render_3d == Settings::StereoRenderOption::Interlaced ||
Settings::values.render_3d == Settings::StereoRenderOption::ReverseInterlaced; render_3d == Settings::StereoRenderOption::ReverseInterlaced;
// Bind necessary state before drawing the screens // Bind necessary state before drawing the screens
BeginRendering(); BeginRendering();
@ -843,10 +848,10 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
draw_info.layer = 0; draw_info.layer = 0;
if (layout.top_screen_enabled) { if (layout.top_screen_enabled) {
if (layout.is_rotated) { if (layout.is_rotated) {
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { if (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()); top_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { } else if (render_3d == Settings::StereoRenderOption::SideBySide) {
DrawSingleScreenRotated(0, (float)top_screen.left / 2, (float)top_screen.top, DrawSingleScreenRotated(0, (float)top_screen.left / 2, (float)top_screen.top,
(float)top_screen.GetWidth() / 2, (float)top_screen.GetWidth() / 2,
(float)top_screen.GetHeight()); (float)top_screen.GetHeight());
@ -854,7 +859,7 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
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.top, (float)top_screen.GetWidth() / 2,
(float)top_screen.GetHeight()); (float)top_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { } else if (render_3d == Settings::StereoRenderOption::CardboardVR) {
DrawSingleScreenRotated(0, layout.top_screen.left, layout.top_screen.top, DrawSingleScreenRotated(0, layout.top_screen.left, layout.top_screen.top,
layout.top_screen.GetWidth(), layout.top_screen.GetWidth(),
layout.top_screen.GetHeight()); layout.top_screen.GetHeight());
@ -869,17 +874,17 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
(float)top_screen.GetHeight()); (float)top_screen.GetHeight());
} }
} else { } else {
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { if (render_3d == Settings::StereoRenderOption::Off) {
DrawSingleScreen(0, (float)top_screen.left, (float)top_screen.top, DrawSingleScreen(0, (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::SideBySide) { } else if (render_3d == Settings::StereoRenderOption::SideBySide) {
DrawSingleScreen(0, (float)top_screen.left / 2, (float)top_screen.top, DrawSingleScreen(0, (float)top_screen.left / 2, (float)top_screen.top,
(float)top_screen.GetWidth() / 2, (float)top_screen.GetHeight()); (float)top_screen.GetWidth() / 2, (float)top_screen.GetHeight());
draw_info.layer = 1; draw_info.layer = 1;
DrawSingleScreen(1, ((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.top, (float)top_screen.GetWidth() / 2,
(float)top_screen.GetHeight()); (float)top_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { } else if (render_3d == Settings::StereoRenderOption::CardboardVR) {
DrawSingleScreen(0, layout.top_screen.left, layout.top_screen.top, DrawSingleScreen(0, layout.top_screen.left, layout.top_screen.top,
layout.top_screen.GetWidth(), layout.top_screen.GetHeight()); layout.top_screen.GetWidth(), layout.top_screen.GetHeight());
draw_info.layer = 1; draw_info.layer = 1;
@ -897,11 +902,11 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
draw_info.layer = 0; draw_info.layer = 0;
if (layout.bottom_screen_enabled) { if (layout.bottom_screen_enabled) {
if (layout.is_rotated) { if (layout.is_rotated) {
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { if (render_3d == Settings::StereoRenderOption::Off) {
DrawSingleScreenRotated(2, (float)bottom_screen.left, (float)bottom_screen.top, DrawSingleScreenRotated(2, (float)bottom_screen.left, (float)bottom_screen.top,
(float)bottom_screen.GetWidth(), (float)bottom_screen.GetWidth(),
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { } else if (render_3d == Settings::StereoRenderOption::SideBySide) {
DrawSingleScreenRotated(2, (float)bottom_screen.left / 2, (float)bottom_screen.top, DrawSingleScreenRotated(2, (float)bottom_screen.left / 2, (float)bottom_screen.top,
(float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetWidth() / 2,
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
@ -910,7 +915,7 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
2, ((float)bottom_screen.left / 2) + ((float)layout.width / 2), 2, ((float)bottom_screen.left / 2) + ((float)layout.width / 2),
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { } else if (render_3d == Settings::StereoRenderOption::CardboardVR) {
DrawSingleScreenRotated(2, layout.bottom_screen.left, layout.bottom_screen.top, DrawSingleScreenRotated(2, layout.bottom_screen.left, layout.bottom_screen.top,
layout.bottom_screen.GetWidth(), layout.bottom_screen.GetWidth(),
layout.bottom_screen.GetHeight()); layout.bottom_screen.GetHeight());
@ -925,10 +930,10 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
(float)bottom_screen.GetWidth(), (float)bottom_screen.GetHeight()); (float)bottom_screen.GetWidth(), (float)bottom_screen.GetHeight());
} }
} else { } else {
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { if (render_3d == Settings::StereoRenderOption::Off) {
DrawSingleScreen(2, (float)bottom_screen.left, (float)bottom_screen.top, DrawSingleScreen(2, (float)bottom_screen.left, (float)bottom_screen.top,
(float)bottom_screen.GetWidth(), (float)bottom_screen.GetHeight()); (float)bottom_screen.GetWidth(), (float)bottom_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { } else if (render_3d == Settings::StereoRenderOption::SideBySide) {
DrawSingleScreen(2, (float)bottom_screen.left / 2, (float)bottom_screen.top, DrawSingleScreen(2, (float)bottom_screen.left / 2, (float)bottom_screen.top,
(float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetWidth() / 2,
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
@ -936,7 +941,7 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
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.top, (float)bottom_screen.GetWidth() / 2,
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { } else if (render_3d == Settings::StereoRenderOption::CardboardVR) {
DrawSingleScreen(2, layout.bottom_screen.left, layout.bottom_screen.top, DrawSingleScreen(2, layout.bottom_screen.left, layout.bottom_screen.top,
layout.bottom_screen.GetWidth(), layout.bottom_screen.GetHeight()); layout.bottom_screen.GetWidth(), layout.bottom_screen.GetHeight());
draw_info.layer = 1; draw_info.layer = 1;
@ -991,8 +996,7 @@ void RendererVulkan::SwapBuffers() {
for (auto& info : screen_infos) { for (auto& info : screen_infos) {
ImageAlloc* alloc = info.display_texture ? info.display_texture : &info.texture.alloc; ImageAlloc* alloc = info.display_texture ? info.display_texture : &info.texture.alloc;
runtime.Transition(*alloc, vk::ImageLayout::eShaderReadOnlyOptimal, 0, runtime.Transition(*alloc, vk::ImageLayout::eShaderReadOnlyOptimal, 0, alloc->levels);
alloc->levels);
} }
DrawScreens(layout, false); DrawScreens(layout, false);
@ -1045,5 +1049,4 @@ void RendererVulkan::Report() const {
telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions);
} }
} // namespace Vulkan } // namespace Vulkan

View File

@ -10,12 +10,12 @@
#include "common/math_util.h" #include "common/math_util.h"
#include "core/hw/gpu.h" #include "core/hw/gpu.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_descriptor_manager.h" #include "video_core/renderer_vulkan/vk_descriptor_manager.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_rasterizer.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
namespace Core { namespace Core {
class TelemetrySession; class TelemetrySession;

View File

@ -4,15 +4,16 @@
#include "common/vector_math.h" #include "common/vector_math.h"
#include "video_core/renderer_vulkan/vk_blit_helper.h" #include "video_core/renderer_vulkan/vk_blit_helper.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_descriptor_manager.h" #include "video_core/renderer_vulkan/vk_descriptor_manager.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/renderer_vulkan/vk_texture_runtime.h" #include "video_core/renderer_vulkan/vk_texture_runtime.h"
namespace Vulkan { namespace Vulkan {
BlitHelper::BlitHelper(const Instance& instance, Scheduler& scheduler, DescriptorManager& desc_manager) BlitHelper::BlitHelper(const Instance& instance, Scheduler& scheduler,
DescriptorManager& desc_manager)
: scheduler{scheduler}, desc_manager{desc_manager}, device{instance.GetDevice()} { : scheduler{scheduler}, desc_manager{desc_manager}, device{instance.GetDevice()} {
constexpr std::string_view cs_source = R"( constexpr std::string_view cs_source = R"(
#version 450 core #version 450 core
@ -142,7 +143,8 @@ void BlitHelper::BlitD24S8ToR32(Surface& source, Surface& dest,
device.updateDescriptorSetWithTemplate(set, update_template, textures[0]); device.updateDescriptorSetWithTemplate(set, update_template, textures[0]);
scheduler.Record([this, set, blit](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { scheduler.Record([this, set, blit](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout, 0, set, {}); render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout,
0, set, {});
render_cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, compute_pipeline); render_cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, compute_pipeline);
const auto src_offset = Common::MakeVec(blit.src_rect.left, blit.src_rect.bottom); const auto src_offset = Common::MakeVec(blit.src_rect.left, blit.src_rect.bottom);

View File

@ -19,8 +19,7 @@ class Surface;
class BlitHelper { class BlitHelper {
public: public:
BlitHelper(const Instance& instance, Scheduler& scheduler, BlitHelper(const Instance& instance, Scheduler& scheduler, DescriptorManager& desc_manager);
DescriptorManager& desc_manager);
~BlitHelper(); ~BlitHelper();
/// Blits D24S8 pixel data to the provided buffer /// Blits D24S8 pixel data to the provided buffer

View File

@ -58,7 +58,8 @@ constexpr vk::ShaderStageFlags ToVkStageFlags(vk::DescriptorType type) {
} }
DescriptorManager::DescriptorManager(const Instance& instance, Scheduler& scheduler) DescriptorManager::DescriptorManager(const Instance& instance, Scheduler& scheduler)
: instance{instance}, scheduler{scheduler}, pool_provider{instance, scheduler.GetMasterSemaphore()} { : instance{instance}, scheduler{scheduler}, pool_provider{instance,
scheduler.GetMasterSemaphore()} {
BuildLayouts(); BuildLayouts();
descriptor_set_dirty.fill(true); descriptor_set_dirty.fill(true);
current_pool = pool_provider.Commit(); current_pool = pool_provider.Commit();
@ -101,7 +102,8 @@ void DescriptorManager::BindDescriptorSets() {
} }
scheduler.Record([this, bound_sets](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { scheduler.Record([this, bound_sets](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline_layout, 0, bound_sets, {}); render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline_layout, 0,
bound_sets, {});
}); });
descriptor_set_dirty.fill(false); descriptor_set_dirty.fill(false);
@ -158,9 +160,7 @@ vk::DescriptorSet DescriptorManager::AllocateSet(vk::DescriptorSetLayout layout)
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
const vk::DescriptorSetAllocateInfo alloc_info = { const vk::DescriptorSetAllocateInfo alloc_info = {
.descriptorPool = current_pool, .descriptorPool = current_pool, .descriptorSetCount = 1, .pSetLayouts = &layout};
.descriptorSetCount = 1,
.pSetLayouts = &layout};
try { try {
return device.allocateDescriptorSets(alloc_info)[0]; return device.allocateDescriptorSets(alloc_info)[0];

View File

@ -2,17 +2,18 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "video_core/renderer_vulkan/vk_format_reinterpreter.h"
#include "video_core/renderer_vulkan/vk_descriptor_manager.h" #include "video_core/renderer_vulkan/vk_descriptor_manager.h"
#include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_format_reinterpreter.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/renderer_vulkan/vk_texture_runtime.h" #include "video_core/renderer_vulkan/vk_texture_runtime.h"
namespace Vulkan { namespace Vulkan {
D24S8toRGBA8::D24S8toRGBA8(const Instance& instance, Scheduler& scheduler, D24S8toRGBA8::D24S8toRGBA8(const Instance& instance, Scheduler& scheduler,
DescriptorManager& desc_manager, TextureRuntime& runtime) DescriptorManager& desc_manager, TextureRuntime& runtime)
: FormatReinterpreterBase{instance, scheduler, desc_manager, runtime}, device{instance.GetDevice()} { : FormatReinterpreterBase{instance, scheduler, desc_manager, runtime},
device{instance.GetDevice()} {
constexpr std::string_view cs_source = R"( constexpr std::string_view cs_source = R"(
#version 450 core #version 450 core
#extension GL_EXT_samplerless_texture_functions : require #extension GL_EXT_samplerless_texture_functions : require
@ -141,7 +142,8 @@ void D24S8toRGBA8::Reinterpret(Surface& source, VideoCore::Rect2D src_rect, Surf
device.updateDescriptorSetWithTemplate(set, update_template, textures[0]); device.updateDescriptorSetWithTemplate(set, update_template, textures[0]);
scheduler.Record([this, set, src_rect](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { scheduler.Record([this, set, src_rect](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout, 0, set, {}); render_cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, compute_pipeline_layout,
0, set, {});
render_cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, compute_pipeline); render_cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, compute_pipeline);
const auto src_offset = Common::MakeVec(src_rect.left, src_rect.bottom); const auto src_offset = Common::MakeVec(src_rect.left, src_rect.bottom);

View File

@ -37,8 +37,8 @@ using ReinterpreterList = std::vector<std::unique_ptr<FormatReinterpreterBase>>;
class D24S8toRGBA8 final : public FormatReinterpreterBase { class D24S8toRGBA8 final : public FormatReinterpreterBase {
public: public:
D24S8toRGBA8(const Instance& instance, Scheduler& scheduler, D24S8toRGBA8(const Instance& instance, Scheduler& scheduler, DescriptorManager& desc_manager,
DescriptorManager& desc_manager, TextureRuntime& runtime); TextureRuntime& runtime);
~D24S8toRGBA8(); ~D24S8toRGBA8();
[[nodiscard]] VideoCore::PixelFormat GetSourceFormat() const override { [[nodiscard]] VideoCore::PixelFormat GetSourceFormat() const override {

View File

@ -4,8 +4,8 @@
#include <span> #include <span>
#include "common/assert.h" #include "common/assert.h"
#include "common/settings.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/settings.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_platform.h" #include "video_core/renderer_vulkan/vk_platform.h"
@ -30,11 +30,9 @@ inline std::string_view GetType(vk::DebugUtilsMessageTypeFlagBitsEXT type) {
}; };
} }
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugHandler( static VKAPI_ATTR VkBool32 VKAPI_CALL
VkDebugUtilsMessageSeverityFlagBitsEXT severity, DebugHandler(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type,
VkDebugUtilsMessageTypeFlagsEXT type, const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) {
const VkDebugUtilsMessengerCallbackDataEXT* callback_data,
void* user_data) {
switch (callback_data->messageIdNumber) { switch (callback_data->messageIdNumber) {
case 0x609a13b: // Vertex attribute at location not consumed by shader case 0x609a13b: // Vertex attribute at location not consumed by shader
@ -59,8 +57,8 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL DebugHandler(
level = Log::Level::Info; level = Log::Level::Info;
} }
LOG_GENERIC(Log::Class::Render_Vulkan, level, "{}: {}", LOG_GENERIC(Log::Class::Render_Vulkan, level, "{}: {}", callback_data->pMessageIdName,
callback_data->pMessageIdName, callback_data->pMessage); callback_data->pMessage);
return VK_FALSE; return VK_FALSE;
} }
@ -93,8 +91,7 @@ vk::Format ToVkFormat(VideoCore::PixelFormat format) {
} }
[[nodiscard]] vk::DebugUtilsMessengerCreateInfoEXT MakeDebugUtilsMessengerInfo() { [[nodiscard]] vk::DebugUtilsMessengerCreateInfoEXT MakeDebugUtilsMessengerInfo() {
return { return {.messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
.messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError | vk::DebugUtilsMessageSeverityFlagBitsEXT::eError |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose, vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose,
@ -102,8 +99,7 @@ vk::Format ToVkFormat(VideoCore::PixelFormat format) {
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
vk::DebugUtilsMessageTypeFlagBitsEXT::eDeviceAddressBinding | vk::DebugUtilsMessageTypeFlagBitsEXT::eDeviceAddressBinding |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance, vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
.pfnUserCallback = DebugHandler .pfnUserCallback = DebugHandler};
};
} }
std::vector<std::string> GetSupportedExtensions(vk::PhysicalDevice physical) { std::vector<std::string> GetSupportedExtensions(vk::PhysicalDevice physical) {
@ -116,9 +112,8 @@ std::vector<std::string> GetSupportedExtensions(vk::PhysicalDevice physical) {
return supported_extensions; return supported_extensions;
} }
Instance::Instance(bool validation, bool dump_command_buffers) : Instance::Instance(bool validation, bool dump_command_buffers)
enable_validation{validation}, : enable_validation{validation}, dump_command_buffers{dump_command_buffers} {
dump_command_buffers{dump_command_buffers}{
// Fetch instance independant function pointers // Fetch instance independant function pointers
auto vkGetInstanceProcAddr = auto vkGetInstanceProcAddr =
dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"); dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
@ -147,17 +142,13 @@ Instance::Instance(bool validation, bool dump_command_buffers) :
} }
const vk::StructureChain instance_chain = { const vk::StructureChain instance_chain = {
vk::InstanceCreateInfo{ vk::InstanceCreateInfo{.flags = flags,
.flags = flags,
.pApplicationInfo = &application_info, .pApplicationInfo = &application_info,
.enabledLayerCount = layer_count, .enabledLayerCount = layer_count,
.ppEnabledLayerNames = layers.data(), .ppEnabledLayerNames = layers.data(),
.enabledExtensionCount = .enabledExtensionCount = static_cast<u32>(extensions.size()),
static_cast<u32>(extensions.size()), .ppEnabledExtensionNames = extensions.data()},
.ppEnabledExtensionNames = extensions.data() MakeDebugUtilsMessengerInfo()};
},
MakeDebugUtilsMessengerInfo()
};
instance = vk::createInstance(instance_chain.get()); instance = vk::createInstance(instance_chain.get());
@ -172,8 +163,8 @@ Instance::Instance(bool validation, bool dump_command_buffers) :
physical_devices = instance.enumeratePhysicalDevices(); physical_devices = instance.enumeratePhysicalDevices();
} }
Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index) : Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index)
enable_validation{Settings::values.renderer_debug}, : enable_validation{Settings::values.renderer_debug},
dump_command_buffers{Settings::values.dump_command_buffers} { dump_command_buffers{Settings::values.dump_command_buffers} {
auto window_info = window.GetWindowInfo(); auto window_info = window.GetWindowInfo();
@ -212,22 +203,19 @@ Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index) :
} }
const vk::StructureChain instance_chain = { const vk::StructureChain instance_chain = {
vk::InstanceCreateInfo{ vk::InstanceCreateInfo{.flags = flags,
.flags = flags,
.pApplicationInfo = &application_info, .pApplicationInfo = &application_info,
.enabledLayerCount = layer_count, .enabledLayerCount = layer_count,
.ppEnabledLayerNames = layers.data(), .ppEnabledLayerNames = layers.data(),
.enabledExtensionCount = .enabledExtensionCount = static_cast<u32>(extensions.size()),
static_cast<u32>(extensions.size()), .ppEnabledExtensionNames = extensions.data()},
.ppEnabledExtensionNames = extensions.data() MakeDebugUtilsMessengerInfo()};
},
MakeDebugUtilsMessengerInfo()
};
try { try {
instance = vk::createInstance(instance_chain.get()); instance = vk::createInstance(instance_chain.get());
} catch (vk::LayerNotPresentError& err) { } catch (vk::LayerNotPresentError& err) {
LOG_CRITICAL(Render_Vulkan, "Validation requested but layer is not available {}", err.what()); LOG_CRITICAL(Render_Vulkan, "Validation requested but layer is not available {}",
err.what());
UNREACHABLE(); UNREACHABLE();
} }
@ -383,8 +371,7 @@ bool Instance::CreateDevice() {
u32 enabled_extension_count = 0; u32 enabled_extension_count = 0;
auto AddExtension = [&](std::string_view extension) -> bool { auto AddExtension = [&](std::string_view extension) -> bool {
auto result = auto result = std::find_if(available_extensions.begin(), available_extensions.end(),
std::find_if(available_extensions.begin(), available_extensions.end(),
[&](const std::string& name) { return name == extension; }); [&](const std::string& name) { return name == extension; });
if (result != available_extensions.end()) { if (result != available_extensions.end()) {
@ -519,16 +506,15 @@ void Instance::CreateDebugMessenger() {
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
vk::DebugUtilsMessageTypeFlagBitsEXT::eDeviceAddressBinding | vk::DebugUtilsMessageTypeFlagBitsEXT::eDeviceAddressBinding |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance, vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
.pfnUserCallback = DebugHandler .pfnUserCallback = DebugHandler};
};
debug_messenger = instance.createDebugUtilsMessengerEXT(debug_info); debug_messenger = instance.createDebugUtilsMessengerEXT(debug_info);
} }
void Instance::CollectTelemetryParameters() { void Instance::CollectTelemetryParameters() {
const vk::StructureChain property_chain = const vk::StructureChain property_chain =
physical_device.getProperties2<vk::PhysicalDeviceProperties2, physical_device
vk::PhysicalDeviceDriverProperties>(); .getProperties2<vk::PhysicalDeviceProperties2, vk::PhysicalDeviceDriverProperties>();
const vk::PhysicalDeviceDriverProperties driver = const vk::PhysicalDeviceDriverProperties driver =
property_chain.get<vk::PhysicalDeviceDriverProperties>(); property_chain.get<vk::PhysicalDeviceDriverProperties>();

View File

@ -1,19 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
namespace Vulkan { namespace Vulkan {
MasterSemaphore::MasterSemaphore(const Instance& instance) : device{instance.GetDevice()} { MasterSemaphore::MasterSemaphore(const Instance& instance) : device{instance.GetDevice()} {
const vk::StructureChain semaphore_chain = { const vk::StructureChain semaphore_chain = {vk::SemaphoreCreateInfo{},
vk::SemaphoreCreateInfo{},
vk::SemaphoreTypeCreateInfoKHR{ vk::SemaphoreTypeCreateInfoKHR{
.semaphoreType = vk::SemaphoreType::eTimeline, .semaphoreType = vk::SemaphoreType::eTimeline,
.initialValue = 0, .initialValue = 0,
} }};
};
semaphore = device.createSemaphore(semaphore_chain.get()); semaphore = device.createSemaphore(semaphore_chain.get());
} }

View File

@ -4,8 +4,8 @@
#pragma once #pragma once
#include <atomic> #include <atomic>
#include <thread>
#include <limits> #include <limits>
#include <thread>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/vk_common.h" #include "video_core/renderer_vulkan/vk_common.h"
@ -78,7 +78,8 @@ public:
.pValues = &tick, .pValues = &tick,
}; };
while (device.waitSemaphoresKHR(&wait_info, WAIT_TIMEOUT) != vk::Result::eSuccess) {} while (device.waitSemaphoresKHR(&wait_info, WAIT_TIMEOUT) != vk::Result::eSuccess) {
}
Refresh(); Refresh();
} }

View File

@ -5,14 +5,14 @@
#include <filesystem> #include <filesystem>
#include "common/common_paths.h" #include "common/common_paths.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/microprofile.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/settings.h" #include "common/microprofile.h"
#include "common/settings.h"
#include "video_core/renderer_vulkan/pica_to_vk.h" #include "video_core/renderer_vulkan/pica_to_vk.h"
#include "video_core/renderer_vulkan/vk_descriptor_manager.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_pipeline_cache.h" #include "video_core/renderer_vulkan/vk_pipeline_cache.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h" #include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_descriptor_manager.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
namespace Vulkan { namespace Vulkan {
@ -62,7 +62,8 @@ vk::ShaderStageFlagBits ToVkShaderStage(std::size_t index) {
return vk::ShaderStageFlagBits::eVertex; return vk::ShaderStageFlagBits::eVertex;
} }
[[nodiscard]] bool IsAttribFormatSupported(const VertexAttribute& attrib, const Instance& instance) { [[nodiscard]] bool IsAttribFormatSupported(const VertexAttribute& attrib,
const Instance& instance) {
static std::unordered_map<vk::Format, bool> format_support_cache; static std::unordered_map<vk::Format, bool> format_support_cache;
vk::PhysicalDevice physical_device = instance.GetPhysicalDevice(); vk::PhysicalDevice physical_device = instance.GetPhysicalDevice();
@ -70,8 +71,10 @@ vk::ShaderStageFlagBits ToVkShaderStage(std::size_t index) {
auto [it, new_format] = format_support_cache.try_emplace(format, false); auto [it, new_format] = format_support_cache.try_emplace(format, false);
if (new_format) { if (new_format) {
LOG_INFO(Render_Vulkan, "Quering support for format {}", vk::to_string(format)); LOG_INFO(Render_Vulkan, "Quering support for format {}", vk::to_string(format));
const vk::FormatFeatureFlags features = physical_device.getFormatProperties(format).bufferFeatures; const vk::FormatFeatureFlags features =
it->second = (features & vk::FormatFeatureFlagBits::eVertexBuffer) == vk::FormatFeatureFlagBits::eVertexBuffer; physical_device.getFormatProperties(format).bufferFeatures;
it->second = (features & vk::FormatFeatureFlagBits::eVertexBuffer) ==
vk::FormatFeatureFlagBits::eVertexBuffer;
} }
return it->second; return it->second;
@ -79,7 +82,8 @@ vk::ShaderStageFlagBits ToVkShaderStage(std::size_t index) {
PipelineCache::PipelineCache(const Instance& instance, Scheduler& scheduler, PipelineCache::PipelineCache(const Instance& instance, Scheduler& scheduler,
RenderpassCache& renderpass_cache, DescriptorManager& desc_manager) RenderpassCache& renderpass_cache, DescriptorManager& desc_manager)
: instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache}, desc_manager{desc_manager} { : instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache},
desc_manager{desc_manager} {
trivial_vertex_shader = Compile(GenerateTrivialVertexShader(), vk::ShaderStageFlagBits::eVertex, trivial_vertex_shader = Compile(GenerateTrivialVertexShader(), vk::ShaderStageFlagBits::eVertex,
instance.GetDevice(), ShaderOptimization::Debug); instance.GetDevice(), ShaderOptimization::Debug);
} }
@ -211,8 +215,7 @@ bool PipelineCache::UseProgrammableVertexShader(const Pica::Regs& regs,
ASSERT(is_supported || attrib.size == 3); ASSERT(is_supported || attrib.size == 3);
config.state.attrib_types[location] = attrib.type.Value(); config.state.attrib_types[location] = attrib.type.Value();
config.state.emulated_attrib_locations[location] = config.state.emulated_attrib_locations[location] = is_supported ? 0 : emulated_attrib_loc++;
is_supported ? 0 : emulated_attrib_loc++;
} }
auto [handle, result] = auto [handle, result] =
@ -223,7 +226,8 @@ bool PipelineCache::UseProgrammableVertexShader(const Pica::Regs& regs,
return false; return false;
} }
scheduler.Record([this, handle = handle, hash = config.Hash()](vk::CommandBuffer, vk::CommandBuffer) { scheduler.Record(
[this, handle = handle, hash = config.Hash()](vk::CommandBuffer, vk::CommandBuffer) {
current_shaders[ProgramType::VS] = handle; current_shaders[ProgramType::VS] = handle;
shader_hashes[ProgramType::VS] = hash; shader_hashes[ProgramType::VS] = hash;
}); });
@ -242,7 +246,8 @@ void PipelineCache::UseFixedGeometryShader(const Pica::Regs& regs) {
const PicaFixedGSConfig gs_config{regs}; const PicaFixedGSConfig gs_config{regs};
scheduler.Record([this, gs_config](vk::CommandBuffer, vk::CommandBuffer) { scheduler.Record([this, gs_config](vk::CommandBuffer, vk::CommandBuffer) {
vk::ShaderModule handle = fixed_geometry_shaders.Get(gs_config, vk::ShaderStageFlagBits::eGeometry, vk::ShaderModule handle =
fixed_geometry_shaders.Get(gs_config, vk::ShaderStageFlagBits::eGeometry,
instance.GetDevice(), ShaderOptimization::High); instance.GetDevice(), ShaderOptimization::High);
current_shaders[ProgramType::GS] = handle; current_shaders[ProgramType::GS] = handle;
shader_hashes[ProgramType::GS] = gs_config.Hash(); shader_hashes[ProgramType::GS] = gs_config.Hash();
@ -256,7 +261,8 @@ void PipelineCache::UseTrivialGeometryShader() {
}); });
} }
MICROPROFILE_DEFINE(Vulkan_FragmentGeneration, "Vulkan", "Fragment Shader Compilation", MP_RGB(255, 100, 100)); MICROPROFILE_DEFINE(Vulkan_FragmentGeneration, "Vulkan", "Fragment Shader Compilation",
MP_RGB(255, 100, 100));
void PipelineCache::UseFragmentShader(const Pica::Regs& regs) { void PipelineCache::UseFragmentShader(const Pica::Regs& regs) {
const PicaFSConfig config{regs, instance}; const PicaFSConfig config{regs, instance};
@ -322,22 +328,19 @@ void PipelineCache::ApplyDynamic(const PipelineInfo& info) {
const bool is_dirty = scheduler.IsStateDirty(StateFlags::Pipeline); const bool is_dirty = scheduler.IsStateDirty(StateFlags::Pipeline);
PipelineInfo current = current_info; PipelineInfo current = current_info;
scheduler.Record([this, info, is_dirty, current](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { scheduler.Record([this, info, is_dirty, current](vk::CommandBuffer render_cmdbuf,
if (info.dynamic.stencil_compare_mask != vk::CommandBuffer) {
current.dynamic.stencil_compare_mask || if (info.dynamic.stencil_compare_mask != current.dynamic.stencil_compare_mask || is_dirty) {
is_dirty) {
render_cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack, render_cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack,
info.dynamic.stencil_compare_mask); info.dynamic.stencil_compare_mask);
} }
if (info.dynamic.stencil_write_mask != current.dynamic.stencil_write_mask || if (info.dynamic.stencil_write_mask != current.dynamic.stencil_write_mask || is_dirty) {
is_dirty) {
render_cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack, render_cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack,
info.dynamic.stencil_write_mask); info.dynamic.stencil_write_mask);
} }
if (info.dynamic.stencil_reference != current.dynamic.stencil_reference || if (info.dynamic.stencil_reference != current.dynamic.stencil_reference || is_dirty) {
is_dirty) {
render_cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack, render_cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
info.dynamic.stencil_reference); info.dynamic.stencil_reference);
} }
@ -364,8 +367,7 @@ void PipelineCache::ApplyDynamic(const PipelineInfo& info) {
render_cmdbuf.setDepthTestEnableEXT(info.depth_stencil.depth_test_enable); render_cmdbuf.setDepthTestEnableEXT(info.depth_stencil.depth_test_enable);
} }
if (info.depth_stencil.depth_write_enable != if (info.depth_stencil.depth_write_enable != current.depth_stencil.depth_write_enable ||
current.depth_stencil.depth_write_enable ||
is_dirty) { is_dirty) {
render_cmdbuf.setDepthWriteEnableEXT(info.depth_stencil.depth_write_enable); render_cmdbuf.setDepthWriteEnableEXT(info.depth_stencil.depth_write_enable);
} }
@ -385,8 +387,7 @@ void PipelineCache::ApplyDynamic(const PipelineInfo& info) {
info.depth_stencil.stencil_pass_op != current.depth_stencil.stencil_pass_op || info.depth_stencil.stencil_pass_op != current.depth_stencil.stencil_pass_op ||
info.depth_stencil.stencil_depth_fail_op != info.depth_stencil.stencil_depth_fail_op !=
current.depth_stencil.stencil_depth_fail_op || current.depth_stencil.stencil_depth_fail_op ||
info.depth_stencil.stencil_compare_op != info.depth_stencil.stencil_compare_op != current.depth_stencil.stencil_compare_op ||
current.depth_stencil.stencil_compare_op ||
is_dirty) { is_dirty) {
render_cmdbuf.setStencilOpEXT( render_cmdbuf.setStencilOpEXT(
vk::StencilFaceFlagBits::eFrontAndBack, vk::StencilFaceFlagBits::eFrontAndBack,
@ -443,10 +444,10 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
const bool is_supported = IsAttribFormatSupported(attrib, instance); const bool is_supported = IsAttribFormatSupported(attrib, instance);
ASSERT_MSG(is_supported || attrib.size == 3); ASSERT_MSG(is_supported || attrib.size == 3);
attributes[i] = vk::VertexInputAttributeDescription{.location = attrib.location, attributes[i] = vk::VertexInputAttributeDescription{
.location = attrib.location,
.binding = attrib.binding, .binding = attrib.binding,
.format = is_supported ? format .format = is_supported ? format : ToVkAttributeFormat(attrib.type, 2),
: ToVkAttributeFormat(attrib.type, 2),
.offset = attrib.offset}; .offset = attrib.offset};
// When the requested 3-component vertex format is unsupported by the hardware // When the requested 3-component vertex format is unsupported by the hardware
@ -454,8 +455,10 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
// by the vertex shader. // by the vertex shader.
if (!is_supported) { if (!is_supported) {
const u32 location = MAX_VERTEX_ATTRIBUTES + emulated_attrib_count++; const u32 location = MAX_VERTEX_ATTRIBUTES + emulated_attrib_count++;
LOG_WARNING(Render_Vulkan, "\nEmulating attrib {} at location {}\n", attrib.location, location); LOG_WARNING(Render_Vulkan, "\nEmulating attrib {} at location {}\n", attrib.location,
attributes[location] = vk::VertexInputAttributeDescription{.location = location, location);
attributes[location] = vk::VertexInputAttributeDescription{
.location = location,
.binding = attrib.binding, .binding = attrib.binding,
.format = ToVkAttributeFormat(attrib.type, 1), .format = ToVkAttributeFormat(attrib.type, 1),
.offset = attrib.offset + AttribBytes(attrib.type, 2)}; .offset = attrib.offset + AttribBytes(attrib.type, 2)};
@ -465,7 +468,8 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
const vk::PipelineVertexInputStateCreateInfo vertex_input_info = { const vk::PipelineVertexInputStateCreateInfo vertex_input_info = {
.vertexBindingDescriptionCount = info.vertex_layout.binding_count, .vertexBindingDescriptionCount = info.vertex_layout.binding_count,
.pVertexBindingDescriptions = bindings.data(), .pVertexBindingDescriptions = bindings.data(),
.vertexAttributeDescriptionCount = info.vertex_layout.attribute_count + emulated_attrib_count, .vertexAttributeDescriptionCount =
info.vertex_layout.attribute_count + emulated_attrib_count,
.pVertexAttributeDescriptions = attributes.data()}; .pVertexAttributeDescriptions = attributes.data()};
const vk::PipelineInputAssemblyStateCreateInfo input_assembly = { const vk::PipelineInputAssemblyStateCreateInfo input_assembly = {

View File

@ -9,8 +9,8 @@
#include "common/hash.h" #include "common/hash.h"
#include "video_core/rasterizer_cache/pixel_format.h" #include "video_core/rasterizer_cache/pixel_format.h"
#include "video_core/regs.h" #include "video_core/regs.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/renderer_vulkan/vk_shader_gen_spv.h" #include "video_core/renderer_vulkan/vk_shader_gen_spv.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/shader/shader_cache.h" #include "video_core/shader/shader_cache.h"
namespace Vulkan { namespace Vulkan {
@ -100,8 +100,8 @@ struct PipelineInfo {
const bool has_stencil = depth_attachment == VideoCore::PixelFormat::D24S8; const bool has_stencil = depth_attachment == VideoCore::PixelFormat::D24S8;
const bool depth_write = const bool depth_write =
depth_stencil.depth_test_enable && depth_stencil.depth_write_enable; depth_stencil.depth_test_enable && depth_stencil.depth_write_enable;
const bool stencil_write = has_stencil && depth_stencil.stencil_test_enable && const bool stencil_write =
dynamic.stencil_write_mask != 0; has_stencil && depth_stencil.stencil_test_enable && dynamic.stencil_write_mask != 0;
return depth_write || stencil_write; return depth_write || stencil_write;
} }
@ -119,8 +119,8 @@ using FixedGeometryShaders = Pica::Shader::ShaderCache<PicaFixedGSConfig, vk::Sh
using FragmentShadersGLSL = using FragmentShadersGLSL =
Pica::Shader::ShaderCache<PicaFSConfig, vk::ShaderModule, &Compile, &GenerateFragmentShader>; Pica::Shader::ShaderCache<PicaFSConfig, vk::ShaderModule, &Compile, &GenerateFragmentShader>;
using FragmentShadersSPV = using FragmentShadersSPV = Pica::Shader::ShaderCache<PicaFSConfig, vk::ShaderModule, &CompileSPV,
Pica::Shader::ShaderCache<PicaFSConfig, vk::ShaderModule, &CompileSPV, &GenerateFragmentShaderSPV>; &GenerateFragmentShaderSPV>;
class Instance; class Instance;
class Scheduler; class Scheduler;
@ -132,8 +132,8 @@ class DescriptorManager;
*/ */
class PipelineCache { class PipelineCache {
public: public:
PipelineCache(const Instance& instance, Scheduler& scheduler, PipelineCache(const Instance& instance, Scheduler& scheduler, RenderpassCache& renderpass_cache,
RenderpassCache& renderpass_cache, DescriptorManager& desc_manager); DescriptorManager& desc_manager);
~PipelineCache(); ~PipelineCache();
/// Loads the pipeline cache stored to disk /// Loads the pipeline cache stored to disk

View File

@ -63,8 +63,7 @@ vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& e
#elif defined(VK_USE_PLATFORM_METAL_EXT) #elif defined(VK_USE_PLATFORM_METAL_EXT)
if (window_info.type == Frontend::WindowSystemType::MacOS) { if (window_info.type == Frontend::WindowSystemType::MacOS) {
const vk::MetalSurfaceCreateInfoEXT macos_ci = { const vk::MetalSurfaceCreateInfoEXT macos_ci = {
.pLayer = static_cast<const CAMetalLayer*>(window_info.render_surface) .pLayer = static_cast<const CAMetalLayer*>(window_info.render_surface)};
};
if (instance.createMetalSurfaceEXT(&macos_ci, nullptr, &surface) != vk::Result::eSuccess) { if (instance.createMetalSurfaceEXT(&macos_ci, nullptr, &surface) != vk::Result::eSuccess) {
LOG_CRITICAL(Render_Vulkan, "Failed to initialize MacOS surface"); LOG_CRITICAL(Render_Vulkan, "Failed to initialize MacOS surface");
@ -74,10 +73,10 @@ vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& e
#elif defined(VK_USE_PLATFORM_ANDROID_KHR) #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
if (window_info.type == Frontend::WindowSystemType::Android) { if (window_info.type == Frontend::WindowSystemType::Android) {
vk::AndroidSurfaceCreateInfoKHR android_ci = { vk::AndroidSurfaceCreateInfoKHR android_ci = {
.window = reinterpret_cast<ANativeWindow*>(window_info.render_surface) .window = reinterpret_cast<ANativeWindow*>(window_info.render_surface)};
};
if (instance.createAndroidSurfaceKHR(&android_ci, nullptr, &surface) != vk::Result::eSuccess) { if (instance.createAndroidSurfaceKHR(&android_ci, nullptr, &surface) !=
vk::Result::eSuccess) {
LOG_CRITICAL(Render_Vulkan, "Failed to initialize Android surface"); LOG_CRITICAL(Render_Vulkan, "Failed to initialize Android surface");
UNREACHABLE(); UNREACHABLE();
} }
@ -145,7 +144,8 @@ std::vector<const char*> GetInstanceExtensions(Frontend::WindowSystemType window
} }
for (const char* extension : extensions) { for (const char* extension : extensions) {
const auto iter = std::find_if(properties.begin(), properties.end(), [extension](const auto& prop) { const auto iter =
std::find_if(properties.begin(), properties.end(), [extension](const auto& prop) {
return std::strcmp(extension, prop.extensionName) == 0; return std::strcmp(extension, prop.extensionName) == 0;
}); });

View File

@ -239,7 +239,8 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
const u32 data_size = loader.byte_count * vertex_num; const u32 data_size = loader.byte_count * vertex_num;
res_cache.FlushRegion(data_addr, data_size); res_cache.FlushRegion(data_addr, data_size);
std::memcpy(array_ptr + buffer_offset, VideoCore::g_memory->GetPhysicalPointer(data_addr), data_size); std::memcpy(array_ptr + buffer_offset, VideoCore::g_memory->GetPhysicalPointer(data_addr),
data_size);
// Create the binding associated with this loader // Create the binding associated with this loader
VertexBinding& binding = layout.bindings[layout.binding_count]; VertexBinding& binding = layout.bindings[layout.binding_count];
@ -259,12 +260,11 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
SetupFixedAttribs(); SetupFixedAttribs();
// Bind the generated bindings // Bind the generated bindings
scheduler.Record([this, layout = pipeline_info.vertex_layout, scheduler.Record([this, layout = pipeline_info.vertex_layout, offsets = binding_offsets](
offsets = binding_offsets](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
std::array<vk::Buffer, 16> buffers; std::array<vk::Buffer, 16> buffers;
buffers.fill(vertex_buffer.GetHandle()); buffers.fill(vertex_buffer.GetHandle());
render_cmdbuf.bindVertexBuffers(0, layout.binding_count, buffers.data(), render_cmdbuf.bindVertexBuffers(0, layout.binding_count, buffers.data(), offsets.data());
offsets.data());
}); });
} }
@ -367,7 +367,8 @@ bool RasterizerVulkan::AccelerateDrawBatch(bool is_indexed) {
bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) { bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) {
const auto& regs = Pica::g_state.regs; const auto& regs = Pica::g_state.regs;
const auto [vs_input_index_min, vs_input_index_max, vs_input_size] = AnalyzeVertexArray(is_indexed); const auto [vs_input_index_min, vs_input_index_max, vs_input_size] =
AnalyzeVertexArray(is_indexed);
if (vs_input_size > VERTEX_BUFFER_SIZE) { if (vs_input_size > VERTEX_BUFFER_SIZE) {
LOG_WARNING(Render_Vulkan, "Too large vertex input size {}", vs_input_size); LOG_WARNING(Render_Vulkan, "Too large vertex input size {}", vs_input_size);
@ -406,13 +407,16 @@ bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) {
index_buffer.Commit(index_buffer_size); index_buffer.Commit(index_buffer_size);
scheduler.Record([this, offset = index_offset, num_vertices = regs.pipeline.num_vertices, scheduler.Record([this, offset = index_offset, num_vertices = regs.pipeline.num_vertices,
index_u16, vertex_offset = vs_input_index_min](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { index_u16, vertex_offset = vs_input_index_min](
const vk::IndexType index_type = index_u16 ? vk::IndexType::eUint16 : vk::IndexType::eUint8EXT; vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const vk::IndexType index_type =
index_u16 ? vk::IndexType::eUint16 : vk::IndexType::eUint8EXT;
render_cmdbuf.bindIndexBuffer(index_buffer.GetHandle(), offset, index_type); render_cmdbuf.bindIndexBuffer(index_buffer.GetHandle(), offset, index_type);
render_cmdbuf.drawIndexed(num_vertices, 1, 0, -vertex_offset, 0); render_cmdbuf.drawIndexed(num_vertices, 1, 0, -vertex_offset, 0);
}); });
} else { } else {
scheduler.Record([num_vertices = regs.pipeline.num_vertices](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { scheduler.Record([num_vertices = regs.pipeline.num_vertices](
vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
render_cmdbuf.draw(num_vertices, 1, 0, 0); render_cmdbuf.draw(num_vertices, 1, 0, 0);
}); });
} }
@ -718,8 +722,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
.render_area = vk::Rect2D{.offset = {static_cast<s32>(draw_rect.left), .render_area = vk::Rect2D{.offset = {static_cast<s32>(draw_rect.left),
static_cast<s32>(draw_rect.bottom)}, static_cast<s32>(draw_rect.bottom)},
.extent = {draw_rect.GetWidth(), draw_rect.GetHeight()}}, .extent = {draw_rect.GetWidth(), draw_rect.GetHeight()}},
.clear = {} .clear = {}};
};
renderpass_cache.EnterRenderpass(renderpass_info); renderpass_cache.EnterRenderpass(renderpass_info);
@ -1043,10 +1046,7 @@ bool RasterizerVulkan::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
void RasterizerVulkan::MakeSoftwareVertexLayout() { void RasterizerVulkan::MakeSoftwareVertexLayout() {
constexpr std::array sizes = {4, 4, 2, 2, 2, 1, 4, 3}; constexpr std::array sizes = {4, 4, 2, 2, 2, 1, 4, 3};
software_layout = VertexLayout{ software_layout = VertexLayout{.binding_count = 1, .attribute_count = 8};
.binding_count = 1,
.attribute_count = 8
};
for (u32 i = 0; i < software_layout.binding_count; i++) { for (u32 i = 0; i < software_layout.binding_count; i++) {
VertexBinding& binding = software_layout.bindings[i]; VertexBinding& binding = software_layout.bindings[i];

View File

@ -94,21 +94,19 @@ void RenderpassCache::EnterRenderpass(const RenderpassState& state) {
return; return;
} }
scheduler.Record([should_end = bool(current_state.renderpass), state] scheduler.Record([should_end = bool(current_state.renderpass),
(vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { state](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
if (should_end) { if (should_end) {
render_cmdbuf.endRenderPass(); render_cmdbuf.endRenderPass();
} }
const vk::RenderPassBeginInfo renderpass_begin_info = { const vk::RenderPassBeginInfo renderpass_begin_info = {.renderPass = state.renderpass,
.renderPass = state.renderpass,
.framebuffer = state.framebuffer, .framebuffer = state.framebuffer,
.renderArea = state.render_area, .renderArea = state.render_area,
.clearValueCount = 1, .clearValueCount = 1,
.pClearValues = &state.clear}; .pClearValues = &state.clear};
render_cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline); render_cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
}); });
if (is_dirty) { if (is_dirty) {
@ -123,9 +121,8 @@ void RenderpassCache::ExitRenderpass() {
return; return;
} }
scheduler.Record([](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { scheduler.Record(
render_cmdbuf.endRenderPass(); [](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { render_cmdbuf.endRenderPass(); });
});
current_state = {}; current_state = {};
} }

View File

@ -27,6 +27,7 @@ struct RenderpassState {
class RenderpassCache { class RenderpassCache {
static constexpr u32 MAX_COLOR_FORMATS = 5; static constexpr u32 MAX_COLOR_FORMATS = 5;
static constexpr u32 MAX_DEPTH_FORMATS = 4; static constexpr u32 MAX_DEPTH_FORMATS = 4;
public: public:
RenderpassCache(const Instance& instance, Scheduler& scheduler); RenderpassCache(const Instance& instance, Scheduler& scheduler);
~RenderpassCache(); ~RenderpassCache();

View File

@ -3,9 +3,9 @@
#include <cstddef> #include <cstddef>
#include <optional> #include <optional>
#include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/renderer_vulkan/vk_resource_pool.h"
namespace Vulkan { namespace Vulkan {
@ -16,7 +16,8 @@ std::size_t ResourcePool::CommitResource() {
// Refresh semaphore to query updated results // Refresh semaphore to query updated results
master_semaphore->Refresh(); master_semaphore->Refresh();
const u64 gpu_tick = master_semaphore->KnownGpuTick(); const u64 gpu_tick = master_semaphore->KnownGpuTick();
const auto search = [this, gpu_tick](std::size_t begin, std::size_t end) -> std::optional<std::size_t> { const auto search = [this, gpu_tick](std::size_t begin,
std::size_t end) -> std::optional<std::size_t> {
for (std::size_t iterator = begin; iterator < end; ++iterator) { for (std::size_t iterator = begin; iterator < end; ++iterator) {
if (gpu_tick >= ticks[iterator]) { if (gpu_tick >= ticks[iterator]) {
ticks[iterator] = master_semaphore->CurrentTick(); ticks[iterator] = master_semaphore->CurrentTick();
@ -85,13 +86,13 @@ void CommandPool::Allocate(std::size_t begin, std::size_t end) {
const vk::CommandPoolCreateInfo pool_create_info = { const vk::CommandPoolCreateInfo pool_create_info = {
.flags = vk::CommandPoolCreateFlagBits::eTransient | .flags = vk::CommandPoolCreateFlagBits::eTransient |
vk::CommandPoolCreateFlagBits::eResetCommandBuffer, vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
.queueFamilyIndex = instance.GetGraphicsQueueFamilyIndex() .queueFamilyIndex = instance.GetGraphicsQueueFamilyIndex()};
};
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
pool.handle = device.createCommandPool(pool_create_info); pool.handle = device.createCommandPool(pool_create_info);
const vk::CommandBufferAllocateInfo buffer_alloc_info = {.commandPool = pool.handle, const vk::CommandBufferAllocateInfo buffer_alloc_info = {
.commandPool = pool.handle,
.level = vk::CommandBufferLevel::ePrimary, .level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = COMMAND_BUFFER_POOL_SIZE}; .commandBufferCount = COMMAND_BUFFER_POOL_SIZE};
@ -125,8 +126,8 @@ void DescriptorPool::Allocate(std::size_t begin, std::size_t end) {
vk::DescriptorPool& pool = pools.emplace_back(); vk::DescriptorPool& pool = pools.emplace_back();
// Choose a sane pool size good for most games // Choose a sane pool size good for most games
static constexpr std::array<vk::DescriptorPoolSize, 5> pool_sizes = {{ static constexpr std::array<vk::DescriptorPoolSize, 5> pool_sizes = {
{vk::DescriptorType::eUniformBuffer, 4096}, {{vk::DescriptorType::eUniformBuffer, 4096},
{vk::DescriptorType::eSampledImage, 4096}, {vk::DescriptorType::eSampledImage, 4096},
{vk::DescriptorType::eSampler, 4096}, {vk::DescriptorType::eSampler, 4096},
{vk::DescriptorType::eUniformTexelBuffer, 2048}, {vk::DescriptorType::eUniformTexelBuffer, 2048},

View File

@ -4,14 +4,15 @@
#include <mutex> #include <mutex>
#include <utility> #include <utility>
#include "common/microprofile.h" #include "common/microprofile.h"
#include "core/settings.h" #include "common/settings.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
namespace Vulkan { namespace Vulkan {
void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer render_cmdbuf, vk::CommandBuffer upload_cmdbuf) { void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer render_cmdbuf,
vk::CommandBuffer upload_cmdbuf) {
auto command = first; auto command = first;
while (command != nullptr) { while (command != nullptr) {
auto next = command->GetNext(); auto next = command->GetNext();
@ -25,9 +26,10 @@ void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer render_cmdbuf, vk::Co
last = nullptr; last = nullptr;
} }
Scheduler::Scheduler(const Instance& instance, RenderpassCache& renderpass_cache, RendererVulkan& renderer) Scheduler::Scheduler(const Instance& instance, RenderpassCache& renderpass_cache,
: instance{instance}, renderpass_cache{renderpass_cache}, renderer{renderer}, master_semaphore{instance}, RendererVulkan& renderer)
command_pool{instance, master_semaphore}, stop_requested{false}, : instance{instance}, renderpass_cache{renderpass_cache}, renderer{renderer},
master_semaphore{instance}, command_pool{instance, master_semaphore}, stop_requested{false},
use_worker_thread{Settings::values.async_command_recording} { use_worker_thread{Settings::values.async_command_recording} {
AllocateWorkerCommandBuffers(); AllocateWorkerCommandBuffers();
if (use_worker_thread) { if (use_worker_thread) {
@ -120,8 +122,7 @@ void Scheduler::WorkerThread() {
void Scheduler::AllocateWorkerCommandBuffers() { void Scheduler::AllocateWorkerCommandBuffers() {
const vk::CommandBufferBeginInfo begin_info = { const vk::CommandBufferBeginInfo begin_info = {
.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
};
upload_cmdbuf = command_pool.Commit(); upload_cmdbuf = command_pool.Commit();
upload_cmdbuf.begin(begin_info); upload_cmdbuf.begin(begin_info);
@ -137,8 +138,8 @@ void Scheduler::SubmitExecution(vk::Semaphore signal_semaphore, vk::Semaphore wa
state = StateFlags::AllDirty; state = StateFlags::AllDirty;
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
Record([signal_semaphore, wait_semaphore, signal_value, this] Record([signal_semaphore, wait_semaphore, signal_value, this](vk::CommandBuffer render_cmdbuf,
(vk::CommandBuffer render_cmdbuf, vk::CommandBuffer upload_cmdbuf) { vk::CommandBuffer upload_cmdbuf) {
MICROPROFILE_SCOPE(Vulkan_Submit); MICROPROFILE_SCOPE(Vulkan_Submit);
upload_cmdbuf.end(); upload_cmdbuf.end();
render_cmdbuf.end(); render_cmdbuf.end();

View File

@ -10,8 +10,8 @@
#include <utility> #include <utility>
#include <queue> #include <queue>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/common_types.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h"
#include "video_core/renderer_vulkan/vk_master_semaphore.h" #include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/renderer_vulkan/vk_resource_pool.h" #include "video_core/renderer_vulkan/vk_resource_pool.h"
@ -105,7 +105,8 @@ private:
public: public:
virtual ~Command() = default; virtual ~Command() = default;
virtual void Execute(vk::CommandBuffer render_cmdbuf, vk::CommandBuffer upload_cmdbuf) const = 0; virtual void Execute(vk::CommandBuffer render_cmdbuf,
vk::CommandBuffer upload_cmdbuf) const = 0;
Command* GetNext() const { Command* GetNext() const {
return next; return next;
@ -128,7 +129,8 @@ private:
TypedCommand(TypedCommand&&) = delete; TypedCommand(TypedCommand&&) = delete;
TypedCommand& operator=(TypedCommand&&) = delete; TypedCommand& operator=(TypedCommand&&) = delete;
void Execute(vk::CommandBuffer render_cmdbuf, vk::CommandBuffer upload_cmdbuf) const override { void Execute(vk::CommandBuffer render_cmdbuf,
vk::CommandBuffer upload_cmdbuf) const override {
command(render_cmdbuf, upload_cmdbuf); command(render_cmdbuf, upload_cmdbuf);
} }

View File

@ -10,8 +10,8 @@
#include "video_core/pica_state.h" #include "video_core/pica_state.h"
#include "video_core/regs_framebuffer.h" #include "video_core/regs_framebuffer.h"
#include "video_core/renderer_opengl/gl_shader_decompiler.h" #include "video_core/renderer_opengl/gl_shader_decompiler.h"
#include "video_core/renderer_vulkan/vk_shader_gen.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_shader_gen.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
using Pica::FramebufferRegs; using Pica::FramebufferRegs;
@ -141,9 +141,9 @@ PicaFSConfig::PicaFSConfig(const Pica::Regs& regs, const Instance& instance) {
state.fog_mode.Assign(regs.texturing.fog_mode); state.fog_mode.Assign(regs.texturing.fog_mode);
state.fog_flip.Assign(regs.texturing.fog_flip != 0); state.fog_flip.Assign(regs.texturing.fog_flip != 0);
state.combiner_buffer_input.Assign(regs.texturing.tev_combiner_buffer_input.update_mask_rgb.Value() | state.combiner_buffer_input.Assign(
regs.texturing.tev_combiner_buffer_input.update_mask_a.Value() regs.texturing.tev_combiner_buffer_input.update_mask_rgb.Value() |
<< 4); regs.texturing.tev_combiner_buffer_input.update_mask_a.Value() << 4);
// Fragment lighting // Fragment lighting
@ -155,14 +155,18 @@ PicaFSConfig::PicaFSConfig(const Pica::Regs& regs, const Instance& instance) {
const auto& light = regs.lighting.light[num]; const auto& light = regs.lighting.light[num];
state.lighting.light[light_index].num.Assign(num); state.lighting.light[light_index].num.Assign(num);
state.lighting.light[light_index].directional.Assign(light.config.directional != 0); state.lighting.light[light_index].directional.Assign(light.config.directional != 0);
state.lighting.light[light_index].two_sided_diffuse.Assign(light.config.two_sided_diffuse != 0); state.lighting.light[light_index].two_sided_diffuse.Assign(light.config.two_sided_diffuse !=
state.lighting.light[light_index].geometric_factor_0.Assign(light.config.geometric_factor_0 != 0); 0);
state.lighting.light[light_index].geometric_factor_1.Assign(light.config.geometric_factor_1 != 0); state.lighting.light[light_index].geometric_factor_0.Assign(
light.config.geometric_factor_0 != 0);
state.lighting.light[light_index].geometric_factor_1.Assign(
light.config.geometric_factor_1 != 0);
state.lighting.light[light_index].dist_atten_enable.Assign( state.lighting.light[light_index].dist_atten_enable.Assign(
!regs.lighting.IsDistAttenDisabled(num)); !regs.lighting.IsDistAttenDisabled(num));
state.lighting.light[light_index].spot_atten_enable.Assign( state.lighting.light[light_index].spot_atten_enable.Assign(
!regs.lighting.IsSpotAttenDisabled(num)); !regs.lighting.IsSpotAttenDisabled(num));
state.lighting.light[light_index].shadow_enable.Assign(!regs.lighting.IsShadowDisabled(num)); state.lighting.light[light_index].shadow_enable.Assign(
!regs.lighting.IsShadowDisabled(num));
} }
state.lighting.lut_d0.enable.Assign(regs.lighting.config1.disable_lut_d0 == 0); state.lighting.lut_d0.enable.Assign(regs.lighting.config1.disable_lut_d0 == 0);
@ -243,7 +247,6 @@ PicaFSConfig::PicaFSConfig(const Pica::Regs& regs, const Instance& instance) {
state.shadow_texture_orthographic.Assign(regs.texturing.shadow.orthographic != 0); state.shadow_texture_orthographic.Assign(regs.texturing.shadow.orthographic != 0);
} }
void PicaShaderConfigCommon::Init(const Pica::ShaderRegs& regs, Pica::Shader::ShaderSetup& setup) { void PicaShaderConfigCommon::Init(const Pica::ShaderRegs& regs, Pica::Shader::ShaderSetup& setup) {
program_hash = setup.GetProgramCodeHash(); program_hash = setup.GetProgramCodeHash();
swizzle_hash = setup.GetSwizzleDataHash(); swizzle_hash = setup.GetSwizzleDataHash();
@ -510,7 +513,8 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper
out += "color_results_1 + color_results_2 - vec3(0.5)"; out += "color_results_1 + color_results_2 - vec3(0.5)";
break; break;
case Operation::Lerp: case Operation::Lerp:
out += "color_results_1 * color_results_3 + color_results_2 * (vec3(1.0) - color_results_3)"; out +=
"color_results_1 * color_results_3 + color_results_2 * (vec3(1.0) - color_results_3)";
break; break;
case Operation::Subtract: case Operation::Subtract:
out += "color_results_1 - color_results_2"; out += "color_results_1 - color_results_2";
@ -523,8 +527,7 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper
break; break;
case Operation::Dot3_RGB: case Operation::Dot3_RGB:
case Operation::Dot3_RGBA: case Operation::Dot3_RGBA:
out += out += "vec3(dot(color_results_1 - vec3(0.5), color_results_2 - vec3(0.5)) * 4.0)";
"vec3(dot(color_results_1 - vec3(0.5), color_results_2 - vec3(0.5)) * 4.0)";
break; break;
default: default:
out += "vec3(0.0)"; out += "vec3(0.0)";
@ -1566,7 +1569,8 @@ do {
// with fragment shader alone, so we emulate this behavior with the color mask. // with fragment shader alone, so we emulate this behavior with the color mask.
break; break;
default: default:
LOG_CRITICAL(HW_GPU, "Unhandled logic_op {:x}", static_cast<u32>(state.logic_op.Value())); LOG_CRITICAL(HW_GPU, "Unhandled logic_op {:x}",
static_cast<u32>(state.logic_op.Value()));
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
} }
@ -1672,7 +1676,8 @@ layout (set = 0, binding = 0, std140) uniform vs_config {
prefix = "u"; prefix = "u";
break; break;
default: default:
LOG_CRITICAL(Render_Vulkan, "Unknown attrib format {}", config.state.attrib_types[i]); LOG_CRITICAL(Render_Vulkan, "Unknown attrib format {}",
config.state.attrib_types[i]);
UNREACHABLE(); UNREACHABLE();
} }
@ -1684,7 +1689,8 @@ layout (set = 0, binding = 0, std140) uniform vs_config {
// Some 3-component attributes might be emulated by breaking them to vec2 + scalar. // Some 3-component attributes might be emulated by breaking them to vec2 + scalar.
// Define them here and combine them below // Define them here and combine them below
for (std::size_t i = 0; i < used_regs.size(); ++i) { for (std::size_t i = 0; i < used_regs.size(); ++i) {
if (const u32 location = config.state.emulated_attrib_locations[i]; location != 0 && used_regs[i]) { if (const u32 location = config.state.emulated_attrib_locations[i];
location != 0 && used_regs[i]) {
std::string_view type; std::string_view type;
switch (config.state.attrib_types[i]) { switch (config.state.attrib_types[i]) {
case Pica::PipelineRegs::VertexAttributeFormat::FLOAT: case Pica::PipelineRegs::VertexAttributeFormat::FLOAT:
@ -1698,11 +1704,13 @@ layout (set = 0, binding = 0, std140) uniform vs_config {
type = "uint"; type = "uint";
break; break;
default: default:
LOG_CRITICAL(Render_Vulkan, "Unknown attrib format {}", config.state.attrib_types[i]); LOG_CRITICAL(Render_Vulkan, "Unknown attrib format {}",
config.state.attrib_types[i]);
UNREACHABLE(); UNREACHABLE();
} }
out += fmt::format("layout(location = {}) in {} vs_in_typed_reg{}_part2;\n", location, type, i); out += fmt::format("layout(location = {}) in {} vs_in_typed_reg{}_part2;\n", location,
type, i);
} }
} }
@ -1712,7 +1720,9 @@ layout (set = 0, binding = 0, std140) uniform vs_config {
for (std::size_t i = 0; i < used_regs.size(); ++i) { for (std::size_t i = 0; i < used_regs.size(); ++i) {
if (used_regs[i]) { if (used_regs[i]) {
if (config.state.emulated_attrib_locations[i] != 0) { if (config.state.emulated_attrib_locations[i] != 0) {
out += fmt::format("vec4 vs_in_reg{0} = vec4(vec2(vs_in_typed_reg{0}), float(vs_in_typed_reg{0}_part2), 0.f);\n", i); out += fmt::format("vec4 vs_in_reg{0} = vec4(vec2(vs_in_typed_reg{0}), "
"float(vs_in_typed_reg{0}_part2), 0.f);\n",
i);
} else { } else {
out += fmt::format("vec4 vs_in_reg{0} = vec4(vs_in_typed_reg{0});\n", i); out += fmt::format("vec4 vs_in_reg{0} = vec4(vs_in_typed_reg{0});\n", i);
} }

View File

@ -16,7 +16,8 @@ using TevStageConfig = TexturingRegs::TevStageConfig;
namespace Vulkan { namespace Vulkan {
FragmentModule::FragmentModule(const PicaFSConfig& config) : Sirit::Module{0x00010300}, config{config} { FragmentModule::FragmentModule(const PicaFSConfig& config)
: Sirit::Module{0x00010300}, config{config} {
DefineArithmeticTypes(); DefineArithmeticTypes();
DefineUniformStructs(); DefineUniformStructs();
DefineInterface(); DefineInterface();
@ -82,13 +83,15 @@ void FragmentModule::Generate() {
void FragmentModule::WriteDepth() { void FragmentModule::WriteDepth() {
const Id input_pointer_id{TypePointer(spv::StorageClass::Input, f32_id)}; const Id input_pointer_id{TypePointer(spv::StorageClass::Input, f32_id)};
const Id gl_frag_coord_z{OpLoad(f32_id, OpAccessChain(input_pointer_id, gl_frag_coord_id, ConstU32(2u)))}; const Id gl_frag_coord_z{
OpLoad(f32_id, OpAccessChain(input_pointer_id, gl_frag_coord_id, ConstU32(2u)))};
const Id z_over_w{OpFma(f32_id, ConstF32(2.f), gl_frag_coord_z, ConstF32(-1.f))}; const Id z_over_w{OpFma(f32_id, ConstF32(2.f), gl_frag_coord_z, ConstF32(-1.f))};
const Id depth_scale{GetShaderDataMember(f32_id, ConstS32(2))}; const Id depth_scale{GetShaderDataMember(f32_id, ConstS32(2))};
const Id depth_offset{GetShaderDataMember(f32_id, ConstS32(3))}; const Id depth_offset{GetShaderDataMember(f32_id, ConstS32(3))};
const Id depth{OpFma(f32_id, z_over_w, depth_scale, depth_offset)}; const Id depth{OpFma(f32_id, z_over_w, depth_scale, depth_offset)};
if (config.state.depthmap_enable == Pica::RasterizerRegs::DepthBuffering::WBuffering) { if (config.state.depthmap_enable == Pica::RasterizerRegs::DepthBuffering::WBuffering) {
const Id gl_frag_coord_w{OpLoad(f32_id, OpAccessChain(input_pointer_id, gl_frag_coord_id, ConstU32(3u)))}; const Id gl_frag_coord_w{
OpLoad(f32_id, OpAccessChain(input_pointer_id, gl_frag_coord_id, ConstU32(3u)))};
const Id depth_over_w{OpFDiv(f32_id, depth, gl_frag_coord_w)}; const Id depth_over_w{OpFDiv(f32_id, depth, gl_frag_coord_w)};
OpStore(gl_frag_depth_id, depth_over_w); OpStore(gl_frag_depth_id, depth_over_w);
} else { } else {
@ -157,8 +160,10 @@ void FragmentModule::WriteLighting() {
const Id q_xyz{OpVectorShuffle(vec_ids.Get(3), q, q, 0, 1, 2)}; const Id q_xyz{OpVectorShuffle(vec_ids.Get(3), q, q, 0, 1, 2)};
const Id q_xyz_cross_v{OpCross(vec_ids.Get(3), q_xyz, v)}; const Id q_xyz_cross_v{OpCross(vec_ids.Get(3), q_xyz, v)};
const Id q_w{OpCompositeExtract(f32_id, q, 3)}; const Id q_w{OpCompositeExtract(f32_id, q, 3)};
const Id val1{OpFAdd(vec_ids.Get(3), q_xyz_cross_v, OpVectorTimesScalar(vec_ids.Get(3), v, q_w))}; const Id val1{
const Id val2{OpVectorTimesScalar(vec_ids.Get(3), OpCross(vec_ids.Get(3), q_xyz, val1), ConstF32(2.f))}; OpFAdd(vec_ids.Get(3), q_xyz_cross_v, OpVectorTimesScalar(vec_ids.Get(3), v, q_w))};
const Id val2{OpVectorTimesScalar(vec_ids.Get(3), OpCross(vec_ids.Get(3), q_xyz, val1),
ConstF32(2.f))};
return OpFAdd(vec_ids.Get(3), v, val2); return OpFAdd(vec_ids.Get(3), v, val2);
}; };
@ -189,7 +194,8 @@ void FragmentModule::WriteLighting() {
const Id index{OpSClamp(i32_id, pos_int, ConstS32(-128), ConstS32(127))}; const Id index{OpSClamp(i32_id, pos_int, ConstS32(-128), ConstS32(127))};
const Id neg_index{OpFNegate(f32_id, OpConvertSToF(f32_id, index))}; const Id neg_index{OpFNegate(f32_id, OpConvertSToF(f32_id, index))};
const Id delta{OpFma(f32_id, pos, ConstF32(128.f), neg_index)}; const Id delta{OpFma(f32_id, pos, ConstF32(128.f), neg_index)};
const Id increment{OpSelect(i32_id, OpSLessThan(bool_id, index, ConstS32(0)), ConstS32(256), ConstS32(0))}; const Id increment{
OpSelect(i32_id, OpSLessThan(bool_id, index, ConstS32(0)), ConstS32(256), ConstS32(0))};
return LookupLightingLUT(lut_index, OpIAdd(i32_id, index, increment), delta); return LookupLightingLUT(lut_index, OpIAdd(i32_id, index, increment), delta);
}; };
@ -203,7 +209,8 @@ void FragmentModule::WriteLighting() {
index = OpDot(f32_id, normal, OpNormalize(vec_ids.Get(3), half_vector)); index = OpDot(f32_id, normal, OpNormalize(vec_ids.Get(3), half_vector));
break; break;
case LightingRegs::LightingLutInput::VH: case LightingRegs::LightingLutInput::VH:
index = OpDot(f32_id, OpNormalize(vec_ids.Get(3), view), OpNormalize(vec_ids.Get(3), half_vector)); index = OpDot(f32_id, OpNormalize(vec_ids.Get(3), view),
OpNormalize(vec_ids.Get(3), half_vector));
break; break;
case LightingRegs::LightingLutInput::NV: case LightingRegs::LightingLutInput::NV:
index = OpDot(f32_id, normal, OpNormalize(vec_ids.Get(3), view)); index = OpDot(f32_id, normal, OpNormalize(vec_ids.Get(3), view));
@ -222,8 +229,10 @@ void FragmentModule::WriteLighting() {
// using the modified normal vector. // using the modified normal vector.
const Id normalized_half_vector{OpNormalize(vec_ids.Get(3), half_vector)}; const Id normalized_half_vector{OpNormalize(vec_ids.Get(3), half_vector)};
const Id normal_dot_half_vector{OpDot(f32_id, normal, normalized_half_vector)}; const Id normal_dot_half_vector{OpDot(f32_id, normal, normalized_half_vector)};
const Id normal_mul_dot{OpVectorTimesScalar(vec_ids.Get(3), normal, normal_dot_half_vector)}; const Id normal_mul_dot{
const Id half_angle_proj{OpFSub(vec_ids.Get(3), normalized_half_vector, normal_mul_dot)}; OpVectorTimesScalar(vec_ids.Get(3), normal, normal_dot_half_vector)};
const Id half_angle_proj{
OpFSub(vec_ids.Get(3), normalized_half_vector, normal_mul_dot)};
// Note: the half angle vector projection is confirmed not normalized before the dot // Note: the half angle vector projection is confirmed not normalized before the dot
// product. The result is in fact not cos(phi) as the name suggested. // product. The result is in fact not cos(phi) as the name suggested.
@ -267,7 +276,8 @@ void FragmentModule::WriteLighting() {
if (light_config.directional) { if (light_config.directional) {
light_vector = OpNormalize(vec_ids.Get(3), light_position); light_vector = OpNormalize(vec_ids.Get(3), light_position);
} else { } else {
light_vector = OpNormalize(vec_ids.Get(3), OpFAdd(vec_ids.Get(3), light_position, view)); light_vector =
OpNormalize(vec_ids.Get(3), OpFAdd(vec_ids.Get(3), light_position, view));
} }
spot_dir = GetLightMember(5); spot_dir = GetLightMember(5);
@ -292,7 +302,8 @@ void FragmentModule::WriteLighting() {
LightingRegs::IsLightingSamplerSupported( LightingRegs::IsLightingSamplerSupported(
lighting.config, LightingRegs::LightingSampler::SpotlightAttenuation)) { lighting.config, LightingRegs::LightingSampler::SpotlightAttenuation)) {
const Id value{GetLutValue(LightingRegs::SpotlightAttenuationSampler(light_config.num), const Id value{GetLutValue(LightingRegs::SpotlightAttenuationSampler(light_config.num),
light_config.num, lighting.lut_sp.type, lighting.lut_sp.abs_input)}; light_config.num, lighting.lut_sp.type,
lighting.lut_sp.abs_input)};
spot_atten = OpFMul(f32_id, ConstF32(lighting.lut_sp.scale), value); spot_atten = OpFMul(f32_id, ConstF32(lighting.lut_sp.scale), value);
} }
@ -301,16 +312,20 @@ void FragmentModule::WriteLighting() {
if (light_config.dist_atten_enable) { if (light_config.dist_atten_enable) {
const Id dist_atten_scale{GetLightMember(7)}; const Id dist_atten_scale{GetLightMember(7)};
const Id dist_atten_bias{GetLightMember(6)}; const Id dist_atten_bias{GetLightMember(6)};
const Id min_view_min_pos{OpFSub(vec_ids.Get(3), OpFNegate(vec_ids.Get(3), view), light_position)}; const Id min_view_min_pos{
const Id index{OpFma(f32_id, dist_atten_scale, OpLength(f32_id, min_view_min_pos), dist_atten_bias)}; OpFSub(vec_ids.Get(3), OpFNegate(vec_ids.Get(3), view), light_position)};
const Id index{OpFma(f32_id, dist_atten_scale, OpLength(f32_id, min_view_min_pos),
dist_atten_bias)};
const Id clamped_index{OpFClamp(f32_id, index, ConstF32(0.f), ConstF32(1.f))}; const Id clamped_index{OpFClamp(f32_id, index, ConstF32(0.f), ConstF32(1.f))};
const Id sampler{ConstS32(static_cast<s32>(LightingRegs::DistanceAttenuationSampler(light_config.num)))}; const Id sampler{ConstS32(
static_cast<s32>(LightingRegs::DistanceAttenuationSampler(light_config.num)))};
dist_atten = LookupLightingLUTUnsigned(sampler, clamped_index); dist_atten = LookupLightingLUTUnsigned(sampler, clamped_index);
} }
if (light_config.geometric_factor_0 || light_config.geometric_factor_1) { if (light_config.geometric_factor_0 || light_config.geometric_factor_1) {
geo_factor = OpDot(f32_id, half_vector, half_vector); geo_factor = OpDot(f32_id, half_vector, half_vector);
const Id dot_div_geo{OpFMin(f32_id, OpFDiv(f32_id, dot_product, geo_factor), ConstF32(1.f))}; const Id dot_div_geo{
OpFMin(f32_id, OpFDiv(f32_id, dot_product, geo_factor), ConstF32(1.f))};
const Id is_geo_factor_zero{OpFOrdEqual(bool_id, geo_factor, ConstF32(0.f))}; const Id is_geo_factor_zero{OpFOrdEqual(bool_id, geo_factor, ConstF32(0.f))};
geo_factor = OpSelect(f32_id, is_geo_factor_zero, ConstF32(0.f), dot_div_geo); geo_factor = OpSelect(f32_id, is_geo_factor_zero, ConstF32(0.f), dot_div_geo);
} }
@ -321,8 +336,9 @@ void FragmentModule::WriteLighting() {
LightingRegs::IsLightingSamplerSupported( LightingRegs::IsLightingSamplerSupported(
lighting.config, LightingRegs::LightingSampler::Distribution0)) { lighting.config, LightingRegs::LightingSampler::Distribution0)) {
// Lookup specular "distribution 0" LUT value // Lookup specular "distribution 0" LUT value
const Id value{GetLutValue(LightingRegs::LightingSampler::Distribution0, light_config.num, const Id value{GetLutValue(LightingRegs::LightingSampler::Distribution0,
lighting.lut_d0.type, lighting.lut_d0.abs_input)}; light_config.num, lighting.lut_d0.type,
lighting.lut_d0.abs_input)};
d0_lut_value = OpFMul(f32_id, ConstF32(lighting.lut_d0.scale), value); d0_lut_value = OpFMul(f32_id, ConstF32(lighting.lut_d0.scale), value);
} }
@ -347,8 +363,9 @@ void FragmentModule::WriteLighting() {
if (lighting.lut_rg.enable && if (lighting.lut_rg.enable &&
LightingRegs::IsLightingSamplerSupported(lighting.config, LightingRegs::IsLightingSamplerSupported(lighting.config,
LightingRegs::LightingSampler::ReflectGreen)) { LightingRegs::LightingSampler::ReflectGreen)) {
const Id value{GetLutValue(LightingRegs::LightingSampler::ReflectGreen, light_config.num, const Id value{GetLutValue(LightingRegs::LightingSampler::ReflectGreen,
lighting.lut_rg.type, lighting.lut_rg.abs_input)}; light_config.num, lighting.lut_rg.type,
lighting.lut_rg.abs_input)};
refl_value_g = OpFMul(f32_id, ConstF32(lighting.lut_rg.scale), value); refl_value_g = OpFMul(f32_id, ConstF32(lighting.lut_rg.scale), value);
} }
@ -369,14 +386,18 @@ void FragmentModule::WriteLighting() {
LightingRegs::IsLightingSamplerSupported( LightingRegs::IsLightingSamplerSupported(
lighting.config, LightingRegs::LightingSampler::Distribution1)) { lighting.config, LightingRegs::LightingSampler::Distribution1)) {
// Lookup specular "distribution 1" LUT value // Lookup specular "distribution 1" LUT value
const Id value{GetLutValue(LightingRegs::LightingSampler::Distribution1, light_config.num, const Id value{GetLutValue(LightingRegs::LightingSampler::Distribution1,
lighting.lut_d1.type, lighting.lut_d1.abs_input)}; light_config.num, lighting.lut_d1.type,
lighting.lut_d1.abs_input)};
d1_lut_value = OpFMul(f32_id, ConstF32(lighting.lut_d1.scale), value); d1_lut_value = OpFMul(f32_id, ConstF32(lighting.lut_d1.scale), value);
} }
const Id refl_value{OpCompositeConstruct(vec_ids.Get(3), refl_value_r, refl_value_g, refl_value_b)}; const Id refl_value{
OpCompositeConstruct(vec_ids.Get(3), refl_value_r, refl_value_g, refl_value_b)};
const Id light_specular_1{GetLightMember(1)}; const Id light_specular_1{GetLightMember(1)};
Id specular_1{OpFMul(vec_ids.Get(3), OpVectorTimesScalar(vec_ids.Get(3), refl_value, d1_lut_value), light_specular_1)}; Id specular_1{OpFMul(vec_ids.Get(3),
OpVectorTimesScalar(vec_ids.Get(3), refl_value, d1_lut_value),
light_specular_1)};
if (light_config.geometric_factor_1) { if (light_config.geometric_factor_1) {
specular_1 = OpVectorTimesScalar(vec_ids.Get(3), specular_1, geo_factor); specular_1 = OpVectorTimesScalar(vec_ids.Get(3), specular_1, geo_factor);
} }
@ -403,7 +424,8 @@ void FragmentModule::WriteLighting() {
} }
const bool shadow_primary_enable = lighting.shadow_primary && light_config.shadow_enable; const bool shadow_primary_enable = lighting.shadow_primary && light_config.shadow_enable;
const bool shadow_secondary_enable = lighting.shadow_secondary && light_config.shadow_enable; const bool shadow_secondary_enable =
lighting.shadow_secondary && light_config.shadow_enable;
const Id shadow_rgb{OpVectorShuffle(vec_ids.Get(3), shadow, shadow, 0, 1, 2)}; const Id shadow_rgb{OpVectorShuffle(vec_ids.Get(3), shadow, shadow, 0, 1, 2)};
const Id light_diffuse{GetLightMember(2)}; const Id light_diffuse{GetLightMember(2)};
@ -437,7 +459,8 @@ void FragmentModule::WriteLighting() {
// Apply shadow attenuation to alpha components if enabled // Apply shadow attenuation to alpha components if enabled
if (lighting.shadow_alpha) { if (lighting.shadow_alpha) {
const Id shadow_a{OpCompositeExtract(f32_id, shadow, 3)}; const Id shadow_a{OpCompositeExtract(f32_id, shadow, 3)};
const Id shadow_a_vec{OpCompositeConstruct(vec_ids.Get(4), ConstF32(1.f, 1.f, 1.f), shadow_a)}; const Id shadow_a_vec{
OpCompositeConstruct(vec_ids.Get(4), ConstF32(1.f, 1.f, 1.f), shadow_a)};
if (lighting.enable_primary_alpha) { if (lighting.enable_primary_alpha) {
diffuse_sum = OpFMul(vec_ids.Get(4), diffuse_sum, shadow_a_vec); diffuse_sum = OpFMul(vec_ids.Get(4), diffuse_sum, shadow_a_vec);
} }
@ -448,7 +471,8 @@ void FragmentModule::WriteLighting() {
// Sum final lighting result // Sum final lighting result
const Id lighting_global_ambient{GetShaderDataMember(vec_ids.Get(3), ConstS32(24))}; const Id lighting_global_ambient{GetShaderDataMember(vec_ids.Get(3), ConstS32(24))};
const Id lighting_global_ambient_rgba{PadVectorF32(lighting_global_ambient, vec_ids.Get(4), 0.f)}; const Id lighting_global_ambient_rgba{
PadVectorF32(lighting_global_ambient, vec_ids.Get(4), 0.f)};
const Id zero_vec{ConstF32(0.f, 0.f, 0.f, 0.f)}; const Id zero_vec{ConstF32(0.f, 0.f, 0.f, 0.f)};
const Id one_vec{ConstF32(1.f, 1.f, 1.f, 1.f)}; const Id one_vec{ConstF32(1.f, 1.f, 1.f, 1.f)};
diffuse_sum = OpFAdd(vec_ids.Get(4), diffuse_sum, lighting_global_ambient_rgba); diffuse_sum = OpFAdd(vec_ids.Get(4), diffuse_sum, lighting_global_ambient_rgba);
@ -484,27 +508,35 @@ void FragmentModule::WriteTevStage(s32 index) {
// result of Dot3_RGBA operation is also placed to the alpha component // result of Dot3_RGBA operation is also placed to the alpha component
alpha_output = OpCompositeExtract(f32_id, color_output, 0); alpha_output = OpCompositeExtract(f32_id, color_output, 0);
} else { } else {
alpha_results_1 = AppendAlphaModifier(stage.alpha_modifier1, stage.alpha_source1, index); alpha_results_1 =
alpha_results_2 = AppendAlphaModifier(stage.alpha_modifier2, stage.alpha_source2, index); AppendAlphaModifier(stage.alpha_modifier1, stage.alpha_source1, index);
alpha_results_3 = AppendAlphaModifier(stage.alpha_modifier3, stage.alpha_source3, index); alpha_results_2 =
AppendAlphaModifier(stage.alpha_modifier2, stage.alpha_source2, index);
alpha_results_3 =
AppendAlphaModifier(stage.alpha_modifier3, stage.alpha_source3, index);
alpha_output = Byteround(AppendAlphaCombiner(stage.alpha_op)); alpha_output = Byteround(AppendAlphaCombiner(stage.alpha_op));
} }
color_output = OpVectorTimesScalar(vec_ids.Get(3), color_output, ConstF32(static_cast<float>(stage.GetColorMultiplier()))); color_output = OpVectorTimesScalar(
color_output = OpFClamp(vec_ids.Get(3), color_output, ConstF32(0.f, 0.f, 0.f), ConstF32(1.f, 1.f, 1.f)); vec_ids.Get(3), color_output, ConstF32(static_cast<float>(stage.GetColorMultiplier())));
alpha_output = OpFMul(f32_id, alpha_output, ConstF32(static_cast<float>(stage.GetAlphaMultiplier()))); color_output = OpFClamp(vec_ids.Get(3), color_output, ConstF32(0.f, 0.f, 0.f),
ConstF32(1.f, 1.f, 1.f));
alpha_output =
OpFMul(f32_id, alpha_output, ConstF32(static_cast<float>(stage.GetAlphaMultiplier())));
alpha_output = OpFClamp(f32_id, alpha_output, ConstF32(0.f), ConstF32(1.f)); alpha_output = OpFClamp(f32_id, alpha_output, ConstF32(0.f), ConstF32(1.f));
last_tex_env_out = OpCompositeConstruct(vec_ids.Get(4), color_output, alpha_output); last_tex_env_out = OpCompositeConstruct(vec_ids.Get(4), color_output, alpha_output);
} }
combiner_buffer = next_combiner_buffer; combiner_buffer = next_combiner_buffer;
if (config.TevStageUpdatesCombinerBufferColor(index)) { if (config.TevStageUpdatesCombinerBufferColor(index)) {
next_combiner_buffer = OpVectorShuffle(vec_ids.Get(4), last_tex_env_out, next_combiner_buffer, 0, 1, 2, 7); next_combiner_buffer =
OpVectorShuffle(vec_ids.Get(4), last_tex_env_out, next_combiner_buffer, 0, 1, 2, 7);
} }
if (config.TevStageUpdatesCombinerBufferAlpha(index)) { if (config.TevStageUpdatesCombinerBufferAlpha(index)) {
next_combiner_buffer = OpVectorShuffle(vec_ids.Get(4), next_combiner_buffer, last_tex_env_out, 0, 1, 2, 7); next_combiner_buffer =
OpVectorShuffle(vec_ids.Get(4), next_combiner_buffer, last_tex_env_out, 0, 1, 2, 7);
} }
} }
@ -549,7 +581,8 @@ bool FragmentModule::WriteAlphaTestCondition(FramebufferRegs::CompareFunc func)
case CompareFunc::LessThanOrEqual: case CompareFunc::LessThanOrEqual:
case CompareFunc::GreaterThan: case CompareFunc::GreaterThan:
case CompareFunc::GreaterThanOrEqual: { case CompareFunc::GreaterThanOrEqual: {
const Id alpha_scaled{OpFMul(f32_id, OpCompositeExtract(f32_id, last_tex_env_out, 3), ConstF32(255.f))}; const Id alpha_scaled{
OpFMul(f32_id, OpCompositeExtract(f32_id, last_tex_env_out, 3), ConstF32(255.f))};
const Id alpha_int{OpConvertFToS(i32_id, alpha_scaled)}; const Id alpha_int{OpConvertFToS(i32_id, alpha_scaled)};
const Id alphatest_ref{GetShaderDataMember(i32_id, ConstS32(1))}; const Id alphatest_ref{GetShaderDataMember(i32_id, ConstS32(1))};
const Id alpha_comp_ref{Compare(alpha_int, alphatest_ref)}; const Id alpha_comp_ref{Compare(alpha_int, alphatest_ref)};
@ -588,9 +621,11 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
const Id abs_dfdx_coord{OpFAbs(vec_ids.Get(2), OpDPdx(vec_ids.Get(2), coord))}; const Id abs_dfdx_coord{OpFAbs(vec_ids.Get(2), OpDPdx(vec_ids.Get(2), coord))};
const Id abs_dfdy_coord{OpFAbs(vec_ids.Get(2), OpDPdy(vec_ids.Get(2), coord))}; const Id abs_dfdy_coord{OpFAbs(vec_ids.Get(2), OpDPdy(vec_ids.Get(2), coord))};
const Id d{OpFMax(vec_ids.Get(2), abs_dfdx_coord, abs_dfdy_coord)}; const Id d{OpFMax(vec_ids.Get(2), abs_dfdx_coord, abs_dfdy_coord)};
const Id dx_dy_max{OpFMax(f32_id, OpCompositeExtract(f32_id, d, 0), OpCompositeExtract(f32_id, d, 1))}; const Id dx_dy_max{
OpFMax(f32_id, OpCompositeExtract(f32_id, d, 0), OpCompositeExtract(f32_id, d, 1))};
const Id lod{OpLog2(f32_id, dx_dy_max)}; const Id lod{OpLog2(f32_id, dx_dy_max)};
return OpImageSampleExplicitLod(vec_ids.Get(4), sampled_image, texcoord, spv::ImageOperandsMask::Lod, lod); return OpImageSampleExplicitLod(vec_ids.Get(4), sampled_image, texcoord,
spv::ImageOperandsMask::Lod, lod);
}; };
const auto Sample = [this](Id tex_id, Id tex_sampler_id, bool projection) { const auto Sample = [this](Id tex_id, Id tex_sampler_id, bool projection) {
@ -600,9 +635,9 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
const Id sampled_image{OpSampledImage(TypeSampledImage(image_type), tex, tex_sampler)}; const Id sampled_image{OpSampledImage(TypeSampledImage(image_type), tex, tex_sampler)};
const Id texcoord0{OpLoad(vec_ids.Get(2), texcoord0_id)}; const Id texcoord0{OpLoad(vec_ids.Get(2), texcoord0_id)};
const Id texcoord0_w{OpLoad(f32_id, texcoord0_w_id)}; const Id texcoord0_w{OpLoad(f32_id, texcoord0_w_id)};
const Id coord{OpCompositeConstruct(vec_ids.Get(3), OpCompositeExtract(f32_id, texcoord0, 0), const Id coord{OpCompositeConstruct(vec_ids.Get(3),
OpCompositeExtract(f32_id, texcoord0, 1), OpCompositeExtract(f32_id, texcoord0, 0),
texcoord0_w)}; OpCompositeExtract(f32_id, texcoord0, 1), texcoord0_w)};
if (projection) { if (projection) {
return OpImageSampleProjImplicitLod(vec_ids.Get(4), sampled_image, coord); return OpImageSampleProjImplicitLod(vec_ids.Get(4), sampled_image, coord);
} else { } else {
@ -663,14 +698,16 @@ Id FragmentModule::CompareShadow(Id pixel, Id z) {
Id FragmentModule::SampleShadow() { Id FragmentModule::SampleShadow() {
const Id texcoord0{OpLoad(vec_ids.Get(2), texcoord0_id)}; const Id texcoord0{OpLoad(vec_ids.Get(2), texcoord0_id)};
const Id texcoord0_w{OpLoad(f32_id, texcoord0_w_id)}; const Id texcoord0_w{OpLoad(f32_id, texcoord0_w_id)};
const Id abs_min_w{OpFMul(f32_id, OpFMin(f32_id, OpFAbs(f32_id, texcoord0_w), const Id abs_min_w{OpFMul(f32_id, OpFMin(f32_id, OpFAbs(f32_id, texcoord0_w), ConstF32(1.f)),
ConstF32(1.f)), ConstF32(16777215.f))}; ConstF32(16777215.f))};
const Id shadow_texture_bias{GetShaderDataMember(i32_id, ConstS32(17))}; const Id shadow_texture_bias{GetShaderDataMember(i32_id, ConstS32(17))};
const Id z_i32{OpSMax(i32_id, ConstS32(0), OpISub(i32_id, OpConvertFToS(i32_id, abs_min_w), shadow_texture_bias))}; const Id z_i32{OpSMax(i32_id, ConstS32(0),
OpISub(i32_id, OpConvertFToS(i32_id, abs_min_w), shadow_texture_bias))};
const Id z{OpBitcast(u32_id, z_i32)}; const Id z{OpBitcast(u32_id, z_i32)};
const Id shadow_texture_px{OpLoad(image_r32_id, shadow_texture_px_id)}; const Id shadow_texture_px{OpLoad(image_r32_id, shadow_texture_px_id)};
const Id px_size{OpImageQuerySize(ivec_ids.Get(2), shadow_texture_px)}; const Id px_size{OpImageQuerySize(ivec_ids.Get(2), shadow_texture_px)};
const Id coord{OpFma(vec_ids.Get(2), OpConvertSToF(vec_ids.Get(2), px_size), texcoord0, ConstF32(-0.5f, -0.5f))}; const Id coord{OpFma(vec_ids.Get(2), OpConvertSToF(vec_ids.Get(2), px_size), texcoord0,
ConstF32(-0.5f, -0.5f))};
const Id coord_floor{OpFloor(vec_ids.Get(2), coord)}; const Id coord_floor{OpFloor(vec_ids.Get(2), coord)};
const Id f{OpFSub(vec_ids.Get(2), coord_floor, coord)}; const Id f{OpFSub(vec_ids.Get(2), coord_floor, coord)};
const Id i{OpConvertFToS(ivec_ids.Get(2), coord_floor)}; const Id i{OpConvertFToS(ivec_ids.Get(2), coord_floor)};
@ -681,7 +718,8 @@ Id FragmentModule::SampleShadow() {
const Id end_label{OpLabel()}; const Id end_label{OpLabel()};
const Id uv_le_zero{OpSLessThan(bvec_ids.Get(2), uv, ConstS32(0, 0))}; const Id uv_le_zero{OpSLessThan(bvec_ids.Get(2), uv, ConstS32(0, 0))};
const Id uv_geq_size{OpSGreaterThanEqual(bvec_ids.Get(2), uv, px_size)}; const Id uv_geq_size{OpSGreaterThanEqual(bvec_ids.Get(2), uv, px_size)};
const Id cond{OpAny(bool_id, OpCompositeConstruct(bvec_ids.Get(4), uv_le_zero, uv_geq_size))}; const Id cond{
OpAny(bool_id, OpCompositeConstruct(bvec_ids.Get(4), uv_le_zero, uv_geq_size))};
OpSelectionMerge(end_label, spv::SelectionControlMask::MaskNone); OpSelectionMerge(end_label, spv::SelectionControlMask::MaskNone);
OpBranchConditional(cond, true_label, false_label); OpBranchConditional(cond, true_label, false_label);
AddLabel(true_label); AddLabel(true_label);
@ -695,8 +733,7 @@ Id FragmentModule::SampleShadow() {
return OpPhi(f32_id, ConstF32(1.f), true_label, result, false_label); return OpPhi(f32_id, ConstF32(1.f), true_label, result, false_label);
}; };
const Id s_xy{OpCompositeConstruct(vec_ids.Get(2), const Id s_xy{OpCompositeConstruct(vec_ids.Get(2), SampleShadow2D(i),
SampleShadow2D(i),
SampleShadow2D(OpIAdd(ivec_ids.Get(2), i, ConstS32(1, 0))))}; SampleShadow2D(OpIAdd(ivec_ids.Get(2), i, ConstS32(1, 0))))};
const Id s_zw{OpCompositeConstruct(vec_ids.Get(2), const Id s_zw{OpCompositeConstruct(vec_ids.Get(2),
SampleShadow2D(OpIAdd(ivec_ids.Get(2), i, ConstS32(0, 1))), SampleShadow2D(OpIAdd(ivec_ids.Get(2), i, ConstS32(0, 1))),
@ -715,7 +752,8 @@ Id FragmentModule::AppendProcTexShiftOffset(Id v, ProcTexShift mode, ProcTexClam
const Id v_i32{OpConvertFToS(i32_id, v)}; const Id v_i32{OpConvertFToS(i32_id, v)};
const auto Shift = [&](bool even) -> Id { const auto Shift = [&](bool even) -> Id {
const Id temp1{OpSDiv(i32_id, even ? OpIAdd(i32_id, v_i32, ConstS32(1)) : v_i32, ConstS32(2))}; const Id temp1{
OpSDiv(i32_id, even ? OpIAdd(i32_id, v_i32, ConstS32(1)) : v_i32, ConstS32(2))};
const Id temp2{OpConvertSToF(f32_id, OpSMod(i32_id, temp1, ConstS32(2)))}; const Id temp2{OpConvertSToF(f32_id, OpSMod(i32_id, temp1, ConstS32(2)))};
return OpFMul(f32_id, offset, temp2); return OpFMul(f32_id, offset, temp2);
}; };
@ -739,7 +777,8 @@ Id FragmentModule::AppendProcTexClamp(Id var, ProcTexClamp mode) {
const auto MirroredRepeat = [&]() -> Id { const auto MirroredRepeat = [&]() -> Id {
const Id fract{OpFract(f32_id, var)}; const Id fract{OpFract(f32_id, var)};
const Id cond{OpIEqual(bool_id, OpSMod(i32_id, OpConvertFToS(i32_id, var), ConstS32(2)), ConstS32(0))}; const Id cond{OpIEqual(bool_id, OpSMod(i32_id, OpConvertFToS(i32_id, var), ConstS32(2)),
ConstS32(0))};
return OpSelect(f32_id, cond, fract, OpFSub(f32_id, one, fract)); return OpSelect(f32_id, cond, fract, OpFSub(f32_id, one, fract));
}; };
@ -802,8 +841,10 @@ void FragmentModule::DefineProcTexSampler() {
// Define noise tables at the beginning of the function // Define noise tables at the beginning of the function
if (config.state.proctex.noise_enable) { if (config.state.proctex.noise_enable) {
noise1d_table = DefineVar<false>(TypeArray(i32_id, ConstU32(16u)), spv::StorageClass::Function); noise1d_table =
noise2d_table = DefineVar<false>(TypeArray(i32_id, ConstU32(16u)), spv::StorageClass::Function); DefineVar<false>(TypeArray(i32_id, ConstU32(16u)), spv::StorageClass::Function);
noise2d_table =
DefineVar<false>(TypeArray(i32_id, ConstU32(16u)), spv::StorageClass::Function);
} }
lut_offsets = DefineVar<false>(TypeArray(i32_id, ConstU32(8u)), spv::StorageClass::Function); lut_offsets = DefineVar<false>(TypeArray(i32_id, ConstU32(8u)), spv::StorageClass::Function);
@ -811,9 +852,15 @@ void FragmentModule::DefineProcTexSampler() {
if (config.state.proctex.coord < 3) { if (config.state.proctex.coord < 3) {
Id texcoord_id{}; Id texcoord_id{};
switch (config.state.proctex.coord.Value()) { switch (config.state.proctex.coord.Value()) {
case 0: texcoord_id = texcoord0_id; break; case 0:
case 1: texcoord_id = texcoord1_id; break; texcoord_id = texcoord0_id;
case 2: texcoord_id = texcoord2_id; break; break;
case 1:
texcoord_id = texcoord1_id;
break;
case 2:
texcoord_id = texcoord2_id;
break;
} }
const Id texcoord{OpLoad(vec_ids.Get(2), texcoord_id)}; const Id texcoord{OpLoad(vec_ids.Get(2), texcoord_id)};
@ -833,12 +880,15 @@ void FragmentModule::DefineProcTexSampler() {
// unlike normal texture, the bias is inside the log2 // unlike normal texture, the bias is inside the log2
const Id proctex_bias{GetShaderDataMember(f32_id, ConstS32(16))}; const Id proctex_bias{GetShaderDataMember(f32_id, ConstS32(16))};
const Id bias{OpFMul(f32_id, ConstF32(static_cast<f32>(config.state.proctex.lut_width)), proctex_bias)}; const Id bias{
const Id duv_xy{OpFAdd(f32_id, OpCompositeExtract(f32_id, duv, 0), OpCompositeExtract(f32_id, duv, 1))}; OpFMul(f32_id, ConstF32(static_cast<f32>(config.state.proctex.lut_width)), proctex_bias)};
const Id duv_xy{
OpFAdd(f32_id, OpCompositeExtract(f32_id, duv, 0), OpCompositeExtract(f32_id, duv, 1))};
Id lod{OpLog2(f32_id, OpFMul(f32_id, OpFAbs(f32_id, bias), duv_xy))}; Id lod{OpLog2(f32_id, OpFMul(f32_id, OpFAbs(f32_id, bias), duv_xy))};
lod = OpSelect(f32_id, OpFOrdEqual(bool_id, proctex_bias, ConstF32(0.f)), ConstF32(0.f), lod); lod = OpSelect(f32_id, OpFOrdEqual(bool_id, proctex_bias, ConstF32(0.f)), ConstF32(0.f), lod);
lod = OpFClamp(f32_id, lod, ConstF32(std::max(0.0f, static_cast<float>(config.state.proctex.lod_min))), lod = OpFClamp(f32_id, lod,
ConstF32(std::max(0.0f, static_cast<float>(config.state.proctex.lod_min))),
ConstF32(std::min(7.0f, static_cast<float>(config.state.proctex.lod_max)))); ConstF32(std::min(7.0f, static_cast<float>(config.state.proctex.lod_max))));
// Get shift offset before noise generation // Get shift offset before noise generation
@ -853,7 +903,8 @@ void FragmentModule::DefineProcTexSampler() {
if (config.state.proctex.noise_enable) { if (config.state.proctex.noise_enable) {
const Id proctex_noise_a{GetShaderDataMember(vec_ids.Get(2), ConstS32(22))}; const Id proctex_noise_a{GetShaderDataMember(vec_ids.Get(2), ConstS32(22))};
const Id noise_coef{ProcTexNoiseCoef(uv)}; const Id noise_coef{ProcTexNoiseCoef(uv)};
uv = OpFAdd(vec_ids.Get(2), uv, OpVectorTimesScalar(vec_ids.Get(2), proctex_noise_a, noise_coef)); uv = OpFAdd(vec_ids.Get(2), uv,
OpVectorTimesScalar(vec_ids.Get(2), proctex_noise_a, noise_coef));
uv = OpFAbs(vec_ids.Get(2), uv); uv = OpFAbs(vec_ids.Get(2), uv);
} }
@ -867,8 +918,8 @@ void FragmentModule::DefineProcTexSampler() {
// Combine and map // Combine and map
const Id proctex_color_map_offset{GetShaderDataMember(i32_id, ConstS32(12))}; const Id proctex_color_map_offset{GetShaderDataMember(i32_id, ConstS32(12))};
const Id lut_coord{AppendProcTexCombineAndMap(config.state.proctex.color_combiner, const Id lut_coord{AppendProcTexCombineAndMap(config.state.proctex.color_combiner, u, v,
u, v, proctex_color_map_offset)}; proctex_color_map_offset)};
Id final_color{}; Id final_color{};
switch (config.state.proctex.lut_filter) { switch (config.state.proctex.lut_filter) {
@ -906,7 +957,8 @@ void FragmentModule::DefineProcTexSampler() {
Id FragmentModule::Byteround(Id variable_id, u32 size) { Id FragmentModule::Byteround(Id variable_id, u32 size) {
if (size > 1) { if (size > 1) {
const Id scaled_vec_id{OpVectorTimesScalar(vec_ids.Get(size), variable_id, ConstF32(255.f))}; const Id scaled_vec_id{
OpVectorTimesScalar(vec_ids.Get(size), variable_id, ConstF32(255.f))};
const Id rounded_id{OpRound(vec_ids.Get(size), scaled_vec_id)}; const Id rounded_id{OpRound(vec_ids.Get(size), scaled_vec_id)};
return OpVectorTimesScalar(vec_ids.Get(size), rounded_id, ConstF32(1.f / 255.f)); return OpVectorTimesScalar(vec_ids.Get(size), rounded_id, ConstF32(1.f / 255.f));
} else { } else {
@ -924,7 +976,8 @@ Id FragmentModule::ProcTexLookupLUT(Id offset, Id coord) {
const Id sampled_image{TypeSampledImage(image_buffer_id)}; const Id sampled_image{TypeSampledImage(image_buffer_id)};
texture_buffer_lut_rg = OpLoad(sampled_image, texture_buffer_lut_rg_id); texture_buffer_lut_rg = OpLoad(sampled_image, texture_buffer_lut_rg_id);
} }
const Id entry{OpImageFetch(vec_ids.Get(4), OpImage(image_buffer_id, texture_buffer_lut_rg), p)}; const Id entry{
OpImageFetch(vec_ids.Get(4), OpImage(image_buffer_id, texture_buffer_lut_rg), p)};
const Id entry_r{OpCompositeExtract(f32_id, entry, 0)}; const Id entry_r{OpCompositeExtract(f32_id, entry, 0)};
const Id entry_g{OpCompositeExtract(f32_id, entry, 1)}; const Id entry_g{OpCompositeExtract(f32_id, entry, 1)};
return OpFClamp(f32_id, OpFma(f32_id, entry_g, index_f, entry_r), ConstF32(0.f), ConstF32(1.f)); return OpFClamp(f32_id, OpFma(f32_id, entry_g, index_f, entry_r), ConstF32(0.f), ConstF32(1.f));
@ -952,7 +1005,8 @@ Id FragmentModule::ProcTexNoiseCoef(Id x) {
const Id table_value{OpLoad(i32_id, OpAccessChain(table_ptr, noise2d_table, u2))}; const Id table_value{OpLoad(i32_id, OpAccessChain(table_ptr, noise2d_table, u2))};
Id v2{ProcTexNoiseRand1D(point_y)}; Id v2{ProcTexNoiseRand1D(point_y)};
v2 = OpIAdd(i32_id, v2, OpSelect(i32_id, cond, ConstS32(4), ConstS32(0))); v2 = OpIAdd(i32_id, v2, OpSelect(i32_id, cond, ConstS32(4), ConstS32(0)));
v2 = OpBitwiseXor(i32_id, v2, OpIMul(i32_id, OpBitwiseAnd(i32_id, u2, ConstS32(1)), ConstS32(6))); v2 = OpBitwiseXor(i32_id, v2,
OpIMul(i32_id, OpBitwiseAnd(i32_id, u2, ConstS32(1)), ConstS32(6)));
v2 = OpIAdd(i32_id, v2, OpIAdd(i32_id, u2, ConstS32(10))); v2 = OpIAdd(i32_id, v2, OpIAdd(i32_id, u2, ConstS32(10)));
v2 = OpBitwiseAnd(i32_id, v2, ConstS32(0xF)); v2 = OpBitwiseAnd(i32_id, v2, ConstS32(0xF));
v2 = OpBitwiseXor(i32_id, v2, table_value); v2 = OpBitwiseXor(i32_id, v2, table_value);
@ -961,7 +1015,8 @@ Id FragmentModule::ProcTexNoiseCoef(Id x) {
const Id proctex_noise_f{GetShaderDataMember(vec_ids.Get(2), ConstS32(21))}; const Id proctex_noise_f{GetShaderDataMember(vec_ids.Get(2), ConstS32(21))};
const Id proctex_noise_p{GetShaderDataMember(vec_ids.Get(2), ConstS32(23))}; const Id proctex_noise_p{GetShaderDataMember(vec_ids.Get(2), ConstS32(23))};
const Id grid{OpFMul(vec_ids.Get(2), OpVectorTimesScalar(vec_ids.Get(2), proctex_noise_f, ConstF32(9.f)), const Id grid{OpFMul(vec_ids.Get(2),
OpVectorTimesScalar(vec_ids.Get(2), proctex_noise_f, ConstF32(9.f)),
OpFAbs(vec_ids.Get(2), OpFAdd(vec_ids.Get(2), x, proctex_noise_p)))}; OpFAbs(vec_ids.Get(2), OpFAdd(vec_ids.Get(2), x, proctex_noise_p)))};
const Id point{OpFloor(vec_ids.Get(2), grid)}; const Id point{OpFloor(vec_ids.Get(2), grid)};
const Id frac{OpFSub(vec_ids.Get(2), grid, point)}; const Id frac{OpFSub(vec_ids.Get(2), grid, point)};
@ -970,12 +1025,15 @@ Id FragmentModule::ProcTexNoiseCoef(Id x) {
const Id frac_x_y{OpFAdd(f32_id, frac_x, frac_y)}; const Id frac_x_y{OpFAdd(f32_id, frac_x, frac_y)};
const Id g0{OpFMul(f32_id, ProcTexNoiseRand2D(point), frac_x_y)}; const Id g0{OpFMul(f32_id, ProcTexNoiseRand2D(point), frac_x_y)};
const Id frac_x_y_min_one{OpFSub(f32_id, frac_x_y, ConstF32(1.f))}; const Id frac_x_y_min_one{OpFSub(f32_id, frac_x_y, ConstF32(1.f))};
const Id g1{OpFMul(f32_id, ProcTexNoiseRand2D(OpFAdd(vec_ids.Get(2), point, ConstF32(1.f, 0.f))), const Id g1{OpFMul(f32_id,
ProcTexNoiseRand2D(OpFAdd(vec_ids.Get(2), point, ConstF32(1.f, 0.f))),
frac_x_y_min_one)}; frac_x_y_min_one)};
const Id g2{OpFMul(f32_id, ProcTexNoiseRand2D(OpFAdd(vec_ids.Get(2), point, ConstF32(0.f, 1.f))), const Id g2{OpFMul(f32_id,
ProcTexNoiseRand2D(OpFAdd(vec_ids.Get(2), point, ConstF32(0.f, 1.f))),
frac_x_y_min_one)}; frac_x_y_min_one)};
const Id frac_x_y_min_two{OpFSub(f32_id, frac_x_y, ConstF32(2.f))}; const Id frac_x_y_min_two{OpFSub(f32_id, frac_x_y, ConstF32(2.f))};
const Id g3{OpFMul(f32_id, ProcTexNoiseRand2D(OpFAdd(vec_ids.Get(2), point, ConstF32(1.f, 1.f))), const Id g3{OpFMul(f32_id,
ProcTexNoiseRand2D(OpFAdd(vec_ids.Get(2), point, ConstF32(1.f, 1.f))),
frac_x_y_min_two)}; frac_x_y_min_two)};
const Id proctex_noise_lut_offset{GetShaderDataMember(i32_id, ConstS32(11))}; const Id proctex_noise_lut_offset{GetShaderDataMember(i32_id, ConstS32(11))};
const Id x_noise{ProcTexLookupLUT(proctex_noise_lut_offset, frac_x)}; const Id x_noise{ProcTexLookupLUT(proctex_noise_lut_offset, frac_x)};
@ -986,15 +1044,17 @@ Id FragmentModule::ProcTexNoiseCoef(Id x) {
} }
Id FragmentModule::SampleProcTexColor(Id lut_coord, Id level) { Id FragmentModule::SampleProcTexColor(Id lut_coord, Id level) {
const Id lut_width{OpShiftRightArithmetic(i32_id, ConstS32(config.state.proctex.lut_width), level)}; const Id lut_width{
OpShiftRightArithmetic(i32_id, ConstS32(config.state.proctex.lut_width), level)};
const Id lut_ptr{TypePointer(spv::StorageClass::Function, i32_id)}; const Id lut_ptr{TypePointer(spv::StorageClass::Function, i32_id)};
// Offsets for level 4-7 seem to be hardcoded // Offsets for level 4-7 seem to be hardcoded
InitTableS32(lut_offsets, config.state.proctex.lut_offset0, config.state.proctex.lut_offset1, InitTableS32(lut_offsets, config.state.proctex.lut_offset0, config.state.proctex.lut_offset1,
config.state.proctex.lut_offset2, config.state.proctex.lut_offset3, config.state.proctex.lut_offset2, config.state.proctex.lut_offset3, 0xF0, 0xF8,
0xF0, 0xF8, 0xFC, 0xFE); 0xFC, 0xFE);
const Id lut_offset{OpLoad(i32_id, OpAccessChain(lut_ptr, lut_offsets, level))}; const Id lut_offset{OpLoad(i32_id, OpAccessChain(lut_ptr, lut_offsets, level))};
// For the color lut, coord=0.0 is lut[offset] and coord=1.0 is lut[offset+width-1] // For the color lut, coord=0.0 is lut[offset] and coord=1.0 is lut[offset+width-1]
lut_coord = OpFMul(f32_id, lut_coord, OpConvertSToF(f32_id, OpISub(i32_id, lut_width, ConstS32(1)))); lut_coord =
OpFMul(f32_id, lut_coord, OpConvertSToF(f32_id, OpISub(i32_id, lut_width, ConstS32(1))));
if (!Sirit::ValidId(texture_buffer_lut_rgba)) { if (!Sirit::ValidId(texture_buffer_lut_rgba)) {
const Id sampled_image{TypeSampledImage(image_buffer_id)}; const Id sampled_image{TypeSampledImage(image_buffer_id)};
@ -1015,7 +1075,8 @@ Id FragmentModule::SampleProcTexColor(Id lut_coord, Id level) {
const Id p2{OpIAdd(i32_id, lut_index_i, proctex_diff_lut_offset)}; const Id p2{OpIAdd(i32_id, lut_index_i, proctex_diff_lut_offset)};
const Id texel1{OpImageFetch(vec_ids.Get(4), lut_rgba, p1)}; const Id texel1{OpImageFetch(vec_ids.Get(4), lut_rgba, p1)};
const Id texel2{OpImageFetch(vec_ids.Get(4), lut_rgba, p2)}; const Id texel2{OpImageFetch(vec_ids.Get(4), lut_rgba, p2)};
return OpFAdd(vec_ids.Get(4), texel1, OpVectorTimesScalar(vec_ids.Get(4), texel2, lut_index_f)); return OpFAdd(vec_ids.Get(4), texel1,
OpVectorTimesScalar(vec_ids.Get(4), texel2, lut_index_f));
} }
case ProcTexFilter::Nearest: case ProcTexFilter::Nearest:
case ProcTexFilter::NearestMipmapLinear: case ProcTexFilter::NearestMipmapLinear:
@ -1041,7 +1102,8 @@ Id FragmentModule::LookupLightingLUT(Id lut_index, Id index, Id delta) {
const Id lut_index_y{OpBitwiseAnd(i32_id, lut_index, ConstS32(3))}; const Id lut_index_y{OpBitwiseAnd(i32_id, lut_index, ConstS32(3))};
const Id lut_offset{GetShaderDataMember(i32_id, ConstS32(19), lut_index_x, lut_index_y)}; const Id lut_offset{GetShaderDataMember(i32_id, ConstS32(19), lut_index_x, lut_index_y)};
const Id coord{OpIAdd(i32_id, lut_offset, index)}; const Id coord{OpIAdd(i32_id, lut_offset, index)};
const Id entry{OpImageFetch(vec_ids.Get(4), OpImage(image_buffer_id, texture_buffer_lut_lf), coord)}; const Id entry{
OpImageFetch(vec_ids.Get(4), OpImage(image_buffer_id, texture_buffer_lut_lf), coord)};
const Id entry_r{OpCompositeExtract(f32_id, entry, 0)}; const Id entry_r{OpCompositeExtract(f32_id, entry, 0)};
const Id entry_g{OpCompositeExtract(f32_id, entry, 1)}; const Id entry_g{OpCompositeExtract(f32_id, entry, 1)};
return OpFma(f32_id, entry_g, delta, entry_r); return OpFma(f32_id, entry_g, delta, entry_r);
@ -1119,9 +1181,7 @@ Id FragmentModule::AppendAlphaModifier(TevStageConfig::AlphaModifier modifier,
const Id source_color{AppendSource(source, index)}; const Id source_color{AppendSource(source, index)};
const Id one_f32{ConstF32(1.f)}; const Id one_f32{ConstF32(1.f)};
const auto Component = [&](s32 c) -> Id { const auto Component = [&](s32 c) -> Id { return OpCompositeExtract(f32_id, source_color, c); };
return OpCompositeExtract(f32_id, source_color, c);
};
switch (modifier) { switch (modifier) {
case AlphaModifier::SourceAlpha: case AlphaModifier::SourceAlpha:
@ -1164,7 +1224,8 @@ Id FragmentModule::AppendColorCombiner(Pica::TexturingRegs::TevStageConfig::Oper
color = OpFAdd(vec_ids.Get(3), color_results_1, color_results_2); color = OpFAdd(vec_ids.Get(3), color_results_1, color_results_2);
break; break;
case Operation::AddSigned: case Operation::AddSigned:
color = OpFSub(vec_ids.Get(3), OpFAdd(vec_ids.Get(3), color_results_1, color_results_2), half_vec); color = OpFSub(vec_ids.Get(3), OpFAdd(vec_ids.Get(3), color_results_1, color_results_2),
half_vec);
break; break;
case Operation::Lerp: case Operation::Lerp:
color = OpFMix(vec_ids.Get(3), color_results_2, color_results_1, color_results_3); color = OpFMix(vec_ids.Get(3), color_results_2, color_results_1, color_results_3);
@ -1176,7 +1237,8 @@ Id FragmentModule::AppendColorCombiner(Pica::TexturingRegs::TevStageConfig::Oper
color = OpFma(vec_ids.Get(3), color_results_1, color_results_2, color_results_3); color = OpFma(vec_ids.Get(3), color_results_1, color_results_2, color_results_3);
break; break;
case Operation::AddThenMultiply: case Operation::AddThenMultiply:
color = OpFMin(vec_ids.Get(3), OpFAdd(vec_ids.Get(3), color_results_1, color_results_2), one_vec); color = OpFMin(vec_ids.Get(3), OpFAdd(vec_ids.Get(3), color_results_1, color_results_2),
one_vec);
color = OpFMul(vec_ids.Get(3), color, color_results_3); color = OpFMul(vec_ids.Get(3), color, color_results_3);
break; break;
case Operation::Dot3_RGB: case Operation::Dot3_RGB:
@ -1267,23 +1329,24 @@ void FragmentModule::DefineEntryPoint() {
} }
void FragmentModule::DefineUniformStructs() { void FragmentModule::DefineUniformStructs() {
const Id light_src_struct_id{TypeStruct(vec_ids.Get(3), vec_ids.Get(3), vec_ids.Get(3), vec_ids.Get(3), const Id light_src_struct_id{TypeStruct(vec_ids.Get(3), vec_ids.Get(3), vec_ids.Get(3),
vec_ids.Get(3), vec_ids.Get(3), f32_id, f32_id)}; vec_ids.Get(3), vec_ids.Get(3), vec_ids.Get(3), f32_id,
f32_id)};
const Id light_src_array_id{TypeArray(light_src_struct_id, ConstU32(NUM_LIGHTS))}; const Id light_src_array_id{TypeArray(light_src_struct_id, ConstU32(NUM_LIGHTS))};
const Id lighting_lut_array_id{TypeArray(ivec_ids.Get(4), ConstU32(NUM_LIGHTING_SAMPLERS / 4))}; const Id lighting_lut_array_id{TypeArray(ivec_ids.Get(4), ConstU32(NUM_LIGHTING_SAMPLERS / 4))};
const Id const_color_array_id{TypeArray(vec_ids.Get(4), ConstU32(NUM_TEV_STAGES))}; const Id const_color_array_id{TypeArray(vec_ids.Get(4), ConstU32(NUM_TEV_STAGES))};
const Id shader_data_struct_id{TypeStruct(i32_id, i32_id, f32_id, f32_id, f32_id, f32_id, i32_id, const Id shader_data_struct_id{TypeStruct(
i32_id, i32_id, i32_id, i32_id, i32_id, i32_id, i32_id, i32_id, i32_id, i32_id, f32_id, f32_id, f32_id, f32_id, i32_id, i32_id, i32_id, i32_id, i32_id,
i32_id, f32_id, i32_id, u32_id, lighting_lut_array_id, vec_ids.Get(3), i32_id, i32_id, i32_id, i32_id, i32_id, f32_id, i32_id, u32_id, lighting_lut_array_id,
vec_ids.Get(2), vec_ids.Get(2), vec_ids.Get(2), vec_ids.Get(3), vec_ids.Get(3), vec_ids.Get(2), vec_ids.Get(2), vec_ids.Get(2), vec_ids.Get(3),
light_src_array_id, const_color_array_id, vec_ids.Get(4), vec_ids.Get(4))}; light_src_array_id, const_color_array_id, vec_ids.Get(4), vec_ids.Get(4))};
constexpr std::array light_src_offsets{0u, 16u, 32u, 48u, 64u, 80u, 92u, 96u}; constexpr std::array light_src_offsets{0u, 16u, 32u, 48u, 64u, 80u, 92u, 96u};
constexpr std::array shader_data_offsets{0u, 4u, 8u, 12u, 16u, 20u, 24u, 28u, 32u, 36u, 40u, 44u, 48u, constexpr std::array shader_data_offsets{
52u, 56u, 60u, 64u, 68u, 72u, 80u, 176u, 192u, 200u, 208u, 0u, 4u, 8u, 12u, 16u, 20u, 24u, 28u, 32u, 36u, 40u, 44u, 48u, 52u, 56u,
224u, 240u, 1136u, 1232u, 1248u}; 60u, 64u, 68u, 72u, 80u, 176u, 192u, 200u, 208u, 224u, 240u, 1136u, 1232u, 1248u};
Decorate(lighting_lut_array_id, spv::Decoration::ArrayStride, 16u); Decorate(lighting_lut_array_id, spv::Decoration::ArrayStride, 16u);
Decorate(light_src_array_id, spv::Decoration::ArrayStride, 112u); Decorate(light_src_array_id, spv::Decoration::ArrayStride, 112u);
@ -1296,8 +1359,8 @@ void FragmentModule::DefineUniformStructs() {
} }
Decorate(shader_data_struct_id, spv::Decoration::Block); Decorate(shader_data_struct_id, spv::Decoration::Block);
shader_data_id = AddGlobalVariable(TypePointer(spv::StorageClass::Uniform, shader_data_struct_id), shader_data_id = AddGlobalVariable(
spv::StorageClass::Uniform); TypePointer(spv::StorageClass::Uniform, shader_data_struct_id), spv::StorageClass::Uniform);
Decorate(shader_data_id, spv::Decoration::DescriptorSet, 0); Decorate(shader_data_id, spv::Decoration::DescriptorSet, 0);
Decorate(shader_data_id, spv::Decoration::Binding, 1); Decorate(shader_data_id, spv::Decoration::Binding, 1);
} }

View File

@ -25,6 +25,7 @@ class FragmentModule : public Sirit::Module {
static constexpr u32 NUM_TEV_STAGES = 6; static constexpr u32 NUM_TEV_STAGES = 6;
static constexpr u32 NUM_LIGHTS = 8; static constexpr u32 NUM_LIGHTS = 8;
static constexpr u32 NUM_LIGHTING_SAMPLERS = 24; static constexpr u32 NUM_LIGHTING_SAMPLERS = 24;
public: public:
FragmentModule(const PicaFSConfig& config); FragmentModule(const PicaFSConfig& config);
~FragmentModule(); ~FragmentModule();
@ -59,8 +60,8 @@ public:
[[nodiscard]] Id AppendProcTexClamp(Id var, Pica::TexturingRegs::ProcTexClamp mode); [[nodiscard]] Id AppendProcTexClamp(Id var, Pica::TexturingRegs::ProcTexClamp mode);
[[nodiscard]] Id AppendProcTexCombineAndMap(Pica::TexturingRegs::ProcTexCombiner combiner, [[nodiscard]] Id AppendProcTexCombineAndMap(Pica::TexturingRegs::ProcTexCombiner combiner, Id u,
Id u, Id v, Id offset); Id v, Id offset);
/// Rounds the provided variable to the nearest 1/255th /// Rounds the provided variable to the nearest 1/255th
[[nodiscard]] Id Byteround(Id variable_id, u32 size = 1); [[nodiscard]] Id Byteround(Id variable_id, u32 size = 1);
@ -84,11 +85,13 @@ public:
[[nodiscard]] Id AppendSource(Pica::TexturingRegs::TevStageConfig::Source source, s32 index); [[nodiscard]] Id AppendSource(Pica::TexturingRegs::TevStageConfig::Source source, s32 index);
/// Writes the color components to use for the specified TEV stage color modifier /// Writes the color components to use for the specified TEV stage color modifier
[[nodiscard]] Id AppendColorModifier(Pica::TexturingRegs::TevStageConfig::ColorModifier modifier, [[nodiscard]] Id AppendColorModifier(
Pica::TexturingRegs::TevStageConfig::ColorModifier modifier,
Pica::TexturingRegs::TevStageConfig::Source source, s32 index); Pica::TexturingRegs::TevStageConfig::Source source, s32 index);
/// Writes the alpha component to use for the specified TEV stage alpha modifier /// Writes the alpha component to use for the specified TEV stage alpha modifier
[[nodiscard]] Id AppendAlphaModifier(Pica::TexturingRegs::TevStageConfig::AlphaModifier modifier, [[nodiscard]] Id AppendAlphaModifier(
Pica::TexturingRegs::TevStageConfig::AlphaModifier modifier,
Pica::TexturingRegs::TevStageConfig::Source source, s32 index); Pica::TexturingRegs::TevStageConfig::Source source, s32 index);
/// Writes the combiner function for the color components for the specified TEV stage operation /// Writes the combiner function for the color components for the specified TEV stage operation

View File

@ -6,8 +6,8 @@
#include <glslang/Include/ResourceLimits.h> #include <glslang/Include/ResourceLimits.h>
#include <glslang/Public/ShaderLang.h> #include <glslang/Public/ShaderLang.h>
#include "common/assert.h" #include "common/assert.h"
#include "common/microprofile.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/microprofile.h"
#include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_shader_util.h"
namespace Vulkan { namespace Vulkan {
@ -220,7 +220,8 @@ vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, v
return CompileSPV(out_code, device); return CompileSPV(out_code, device);
} }
MICROPROFILE_DEFINE(Vulkan_SPVCompilation, "Vulkan", "SPIR-V Shader Compilation", MP_RGB(100, 255, 52)); MICROPROFILE_DEFINE(Vulkan_SPVCompilation, "Vulkan", "SPIR-V Shader Compilation",
MP_RGB(100, 255, 52));
vk::ShaderModule CompileSPV(std::vector<u32> code, vk::Device device) { vk::ShaderModule CompileSPV(std::vector<u32> code, vk::Device device) {
MICROPROFILE_SCOPE(Vulkan_SPVCompilation); MICROPROFILE_SCOPE(Vulkan_SPVCompilation);
const vk::ShaderModuleCreateInfo shader_info = {.codeSize = code.size() * sizeof(u32), const vk::ShaderModuleCreateInfo shader_info = {.codeSize = code.size() * sizeof(u32),

View File

@ -5,11 +5,11 @@
#include <algorithm> #include <algorithm>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/microprofile.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/microprofile.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include <vk_mem_alloc.h> #include <vk_mem_alloc.h>
@ -80,16 +80,15 @@ StagingBuffer::~StagingBuffer() {
vmaDestroyBuffer(instance.GetAllocator(), static_cast<VkBuffer>(buffer), allocation); vmaDestroyBuffer(instance.GetAllocator(), static_cast<VkBuffer>(buffer), allocation);
} }
StreamBuffer::StreamBuffer(const Instance& instance, Scheduler& scheduler, u32 size, StreamBuffer::StreamBuffer(const Instance& instance, Scheduler& scheduler, u32 size, bool readback)
bool readback) : instance{instance}, scheduler{scheduler}, staging{instance, size, readback}, total_size{size},
: instance{instance}, scheduler{scheduler}, staging{instance, size, readback}, bucket_size{size / BUCKET_COUNT}, readback{readback} {}
total_size{size}, bucket_size{size / BUCKET_COUNT}, readback{readback} {}
StreamBuffer::StreamBuffer(const Instance& instance, Scheduler& scheduler, u32 size, StreamBuffer::StreamBuffer(const Instance& instance, Scheduler& scheduler, u32 size,
vk::BufferUsageFlagBits usage, std::span<const vk::Format> view_formats, vk::BufferUsageFlagBits usage, std::span<const vk::Format> view_formats,
bool readback) bool readback)
: instance{instance}, scheduler{scheduler}, staging{instance, size, readback}, : instance{instance}, scheduler{scheduler}, staging{instance, size, readback}, usage{usage},
usage{usage}, total_size{size}, bucket_size{size / BUCKET_COUNT}, readback{readback} { total_size{size}, bucket_size{size / BUCKET_COUNT}, readback{readback} {
const vk::BufferCreateInfo buffer_info = { const vk::BufferCreateInfo buffer_info = {
.size = total_size, .usage = usage | vk::BufferUsageFlagBits::eTransferDst}; .size = total_size, .usage = usage | vk::BufferUsageFlagBits::eTransferDst};
@ -176,7 +175,8 @@ void StreamBuffer::Flush() {
VmaAllocator allocator = instance.GetAllocator(); VmaAllocator allocator = instance.GetAllocator();
vmaFlushAllocation(allocator, staging.allocation, flush_offset, flush_size); vmaFlushAllocation(allocator, staging.allocation, flush_offset, flush_size);
if (gpu_buffer) { if (gpu_buffer) {
scheduler.Record([this, flush_offset = flush_offset, flush_size](vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) { scheduler.Record([this, flush_offset = flush_offset,
flush_size](vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) {
const vk::BufferCopy copy_region = { const vk::BufferCopy copy_region = {
.srcOffset = flush_offset, .dstOffset = flush_offset, .size = flush_size}; .srcOffset = flush_offset, .dstOffset = flush_offset, .size = flush_size};
@ -191,10 +191,9 @@ void StreamBuffer::Flush() {
.offset = flush_offset, .offset = flush_offset,
.size = flush_size}; .size = flush_size};
upload_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, upload_cmdbuf.pipelineBarrier(
MakePipelineStage(usage), vk::PipelineStageFlagBits::eTransfer, MakePipelineStage(usage),
vk::DependencyFlagBits::eByRegion, {}, buffer_barrier, vk::DependencyFlagBits::eByRegion, {}, buffer_barrier, {});
{});
}); });
} }
flush_offset = buffer_offset; flush_offset = buffer_offset;

View File

@ -30,10 +30,10 @@ struct StagingBuffer {
class StreamBuffer { class StreamBuffer {
static constexpr u32 MAX_BUFFER_VIEWS = 3; static constexpr u32 MAX_BUFFER_VIEWS = 3;
static constexpr u32 BUCKET_COUNT = 8; static constexpr u32 BUCKET_COUNT = 8;
public: public:
/// Staging only constructor /// Staging only constructor
StreamBuffer(const Instance& instance, Scheduler& scheduler, u32 size, StreamBuffer(const Instance& instance, Scheduler& scheduler, u32 size, bool readback = false);
bool readback = false);
/// Staging + GPU streaming constructor /// Staging + GPU streaming constructor
StreamBuffer(const Instance& instance, Scheduler& scheduler, u32 size, StreamBuffer(const Instance& instance, Scheduler& scheduler, u32 size,
vk::BufferUsageFlagBits usage, std::span<const vk::Format> views, vk::BufferUsageFlagBits usage, std::span<const vk::Format> views,

View File

@ -5,7 +5,7 @@
#include <algorithm> #include <algorithm>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "core/settings.h" #include "common/settings.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h" #include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
@ -13,9 +13,10 @@
namespace Vulkan { namespace Vulkan {
Swapchain::Swapchain(const Instance& instance, Scheduler& scheduler, RenderpassCache& renderpass_cache) Swapchain::Swapchain(const Instance& instance, Scheduler& scheduler,
: instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache}, RenderpassCache& renderpass_cache)
surface{instance.GetSurface()} { : instance{instance}, scheduler{scheduler},
renderpass_cache{renderpass_cache}, surface{instance.GetSurface()} {
FindPresentFormat(); FindPresentFormat();
SetPresentMode(); SetPresentMode();
renderpass_cache.CreatePresentRenderpass(surface_format.format); renderpass_cache.CreatePresentRenderpass(surface_format.format);
@ -85,8 +86,8 @@ MICROPROFILE_DEFINE(Vulkan_Acquire, "Vulkan", "Swapchain Acquire", MP_RGB(185, 6
void Swapchain::AcquireNextImage() { void Swapchain::AcquireNextImage() {
MICROPROFILE_SCOPE(Vulkan_Acquire); MICROPROFILE_SCOPE(Vulkan_Acquire);
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
vk::Result result = device.acquireNextImageKHR(swapchain, UINT64_MAX, image_acquired[frame_index], vk::Result result = device.acquireNextImageKHR(
VK_NULL_HANDLE, &image_index); swapchain, UINT64_MAX, image_acquired[frame_index], VK_NULL_HANDLE, &image_index);
switch (result) { switch (result) {
case vk::Result::eSuccess: case vk::Result::eSuccess:
@ -137,7 +138,8 @@ void Swapchain::FindPresentFormat() {
if (formats.size() == 1 && formats[0].format == vk::Format::eUndefined) { if (formats.size() == 1 && formats[0].format == vk::Format::eUndefined) {
surface_format.format = vk::Format::eB8G8R8A8Unorm; surface_format.format = vk::Format::eB8G8R8A8Unorm;
} else { } else {
auto it = std::find_if(formats.begin(), formats.end(), [](vk::SurfaceFormatKHR format) -> bool { auto it =
std::find_if(formats.begin(), formats.end(), [](vk::SurfaceFormatKHR format) -> bool {
return format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear && return format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear &&
format.format == vk::Format::eB8G8R8A8Unorm; format.format == vk::Format::eB8G8R8A8Unorm;
}); });
@ -172,7 +174,6 @@ void Swapchain::SetPresentMode() {
present_mode = vk::PresentModeKHR::eMailbox; present_mode = vk::PresentModeKHR::eMailbox;
} }
} }
} }
void Swapchain::SetSurfaceProperties(u32 width, u32 height) { void Swapchain::SetSurfaceProperties(u32 width, u32 height) {
@ -183,8 +184,8 @@ void Swapchain::SetSurfaceProperties(u32 width, u32 height) {
if (capabilities.currentExtent.width == std::numeric_limits<u32>::max()) { if (capabilities.currentExtent.width == std::numeric_limits<u32>::max()) {
extent.width = extent.width =
std::clamp(width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width); std::clamp(width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height = extent.height = std::clamp(height, capabilities.minImageExtent.height,
std::clamp(height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height); capabilities.maxImageExtent.height);
} }
// Select number of images in swap chain, we prefer one buffer in the background to work on // Select number of images in swap chain, we prefer one buffer in the background to work on

View File

@ -16,9 +16,9 @@ class RenderpassCache;
class Swapchain { class Swapchain {
static constexpr u32 PREFERRED_IMAGE_COUNT = 8; static constexpr u32 PREFERRED_IMAGE_COUNT = 8;
public: public:
Swapchain(const Instance& instance, Scheduler& scheduler, Swapchain(const Instance& instance, Scheduler& scheduler, RenderpassCache& renderpass_cache);
RenderpassCache& renderpass_cache);
~Swapchain(); ~Swapchain();
/// Creates (or recreates) the swapchain with a given size. /// Creates (or recreates) the swapchain with a given size.

View File

@ -65,9 +65,11 @@ constexpr u32 DOWNLOAD_BUFFER_SIZE = 32 * 1024 * 1024;
TextureRuntime::TextureRuntime(const Instance& instance, Scheduler& scheduler, TextureRuntime::TextureRuntime(const Instance& instance, Scheduler& scheduler,
RenderpassCache& renderpass_cache, DescriptorManager& desc_manager) RenderpassCache& renderpass_cache, DescriptorManager& desc_manager)
: instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache}, desc_manager{desc_manager}, : instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache},
blit_helper{instance, scheduler, desc_manager}, upload_buffer{instance, scheduler, UPLOAD_BUFFER_SIZE}, desc_manager{desc_manager}, blit_helper{instance, scheduler, desc_manager},
download_buffer{instance, scheduler, DOWNLOAD_BUFFER_SIZE, true} { upload_buffer{instance, scheduler, UPLOAD_BUFFER_SIZE}, download_buffer{instance, scheduler,
DOWNLOAD_BUFFER_SIZE,
true} {
auto Register = [this](VideoCore::PixelFormat dest, auto Register = [this](VideoCore::PixelFormat dest,
std::unique_ptr<FormatReinterpreterBase>&& obj) { std::unique_ptr<FormatReinterpreterBase>&& obj) {
@ -331,8 +333,8 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
} }
if (clear.texture_rect == surface.GetScaledRect()) { if (clear.texture_rect == surface.GetScaledRect()) {
scheduler.Record( scheduler.Record([aspect, image = surface.alloc.image, clear_value,
[aspect, image = surface.alloc.image, clear_value, clear](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { clear](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const vk::ImageSubresourceRange range = {.aspectMask = aspect, const vk::ImageSubresourceRange range = {.aspectMask = aspect,
.baseMipLevel = clear.texture_level, .baseMipLevel = clear.texture_level,
.levelCount = 1, .levelCount = 1,
@ -340,8 +342,8 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
.layerCount = 1}; .layerCount = 1};
if (aspect & vk::ImageAspectFlagBits::eColor) { if (aspect & vk::ImageAspectFlagBits::eColor) {
render_cmdbuf.clearColorImage(image, vk::ImageLayout::eTransferDstOptimal, clear_value.color, render_cmdbuf.clearColorImage(image, vk::ImageLayout::eTransferDstOptimal,
range); clear_value.color, range);
} else if (aspect & vk::ImageAspectFlagBits::eDepth || } else if (aspect & vk::ImageAspectFlagBits::eDepth ||
aspect & vk::ImageAspectFlagBits::eStencil) { aspect & vk::ImageAspectFlagBits::eStencil) {
render_cmdbuf.clearDepthStencilImage(image, vk::ImageLayout::eTransferDstOptimal, render_cmdbuf.clearDepthStencilImage(image, vk::ImageLayout::eTransferDstOptimal,
@ -355,8 +357,8 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
surface.pixel_format, VideoCore::PixelFormat::Invalid, true); surface.pixel_format, VideoCore::PixelFormat::Invalid, true);
surface.Transition(vk::ImageLayout::eColorAttachmentOptimal, 0, 1); surface.Transition(vk::ImageLayout::eColorAttachmentOptimal, 0, 1);
} else if (aspect & vk::ImageAspectFlagBits::eDepth) { } else if (aspect & vk::ImageAspectFlagBits::eDepth) {
clear_renderpass = renderpass_cache.GetRenderpass( clear_renderpass = renderpass_cache.GetRenderpass(VideoCore::PixelFormat::Invalid,
VideoCore::PixelFormat::Invalid, surface.pixel_format, true); surface.pixel_format, true);
surface.Transition(vk::ImageLayout::eDepthStencilAttachmentOptimal, 0, 1); surface.Transition(vk::ImageLayout::eDepthStencilAttachmentOptimal, 0, 1);
} }
@ -383,8 +385,7 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
static_cast<s32>(clear.texture_rect.bottom)}, static_cast<s32>(clear.texture_rect.bottom)},
.extent = {clear.texture_rect.GetWidth(), .extent = {clear.texture_rect.GetWidth(),
clear.texture_rect.GetHeight()}}, clear.texture_rect.GetHeight()}},
.clear = clear_value .clear = clear_value};
};
renderpass_cache.EnterRenderpass(clear_info); renderpass_cache.EnterRenderpass(clear_info);
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
@ -401,22 +402,24 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
dest.Transition(vk::ImageLayout::eTransferDstOptimal, copy.dst_level, 1); dest.Transition(vk::ImageLayout::eTransferDstOptimal, copy.dst_level, 1);
scheduler.Record([src_image = source.alloc.image, src_type = source.type, scheduler.Record([src_image = source.alloc.image, src_type = source.type,
dst_image = dest.alloc.image, dst_type = dest.type, copy](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { dst_image = dest.alloc.image, dst_type = dest.type,
const vk::ImageCopy image_copy = { copy](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
.srcSubresource = {.aspectMask = ToVkAspect(src_type), const vk::ImageCopy image_copy = {.srcSubresource = {.aspectMask = ToVkAspect(src_type),
.mipLevel = copy.src_level, .mipLevel = copy.src_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1}, .layerCount = 1},
.srcOffset = {static_cast<s32>(copy.src_offset.x), static_cast<s32>(copy.src_offset.y), 0}, .srcOffset = {static_cast<s32>(copy.src_offset.x),
static_cast<s32>(copy.src_offset.y), 0},
.dstSubresource = {.aspectMask = ToVkAspect(dst_type), .dstSubresource = {.aspectMask = ToVkAspect(dst_type),
.mipLevel = copy.dst_level, .mipLevel = copy.dst_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1}, .layerCount = 1},
.dstOffset = {static_cast<s32>(copy.dst_offset.x), static_cast<s32>(copy.dst_offset.y), 0}, .dstOffset = {static_cast<s32>(copy.dst_offset.x),
static_cast<s32>(copy.dst_offset.y), 0},
.extent = {copy.extent.width, copy.extent.height, 1}}; .extent = {copy.extent.width, copy.extent.height, 1}};
render_cmdbuf.copyImage(src_image, vk::ImageLayout::eTransferSrcOptimal, render_cmdbuf.copyImage(src_image, vk::ImageLayout::eTransferSrcOptimal, dst_image,
dst_image, vk::ImageLayout::eTransferDstOptimal, image_copy); vk::ImageLayout::eTransferDstOptimal, image_copy);
}); });
return true; return true;
@ -431,7 +434,8 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
scheduler.Record([src_iamge = source.alloc.image, src_type = source.type, scheduler.Record([src_iamge = source.alloc.image, src_type = source.type,
dst_image = dest.alloc.image, dst_type = dest.type, dst_image = dest.alloc.image, dst_type = dest.type,
format = source.pixel_format, blit](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { format = source.pixel_format,
blit](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const std::array source_offsets = {vk::Offset3D{static_cast<s32>(blit.src_rect.left), const std::array source_offsets = {vk::Offset3D{static_cast<s32>(blit.src_rect.left),
static_cast<s32>(blit.src_rect.bottom), 0}, static_cast<s32>(blit.src_rect.bottom), 0},
vk::Offset3D{static_cast<s32>(blit.src_rect.right), vk::Offset3D{static_cast<s32>(blit.src_rect.right),
@ -460,9 +464,8 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
? vk::Filter::eNearest ? vk::Filter::eNearest
: vk::Filter::eLinear; : vk::Filter::eLinear;
render_cmdbuf.blitImage(src_iamge, vk::ImageLayout::eTransferSrcOptimal, render_cmdbuf.blitImage(src_iamge, vk::ImageLayout::eTransferSrcOptimal, dst_image,
dst_image, vk::ImageLayout::eTransferDstOptimal, blit_area, vk::ImageLayout::eTransferDstOptimal, blit_area, filtering);
filtering);
}); });
return true; return true;
@ -519,7 +522,8 @@ bool TextureRuntime::NeedsConvertion(VideoCore::PixelFormat format) const {
!traits.attachment_support); !traits.attachment_support);
} }
void TextureRuntime::Transition(ImageAlloc& alloc, vk::ImageLayout new_layout, u32 level, u32 level_count) { void TextureRuntime::Transition(ImageAlloc& alloc, vk::ImageLayout new_layout, u32 level,
u32 level_count) {
LayoutTracker& tracker = alloc.tracker; LayoutTracker& tracker = alloc.tracker;
if (tracker.IsRangeEqual(new_layout, level, level_count) || !alloc.image) { if (tracker.IsRangeEqual(new_layout, level, level_count) || !alloc.image) {
return; return;
@ -601,12 +605,11 @@ void TextureRuntime::Transition(ImageAlloc& alloc, vk::ImageLayout new_layout, u
LayoutInfo dest = GetLayoutInfo(new_layout); LayoutInfo dest = GetLayoutInfo(new_layout);
tracker.ForEachLayoutRange( tracker.ForEachLayoutRange(
level, level_count, new_layout, [&](u32 start, u32 count, vk::ImageLayout old_layout) { level, level_count, new_layout, [&](u32 start, u32 count, vk::ImageLayout old_layout) {
scheduler.Record([old_layout, new_layout, dest, start, count, scheduler.Record([old_layout, new_layout, dest, start, count, image = alloc.image,
image = alloc.image, aspect = alloc.aspect, aspect = alloc.aspect, layers = alloc.layers,
layers = alloc.layers, GetLayoutInfo](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { GetLayoutInfo](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
LayoutInfo source = GetLayoutInfo(old_layout); LayoutInfo source = GetLayoutInfo(old_layout);
const vk::ImageMemoryBarrier barrier = { const vk::ImageMemoryBarrier barrier = {.srcAccessMask = source.access,
.srcAccessMask = source.access,
.dstAccessMask = dest.access, .dstAccessMask = dest.access,
.oldLayout = old_layout, .oldLayout = old_layout,
.newLayout = new_layout, .newLayout = new_layout,
@ -683,8 +686,8 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
ScaledUpload(upload, staging); ScaledUpload(upload, staging);
} else { } else {
Transition(vk::ImageLayout::eTransferDstOptimal, upload.texture_level, 1); Transition(vk::ImageLayout::eTransferDstOptimal, upload.texture_level, 1);
scheduler.Record([aspect = alloc.aspect, image = alloc.image, scheduler.Record([aspect = alloc.aspect, image = alloc.image, format = alloc.format,
format = alloc.format, staging, upload](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { staging, upload](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
u32 region_count = 0; u32 region_count = 0;
std::array<vk::BufferImageCopy, 2> copy_regions; std::array<vk::BufferImageCopy, 2> copy_regions;
@ -713,8 +716,9 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
} }
} }
render_cmdbuf.copyBufferToImage(staging.buffer, image, vk::ImageLayout::eTransferDstOptimal, render_cmdbuf.copyBufferToImage(staging.buffer, image,
region_count, copy_regions.data()); vk::ImageLayout::eTransferDstOptimal, region_count,
copy_regions.data());
}); });
runtime.upload_buffer.Commit(staging.size); runtime.upload_buffer.Commit(staging.size);
@ -741,8 +745,8 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
ScaledDownload(download, staging); ScaledDownload(download, staging);
} else { } else {
Transition(vk::ImageLayout::eTransferSrcOptimal, download.texture_level, 1); Transition(vk::ImageLayout::eTransferSrcOptimal, download.texture_level, 1);
scheduler.Record([aspect = alloc.aspect, image = alloc.image, scheduler.Record([aspect = alloc.aspect, image = alloc.image, staging,
staging, download](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer){ download](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const VideoCore::Rect2D rect = download.texture_rect; const VideoCore::Rect2D rect = download.texture_rect;
const vk::BufferImageCopy copy_region = { const vk::BufferImageCopy copy_region = {
.bufferOffset = staging.buffer_offset + download.buffer_offset, .bufferOffset = staging.buffer_offset + download.buffer_offset,