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) {
// 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) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

View File

@ -148,7 +148,7 @@ public:
// disable vsync for any shared contexts
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->setShareContext(share_context);
@ -281,8 +281,8 @@ private:
class OpenGLRenderWidget : public RenderWidget {
public:
explicit OpenGLRenderWidget(GRenderWindow* parent, bool is_secondary) :
RenderWidget(parent), is_secondary(is_secondary) {
explicit OpenGLRenderWidget(GRenderWindow* parent, bool is_secondary)
: RenderWidget(parent), is_secondary(is_secondary) {
windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
}
@ -341,7 +341,9 @@ static Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window
#if defined(WIN32)
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
#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
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
wsi.display_connection = pni->nativeResourceForWindow("display", window);
@ -552,7 +554,7 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
}
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 ||
graphics_api == Settings::GraphicsAPI::OpenGLES) {
auto c = static_cast<OpenGLSharedContext*>(main_context.get());
@ -576,7 +578,7 @@ bool GRenderWindow::InitRenderTarget() {
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) {
case Settings::GraphicsAPI::OpenGL:
case Settings::GraphicsAPI::OpenGLES:

View File

@ -3,8 +3,8 @@
// Refer to the license.txt file included.
#include <QDesktopServices>
#include <QUrl>
#include <QMessageBox>
#include <QUrl>
#include "citra_qt/configuration/configure_debug.h"
#include "citra_qt/debugger/console.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) {
if (checked && Settings::values.graphics_api == Settings::GraphicsAPI::Vulkan) {
if (checked && Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::Vulkan) {
try {
Vulkan::Instance debug_inst{true};
} catch (vk::LayerNotPresentError&) {
ui->toggle_renderer_debug->toggle();
QMessageBox::warning(
this, tr("Validation layer not available"),
QMessageBox::warning(this, tr("Validation layer not available"),
tr("Unable to enable debug renderer because the layer "
"<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) {
if (checked && Settings::values.graphics_api == Settings::GraphicsAPI::Vulkan) {
if (checked && Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::Vulkan) {
try {
Vulkan::Instance debug_inst{false, true};
} catch (vk::LayerNotPresentError&) {
ui->toggle_dump_command_buffers->toggle();
QMessageBox::warning(
this, tr("Command buffer dumping not available"),
QMessageBox::warning(this, tr("Command buffer dumping not available"),
tr("Unable to enable command buffer dumping because the layer "
"<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_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.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->physical_device_combo->setCurrentIndex(static_cast<int>(Settings::values.physical_device.GetValue()));
ui->graphics_api_combo->setCurrentIndex(
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->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);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync_new, ui->toggle_vsync_new,
use_vsync_new);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api, ui->graphics_api_combo);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.physical_device, ui->physical_device_combo);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_command_recording, ui->toggle_async_recording,
async_command_recording);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.spirv_shader_gen, ui->spirv_shader_gen,
spirv_shader_gen);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api,
ui->graphics_api_combo);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.physical_device,
ui->physical_device_combo);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_command_recording,
ui->toggle_async_recording, async_command_recording);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.spirv_shader_gen,
ui->spirv_shader_gen, spirv_shader_gen);
if (Settings::IsConfiguringGlobal()) {
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;
ui->physical_device_label->setVisible(is_visible);
ui->physical_device_combo->setVisible(is_visible);
<<<<<<< HEAD
}
=======
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"),
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) {
api_index = (api_index + 1) % graphics_apis.size();
Settings::values.graphics_api = static_cast<Settings::GraphicsAPI>(api_index);

View File

@ -4,8 +4,8 @@
#include <limits>
#include "core/memory.h"
#include "video_core/rasterizer_accelerated.h"
#include "video_core/pica_state.h"
#include "video_core/rasterizer_accelerated.h"
#include "video_core/video_core.h"
namespace VideoCore {
@ -711,16 +711,15 @@ void RasterizerAccelerated::SyncAlphaTest() {
}
void RasterizerAccelerated::SyncCombinerColor() {
auto combiner_color =
ColorRGBA8(Pica::g_state.regs.texturing.tev_combiner_buffer_color.raw);
auto combiner_color = ColorRGBA8(Pica::g_state.regs.texturing.tev_combiner_buffer_color.raw);
if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
uniform_block_data.dirty = true;
}
}
void RasterizerAccelerated::SyncTevConstColor(std::size_t stage_index,
const Pica::TexturingRegs::TevStageConfig& tev_stage) {
void RasterizerAccelerated::SyncTevConstColor(
std::size_t stage_index, const Pica::TexturingRegs::TevStageConfig& tev_stage) {
const auto const_color = ColorRGBA8(tev_stage.const_color);
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) {
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) {
uniform_block_data.data.light_src[light_index].spot_direction = spot_direction;

View File

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

View File

@ -5,8 +5,8 @@
#pragma once
#include <array>
#include "common/math_util.h"
#include "common/bit_field.h"
#include "common/math_util.h"
#include "common/vector_math.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)
: driver{driver}, runtime{driver}, res_cache{*this, runtime},
shader_program_manager{emu_window, driver, !driver.IsOpenGLES()},
vertex_buffer{GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE},
uniform_buffer{GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE},
index_buffer{GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE},
texture_buffer{GL_TEXTURE_BUFFER, TEXTURE_BUFFER_SIZE},
vertex_buffer{GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE}, uniform_buffer{GL_UNIFORM_BUFFER,
UNIFORM_BUFFER_SIZE},
index_buffer{GL_ELEMENT_ARRAY_BUFFER, INDEX_BUFFER_SIZE}, texture_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
@ -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));
bool RasterizerOpenGL::SetupVertexShader() {
MICROPROFILE_SCOPE(OpenGL_VS);
return shader_program_manager.UseProgrammableVertexShader(Pica::g_state.regs,
Pica::g_state.vs);
return shader_program_manager.UseProgrammableVertexShader(Pica::g_state.regs, Pica::g_state.vs);
}
MICROPROFILE_DEFINE(OpenGL_GS, "OpenGL", "Geometry Shader Setup", MP_RGB(128, 192, 128));

View File

@ -7,11 +7,11 @@
#include <thread>
#include <unordered_map>
#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_shader_disk_cache.h"
#include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_driver.h"
#include "video_core/video_core.h"
namespace OpenGL {
@ -374,7 +374,8 @@ public:
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} {}
ShaderProgramManager::~ShaderProgramManager() = default;

View File

@ -12,7 +12,8 @@ MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
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_buffer.Create();
glBindBuffer(gl_target, gl_buffer.handle);
@ -20,11 +21,12 @@ OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool readback,
if (GLAD_GL_ARB_buffer_storage) {
persistent = true;
coherent = prefer_coherent;
GLbitfield flags =
(readback ? GL_MAP_READ_BIT : GL_MAP_WRITE_BIT) | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0);
GLbitfield flags = (readback ? GL_MAP_READ_BIT : GL_MAP_WRITE_BIT) | GL_MAP_PERSISTENT_BIT |
(coherent ? GL_MAP_COHERENT_BIT : 0);
glBufferStorage(gl_target, size, nullptr, flags);
mapped_ptr = static_cast<u8*>(glMapBufferRange(
gl_target, 0, buffer_size, flags | (!coherent && !readback ? GL_MAP_FLUSH_EXPLICIT_BIT : 0)));
mapped_ptr = static_cast<u8*>(
glMapBufferRange(gl_target, 0, buffer_size,
flags | (!coherent && !readback ? GL_MAP_FLUSH_EXPLICIT_BIT : 0)));
} else {
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) {
MICROPROFILE_SCOPE(OpenGL_StreamBuffer);
GLbitfield flags = (readback ? GL_MAP_READ_BIT : GL_MAP_WRITE_BIT) | (persistent ? GL_MAP_PERSISTENT_BIT : 0) |
(coherent ? GL_MAP_COHERENT_BIT : 0) | (!coherent && !readback ? GL_MAP_FLUSH_EXPLICIT_BIT : 0) |
GLbitfield flags = (readback ? GL_MAP_READ_BIT : GL_MAP_WRITE_BIT) |
(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);
mapped_ptr = static_cast<u8*>(
glMapBufferRange(gl_target, buffer_pos, buffer_size - buffer_pos, flags));

View File

@ -10,7 +10,8 @@ namespace OpenGL {
class OGLStreamBuffer : private NonCopyable {
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();
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;
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},
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);
glReadPixels(download.texture_rect.left, download.texture_rect.bottom,
download.texture_rect.GetWidth(), download.texture_rect.GetHeight(),
tuple.format, tuple.type,
reinterpret_cast<void*>(staging.buffer_offset));
tuple.format, tuple.type, reinterpret_cast<void*>(staging.buffer_offset));
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);
}
void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload,
const StagingData& staging) {
void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging) {
const u32 rect_width = upload.texture_rect.GetWidth();
const u32 rect_height = upload.texture_rect.GetHeight();
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_height = download.texture_rect.GetHeight();
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);
if (driver.IsOpenGLES()) {
const auto& downloader_es = runtime.GetDownloaderES();
downloader_es.GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, rect_height, rect_width,
reinterpret_cast<void*>(staging.buffer_offset));
downloader_es.GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, rect_height,
rect_width, reinterpret_cast<void*>(staging.buffer_offset));
} else {
glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type,
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)
: RendererBase{window, secondary_window}, driver{Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES,
Settings::values.renderer_debug},
: RendererBase{window, secondary_window}, driver{Settings::values.graphics_api.GetValue() ==
Settings::GraphicsAPI::OpenGLES,
Settings::values.renderer_debug.GetValue()},
frame_dumper(Core::System::GetInstance().VideoDumper(), window) {
window.mailbox = std::make_unique<OGLTextureMailbox>();
if (secondary_window) {

View File

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

View File

@ -10,12 +10,12 @@
#include "common/math_util.h"
#include "core/hw/gpu.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_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
#include "video_core/renderer_vulkan/vk_instance.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_swapchain.h"
namespace Core {
class TelemetrySession;

View File

@ -4,15 +4,16 @@
#include "common/vector_math.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_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"
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()} {
constexpr std::string_view cs_source = R"(
#version 450 core
@ -142,7 +143,8 @@ void BlitHelper::BlitD24S8ToR32(Surface& source, Surface& dest,
device.updateDescriptorSetWithTemplate(set, update_template, textures[0]);
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);
const auto src_offset = Common::MakeVec(blit.src_rect.left, blit.src_rect.bottom);

View File

@ -19,8 +19,7 @@ class Surface;
class BlitHelper {
public:
BlitHelper(const Instance& instance, Scheduler& scheduler,
DescriptorManager& desc_manager);
BlitHelper(const Instance& instance, Scheduler& scheduler, DescriptorManager& desc_manager);
~BlitHelper();
/// 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)
: instance{instance}, scheduler{scheduler}, pool_provider{instance, scheduler.GetMasterSemaphore()} {
: instance{instance}, scheduler{scheduler}, pool_provider{instance,
scheduler.GetMasterSemaphore()} {
BuildLayouts();
descriptor_set_dirty.fill(true);
current_pool = pool_provider.Commit();
@ -101,7 +102,8 @@ void DescriptorManager::BindDescriptorSets() {
}
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);
@ -158,9 +160,7 @@ vk::DescriptorSet DescriptorManager::AllocateSet(vk::DescriptorSetLayout layout)
vk::Device device = instance.GetDevice();
const vk::DescriptorSetAllocateInfo alloc_info = {
.descriptorPool = current_pool,
.descriptorSetCount = 1,
.pSetLayouts = &layout};
.descriptorPool = current_pool, .descriptorSetCount = 1, .pSetLayouts = &layout};
try {
return device.allocateDescriptorSets(alloc_info)[0];

View File

@ -2,17 +2,18 @@
// Licensed under GPLv2 or any later version
// 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_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_shader_util.h"
#include "video_core/renderer_vulkan/vk_texture_runtime.h"
namespace Vulkan {
D24S8toRGBA8::D24S8toRGBA8(const Instance& instance, Scheduler& scheduler,
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"(
#version 450 core
#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]);
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);
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 {
public:
D24S8toRGBA8(const Instance& instance, Scheduler& scheduler,
DescriptorManager& desc_manager, TextureRuntime& runtime);
D24S8toRGBA8(const Instance& instance, Scheduler& scheduler, DescriptorManager& desc_manager,
TextureRuntime& runtime);
~D24S8toRGBA8();
[[nodiscard]] VideoCore::PixelFormat GetSourceFormat() const override {

View File

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

View File

@ -1,19 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// 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_master_semaphore.h"
namespace Vulkan {
MasterSemaphore::MasterSemaphore(const Instance& instance) : device{instance.GetDevice()} {
const vk::StructureChain semaphore_chain = {
vk::SemaphoreCreateInfo{},
const vk::StructureChain semaphore_chain = {vk::SemaphoreCreateInfo{},
vk::SemaphoreTypeCreateInfoKHR{
.semaphoreType = vk::SemaphoreType::eTimeline,
.initialValue = 0,
}
};
}};
semaphore = device.createSemaphore(semaphore_chain.get());
}

View File

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

View File

@ -5,14 +5,14 @@
#include <filesystem>
#include "common/common_paths.h"
#include "common/file_util.h"
#include "common/microprofile.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/vk_descriptor_manager.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_descriptor_manager.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
namespace Vulkan {
@ -62,7 +62,8 @@ vk::ShaderStageFlagBits ToVkShaderStage(std::size_t index) {
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;
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);
if (new_format) {
LOG_INFO(Render_Vulkan, "Quering support for format {}", vk::to_string(format));
const vk::FormatFeatureFlags features = physical_device.getFormatProperties(format).bufferFeatures;
it->second = (features & vk::FormatFeatureFlagBits::eVertexBuffer) == vk::FormatFeatureFlagBits::eVertexBuffer;
const vk::FormatFeatureFlags features =
physical_device.getFormatProperties(format).bufferFeatures;
it->second = (features & vk::FormatFeatureFlagBits::eVertexBuffer) ==
vk::FormatFeatureFlagBits::eVertexBuffer;
}
return it->second;
@ -79,7 +82,8 @@ vk::ShaderStageFlagBits ToVkShaderStage(std::size_t index) {
PipelineCache::PipelineCache(const Instance& instance, Scheduler& scheduler,
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,
instance.GetDevice(), ShaderOptimization::Debug);
}
@ -211,8 +215,7 @@ bool PipelineCache::UseProgrammableVertexShader(const Pica::Regs& regs,
ASSERT(is_supported || attrib.size == 3);
config.state.attrib_types[location] = attrib.type.Value();
config.state.emulated_attrib_locations[location] =
is_supported ? 0 : emulated_attrib_loc++;
config.state.emulated_attrib_locations[location] = is_supported ? 0 : emulated_attrib_loc++;
}
auto [handle, result] =
@ -223,7 +226,8 @@ bool PipelineCache::UseProgrammableVertexShader(const Pica::Regs& regs,
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;
shader_hashes[ProgramType::VS] = hash;
});
@ -242,7 +246,8 @@ void PipelineCache::UseFixedGeometryShader(const Pica::Regs& regs) {
const PicaFixedGSConfig gs_config{regs};
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);
current_shaders[ProgramType::GS] = handle;
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) {
const PicaFSConfig config{regs, instance};
@ -322,22 +328,19 @@ void PipelineCache::ApplyDynamic(const PipelineInfo& info) {
const bool is_dirty = scheduler.IsStateDirty(StateFlags::Pipeline);
PipelineInfo current = current_info;
scheduler.Record([this, info, is_dirty, current](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
if (info.dynamic.stencil_compare_mask !=
current.dynamic.stencil_compare_mask ||
is_dirty) {
scheduler.Record([this, info, is_dirty, current](vk::CommandBuffer render_cmdbuf,
vk::CommandBuffer) {
if (info.dynamic.stencil_compare_mask != current.dynamic.stencil_compare_mask || is_dirty) {
render_cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack,
info.dynamic.stencil_compare_mask);
}
if (info.dynamic.stencil_write_mask != current.dynamic.stencil_write_mask ||
is_dirty) {
if (info.dynamic.stencil_write_mask != current.dynamic.stencil_write_mask || is_dirty) {
render_cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack,
info.dynamic.stencil_write_mask);
}
if (info.dynamic.stencil_reference != current.dynamic.stencil_reference ||
is_dirty) {
if (info.dynamic.stencil_reference != current.dynamic.stencil_reference || is_dirty) {
render_cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
info.dynamic.stencil_reference);
}
@ -364,8 +367,7 @@ void PipelineCache::ApplyDynamic(const PipelineInfo& info) {
render_cmdbuf.setDepthTestEnableEXT(info.depth_stencil.depth_test_enable);
}
if (info.depth_stencil.depth_write_enable !=
current.depth_stencil.depth_write_enable ||
if (info.depth_stencil.depth_write_enable != current.depth_stencil.depth_write_enable ||
is_dirty) {
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_depth_fail_op !=
current.depth_stencil.stencil_depth_fail_op ||
info.depth_stencil.stencil_compare_op !=
current.depth_stencil.stencil_compare_op ||
info.depth_stencil.stencil_compare_op != current.depth_stencil.stencil_compare_op ||
is_dirty) {
render_cmdbuf.setStencilOpEXT(
vk::StencilFaceFlagBits::eFrontAndBack,
@ -443,10 +444,10 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
const bool is_supported = IsAttribFormatSupported(attrib, instance);
ASSERT_MSG(is_supported || attrib.size == 3);
attributes[i] = vk::VertexInputAttributeDescription{.location = attrib.location,
attributes[i] = vk::VertexInputAttributeDescription{
.location = attrib.location,
.binding = attrib.binding,
.format = is_supported ? format
: ToVkAttributeFormat(attrib.type, 2),
.format = is_supported ? format : ToVkAttributeFormat(attrib.type, 2),
.offset = attrib.offset};
// 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.
if (!is_supported) {
const u32 location = MAX_VERTEX_ATTRIBUTES + emulated_attrib_count++;
LOG_WARNING(Render_Vulkan, "\nEmulating attrib {} at location {}\n", attrib.location, location);
attributes[location] = vk::VertexInputAttributeDescription{.location = location,
LOG_WARNING(Render_Vulkan, "\nEmulating attrib {} at location {}\n", attrib.location,
location);
attributes[location] = vk::VertexInputAttributeDescription{
.location = location,
.binding = attrib.binding,
.format = ToVkAttributeFormat(attrib.type, 1),
.offset = attrib.offset + AttribBytes(attrib.type, 2)};
@ -465,7 +468,8 @@ vk::Pipeline PipelineCache::BuildPipeline(const PipelineInfo& info) {
const vk::PipelineVertexInputStateCreateInfo vertex_input_info = {
.vertexBindingDescriptionCount = info.vertex_layout.binding_count,
.pVertexBindingDescriptions = bindings.data(),
.vertexAttributeDescriptionCount = info.vertex_layout.attribute_count + emulated_attrib_count,
.vertexAttributeDescriptionCount =
info.vertex_layout.attribute_count + emulated_attrib_count,
.pVertexAttributeDescriptions = attributes.data()};
const vk::PipelineInputAssemblyStateCreateInfo input_assembly = {

View File

@ -9,8 +9,8 @@
#include "common/hash.h"
#include "video_core/rasterizer_cache/pixel_format.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_util.h"
#include "video_core/shader/shader_cache.h"
namespace Vulkan {
@ -100,8 +100,8 @@ struct PipelineInfo {
const bool has_stencil = depth_attachment == VideoCore::PixelFormat::D24S8;
const bool depth_write =
depth_stencil.depth_test_enable && depth_stencil.depth_write_enable;
const bool stencil_write = has_stencil && depth_stencil.stencil_test_enable &&
dynamic.stencil_write_mask != 0;
const bool stencil_write =
has_stencil && depth_stencil.stencil_test_enable && dynamic.stencil_write_mask != 0;
return depth_write || stencil_write;
}
@ -119,8 +119,8 @@ using FixedGeometryShaders = Pica::Shader::ShaderCache<PicaFixedGSConfig, vk::Sh
using FragmentShadersGLSL =
Pica::Shader::ShaderCache<PicaFSConfig, vk::ShaderModule, &Compile, &GenerateFragmentShader>;
using FragmentShadersSPV =
Pica::Shader::ShaderCache<PicaFSConfig, vk::ShaderModule, &CompileSPV, &GenerateFragmentShaderSPV>;
using FragmentShadersSPV = Pica::Shader::ShaderCache<PicaFSConfig, vk::ShaderModule, &CompileSPV,
&GenerateFragmentShaderSPV>;
class Instance;
class Scheduler;
@ -132,8 +132,8 @@ class DescriptorManager;
*/
class PipelineCache {
public:
PipelineCache(const Instance& instance, Scheduler& scheduler,
RenderpassCache& renderpass_cache, DescriptorManager& desc_manager);
PipelineCache(const Instance& instance, Scheduler& scheduler, RenderpassCache& renderpass_cache,
DescriptorManager& desc_manager);
~PipelineCache();
/// 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)
if (window_info.type == Frontend::WindowSystemType::MacOS) {
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) {
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)
if (window_info.type == Frontend::WindowSystemType::Android) {
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");
UNREACHABLE();
}
@ -145,7 +144,8 @@ std::vector<const char*> GetInstanceExtensions(Frontend::WindowSystemType window
}
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;
});

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;
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
VertexBinding& binding = layout.bindings[layout.binding_count];
@ -259,12 +260,11 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
SetupFixedAttribs();
// Bind the generated bindings
scheduler.Record([this, layout = pipeline_info.vertex_layout,
offsets = binding_offsets](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
scheduler.Record([this, layout = pipeline_info.vertex_layout, offsets = binding_offsets](
vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
std::array<vk::Buffer, 16> buffers;
buffers.fill(vertex_buffer.GetHandle());
render_cmdbuf.bindVertexBuffers(0, layout.binding_count, buffers.data(),
offsets.data());
render_cmdbuf.bindVertexBuffers(0, layout.binding_count, buffers.data(), offsets.data());
});
}
@ -367,7 +367,8 @@ bool RasterizerVulkan::AccelerateDrawBatch(bool is_indexed) {
bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) {
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) {
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);
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) {
const vk::IndexType index_type = index_u16 ? vk::IndexType::eUint16 : vk::IndexType::eUint8EXT;
index_u16, vertex_offset = vs_input_index_min](
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.drawIndexed(num_vertices, 1, 0, -vertex_offset, 0);
});
} 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);
});
}
@ -718,8 +722,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
.render_area = vk::Rect2D{.offset = {static_cast<s32>(draw_rect.left),
static_cast<s32>(draw_rect.bottom)},
.extent = {draw_rect.GetWidth(), draw_rect.GetHeight()}},
.clear = {}
};
.clear = {}};
renderpass_cache.EnterRenderpass(renderpass_info);
@ -1043,10 +1046,7 @@ bool RasterizerVulkan::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
void RasterizerVulkan::MakeSoftwareVertexLayout() {
constexpr std::array sizes = {4, 4, 2, 2, 2, 1, 4, 3};
software_layout = VertexLayout{
.binding_count = 1,
.attribute_count = 8
};
software_layout = VertexLayout{.binding_count = 1, .attribute_count = 8};
for (u32 i = 0; i < software_layout.binding_count; i++) {
VertexBinding& binding = software_layout.bindings[i];

View File

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

View File

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

View File

@ -3,9 +3,9 @@
#include <cstddef>
#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_master_semaphore.h"
#include "video_core/renderer_vulkan/vk_resource_pool.h"
namespace Vulkan {
@ -16,7 +16,8 @@ std::size_t ResourcePool::CommitResource() {
// Refresh semaphore to query updated results
master_semaphore->Refresh();
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) {
if (gpu_tick >= ticks[iterator]) {
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 = {
.flags = vk::CommandPoolCreateFlagBits::eTransient |
vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
.queueFamilyIndex = instance.GetGraphicsQueueFamilyIndex()
};
.queueFamilyIndex = instance.GetGraphicsQueueFamilyIndex()};
vk::Device device = instance.GetDevice();
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,
.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();
// Choose a sane pool size good for most games
static constexpr std::array<vk::DescriptorPoolSize, 5> pool_sizes = {{
{vk::DescriptorType::eUniformBuffer, 4096},
static constexpr std::array<vk::DescriptorPoolSize, 5> pool_sizes = {
{{vk::DescriptorType::eUniformBuffer, 4096},
{vk::DescriptorType::eSampledImage, 4096},
{vk::DescriptorType::eSampler, 4096},
{vk::DescriptorType::eUniformTexelBuffer, 2048},

View File

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

View File

@ -10,8 +10,8 @@
#include <utility>
#include <queue>
#include "common/alignment.h"
#include "common/common_types.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_resource_pool.h"
@ -105,7 +105,8 @@ private:
public:
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 {
return next;
@ -128,7 +129,8 @@ private:
TypedCommand(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);
}

View File

@ -10,8 +10,8 @@
#include "video_core/pica_state.h"
#include "video_core/regs_framebuffer.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_shader_gen.h"
#include "video_core/video_core.h"
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_flip.Assign(regs.texturing.fog_flip != 0);
state.combiner_buffer_input.Assign(regs.texturing.tev_combiner_buffer_input.update_mask_rgb.Value() |
regs.texturing.tev_combiner_buffer_input.update_mask_a.Value()
<< 4);
state.combiner_buffer_input.Assign(
regs.texturing.tev_combiner_buffer_input.update_mask_rgb.Value() |
regs.texturing.tev_combiner_buffer_input.update_mask_a.Value() << 4);
// Fragment lighting
@ -155,14 +155,18 @@ PicaFSConfig::PicaFSConfig(const Pica::Regs& regs, const Instance& instance) {
const auto& light = regs.lighting.light[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].two_sided_diffuse.Assign(light.config.two_sided_diffuse != 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].two_sided_diffuse.Assign(light.config.two_sided_diffuse !=
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(
!regs.lighting.IsDistAttenDisabled(num));
state.lighting.light[light_index].spot_atten_enable.Assign(
!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);
@ -243,7 +247,6 @@ PicaFSConfig::PicaFSConfig(const Pica::Regs& regs, const Instance& instance) {
state.shadow_texture_orthographic.Assign(regs.texturing.shadow.orthographic != 0);
}
void PicaShaderConfigCommon::Init(const Pica::ShaderRegs& regs, Pica::Shader::ShaderSetup& setup) {
program_hash = setup.GetProgramCodeHash();
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)";
break;
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;
case Operation::Subtract:
out += "color_results_1 - color_results_2";
@ -523,8 +527,7 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper
break;
case Operation::Dot3_RGB:
case Operation::Dot3_RGBA:
out +=
"vec3(dot(color_results_1 - vec3(0.5), color_results_2 - vec3(0.5)) * 4.0)";
out += "vec3(dot(color_results_1 - vec3(0.5), color_results_2 - vec3(0.5)) * 4.0)";
break;
default:
out += "vec3(0.0)";
@ -1566,7 +1569,8 @@ do {
// with fragment shader alone, so we emulate this behavior with the color mask.
break;
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();
}
}
@ -1672,7 +1676,8 @@ layout (set = 0, binding = 0, std140) uniform vs_config {
prefix = "u";
break;
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();
}
@ -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.
// Define them here and combine them below
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;
switch (config.state.attrib_types[i]) {
case Pica::PipelineRegs::VertexAttributeFormat::FLOAT:
@ -1698,11 +1704,13 @@ layout (set = 0, binding = 0, std140) uniform vs_config {
type = "uint";
break;
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();
}
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) {
if (used_regs[i]) {
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 {
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 {
FragmentModule::FragmentModule(const PicaFSConfig& config) : Sirit::Module{0x00010300}, config{config} {
FragmentModule::FragmentModule(const PicaFSConfig& config)
: Sirit::Module{0x00010300}, config{config} {
DefineArithmeticTypes();
DefineUniformStructs();
DefineInterface();
@ -82,13 +83,15 @@ void FragmentModule::Generate() {
void FragmentModule::WriteDepth() {
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 depth_scale{GetShaderDataMember(f32_id, ConstS32(2))};
const Id depth_offset{GetShaderDataMember(f32_id, ConstS32(3))};
const Id depth{OpFma(f32_id, z_over_w, depth_scale, depth_offset)};
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)};
OpStore(gl_frag_depth_id, depth_over_w);
} 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_cross_v{OpCross(vec_ids.Get(3), q_xyz, v)};
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 val2{OpVectorTimesScalar(vec_ids.Get(3), OpCross(vec_ids.Get(3), q_xyz, val1), ConstF32(2.f))};
const Id val1{
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);
};
@ -189,7 +194,8 @@ void FragmentModule::WriteLighting() {
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 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);
};
@ -203,7 +209,8 @@ void FragmentModule::WriteLighting() {
index = OpDot(f32_id, normal, OpNormalize(vec_ids.Get(3), half_vector));
break;
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;
case LightingRegs::LightingLutInput::NV:
index = OpDot(f32_id, normal, OpNormalize(vec_ids.Get(3), view));
@ -222,8 +229,10 @@ void FragmentModule::WriteLighting() {
// using the modified normal 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_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)};
const Id 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
// product. The result is in fact not cos(phi) as the name suggested.
@ -267,7 +276,8 @@ void FragmentModule::WriteLighting() {
if (light_config.directional) {
light_vector = OpNormalize(vec_ids.Get(3), light_position);
} 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);
@ -292,7 +302,8 @@ void FragmentModule::WriteLighting() {
LightingRegs::IsLightingSamplerSupported(
lighting.config, LightingRegs::LightingSampler::SpotlightAttenuation)) {
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);
}
@ -301,16 +312,20 @@ void FragmentModule::WriteLighting() {
if (light_config.dist_atten_enable) {
const Id dist_atten_scale{GetLightMember(7)};
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 index{OpFma(f32_id, dist_atten_scale, OpLength(f32_id, min_view_min_pos), dist_atten_bias)};
const Id min_view_min_pos{
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 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);
}
if (light_config.geometric_factor_0 || light_config.geometric_factor_1) {
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))};
geo_factor = OpSelect(f32_id, is_geo_factor_zero, ConstF32(0.f), dot_div_geo);
}
@ -321,8 +336,9 @@ void FragmentModule::WriteLighting() {
LightingRegs::IsLightingSamplerSupported(
lighting.config, LightingRegs::LightingSampler::Distribution0)) {
// Lookup specular "distribution 0" LUT value
const Id value{GetLutValue(LightingRegs::LightingSampler::Distribution0, light_config.num,
lighting.lut_d0.type, lighting.lut_d0.abs_input)};
const Id value{GetLutValue(LightingRegs::LightingSampler::Distribution0,
light_config.num, lighting.lut_d0.type,
lighting.lut_d0.abs_input)};
d0_lut_value = OpFMul(f32_id, ConstF32(lighting.lut_d0.scale), value);
}
@ -347,8 +363,9 @@ void FragmentModule::WriteLighting() {
if (lighting.lut_rg.enable &&
LightingRegs::IsLightingSamplerSupported(lighting.config,
LightingRegs::LightingSampler::ReflectGreen)) {
const Id value{GetLutValue(LightingRegs::LightingSampler::ReflectGreen, light_config.num,
lighting.lut_rg.type, lighting.lut_rg.abs_input)};
const Id value{GetLutValue(LightingRegs::LightingSampler::ReflectGreen,
light_config.num, lighting.lut_rg.type,
lighting.lut_rg.abs_input)};
refl_value_g = OpFMul(f32_id, ConstF32(lighting.lut_rg.scale), value);
}
@ -369,14 +386,18 @@ void FragmentModule::WriteLighting() {
LightingRegs::IsLightingSamplerSupported(
lighting.config, LightingRegs::LightingSampler::Distribution1)) {
// Lookup specular "distribution 1" LUT value
const Id value{GetLutValue(LightingRegs::LightingSampler::Distribution1, light_config.num,
lighting.lut_d1.type, lighting.lut_d1.abs_input)};
const Id value{GetLutValue(LightingRegs::LightingSampler::Distribution1,
light_config.num, lighting.lut_d1.type,
lighting.lut_d1.abs_input)};
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)};
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) {
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_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 light_diffuse{GetLightMember(2)};
@ -437,7 +459,8 @@ void FragmentModule::WriteLighting() {
// Apply shadow attenuation to alpha components if enabled
if (lighting.shadow_alpha) {
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) {
diffuse_sum = OpFMul(vec_ids.Get(4), diffuse_sum, shadow_a_vec);
}
@ -448,7 +471,8 @@ void FragmentModule::WriteLighting() {
// Sum final lighting result
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 one_vec{ConstF32(1.f, 1.f, 1.f, 1.f)};
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
alpha_output = OpCompositeExtract(f32_id, color_output, 0);
} else {
alpha_results_1 = AppendAlphaModifier(stage.alpha_modifier1, stage.alpha_source1, index);
alpha_results_2 = AppendAlphaModifier(stage.alpha_modifier2, stage.alpha_source2, index);
alpha_results_3 = AppendAlphaModifier(stage.alpha_modifier3, stage.alpha_source3, index);
alpha_results_1 =
AppendAlphaModifier(stage.alpha_modifier1, stage.alpha_source1, 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));
}
color_output = OpVectorTimesScalar(vec_ids.Get(3), color_output, ConstF32(static_cast<float>(stage.GetColorMultiplier())));
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())));
color_output = OpVectorTimesScalar(
vec_ids.Get(3), color_output, ConstF32(static_cast<float>(stage.GetColorMultiplier())));
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));
last_tex_env_out = OpCompositeConstruct(vec_ids.Get(4), color_output, alpha_output);
}
combiner_buffer = next_combiner_buffer;
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)) {
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::GreaterThan:
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 alphatest_ref{GetShaderDataMember(i32_id, ConstS32(1))};
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_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 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)};
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) {
@ -600,9 +635,9 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
const Id sampled_image{OpSampledImage(TypeSampledImage(image_type), tex, tex_sampler)};
const Id texcoord0{OpLoad(vec_ids.Get(2), texcoord0_id)};
const Id texcoord0_w{OpLoad(f32_id, texcoord0_w_id)};
const Id coord{OpCompositeConstruct(vec_ids.Get(3), OpCompositeExtract(f32_id, texcoord0, 0),
OpCompositeExtract(f32_id, texcoord0, 1),
texcoord0_w)};
const Id coord{OpCompositeConstruct(vec_ids.Get(3),
OpCompositeExtract(f32_id, texcoord0, 0),
OpCompositeExtract(f32_id, texcoord0, 1), texcoord0_w)};
if (projection) {
return OpImageSampleProjImplicitLod(vec_ids.Get(4), sampled_image, coord);
} else {
@ -663,14 +698,16 @@ Id FragmentModule::CompareShadow(Id pixel, Id z) {
Id FragmentModule::SampleShadow() {
const Id texcoord0{OpLoad(vec_ids.Get(2), texcoord0_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),
ConstF32(1.f)), ConstF32(16777215.f))};
const Id abs_min_w{OpFMul(f32_id, OpFMin(f32_id, OpFAbs(f32_id, texcoord0_w), ConstF32(1.f)),
ConstF32(16777215.f))};
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 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 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 f{OpFSub(vec_ids.Get(2), coord_floor, coord)};
const Id i{OpConvertFToS(ivec_ids.Get(2), coord_floor)};
@ -681,7 +718,8 @@ Id FragmentModule::SampleShadow() {
const Id end_label{OpLabel()};
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 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);
OpBranchConditional(cond, true_label, false_label);
AddLabel(true_label);
@ -695,8 +733,7 @@ Id FragmentModule::SampleShadow() {
return OpPhi(f32_id, ConstF32(1.f), true_label, result, false_label);
};
const Id s_xy{OpCompositeConstruct(vec_ids.Get(2),
SampleShadow2D(i),
const Id s_xy{OpCompositeConstruct(vec_ids.Get(2), SampleShadow2D(i),
SampleShadow2D(OpIAdd(ivec_ids.Get(2), i, ConstS32(1, 0))))};
const Id s_zw{OpCompositeConstruct(vec_ids.Get(2),
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 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)))};
return OpFMul(f32_id, offset, temp2);
};
@ -739,7 +777,8 @@ Id FragmentModule::AppendProcTexClamp(Id var, ProcTexClamp mode) {
const auto MirroredRepeat = [&]() -> Id {
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));
};
@ -802,8 +841,10 @@ void FragmentModule::DefineProcTexSampler() {
// Define noise tables at the beginning of the function
if (config.state.proctex.noise_enable) {
noise1d_table = DefineVar<false>(TypeArray(i32_id, ConstU32(16u)), spv::StorageClass::Function);
noise2d_table = DefineVar<false>(TypeArray(i32_id, ConstU32(16u)), spv::StorageClass::Function);
noise1d_table =
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);
@ -811,9 +852,15 @@ void FragmentModule::DefineProcTexSampler() {
if (config.state.proctex.coord < 3) {
Id texcoord_id{};
switch (config.state.proctex.coord.Value()) {
case 0: texcoord_id = texcoord0_id; break;
case 1: texcoord_id = texcoord1_id; break;
case 2: texcoord_id = texcoord2_id; break;
case 0:
texcoord_id = texcoord0_id;
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)};
@ -833,12 +880,15 @@ void FragmentModule::DefineProcTexSampler() {
// unlike normal texture, the bias is inside the log2
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 duv_xy{OpFAdd(f32_id, OpCompositeExtract(f32_id, duv, 0), OpCompositeExtract(f32_id, duv, 1))};
const Id bias{
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))};
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))));
// Get shift offset before noise generation
@ -853,7 +903,8 @@ void FragmentModule::DefineProcTexSampler() {
if (config.state.proctex.noise_enable) {
const Id proctex_noise_a{GetShaderDataMember(vec_ids.Get(2), ConstS32(22))};
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);
}
@ -867,8 +918,8 @@ void FragmentModule::DefineProcTexSampler() {
// Combine and map
const Id proctex_color_map_offset{GetShaderDataMember(i32_id, ConstS32(12))};
const Id lut_coord{AppendProcTexCombineAndMap(config.state.proctex.color_combiner,
u, v, proctex_color_map_offset)};
const Id lut_coord{AppendProcTexCombineAndMap(config.state.proctex.color_combiner, u, v,
proctex_color_map_offset)};
Id final_color{};
switch (config.state.proctex.lut_filter) {
@ -906,7 +957,8 @@ void FragmentModule::DefineProcTexSampler() {
Id FragmentModule::Byteround(Id variable_id, u32 size) {
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)};
return OpVectorTimesScalar(vec_ids.Get(size), rounded_id, ConstF32(1.f / 255.f));
} else {
@ -924,7 +976,8 @@ Id FragmentModule::ProcTexLookupLUT(Id offset, Id coord) {
const Id sampled_image{TypeSampledImage(image_buffer_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_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));
@ -952,7 +1005,8 @@ Id FragmentModule::ProcTexNoiseCoef(Id x) {
const Id table_value{OpLoad(i32_id, OpAccessChain(table_ptr, noise2d_table, u2))};
Id v2{ProcTexNoiseRand1D(point_y)};
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 = OpBitwiseAnd(i32_id, v2, ConstS32(0xF));
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_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)))};
const Id point{OpFloor(vec_ids.Get(2), grid)};
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 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 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)};
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)};
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)};
const Id proctex_noise_lut_offset{GetShaderDataMember(i32_id, ConstS32(11))};
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) {
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)};
// Offsets for level 4-7 seem to be hardcoded
InitTableS32(lut_offsets, config.state.proctex.lut_offset0, config.state.proctex.lut_offset1,
config.state.proctex.lut_offset2, config.state.proctex.lut_offset3,
0xF0, 0xF8, 0xFC, 0xFE);
config.state.proctex.lut_offset2, config.state.proctex.lut_offset3, 0xF0, 0xF8,
0xFC, 0xFE);
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]
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)) {
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 texel1{OpImageFetch(vec_ids.Get(4), lut_rgba, p1)};
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::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_offset{GetShaderDataMember(i32_id, ConstS32(19), lut_index_x, lut_index_y)};
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_g{OpCompositeExtract(f32_id, entry, 1)};
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 one_f32{ConstF32(1.f)};
const auto Component = [&](s32 c) -> Id {
return OpCompositeExtract(f32_id, source_color, c);
};
const auto Component = [&](s32 c) -> Id { return OpCompositeExtract(f32_id, source_color, c); };
switch (modifier) {
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);
break;
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;
case Operation::Lerp:
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);
break;
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);
break;
case Operation::Dot3_RGB:
@ -1267,23 +1329,24 @@ void FragmentModule::DefineEntryPoint() {
}
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),
vec_ids.Get(3), vec_ids.Get(3), f32_id, f32_id)};
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), vec_ids.Get(3), f32_id,
f32_id)};
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 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,
i32_id, i32_id, i32_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),
vec_ids.Get(2), vec_ids.Get(2), vec_ids.Get(2), vec_ids.Get(3),
const Id shader_data_struct_id{TypeStruct(
i32_id, i32_id, f32_id, f32_id, f32_id, f32_id, i32_id, i32_id, i32_id, i32_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), 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))};
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,
52u, 56u, 60u, 64u, 68u, 72u, 80u, 176u, 192u, 200u, 208u,
224u, 240u, 1136u, 1232u, 1248u};
constexpr std::array shader_data_offsets{
0u, 4u, 8u, 12u, 16u, 20u, 24u, 28u, 32u, 36u, 40u, 44u, 48u, 52u, 56u,
60u, 64u, 68u, 72u, 80u, 176u, 192u, 200u, 208u, 224u, 240u, 1136u, 1232u, 1248u};
Decorate(lighting_lut_array_id, spv::Decoration::ArrayStride, 16u);
Decorate(light_src_array_id, spv::Decoration::ArrayStride, 112u);
@ -1296,8 +1359,8 @@ void FragmentModule::DefineUniformStructs() {
}
Decorate(shader_data_struct_id, spv::Decoration::Block);
shader_data_id = AddGlobalVariable(TypePointer(spv::StorageClass::Uniform, shader_data_struct_id),
spv::StorageClass::Uniform);
shader_data_id = AddGlobalVariable(
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::Binding, 1);
}

View File

@ -25,6 +25,7 @@ class FragmentModule : public Sirit::Module {
static constexpr u32 NUM_TEV_STAGES = 6;
static constexpr u32 NUM_LIGHTS = 8;
static constexpr u32 NUM_LIGHTING_SAMPLERS = 24;
public:
FragmentModule(const PicaFSConfig& config);
~FragmentModule();
@ -59,8 +60,8 @@ public:
[[nodiscard]] Id AppendProcTexClamp(Id var, Pica::TexturingRegs::ProcTexClamp mode);
[[nodiscard]] Id AppendProcTexCombineAndMap(Pica::TexturingRegs::ProcTexCombiner combiner,
Id u, Id v, Id offset);
[[nodiscard]] Id AppendProcTexCombineAndMap(Pica::TexturingRegs::ProcTexCombiner combiner, Id u,
Id v, Id offset);
/// Rounds the provided variable to the nearest 1/255th
[[nodiscard]] Id Byteround(Id variable_id, u32 size = 1);
@ -84,11 +85,13 @@ public:
[[nodiscard]] Id AppendSource(Pica::TexturingRegs::TevStageConfig::Source source, s32 index);
/// 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);
/// 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);
/// 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/Public/ShaderLang.h>
#include "common/assert.h"
#include "common/microprofile.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
namespace Vulkan {
@ -220,7 +220,8 @@ vk::ShaderModule Compile(std::string_view code, vk::ShaderStageFlagBits stage, v
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) {
MICROPROFILE_SCOPE(Vulkan_SPVCompilation);
const vk::ShaderModuleCreateInfo shader_info = {.codeSize = code.size() * sizeof(u32),

View File

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

View File

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

View File

@ -5,7 +5,7 @@
#include <algorithm>
#include "common/logging/log.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_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
@ -13,9 +13,10 @@
namespace Vulkan {
Swapchain::Swapchain(const Instance& instance, Scheduler& scheduler, RenderpassCache& renderpass_cache)
: instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache},
surface{instance.GetSurface()} {
Swapchain::Swapchain(const Instance& instance, Scheduler& scheduler,
RenderpassCache& renderpass_cache)
: instance{instance}, scheduler{scheduler},
renderpass_cache{renderpass_cache}, surface{instance.GetSurface()} {
FindPresentFormat();
SetPresentMode();
renderpass_cache.CreatePresentRenderpass(surface_format.format);
@ -85,8 +86,8 @@ MICROPROFILE_DEFINE(Vulkan_Acquire, "Vulkan", "Swapchain Acquire", MP_RGB(185, 6
void Swapchain::AcquireNextImage() {
MICROPROFILE_SCOPE(Vulkan_Acquire);
vk::Device device = instance.GetDevice();
vk::Result result = device.acquireNextImageKHR(swapchain, UINT64_MAX, image_acquired[frame_index],
VK_NULL_HANDLE, &image_index);
vk::Result result = device.acquireNextImageKHR(
swapchain, UINT64_MAX, image_acquired[frame_index], VK_NULL_HANDLE, &image_index);
switch (result) {
case vk::Result::eSuccess:
@ -137,7 +138,8 @@ void Swapchain::FindPresentFormat() {
if (formats.size() == 1 && formats[0].format == vk::Format::eUndefined) {
surface_format.format = vk::Format::eB8G8R8A8Unorm;
} 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 &&
format.format == vk::Format::eB8G8R8A8Unorm;
});
@ -172,7 +174,6 @@ void Swapchain::SetPresentMode() {
present_mode = vk::PresentModeKHR::eMailbox;
}
}
}
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()) {
extent.width =
std::clamp(width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height =
std::clamp(height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
extent.height = std::clamp(height, capabilities.minImageExtent.height,
capabilities.maxImageExtent.height);
}
// 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 {
static constexpr u32 PREFERRED_IMAGE_COUNT = 8;
public:
Swapchain(const Instance& instance, Scheduler& scheduler,
RenderpassCache& renderpass_cache);
Swapchain(const Instance& instance, Scheduler& scheduler, RenderpassCache& renderpass_cache);
~Swapchain();
/// 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,
RenderpassCache& renderpass_cache, DescriptorManager& desc_manager)
: instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache}, desc_manager{desc_manager},
blit_helper{instance, scheduler, desc_manager}, upload_buffer{instance, scheduler, UPLOAD_BUFFER_SIZE},
download_buffer{instance, scheduler, DOWNLOAD_BUFFER_SIZE, true} {
: instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache},
desc_manager{desc_manager}, blit_helper{instance, scheduler, desc_manager},
upload_buffer{instance, scheduler, UPLOAD_BUFFER_SIZE}, download_buffer{instance, scheduler,
DOWNLOAD_BUFFER_SIZE,
true} {
auto Register = [this](VideoCore::PixelFormat dest,
std::unique_ptr<FormatReinterpreterBase>&& obj) {
@ -331,8 +333,8 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
}
if (clear.texture_rect == surface.GetScaledRect()) {
scheduler.Record(
[aspect, image = surface.alloc.image, clear_value, clear](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
scheduler.Record([aspect, image = surface.alloc.image, clear_value,
clear](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const vk::ImageSubresourceRange range = {.aspectMask = aspect,
.baseMipLevel = clear.texture_level,
.levelCount = 1,
@ -340,8 +342,8 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
.layerCount = 1};
if (aspect & vk::ImageAspectFlagBits::eColor) {
render_cmdbuf.clearColorImage(image, vk::ImageLayout::eTransferDstOptimal, clear_value.color,
range);
render_cmdbuf.clearColorImage(image, vk::ImageLayout::eTransferDstOptimal,
clear_value.color, range);
} else if (aspect & vk::ImageAspectFlagBits::eDepth ||
aspect & vk::ImageAspectFlagBits::eStencil) {
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.Transition(vk::ImageLayout::eColorAttachmentOptimal, 0, 1);
} else if (aspect & vk::ImageAspectFlagBits::eDepth) {
clear_renderpass = renderpass_cache.GetRenderpass(
VideoCore::PixelFormat::Invalid, surface.pixel_format, true);
clear_renderpass = renderpass_cache.GetRenderpass(VideoCore::PixelFormat::Invalid,
surface.pixel_format, true);
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)},
.extent = {clear.texture_rect.GetWidth(),
clear.texture_rect.GetHeight()}},
.clear = clear_value
};
.clear = clear_value};
renderpass_cache.EnterRenderpass(clear_info);
renderpass_cache.ExitRenderpass();
@ -401,22 +402,24 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
dest.Transition(vk::ImageLayout::eTransferDstOptimal, copy.dst_level, 1);
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) {
const vk::ImageCopy image_copy = {
.srcSubresource = {.aspectMask = ToVkAspect(src_type),
dst_image = dest.alloc.image, dst_type = dest.type,
copy](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const vk::ImageCopy image_copy = {.srcSubresource = {.aspectMask = ToVkAspect(src_type),
.mipLevel = copy.src_level,
.baseArrayLayer = 0,
.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),
.mipLevel = copy.dst_level,
.baseArrayLayer = 0,
.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}};
render_cmdbuf.copyImage(src_image, vk::ImageLayout::eTransferSrcOptimal,
dst_image, vk::ImageLayout::eTransferDstOptimal, image_copy);
render_cmdbuf.copyImage(src_image, vk::ImageLayout::eTransferSrcOptimal, dst_image,
vk::ImageLayout::eTransferDstOptimal, image_copy);
});
return true;
@ -431,7 +434,8 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
scheduler.Record([src_iamge = source.alloc.image, src_type = source.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),
static_cast<s32>(blit.src_rect.bottom), 0},
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::eLinear;
render_cmdbuf.blitImage(src_iamge, vk::ImageLayout::eTransferSrcOptimal,
dst_image, vk::ImageLayout::eTransferDstOptimal, blit_area,
filtering);
render_cmdbuf.blitImage(src_iamge, vk::ImageLayout::eTransferSrcOptimal, dst_image,
vk::ImageLayout::eTransferDstOptimal, blit_area, filtering);
});
return true;
@ -519,7 +522,8 @@ bool TextureRuntime::NeedsConvertion(VideoCore::PixelFormat format) const {
!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;
if (tracker.IsRangeEqual(new_layout, level, level_count) || !alloc.image) {
return;
@ -601,12 +605,11 @@ void TextureRuntime::Transition(ImageAlloc& alloc, vk::ImageLayout new_layout, u
LayoutInfo dest = GetLayoutInfo(new_layout);
tracker.ForEachLayoutRange(
level, level_count, new_layout, [&](u32 start, u32 count, vk::ImageLayout old_layout) {
scheduler.Record([old_layout, new_layout, dest, start, count,
image = alloc.image, aspect = alloc.aspect,
layers = alloc.layers, GetLayoutInfo](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
scheduler.Record([old_layout, new_layout, dest, start, count, image = alloc.image,
aspect = alloc.aspect, layers = alloc.layers,
GetLayoutInfo](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
LayoutInfo source = GetLayoutInfo(old_layout);
const vk::ImageMemoryBarrier barrier = {
.srcAccessMask = source.access,
const vk::ImageMemoryBarrier barrier = {.srcAccessMask = source.access,
.dstAccessMask = dest.access,
.oldLayout = old_layout,
.newLayout = new_layout,
@ -683,8 +686,8 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
ScaledUpload(upload, staging);
} else {
Transition(vk::ImageLayout::eTransferDstOptimal, upload.texture_level, 1);
scheduler.Record([aspect = alloc.aspect, image = alloc.image,
format = alloc.format, staging, upload](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
scheduler.Record([aspect = alloc.aspect, image = alloc.image, format = alloc.format,
staging, upload](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
u32 region_count = 0;
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,
region_count, copy_regions.data());
render_cmdbuf.copyBufferToImage(staging.buffer, image,
vk::ImageLayout::eTransferDstOptimal, region_count,
copy_regions.data());
});
runtime.upload_buffer.Commit(staging.size);
@ -741,8 +745,8 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
ScaledDownload(download, staging);
} else {
Transition(vk::ImageLayout::eTransferSrcOptimal, download.texture_level, 1);
scheduler.Record([aspect = alloc.aspect, image = alloc.image,
staging, download](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer){
scheduler.Record([aspect = alloc.aspect, image = alloc.image, staging,
download](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const VideoCore::Rect2D rect = download.texture_rect;
const vk::BufferImageCopy copy_region = {
.bufferOffset = staging.buffer_offset + download.buffer_offset,