mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-04-25 07:58:40 -05:00
VideoCommon: optionally apply materials to EFBs
After an EFB operation is turned into a texture, if there is a graphics mod action that provides a custom material, update the EFB texture with the material
This commit is contained in:
parent
7bfd43eb1a
commit
1f72403ec7
|
|
@ -2329,6 +2329,26 @@ void TextureCacheBase::CopyRenderTargetToTexture(
|
|||
isIntensity, gamma, clamp_top, clamp_bottom,
|
||||
GetVRAMCopyFilterCoefficients(filter_coefficients));
|
||||
|
||||
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)
|
||||
{
|
||||
GraphicsModActionData::PostEFB efb;
|
||||
for (const auto& action : g_graphics_mod_manager->GetEFBActions(info))
|
||||
{
|
||||
action->AfterEFB(&efb);
|
||||
if (efb.material)
|
||||
{
|
||||
ApplyMaterialToCacheEntry(*efb.material, entry.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_xfb_copy && (g_ActiveConfig.bDumpXFBTarget || g_ActiveConfig.bGraphicMods))
|
||||
{
|
||||
const std::string id = fmt::format("{}x{}", tex_w, tex_h);
|
||||
|
|
@ -3035,6 +3055,110 @@ bool TextureCacheBase::DecodeTextureOnGPU(RcTcacheEntry& entry, u32 dst_level, c
|
|||
return true;
|
||||
}
|
||||
|
||||
void TextureCacheBase::ApplyMaterialToCacheEntry(const VideoCommon::MaterialResource& material,
|
||||
TCacheEntry* entry)
|
||||
{
|
||||
const auto material_data = material.GetData();
|
||||
if (!material_data) [[unlikely]]
|
||||
return;
|
||||
|
||||
// Make a copy, we can't write to our texture and use its framebuffer
|
||||
// at the same time
|
||||
auto new_entry = AllocateCacheEntry(entry->texture->GetConfig());
|
||||
new_entry->SetGeneralParameters(entry->addr, entry->size_in_bytes, entry->format,
|
||||
entry->should_force_safe_hashing);
|
||||
new_entry->SetDimensions(entry->native_width, entry->native_height, 1);
|
||||
new_entry->SetEfbCopy(entry->memory_stride);
|
||||
new_entry->may_have_overlapping_textures = false;
|
||||
new_entry->frameCount = FRAMECOUNT_INVALID;
|
||||
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
entry->texture->FinishedRendering();
|
||||
|
||||
const auto custom_uniforms = material_data->GetUniforms();
|
||||
|
||||
// Set up uniforms.
|
||||
// TODO: this struct should be shared with post processing
|
||||
struct Uniforms
|
||||
{
|
||||
std::array<float, 4> source_resolution;
|
||||
std::array<float, 4> target_resolution;
|
||||
std::array<float, 4> window_resolution;
|
||||
std::array<float, 4> source_rectangle;
|
||||
s32 source_layer;
|
||||
s32 source_layer_pad[3];
|
||||
u32 time;
|
||||
u32 time_pad[3];
|
||||
s32 graphics_api;
|
||||
s32 graphics_api_pad[3];
|
||||
u32 efb_scale;
|
||||
u32 efb_scale_pad[3];
|
||||
} uniforms;
|
||||
|
||||
const float rcp_src_width = 1.0f / entry->texture->GetWidth();
|
||||
const float rcp_src_height = 1.0f / entry->texture->GetHeight();
|
||||
|
||||
uniforms.source_resolution = {static_cast<float>(entry->texture->GetWidth()),
|
||||
static_cast<float>(entry->texture->GetHeight()), rcp_src_width,
|
||||
rcp_src_height};
|
||||
|
||||
// The target resolution is the same here, since we're
|
||||
// injecting into the texture
|
||||
uniforms.target_resolution = uniforms.source_resolution;
|
||||
|
||||
const auto present_rect = g_presenter->GetTargetRectangle();
|
||||
uniforms.window_resolution = {static_cast<float>(present_rect.GetWidth()),
|
||||
static_cast<float>(present_rect.GetHeight()),
|
||||
1.0f / static_cast<float>(present_rect.GetWidth()),
|
||||
1.0f / static_cast<float>(present_rect.GetHeight())};
|
||||
|
||||
uniforms.source_rectangle = {0, 0, 1, 1};
|
||||
uniforms.source_layer = 0;
|
||||
uniforms.time = 0;
|
||||
uniforms.graphics_api = static_cast<s32>(g_backend_info.api_type);
|
||||
uniforms.efb_scale = g_framebuffer_manager->GetEFBScale();
|
||||
|
||||
Common::UniqueBuffer<u8> uniform_buffer(custom_uniforms.size() + sizeof(uniforms));
|
||||
std::memcpy(uniform_buffer.data(), &uniforms, sizeof(uniforms));
|
||||
std::memcpy(uniform_buffer.data() + sizeof(uniforms), custom_uniforms.data(),
|
||||
custom_uniforms.size());
|
||||
g_vertex_manager->UploadUtilityUniforms(uniform_buffer.data(),
|
||||
static_cast<u32>(uniform_buffer.size()));
|
||||
|
||||
// Set framebuffer and viewport based on new entry
|
||||
g_gfx->SetAndDiscardFramebuffer(new_entry->framebuffer.get());
|
||||
g_gfx->SetViewportAndScissor(new_entry->framebuffer->GetRect());
|
||||
g_gfx->SetPipeline(material_data->GetPipeline());
|
||||
|
||||
g_gfx->SetTexture(0, entry->texture.get());
|
||||
g_gfx->SetSamplerState(0, RenderState::GetPointSamplerState());
|
||||
|
||||
for (const auto texture : material_data->GetTextures())
|
||||
{
|
||||
g_gfx->SetTexture(texture.sampler_index, texture.texture);
|
||||
g_gfx->SetSamplerState(texture.sampler_index, texture.sampler);
|
||||
}
|
||||
|
||||
g_gfx->Draw(0, 3);
|
||||
g_gfx->EndUtilityDrawing();
|
||||
|
||||
// Finish rendering new entry
|
||||
new_entry->texture->FinishedRendering();
|
||||
|
||||
// Swap new entry and existing entry
|
||||
std::swap(entry->texture, new_entry->texture);
|
||||
std::swap(entry->framebuffer, new_entry->framebuffer);
|
||||
|
||||
// Return old entry to pool for use in another pass
|
||||
// or future functionality
|
||||
ReleaseToPool(new_entry.get());
|
||||
|
||||
if (auto* const next_material = material_data->GetNextMaterial(); next_material)
|
||||
{
|
||||
ApplyMaterialToCacheEntry(*next_material, entry);
|
||||
}
|
||||
}
|
||||
|
||||
u32 TCacheEntry::BytesPerRow() const
|
||||
{
|
||||
// RGBA takes two cache lines per block; all others take one
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ namespace VideoCommon
|
|||
{
|
||||
class CustomTextureData;
|
||||
class GameTextureAsset;
|
||||
class MaterialResource;
|
||||
} // namespace VideoCommon
|
||||
|
||||
constexpr std::string_view EFB_DUMP_PREFIX = "efb1";
|
||||
|
|
@ -407,6 +408,8 @@ private:
|
|||
void DoSaveState(PointerWrap& p);
|
||||
void DoLoadState(PointerWrap& p);
|
||||
|
||||
void ApplyMaterialToCacheEntry(const VideoCommon::MaterialResource& material, TCacheEntry* entry);
|
||||
|
||||
// m_textures_by_address is the authoritive version of what's actually "in" the texture cache
|
||||
// but it's possible for invalidated TCache entries to live on elsewhere
|
||||
TexAddrCache m_textures_by_address;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user