renderer_vulkan: Port per-game to vulkan renderer
This commit is contained in:
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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>();
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
});
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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 = {};
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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},
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
Reference in New Issue
Block a user