mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-24 13:34:57 +00:00
VideoCommon: update emulation classes for graphics mod 2.0
This commit is contained in:
parent
61644f4de5
commit
f3e6c1e74b
7 changed files with 535 additions and 329 deletions
|
@ -4,6 +4,7 @@
|
|||
#include "VideoCommon/TextureCacheBase.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
@ -39,8 +40,7 @@
|
|||
#include "VideoCommon/Assets/CustomTextureData.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/FBInfo.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModBackend.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h"
|
||||
#include "VideoCommon/HiresTextures.h"
|
||||
#include "VideoCommon/OpcodeDecoding.h"
|
||||
|
@ -135,6 +135,31 @@ void TextureCacheBase::Invalidate()
|
|||
FlushEFBCopies();
|
||||
TMEM::InvalidateAll();
|
||||
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& mod_manager = system.GetGraphicsModManager();
|
||||
for (auto& tex : m_textures_by_address)
|
||||
{
|
||||
const auto& entry = tex.second;
|
||||
if (entry->is_efb_copy)
|
||||
{
|
||||
mod_manager.GetBackend().OnTextureUnload(GraphicsModSystem::TextureType::EFB,
|
||||
entry->texture_info_name);
|
||||
}
|
||||
else if (entry->is_xfb_copy)
|
||||
{
|
||||
mod_manager.GetBackend().OnTextureUnload(GraphicsModSystem::TextureType::XFB,
|
||||
entry->texture_info_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
mod_manager.GetBackend().OnTextureUnload(GraphicsModSystem::TextureType::Normal,
|
||||
entry->texture_info_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& bind : m_bound_textures)
|
||||
bind.reset();
|
||||
m_textures_by_hash.clear();
|
||||
|
@ -270,15 +295,6 @@ bool TextureCacheBase::DidLinkedAssetsChange(const TCacheEntry& entry)
|
|||
}
|
||||
}
|
||||
|
||||
for (const auto& cached_asset : entry.linked_asset_dependencies)
|
||||
{
|
||||
if (cached_asset.m_asset)
|
||||
{
|
||||
if (cached_asset.m_asset->GetLastLoadedTime() > cached_asset.m_cached_write_time)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1292,16 +1308,21 @@ TCacheEntry* TextureCacheBase::LoadImpl(const TextureInfo& texture_info, bool fo
|
|||
return nullptr;
|
||||
|
||||
entry->frameCount = FRAMECOUNT_INVALID;
|
||||
if (entry->texture_info_name.empty() && g_ActiveConfig.bGraphicMods)
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
entry->texture_info_name = texture_info.CalculateTextureName().GetFullName();
|
||||
|
||||
GraphicsModActionData::TextureLoad texture_load{entry->texture_info_name};
|
||||
for (const auto& action :
|
||||
g_graphics_mod_manager->GetTextureLoadActions(entry->texture_info_name))
|
||||
if (entry->texture_info_name.empty())
|
||||
{
|
||||
action->OnTextureLoad(&texture_load);
|
||||
entry->texture_info_name = texture_info.CalculateTextureName().GetFullName();
|
||||
}
|
||||
|
||||
GraphicsModSystem::TextureView texture;
|
||||
texture.hash_name = entry->texture_info_name;
|
||||
texture.texture_data = entry->texture.get();
|
||||
texture.texture_type = GraphicsModSystem::TextureType::Normal;
|
||||
texture.unit = texture_info.GetStage();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& mod_manager = system.GetGraphicsModManager();
|
||||
mod_manager.GetBackend().OnTextureLoad(texture);
|
||||
}
|
||||
m_bound_textures[texture_info.GetStage()] = entry;
|
||||
|
||||
|
@ -1587,42 +1608,6 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<VideoCommon::CachedAsset<VideoCommon::CustomAsset>> additional_dependencies;
|
||||
|
||||
std::string texture_name = "";
|
||||
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
u32 height = texture_info.GetRawHeight();
|
||||
u32 width = texture_info.GetRawWidth();
|
||||
if (hires_texture)
|
||||
{
|
||||
auto asset = hires_texture->GetAsset();
|
||||
if (asset)
|
||||
{
|
||||
auto data = asset->GetData();
|
||||
if (data)
|
||||
{
|
||||
if (!data->m_texture.m_slices.empty())
|
||||
{
|
||||
if (!data->m_texture.m_slices[0].m_levels.empty())
|
||||
{
|
||||
height = data->m_texture.m_slices[0].m_levels[0].height;
|
||||
width = data->m_texture.m_slices[0].m_levels[0].width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
texture_name = texture_info.CalculateTextureName().GetFullName();
|
||||
GraphicsModActionData::TextureCreate texture_create{
|
||||
texture_name, width, height, &cached_game_assets, &additional_dependencies};
|
||||
for (const auto& action : g_graphics_mod_manager->GetTextureCreateActions(texture_name))
|
||||
{
|
||||
action->OnTextureCreate(&texture_create);
|
||||
}
|
||||
}
|
||||
|
||||
data_for_assets.reserve(cached_game_assets.size());
|
||||
for (auto& cached_asset : cached_game_assets)
|
||||
{
|
||||
|
@ -1644,8 +1629,20 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
|
|||
texture_info, textureCacheSafetyColorSampleSize,
|
||||
std::move(data_for_assets), has_arbitrary_mipmaps, skip_texture_dump);
|
||||
entry->linked_game_texture_assets = std::move(cached_game_assets);
|
||||
entry->linked_asset_dependencies = std::move(additional_dependencies);
|
||||
entry->texture_info_name = std::move(texture_name);
|
||||
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
entry->texture_info_name = texture_info.CalculateTextureName().GetFullName();
|
||||
|
||||
GraphicsModSystem::TextureView texture;
|
||||
texture.hash_name = entry->texture_info_name;
|
||||
texture.texture_data = entry->texture.get();
|
||||
texture.texture_type = GraphicsModSystem::TextureType::Normal;
|
||||
texture.unit = texture_info.GetStage();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& mod_manager = system.GetGraphicsModManager();
|
||||
mod_manager.GetBackend().OnTextureCreate(texture);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
@ -2299,36 +2296,6 @@ void TextureCacheBase::CopyRenderTargetToTexture(
|
|||
return;
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
FBInfo info;
|
||||
info.m_width = tex_w;
|
||||
info.m_height = tex_h;
|
||||
info.m_texture_format = baseFormat;
|
||||
if (is_xfb_copy)
|
||||
{
|
||||
for (const auto& action : g_graphics_mod_manager->GetXFBActions(info))
|
||||
{
|
||||
action->OnXFB();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool skip = false;
|
||||
GraphicsModActionData::EFB efb{tex_w, tex_h, &skip, &scaled_tex_w, &scaled_tex_h};
|
||||
for (const auto& action : g_graphics_mod_manager->GetEFBActions(info))
|
||||
{
|
||||
action->OnEFB(&efb);
|
||||
}
|
||||
if (skip == true)
|
||||
{
|
||||
if (copy_to_ram)
|
||||
UninitializeEFBMemory(dst, dstStride, bytes_per_row, num_blocks_y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dstStride < bytes_per_row)
|
||||
{
|
||||
// This kind of efb copy results in a scrambled image.
|
||||
|
@ -2382,7 +2349,7 @@ void TextureCacheBase::CopyRenderTargetToTexture(
|
|||
|
||||
if (is_xfb_copy && (g_ActiveConfig.bDumpXFBTarget || g_ActiveConfig.bGraphicMods))
|
||||
{
|
||||
const std::string id = fmt::format("{}x{}", tex_w, tex_h);
|
||||
const std::string id = fmt::format("n{:06}_{}x{}", xfb_count++, tex_w, tex_h);
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
entry->texture_info_name = fmt::format("{}_{}", XFB_DUMP_PREFIX, id);
|
||||
|
@ -2390,9 +2357,8 @@ void TextureCacheBase::CopyRenderTargetToTexture(
|
|||
|
||||
if (g_ActiveConfig.bDumpXFBTarget)
|
||||
{
|
||||
entry->texture->Save(fmt::format("{}{}_n{:06}_{}.png",
|
||||
File::GetUserPath(D_DUMPTEXTURES_IDX), XFB_DUMP_PREFIX,
|
||||
xfb_count++, id),
|
||||
entry->texture->Save(fmt::format("{}{}_{}.png", File::GetUserPath(D_DUMPTEXTURES_IDX),
|
||||
XFB_DUMP_PREFIX, id),
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
@ -2413,6 +2379,23 @@ void TextureCacheBase::CopyRenderTargetToTexture(
|
|||
0);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
GraphicsModSystem::TextureView texture;
|
||||
texture.hash_name = entry->texture_info_name;
|
||||
texture.texture_data = entry->texture.get();
|
||||
if (is_xfb_copy)
|
||||
{
|
||||
texture.texture_type = GraphicsModSystem::TextureType::XFB;
|
||||
}
|
||||
else
|
||||
{
|
||||
texture.texture_type = GraphicsModSystem::TextureType::EFB;
|
||||
}
|
||||
auto& mod_manager = system.GetGraphicsModManager();
|
||||
mod_manager.GetBackend().OnTextureCreate(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2459,6 +2442,37 @@ void TextureCacheBase::CopyRenderTargetToTexture(
|
|||
}
|
||||
}
|
||||
|
||||
InvalideOverlappingTextures(dstStride, dstAddr, bytes_per_row, num_blocks_y, copy_to_vram,
|
||||
copy_to_ram);
|
||||
|
||||
if (OpcodeDecoder::g_record_fifo_data)
|
||||
{
|
||||
// Mark the memory behind this efb copy as dynamicly generated for the Fifo log
|
||||
u32 address = dstAddr;
|
||||
for (u32 i = 0; i < num_blocks_y; i++)
|
||||
{
|
||||
Core::System::GetInstance().GetFifoRecorder().UseMemory(address, bytes_per_row,
|
||||
MemoryUpdate::Type::TextureMap, true);
|
||||
address += dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
// Even if the copy is deferred, still compute the hash. This way if the copy is used as a texture
|
||||
// in a subsequent draw before it is flushed, it will have the same hash.
|
||||
if (entry)
|
||||
{
|
||||
const u64 hash = entry->CalculateHash();
|
||||
entry->SetHashes(hash, hash);
|
||||
m_textures_by_address.emplace(dstAddr, std::move(entry));
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCacheBase::InvalideOverlappingTextures(u32 dstStride, u32 dstAddr, u32 bytes_per_row,
|
||||
u32 num_blocks_y, bool copy_to_vram,
|
||||
bool copy_to_ram)
|
||||
{
|
||||
const u32 covered_range = num_blocks_y * dstStride;
|
||||
|
||||
// Invalidate all textures, if they are either fully overwritten by our efb copy, or if they
|
||||
// have a different stride than our efb copy. Partly overwritten textures with the same stride
|
||||
// as our efb copy are marked to check them for partial texture updates.
|
||||
|
@ -2521,27 +2535,6 @@ void TextureCacheBase::CopyRenderTargetToTexture(
|
|||
}
|
||||
++iter.first;
|
||||
}
|
||||
|
||||
if (OpcodeDecoder::g_record_fifo_data)
|
||||
{
|
||||
// Mark the memory behind this efb copy as dynamicly generated for the Fifo log
|
||||
u32 address = dstAddr;
|
||||
for (u32 i = 0; i < num_blocks_y; i++)
|
||||
{
|
||||
Core::System::GetInstance().GetFifoRecorder().UseMemory(address, bytes_per_row,
|
||||
MemoryUpdate::Type::TextureMap, true);
|
||||
address += dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
// Even if the copy is deferred, still compute the hash. This way if the copy is used as a texture
|
||||
// in a subsequent draw before it is flushed, it will have the same hash.
|
||||
if (entry)
|
||||
{
|
||||
const u64 hash = entry->CalculateHash();
|
||||
entry->SetHashes(hash, hash);
|
||||
m_textures_by_address.emplace(dstAddr, std::move(entry));
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCacheBase::FlushEFBCopies()
|
||||
|
@ -2792,6 +2785,27 @@ TextureCacheBase::InvalidateTexture(TexAddrCache::iterator iter, bool discard_pe
|
|||
|
||||
RcTcacheEntry& entry = iter->second;
|
||||
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& mod_manager = system.GetGraphicsModManager();
|
||||
if (entry->is_efb_copy)
|
||||
{
|
||||
mod_manager.GetBackend().OnTextureUnload(GraphicsModSystem::TextureType::EFB,
|
||||
entry->texture_info_name);
|
||||
}
|
||||
else if (entry->is_xfb_copy)
|
||||
{
|
||||
mod_manager.GetBackend().OnTextureUnload(GraphicsModSystem::TextureType::XFB,
|
||||
entry->texture_info_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
mod_manager.GetBackend().OnTextureUnload(GraphicsModSystem::TextureType::Normal,
|
||||
entry->texture_info_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (entry->textures_by_hash_iter != m_textures_by_hash.end())
|
||||
{
|
||||
m_textures_by_hash.erase(entry->textures_by_hash_iter);
|
||||
|
|
|
@ -168,7 +168,6 @@ struct TCacheEntry
|
|||
std::string texture_info_name = "";
|
||||
|
||||
std::vector<VideoCommon::CachedAsset<VideoCommon::GameTextureAsset>> linked_game_texture_assets;
|
||||
std::vector<VideoCommon::CachedAsset<VideoCommon::CustomAsset>> linked_asset_dependencies;
|
||||
|
||||
explicit TCacheEntry(std::unique_ptr<AbstractTexture> tex,
|
||||
std::unique_ptr<AbstractFramebuffer> fb);
|
||||
|
@ -345,6 +344,9 @@ private:
|
|||
|
||||
static bool DidLinkedAssetsChange(const TCacheEntry& entry);
|
||||
|
||||
void InvalideOverlappingTextures(u32 dstStride, u32 dstAddr, u32 bytes_per_row, u32 num_blocks_y,
|
||||
bool copy_to_vram, bool copy_to_ram);
|
||||
|
||||
TCacheEntry* LoadImpl(const TextureInfo& texture_info, bool force_reload);
|
||||
|
||||
bool CreateUtilityTextures();
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <cmath>
|
||||
#include <memory>
|
||||
|
||||
#include <xxhash.h>
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Contains.h"
|
||||
|
@ -25,8 +27,6 @@
|
|||
#include "VideoCommon/DataReader.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/GeometryShaderManager.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h"
|
||||
#include "VideoCommon/IndexGenerator.h"
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
|
@ -123,8 +123,8 @@ bool VertexManagerBase::Initialize()
|
|||
m_after_present_event = AfterPresentEvent::Register(
|
||||
[this](const PresentInfo& pi) { m_ticks_elapsed = pi.emulated_timestamp; },
|
||||
"VertexManagerBase");
|
||||
m_index_generator.Init();
|
||||
m_custom_shader_cache = std::make_unique<CustomShaderCache>();
|
||||
|
||||
m_index_generator.Init(false);
|
||||
m_cpu_cull.Init();
|
||||
return true;
|
||||
}
|
||||
|
@ -137,6 +137,14 @@ u32 VertexManagerBase::GetRemainingSize() const
|
|||
void VertexManagerBase::AddIndices(OpcodeDecoder::Primitive primitive, u32 num_vertices)
|
||||
{
|
||||
m_index_generator.AddIndices(primitive, num_vertices);
|
||||
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
// Tell any graphics mod backend we had more indices
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& mod_manager = system.GetGraphicsModManager();
|
||||
mod_manager.GetBackend().AddIndices(primitive, num_vertices);
|
||||
}
|
||||
}
|
||||
|
||||
bool VertexManagerBase::AreAllVerticesCulled(VertexLoaderBase* loader,
|
||||
|
@ -183,6 +191,13 @@ DataReader VertexManagerBase::PrepareForAdditionalData(OpcodeDecoder::Primitive
|
|||
// need to alloc new buffer
|
||||
if (m_is_flushed) [[unlikely]]
|
||||
{
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& mod_manager = system.GetGraphicsModManager();
|
||||
mod_manager.GetBackend().ResetIndices();
|
||||
}
|
||||
|
||||
if (cullall)
|
||||
{
|
||||
// This buffer isn't getting sent to the GPU. Just allocate it on the cpu.
|
||||
|
@ -336,6 +351,7 @@ void VertexManagerBase::ResetBuffer(u32 vertex_stride)
|
|||
m_cur_buffer_pointer = m_cpu_vertex_buffer.data();
|
||||
m_end_buffer_pointer = m_base_buffer_pointer + m_cpu_vertex_buffer.size();
|
||||
m_index_generator.Start(m_cpu_index_buffer.data());
|
||||
m_last_reset_pointer = m_cur_buffer_pointer;
|
||||
}
|
||||
|
||||
void VertexManagerBase::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices,
|
||||
|
@ -547,58 +563,164 @@ void VertexManagerBase::Flush()
|
|||
}
|
||||
|
||||
auto& pixel_shader_manager = system.GetPixelShaderManager();
|
||||
auto& geometry_shader_manager = system.GetGeometryShaderManager();
|
||||
auto& vertex_shader_manager = system.GetVertexShaderManager();
|
||||
auto& xf_state_manager = system.GetXFStateManager();
|
||||
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
const double seconds_elapsed =
|
||||
static_cast<double>(m_ticks_elapsed) / system.GetSystemTimers().GetTicksPerSecond();
|
||||
pixel_shader_manager.constants.time_ms = seconds_elapsed * 1000;
|
||||
}
|
||||
const auto used_textures = UsedTextures();
|
||||
|
||||
CalculateNormals(VertexLoaderManager::GetCurrentVertexFormat());
|
||||
// Calculate ZSlope for zfreeze
|
||||
const auto used_textures = UsedTextures();
|
||||
std::vector<std::string> texture_names;
|
||||
Common::SmallVector<u32, 8> texture_units;
|
||||
Common::SmallVector<GraphicsModSystem::TextureView, 8> textures;
|
||||
std::array<SamplerState, 8> samplers;
|
||||
if (!m_cull_all)
|
||||
{
|
||||
if (!g_ActiveConfig.bGraphicMods)
|
||||
for (const u32 i : used_textures)
|
||||
{
|
||||
for (const u32 i : used_textures)
|
||||
{
|
||||
const auto cache_entry = g_texture_cache->Load(TextureInfo::FromStage(i));
|
||||
if (!cache_entry)
|
||||
continue;
|
||||
const float custom_tex_scale = cache_entry->GetWidth() / float(cache_entry->native_width);
|
||||
samplers[i] = TextureCacheBase::GetSamplerState(
|
||||
i, custom_tex_scale, cache_entry->is_custom_tex, cache_entry->has_arbitrary_mips);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const u32 i : used_textures)
|
||||
{
|
||||
const auto cache_entry = g_texture_cache->Load(TextureInfo::FromStage(i));
|
||||
if (cache_entry)
|
||||
{
|
||||
if (!Common::Contains(texture_names, cache_entry->texture_info_name))
|
||||
{
|
||||
texture_names.push_back(cache_entry->texture_info_name);
|
||||
texture_units.push_back(i);
|
||||
}
|
||||
const auto cache_entry = g_texture_cache->Load(TextureInfo::FromStage(i));
|
||||
if (!cache_entry)
|
||||
continue;
|
||||
const float custom_tex_scale = cache_entry->GetWidth() / float(cache_entry->native_width);
|
||||
samplers[i] = TextureCacheBase::GetSamplerState(
|
||||
i, custom_tex_scale, cache_entry->is_custom_tex, cache_entry->has_arbitrary_mips);
|
||||
|
||||
const float custom_tex_scale = cache_entry->GetWidth() / float(cache_entry->native_width);
|
||||
samplers[i] = TextureCacheBase::GetSamplerState(
|
||||
i, custom_tex_scale, cache_entry->is_custom_tex, cache_entry->has_arbitrary_mips);
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
GraphicsModSystem::TextureView texture;
|
||||
texture.hash_name = cache_entry->texture_info_name;
|
||||
texture.texture_data = cache_entry->texture.get();
|
||||
if (cache_entry->is_efb_copy)
|
||||
{
|
||||
texture.texture_type = GraphicsModSystem::EFB;
|
||||
}
|
||||
else if (cache_entry->is_xfb_copy)
|
||||
{
|
||||
texture.texture_type = GraphicsModSystem::XFB;
|
||||
}
|
||||
else
|
||||
{
|
||||
texture.texture_type = GraphicsModSystem::Normal;
|
||||
}
|
||||
texture.unit = i;
|
||||
textures.push_back(std::move(texture));
|
||||
}
|
||||
}
|
||||
}
|
||||
vertex_shader_manager.SetConstants(texture_names, xf_state_manager);
|
||||
|
||||
/*Common::SmallVector<std::pair<GraphicsMods::LightID, int>, 8> lights_this_draw;
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
// Add any lights
|
||||
const auto& lights_changed = xf_state_manager.GetLightsChanged();
|
||||
if (lights_changed[0] >= 0)
|
||||
{
|
||||
const int istart = lights_changed[0] / 0x10;
|
||||
const int iend = (lights_changed[1] + 15) / 0x10;
|
||||
|
||||
for (int i = istart; i < iend; ++i)
|
||||
{
|
||||
const Light& light = xfmem.lights[i];
|
||||
|
||||
VertexShaderConstants::Light dstlight;
|
||||
|
||||
// xfmem.light.color is packed as abgr in u8[4], so we have to swap the order
|
||||
dstlight.color[0] = light.color[3];
|
||||
dstlight.color[1] = light.color[2];
|
||||
dstlight.color[2] = light.color[1];
|
||||
dstlight.color[3] = light.color[0];
|
||||
|
||||
dstlight.cosatt[0] = light.cosatt[0];
|
||||
dstlight.cosatt[1] = light.cosatt[1];
|
||||
dstlight.cosatt[2] = light.cosatt[2];
|
||||
|
||||
if (fabs(light.distatt[0]) < 0.00001f && fabs(light.distatt[1]) < 0.00001f &&
|
||||
fabs(light.distatt[2]) < 0.00001f)
|
||||
{
|
||||
// dist attenuation, make sure not equal to 0!!!
|
||||
dstlight.distatt[0] = .00001f;
|
||||
}
|
||||
else
|
||||
{
|
||||
dstlight.distatt[0] = light.distatt[0];
|
||||
}
|
||||
dstlight.distatt[1] = light.distatt[1];
|
||||
dstlight.distatt[2] = light.distatt[2];
|
||||
|
||||
dstlight.pos[0] = light.dpos[0];
|
||||
dstlight.pos[1] = light.dpos[1];
|
||||
dstlight.pos[2] = light.dpos[2];
|
||||
|
||||
// TODO: Hardware testing is needed to confirm that this normalization is correct
|
||||
auto sanitize = [](float f) {
|
||||
if (std::isnan(f))
|
||||
return 0.0f;
|
||||
else if (std::isinf(f))
|
||||
return f > 0.0f ? 1.0f : -1.0f;
|
||||
else
|
||||
return f;
|
||||
};
|
||||
double norm = double(light.ddir[0]) * double(light.ddir[0]) +
|
||||
double(light.ddir[1]) * double(light.ddir[1]) +
|
||||
double(light.ddir[2]) * double(light.ddir[2]);
|
||||
norm = 1.0 / sqrt(norm);
|
||||
dstlight.dir[0] = sanitize(static_cast<float>(light.ddir[0] * norm));
|
||||
dstlight.dir[1] = sanitize(static_cast<float>(light.ddir[1] * norm));
|
||||
dstlight.dir[2] = sanitize(static_cast<float>(light.ddir[2] * norm));
|
||||
|
||||
XXH3_64bits_reset_withSeed(m_hash_state_impl->m_graphics_mod_light_hash_state,
|
||||
m_hash_state_impl->m_graphics_mod_hash_seed);
|
||||
// XXH3_64bits_update(m_hash_state_impl->m_graphics_mod_light_hash_state, &dstlight.color,
|
||||
// sizeof(int4));
|
||||
XXH3_64bits_update(m_hash_state_impl->m_graphics_mod_light_hash_state, &dstlight.cosatt,
|
||||
sizeof(float4));
|
||||
XXH3_64bits_update(m_hash_state_impl->m_graphics_mod_light_hash_state, &dstlight.distatt,
|
||||
sizeof(float4));
|
||||
// XXH3_64bits_update(m_hash_state_impl->m_graphics_mod_light_hash_state, &dstlight.dir,
|
||||
// sizeof(float4));
|
||||
const auto light_id = GraphicsMods::LightID(
|
||||
XXH3_64bits_digest(m_hash_state_impl->m_graphics_mod_light_hash_state));
|
||||
lights_this_draw.emplace_back(light_id, i);
|
||||
|
||||
if (editor.IsEnabled())
|
||||
{
|
||||
GraphicsModEditor::LightData light_data;
|
||||
light_data.m_id = light_id;
|
||||
light_data.m_create_time = std::chrono::steady_clock::now();
|
||||
light_data.m_color = dstlight.color;
|
||||
light_data.m_cosatt = dstlight.cosatt;
|
||||
light_data.m_dir = dstlight.dir;
|
||||
light_data.m_distatt = dstlight.distatt;
|
||||
light_data.m_pos = dstlight.pos;
|
||||
editor.AddLightData(std::move(light_data));
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
vertex_shader_manager.SetConstants(xf_state_manager);
|
||||
/*if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
if (editor.IsEnabled())
|
||||
{
|
||||
for (const auto& light_this_draw : lights_this_draw)
|
||||
{
|
||||
auto& light = vertex_shader_manager.constants.lights[light_this_draw.second];
|
||||
const auto light_id = light_this_draw.first;
|
||||
bool skip = false;
|
||||
GraphicsModActionData::Light light_action_data{&light.color, &light.cosatt, &light.distatt,
|
||||
&light.pos, &light.dir, &skip};
|
||||
for (const auto& action : editor.GetLightActions(light_id))
|
||||
{
|
||||
action->OnLight(&light_action_data);
|
||||
}
|
||||
if (skip)
|
||||
{
|
||||
light.color = {};
|
||||
light.cosatt = {};
|
||||
light.distatt = {};
|
||||
light.pos = {};
|
||||
light.dir = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
if (!bpmem.genMode.zfreeze)
|
||||
{
|
||||
// Must be done after VertexShaderManager::SetConstants()
|
||||
|
@ -612,27 +734,6 @@ void VertexManagerBase::Flush()
|
|||
|
||||
if (!m_cull_all)
|
||||
{
|
||||
CustomPixelShaderContents custom_pixel_shader_contents;
|
||||
std::optional<CustomPixelShader> custom_pixel_shader;
|
||||
std::vector<std::string> custom_pixel_texture_names;
|
||||
std::span<u8> custom_pixel_shader_uniforms;
|
||||
bool skip = false;
|
||||
for (size_t i = 0; i < texture_names.size(); i++)
|
||||
{
|
||||
GraphicsModActionData::DrawStarted draw_started{texture_units, &skip, &custom_pixel_shader,
|
||||
&custom_pixel_shader_uniforms};
|
||||
for (const auto& action : g_graphics_mod_manager->GetDrawStartedActions(texture_names[i]))
|
||||
{
|
||||
action->OnDrawStarted(&draw_started);
|
||||
if (custom_pixel_shader)
|
||||
{
|
||||
custom_pixel_shader_contents.shaders.push_back(*custom_pixel_shader);
|
||||
custom_pixel_texture_names.push_back(texture_names[i]);
|
||||
}
|
||||
custom_pixel_shader = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
// Now the vertices can be flushed to the GPU. Everything following the CommitBuffer() call
|
||||
// must be careful to not upload any utility vertices, as the binding will be lost otherwise.
|
||||
const u32 num_indices = m_index_generator.GetIndexLen();
|
||||
|
@ -647,28 +748,30 @@ void VertexManagerBase::Flush()
|
|||
if (PerfQueryBase::ShouldEmulate())
|
||||
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
||||
|
||||
if (!skip)
|
||||
UpdatePipelineConfig();
|
||||
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
UpdatePipelineConfig();
|
||||
UpdatePipelineObject();
|
||||
if (m_current_pipeline_object)
|
||||
{
|
||||
const AbstractPipeline* pipeline_object = m_current_pipeline_object;
|
||||
if (!custom_pixel_shader_contents.shaders.empty())
|
||||
{
|
||||
if (const auto custom_pipeline =
|
||||
GetCustomPipeline(custom_pixel_shader_contents, m_current_pipeline_config,
|
||||
m_current_uber_pipeline_config, m_current_pipeline_object))
|
||||
{
|
||||
pipeline_object = custom_pipeline;
|
||||
}
|
||||
}
|
||||
RenderDrawCall(pixel_shader_manager, geometry_shader_manager, custom_pixel_shader_contents,
|
||||
custom_pixel_shader_uniforms, m_current_primitive_type, pipeline_object);
|
||||
}
|
||||
GraphicsModSystem::DrawDataView draw_data;
|
||||
draw_data.index_data = {m_index_generator.GetIndexDataStart(),
|
||||
m_index_generator.GetIndexLen()};
|
||||
draw_data.projection_type = xfmem.projection.type;
|
||||
draw_data.uid = &m_current_pipeline_config;
|
||||
draw_data.vertex_data = {m_last_reset_pointer, m_index_generator.GetNumVerts()};
|
||||
draw_data.textures = std::move(textures);
|
||||
draw_data.samplers = std::move(samplers);
|
||||
draw_data.vertex_format = VertexLoaderManager::GetCurrentVertexFormat();
|
||||
draw_data.gpu_skinning_position_transform = vertex_shader_manager.constants.transformmatrices;
|
||||
draw_data.gpu_skinning_normal_transform = vertex_shader_manager.constants.normalmatrices;
|
||||
|
||||
auto& mod_manager = system.GetGraphicsModManager();
|
||||
mod_manager.GetBackend().OnDraw(draw_data, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawEmulatedMesh();
|
||||
}
|
||||
|
||||
// Track the total emulated state draws
|
||||
INCSTAT(g_stats.this_frame.num_draw_calls);
|
||||
|
||||
// Even if we skip the draw, emulated state should still be impacted
|
||||
|
@ -941,7 +1044,7 @@ void VertexManagerBase::UpdatePipelineObject()
|
|||
void VertexManagerBase::OnConfigChange()
|
||||
{
|
||||
// Reload index generator function tables in case VS expand config changed
|
||||
m_index_generator.Init();
|
||||
m_index_generator.Init(false);
|
||||
}
|
||||
|
||||
void VertexManagerBase::OnDraw()
|
||||
|
@ -1059,38 +1162,34 @@ void VertexManagerBase::OnEndFrame()
|
|||
InvalidatePipelineObject();
|
||||
}
|
||||
|
||||
void VertexManagerBase::NotifyCustomShaderCacheOfHostChange(const ShaderHostConfig& host_config)
|
||||
void VertexManagerBase::DrawEmulatedMesh()
|
||||
{
|
||||
m_custom_shader_cache->SetHostConfig(host_config);
|
||||
m_custom_shader_cache->Reload();
|
||||
}
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& geometry_shader_manager = system.GetGeometryShaderManager();
|
||||
auto& pixel_shader_manager = system.GetPixelShaderManager();
|
||||
auto& vertex_shader_manager = system.GetVertexShaderManager();
|
||||
|
||||
void VertexManagerBase::RenderDrawCall(
|
||||
PixelShaderManager& pixel_shader_manager, GeometryShaderManager& geometry_shader_manager,
|
||||
const CustomPixelShaderContents& custom_pixel_shader_contents,
|
||||
std::span<u8> custom_pixel_shader_uniforms, PrimitiveType primitive_type,
|
||||
const AbstractPipeline* current_pipeline)
|
||||
{
|
||||
// Now we can upload uniforms, as nothing else will override them.
|
||||
geometry_shader_manager.SetConstants(primitive_type);
|
||||
UpdatePipelineObject();
|
||||
|
||||
static const auto identity_mat = Common::Matrix44::Identity();
|
||||
memcpy(vertex_shader_manager.constants.custom_transform.data(), identity_mat.data.data(),
|
||||
4 * sizeof(float4));
|
||||
|
||||
geometry_shader_manager.SetConstants(m_current_primitive_type);
|
||||
pixel_shader_manager.SetConstants();
|
||||
if (!custom_pixel_shader_uniforms.empty() &&
|
||||
pixel_shader_manager.custom_constants.data() != custom_pixel_shader_uniforms.data())
|
||||
{
|
||||
pixel_shader_manager.custom_constants_dirty = true;
|
||||
}
|
||||
pixel_shader_manager.custom_constants = custom_pixel_shader_uniforms;
|
||||
UploadUniforms();
|
||||
|
||||
g_gfx->SetPipeline(current_pipeline);
|
||||
g_gfx->SetPipeline(m_current_pipeline_object);
|
||||
|
||||
u32 base_vertex, base_index;
|
||||
CommitBuffer(m_index_generator.GetNumVerts(),
|
||||
VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride(),
|
||||
m_index_generator.GetIndexLen(), &base_vertex, &base_index);
|
||||
|
||||
if (g_backend_info.api_type != APIType::D3D && g_ActiveConfig.UseVSForLinePointExpand() &&
|
||||
(primitive_type == PrimitiveType::Points || primitive_type == PrimitiveType::Lines))
|
||||
if (g_ActiveConfig.backend_info.api_type != APIType::D3D &&
|
||||
g_ActiveConfig.UseVSForLinePointExpand() &&
|
||||
(m_current_primitive_type == PrimitiveType::Points ||
|
||||
m_current_primitive_type == PrimitiveType::Lines))
|
||||
{
|
||||
// VS point/line expansion puts the vertex id at gl_VertexID << 2
|
||||
// That means the base vertex has to be adjusted to match
|
||||
|
@ -1101,69 +1200,183 @@ void VertexManagerBase::RenderDrawCall(
|
|||
DrawCurrentBatch(base_index, m_index_generator.GetIndexLen(), base_vertex);
|
||||
}
|
||||
|
||||
const AbstractPipeline* VertexManagerBase::GetCustomPipeline(
|
||||
const CustomPixelShaderContents& custom_pixel_shader_contents,
|
||||
const VideoCommon::GXPipelineUid& current_pipeline_config,
|
||||
const VideoCommon::GXUberPipelineUid& current_uber_pipeline_config,
|
||||
const AbstractPipeline* current_pipeline) const
|
||||
void VertexManagerBase::DrawEmulatedMesh(GraphicsModSystem::MaterialResource* material_resource,
|
||||
const Common::Matrix44& custom_transform)
|
||||
{
|
||||
if (current_pipeline)
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& vertex_shader_manager = system.GetVertexShaderManager();
|
||||
auto& geometry_shader_manager = system.GetGeometryShaderManager();
|
||||
auto& pixel_shader_manager = system.GetPixelShaderManager();
|
||||
|
||||
memcpy(vertex_shader_manager.constants.custom_transform.data(), custom_transform.data.data(),
|
||||
4 * sizeof(float4));
|
||||
|
||||
// Now we can upload uniforms, as nothing else will override them.
|
||||
geometry_shader_manager.SetConstants(m_current_primitive_type);
|
||||
pixel_shader_manager.SetConstants();
|
||||
if (material_resource && !material_resource->pixel_uniform_data.empty())
|
||||
{
|
||||
if (!custom_pixel_shader_contents.shaders.empty())
|
||||
pixel_shader_manager.custom_constants = material_resource->pixel_uniform_data;
|
||||
pixel_shader_manager.custom_constants_dirty = true;
|
||||
}
|
||||
UploadUniforms();
|
||||
|
||||
if (material_resource)
|
||||
{
|
||||
g_gfx->SetPipeline(material_resource->pipeline);
|
||||
|
||||
const std::size_t custom_sampler_index_offset = 8;
|
||||
for (std::size_t i = 0; i < material_resource->textures.size(); i++)
|
||||
{
|
||||
CustomShaderInstance custom_shaders;
|
||||
custom_shaders.pixel_contents = custom_pixel_shader_contents;
|
||||
switch (g_ActiveConfig.iShaderCompilationMode)
|
||||
{
|
||||
case ShaderCompilationMode::Synchronous:
|
||||
case ShaderCompilationMode::AsynchronousSkipRendering:
|
||||
{
|
||||
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||
current_pipeline_config, custom_shaders, current_pipeline->m_config))
|
||||
{
|
||||
return *pipeline;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ShaderCompilationMode::SynchronousUberShaders:
|
||||
{
|
||||
// D3D has issues compiling large custom ubershaders
|
||||
// use specialized shaders instead
|
||||
if (g_backend_info.api_type == APIType::D3D)
|
||||
{
|
||||
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||
current_pipeline_config, custom_shaders, current_pipeline->m_config))
|
||||
{
|
||||
return *pipeline;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||
current_uber_pipeline_config, custom_shaders, current_pipeline->m_config))
|
||||
{
|
||||
return *pipeline;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ShaderCompilationMode::AsynchronousUberShaders:
|
||||
{
|
||||
if (auto pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||
current_pipeline_config, custom_shaders, current_pipeline->m_config))
|
||||
{
|
||||
return *pipeline;
|
||||
}
|
||||
else if (auto uber_pipeline = m_custom_shader_cache->GetPipelineAsync(
|
||||
current_uber_pipeline_config, custom_shaders, current_pipeline->m_config))
|
||||
{
|
||||
return *uber_pipeline;
|
||||
}
|
||||
}
|
||||
break;
|
||||
};
|
||||
auto& texture_resource = material_resource->textures[i];
|
||||
if (texture_resource.sampler == nullptr || texture_resource.texture == nullptr) [[unlikely]]
|
||||
continue;
|
||||
g_gfx->SetTexture(texture_resource.sampler_index + custom_sampler_index_offset,
|
||||
texture_resource.texture);
|
||||
g_gfx->SetSamplerState(texture_resource.sampler_index + custom_sampler_index_offset,
|
||||
*texture_resource.sampler);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdatePipelineObject();
|
||||
g_gfx->SetPipeline(m_current_pipeline_object);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
u32 base_vertex, base_index;
|
||||
CommitBuffer(m_index_generator.GetNumVerts(),
|
||||
VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride(),
|
||||
m_index_generator.GetIndexLen(), &base_vertex, &base_index);
|
||||
|
||||
if (g_backend_info.api_type != APIType::D3D && g_ActiveConfig.UseVSForLinePointExpand() &&
|
||||
(m_current_primitive_type == PrimitiveType::Points ||
|
||||
m_current_primitive_type == PrimitiveType::Lines))
|
||||
{
|
||||
// VS point/line expansion puts the vertex id at gl_VertexID << 2
|
||||
// That means the base vertex has to be adjusted to match
|
||||
// (The shader adds this after shifting right on D3D, so no need to do this)
|
||||
base_vertex <<= 2;
|
||||
}
|
||||
|
||||
DrawCurrentBatch(base_index, m_index_generator.GetIndexLen(), base_vertex);
|
||||
|
||||
if (material_resource && material_resource->next)
|
||||
{
|
||||
RedrawWithNewMaterial(base_vertex, base_index, m_index_generator.GetIndexLen(),
|
||||
m_current_primitive_type, material_resource->next);
|
||||
}
|
||||
}
|
||||
|
||||
void VertexManagerBase::DrawCustomMesh(GraphicsModSystem::MeshResource* mesh_resource,
|
||||
const Common::Matrix44& custom_transform,
|
||||
bool ignore_mesh_transform)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& vertex_shader_manager = system.GetVertexShaderManager();
|
||||
auto& geometry_shader_manager = system.GetGeometryShaderManager();
|
||||
auto& pixel_shader_manager = system.GetPixelShaderManager();
|
||||
|
||||
for (const auto& mesh_chunk : mesh_resource->mesh_chunks)
|
||||
{
|
||||
// TODO: draw with a generic material?
|
||||
if (!mesh_chunk.material) [[unlikely]]
|
||||
continue;
|
||||
|
||||
if (!mesh_chunk.material->pipeline || !mesh_chunk.material->pipeline->m_config.vertex_shader ||
|
||||
!mesh_chunk.material->pipeline->m_config.pixel_shader) [[unlikely]]
|
||||
continue;
|
||||
|
||||
vertex_shader_manager.SetVertexFormat(mesh_chunk.components_available,
|
||||
mesh_chunk.vertex_format->GetVertexDeclaration());
|
||||
|
||||
Common::Matrix44 computed_transform;
|
||||
computed_transform = Common::Matrix44::Translate(mesh_resource->pivot_point) * custom_transform;
|
||||
if (!ignore_mesh_transform)
|
||||
{
|
||||
computed_transform *= mesh_chunk.transform;
|
||||
}
|
||||
memcpy(vertex_shader_manager.constants.custom_transform.data(), computed_transform.data.data(),
|
||||
4 * sizeof(float4));
|
||||
|
||||
// Now we can upload uniforms, as nothing else will override them.
|
||||
geometry_shader_manager.SetConstants(mesh_chunk.primitive_type);
|
||||
pixel_shader_manager.SetConstants();
|
||||
if (!mesh_chunk.material->pixel_uniform_data.empty())
|
||||
{
|
||||
pixel_shader_manager.custom_constants_dirty = true;
|
||||
pixel_shader_manager.custom_constants = mesh_chunk.material->pixel_uniform_data;
|
||||
}
|
||||
UploadUniforms();
|
||||
|
||||
g_gfx->SetPipeline(mesh_chunk.material->pipeline);
|
||||
|
||||
const std::size_t custom_sampler_index_offset = 8;
|
||||
for (std::size_t i = 0; i < mesh_chunk.material->textures.size(); i++)
|
||||
{
|
||||
auto& texture_resource = mesh_chunk.material->textures[i];
|
||||
if (texture_resource.sampler == nullptr || texture_resource.texture == nullptr) [[unlikely]]
|
||||
continue;
|
||||
g_gfx->SetTexture(texture_resource.sampler_index + custom_sampler_index_offset,
|
||||
texture_resource.texture);
|
||||
g_gfx->SetSamplerState(texture_resource.sampler_index + custom_sampler_index_offset,
|
||||
*texture_resource.sampler);
|
||||
}
|
||||
|
||||
u32 base_vertex, base_index;
|
||||
UploadUtilityVertices(
|
||||
mesh_chunk.vertex_data.data(), mesh_chunk.vertex_stride,
|
||||
static_cast<u32>(mesh_chunk.vertex_data.size()), mesh_chunk.index_data.data(),
|
||||
static_cast<u32>(mesh_chunk.index_data.size()), &base_vertex, &base_index);
|
||||
g_gfx->DrawIndexed(base_index, static_cast<u32>(mesh_chunk.index_data.size()), base_vertex);
|
||||
|
||||
if (mesh_chunk.material->next)
|
||||
{
|
||||
RedrawWithNewMaterial(base_vertex, base_index, static_cast<u32>(mesh_chunk.index_data.size()),
|
||||
mesh_chunk.primitive_type, mesh_chunk.material->next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VertexManagerBase::RedrawWithNewMaterial(
|
||||
u32 base_vertex, u32 base_index, u32 index_size, PrimitiveType primitive_type,
|
||||
GraphicsModSystem::MaterialResource* material_resource)
|
||||
{
|
||||
if (!material_resource) [[unlikely]]
|
||||
return;
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& geometry_shader_manager = system.GetGeometryShaderManager();
|
||||
auto& pixel_shader_manager = system.GetPixelShaderManager();
|
||||
|
||||
// Now we can upload uniforms, as nothing else will override them.
|
||||
geometry_shader_manager.SetConstants(primitive_type);
|
||||
pixel_shader_manager.SetConstants();
|
||||
if (!material_resource->pixel_uniform_data.empty())
|
||||
{
|
||||
pixel_shader_manager.custom_constants = material_resource->pixel_uniform_data;
|
||||
pixel_shader_manager.custom_constants_dirty = true;
|
||||
}
|
||||
UploadUniforms();
|
||||
|
||||
g_gfx->SetPipeline(material_resource->pipeline);
|
||||
|
||||
const std::size_t custom_sampler_index_offset = 8;
|
||||
for (std::size_t i = 0; i < material_resource->textures.size(); i++)
|
||||
{
|
||||
auto& texture_resource = material_resource->textures[i];
|
||||
if (texture_resource.sampler == nullptr || texture_resource.texture == nullptr) [[unlikely]]
|
||||
continue;
|
||||
g_gfx->SetTexture(texture_resource.sampler_index + custom_sampler_index_offset,
|
||||
texture_resource.texture);
|
||||
g_gfx->SetSamplerState(texture_resource.sampler_index + custom_sampler_index_offset,
|
||||
*texture_resource.sampler);
|
||||
}
|
||||
|
||||
DrawCurrentBatch(base_index, index_size, base_vertex);
|
||||
|
||||
if (material_resource->next)
|
||||
{
|
||||
RedrawWithNewMaterial(base_vertex, base_index, index_size, primitive_type,
|
||||
material_resource->next);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/BitSet.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MathUtil.h"
|
||||
#include "Common/Matrix.h"
|
||||
#include "VideoCommon/CPUCull.h"
|
||||
#include "VideoCommon/IndexGenerator.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
|
@ -16,7 +18,6 @@
|
|||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
struct CustomPixelShaderContents;
|
||||
class CustomShaderCache;
|
||||
class DataReader;
|
||||
class GeometryShaderManager;
|
||||
class NativeVertexFormat;
|
||||
|
@ -24,6 +25,12 @@ class PixelShaderManager;
|
|||
class PointerWrap;
|
||||
struct PortableVertexDeclaration;
|
||||
|
||||
namespace GraphicsModSystem
|
||||
{
|
||||
struct MaterialResource;
|
||||
struct MeshResource;
|
||||
} // namespace GraphicsModSystem
|
||||
|
||||
struct Slope
|
||||
{
|
||||
float dfdx;
|
||||
|
@ -134,7 +141,6 @@ public:
|
|||
m_current_pipeline_object = nullptr;
|
||||
m_pipeline_config_changed = true;
|
||||
}
|
||||
void NotifyCustomShaderCacheOfHostChange(const ShaderHostConfig& host_config);
|
||||
|
||||
// Utility pipeline drawing (e.g. EFB copies, post-processing, UI).
|
||||
virtual void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size);
|
||||
|
@ -171,7 +177,22 @@ public:
|
|||
// Call at the end of a frame.
|
||||
void OnEndFrame();
|
||||
|
||||
// Draws the normal mesh sourced from emulation
|
||||
void DrawEmulatedMesh();
|
||||
|
||||
// Draws the normal mesh sourced from emulation, with a custom shader and/or transform
|
||||
void DrawEmulatedMesh(GraphicsModSystem::MaterialResource* material_resource,
|
||||
const Common::Matrix44& custom_transform);
|
||||
|
||||
// Draw a custom mesh sourced from a mod, with a custom shader and custom vertex information
|
||||
void DrawCustomMesh(GraphicsModSystem::MeshResource* mesh_resource,
|
||||
const Common::Matrix44& custom_transform, bool ignore_mesh_transform);
|
||||
|
||||
protected:
|
||||
void RedrawWithNewMaterial(u32 base_vertex, u32 base_index, u32 index_size,
|
||||
PrimitiveType primitive_type,
|
||||
GraphicsModSystem::MaterialResource* material_resource);
|
||||
|
||||
// When utility uniforms are used, the GX uniforms need to be re-written afterwards.
|
||||
static void InvalidateConstants();
|
||||
|
||||
|
@ -199,6 +220,7 @@ protected:
|
|||
u8* m_cur_buffer_pointer = nullptr;
|
||||
u8* m_base_buffer_pointer = nullptr;
|
||||
u8* m_end_buffer_pointer = nullptr;
|
||||
u8* m_last_reset_pointer = nullptr;
|
||||
|
||||
// Alternative buffers in CPU memory for primitives we are going to discard.
|
||||
std::vector<u8> m_cpu_vertex_buffer;
|
||||
|
@ -223,20 +245,9 @@ private:
|
|||
// Minimum number of draws per command buffer when attempting to preempt a readback operation.
|
||||
static constexpr u32 MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK = 10;
|
||||
|
||||
void RenderDrawCall(PixelShaderManager& pixel_shader_manager,
|
||||
GeometryShaderManager& geometry_shader_manager,
|
||||
const CustomPixelShaderContents& custom_pixel_shader_contents,
|
||||
std::span<u8> custom_pixel_shader_uniforms, PrimitiveType primitive_type,
|
||||
const AbstractPipeline* current_pipeline);
|
||||
void UpdatePipelineConfig();
|
||||
void UpdatePipelineObject();
|
||||
|
||||
const AbstractPipeline*
|
||||
GetCustomPipeline(const CustomPixelShaderContents& custom_pixel_shader_contents,
|
||||
const VideoCommon::GXPipelineUid& current_pipeline_config,
|
||||
const VideoCommon::GXUberPipelineUid& current_uber_pipeline_confi,
|
||||
const AbstractPipeline* current_pipeline) const;
|
||||
|
||||
bool m_is_flushed = true;
|
||||
FlushStatistics m_flush_statistics = {};
|
||||
|
||||
|
@ -248,7 +259,6 @@ private:
|
|||
std::vector<u32> m_scheduled_command_buffer_kicks;
|
||||
bool m_allow_background_execution = true;
|
||||
|
||||
std::unique_ptr<CustomShaderCache> m_custom_shader_cache;
|
||||
u64 m_ticks_elapsed = 0;
|
||||
|
||||
Common::EventHook m_frame_end_event;
|
||||
|
|
|
@ -12,13 +12,12 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/Matrix.h"
|
||||
#include "Core/System.h"
|
||||
#include "VideoCommon/BPFunctions.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/CPMemory.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/FreeLookCamera.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h"
|
||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
@ -29,7 +28,6 @@
|
|||
void VertexShaderManager::Init()
|
||||
{
|
||||
// Initialize state tracking variables
|
||||
m_projection_graphics_mod_change = false;
|
||||
|
||||
constants = {};
|
||||
|
||||
|
@ -156,8 +154,7 @@ bool VertexShaderManager::UseVertexDepthRange()
|
|||
|
||||
// Syncs the shader constant buffers with xfmem
|
||||
// TODO: A cleaner way to control the matrices without making a mess in the parameters field
|
||||
void VertexShaderManager::SetConstants(const std::vector<std::string>& textures,
|
||||
XFStateManager& xf_state_manager)
|
||||
void VertexShaderManager::SetConstants(XFStateManager& xf_state_manager)
|
||||
{
|
||||
if (constants.missing_color_hex != g_ActiveConfig.iMissingColorValue)
|
||||
{
|
||||
|
@ -387,38 +384,12 @@ void VertexShaderManager::SetConstants(const std::vector<std::string>& textures,
|
|||
g_stats.AddScissorRect();
|
||||
}
|
||||
|
||||
std::vector<GraphicsModAction*> projection_actions;
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
for (const auto& action : g_graphics_mod_manager->GetProjectionActions(xfmem.projection.type))
|
||||
{
|
||||
projection_actions.push_back(action);
|
||||
}
|
||||
|
||||
for (const auto& texture : textures)
|
||||
{
|
||||
for (const auto& action :
|
||||
g_graphics_mod_manager->GetProjectionTextureActions(xfmem.projection.type, texture))
|
||||
{
|
||||
projection_actions.push_back(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (xf_state_manager.DidProjectionChange() || g_freelook_camera.GetController()->IsDirty() ||
|
||||
!projection_actions.empty() || m_projection_graphics_mod_change)
|
||||
if (xf_state_manager.DidProjectionChange() || g_freelook_camera.GetController()->IsDirty())
|
||||
{
|
||||
xf_state_manager.ResetProjection();
|
||||
m_projection_graphics_mod_change = !projection_actions.empty();
|
||||
|
||||
auto corrected_matrix = LoadProjectionMatrix();
|
||||
|
||||
GraphicsModActionData::Projection projection{&corrected_matrix};
|
||||
for (const auto& action : projection_actions)
|
||||
{
|
||||
action->OnProjection(&projection);
|
||||
}
|
||||
|
||||
memcpy(constants.projection.data(), corrected_matrix.data.data(), 4 * sizeof(float4));
|
||||
dirty = true;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/BitSet.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
@ -26,7 +25,7 @@ public:
|
|||
|
||||
// constant management
|
||||
void SetProjectionMatrix(XFStateManager& xf_state_manager);
|
||||
void SetConstants(const std::vector<std::string>& textures, XFStateManager& xf_state_manager);
|
||||
void SetConstants(XFStateManager& xf_state_manager);
|
||||
|
||||
// data: 3 floats representing the X, Y and Z vertex model coordinates and the posmatrix index.
|
||||
// out: 4 floats which will be initialized with the corresponding clip space coordinates
|
||||
|
@ -82,7 +81,5 @@ private:
|
|||
alignas(16) std::array<float, 16> m_projection_matrix;
|
||||
|
||||
// track changes
|
||||
bool m_projection_graphics_mod_change = false;
|
||||
|
||||
Common::Matrix44 LoadProjectionMatrix();
|
||||
};
|
||||
|
|
|
@ -343,6 +343,8 @@ bool VideoBackendBase::InitializeShared(std::unique_ptr<AbstractGfx> gfx,
|
|||
memset(reinterpret_cast<u8*>(&g_preprocess_cp_state), 0, sizeof(g_preprocess_cp_state));
|
||||
s_tex_mem.fill(0);
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
|
||||
// do not initialize again for the config window
|
||||
m_initialized = true;
|
||||
|
||||
|
@ -359,21 +361,19 @@ bool VideoBackendBase::InitializeShared(std::unique_ptr<AbstractGfx> gfx,
|
|||
g_frame_dumper = std::make_unique<FrameDumper>();
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>();
|
||||
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
|
||||
g_graphics_mod_manager = std::make_unique<GraphicsModManager>();
|
||||
g_widescreen = std::make_unique<WidescreenManager>();
|
||||
|
||||
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
|
||||
!g_perf_query->Initialize() || !g_presenter->Initialize() ||
|
||||
!g_framebuffer_manager->Initialize() || !g_texture_cache->Initialize() ||
|
||||
(g_backend_info.bSupportsBBox && !g_bounding_box->Initialize()) ||
|
||||
!g_graphics_mod_manager->Initialize())
|
||||
!system.GetGraphicsModManager().Initialize())
|
||||
{
|
||||
PanicAlertFmtT("Failed to initialize renderer classes");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& command_processor = system.GetCommandProcessor();
|
||||
command_processor.Init();
|
||||
system.GetFifo().Init();
|
||||
|
@ -412,7 +412,6 @@ void VideoBackendBase::ShutdownShared()
|
|||
|
||||
g_bounding_box.reset();
|
||||
g_perf_query.reset();
|
||||
g_graphics_mod_manager.reset();
|
||||
g_texture_cache.reset();
|
||||
g_framebuffer_manager.reset();
|
||||
g_shader_cache.reset();
|
||||
|
|
Loading…
Add table
Reference in a new issue