Merge branch 'master' of https://github.com/dolphin-emu/dolphin into dolphin-emu-master

This commit is contained in:
Nayla Hanegan 2024-08-23 13:38:17 -04:00
commit 7e6752e8fc
516 changed files with 60670 additions and 270317 deletions

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractTexture.h"
AbstractFramebuffer::AbstractFramebuffer(AbstractTexture* color_attachment,

View file

@ -574,6 +574,14 @@ bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::stri
std::vector<u8> buffer(file.GetSize());
file.ReadBytes(buffer.data(), file.GetSize());
return LoadPNGTexture(level, buffer);
}
bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::vector<u8>& buffer)
{
if (!level) [[unlikely]]
return false;
if (!Common::LoadPNG(buffer, &level->data, &level->width, &level->height))
return false;

View file

@ -33,4 +33,5 @@ bool LoadDDSTexture(CustomTextureData* texture, const std::string& filename);
bool LoadDDSTexture(CustomTextureData::ArraySlice::Level* level, const std::string& filename,
u32 mip_level);
bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::string& filename);
bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::vector<u8>& buffer);
} // namespace VideoCommon

View file

@ -10,6 +10,7 @@
#include "Common/FileUtil.h"
#include "Common/IOFile.h"
#include "Common/JsonUtil.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "VideoCommon/Assets/MaterialAsset.h"
@ -133,24 +134,16 @@ CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadPixelShader(const
return {};
}
std::string json_data;
if (!File::ReadFileToString(PathToString(metadata->second), json_data))
{
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to load the json file '{}',", asset_id,
PathToString(metadata->second));
return {};
}
picojson::value root;
const auto error = picojson::parse(root, json_data);
if (!error.empty())
std::string error;
if (!JsonFromFile(PathToString(metadata->second), &root, &error))
{
ERROR_LOG_FMT(VIDEO,
"Asset '{}' error - failed to load the json file '{}', due to parse error: {}",
asset_id, PathToString(metadata->second), error);
return {};
}
if (!root.is<picojson::object>())
{
ERROR_LOG_FMT(
@ -181,18 +174,21 @@ CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadMaterial(const As
}
const auto& asset_path = asset_map.begin()->second;
std::string json_data;
if (!File::ReadFileToString(PathToString(asset_path), json_data))
std::size_t metadata_size;
{
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - material failed to load the json file '{}',",
asset_id, PathToString(asset_path));
return {};
std::error_code ec;
metadata_size = std::filesystem::file_size(asset_path, ec);
if (ec)
{
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to get material file size with error '{}'!",
asset_id, ec);
return {};
}
}
picojson::value root;
const auto error = picojson::parse(root, json_data);
if (!error.empty())
std::string error;
if (!JsonFromFile(PathToString(asset_path), &root, &error))
{
ERROR_LOG_FMT(
VIDEO,
@ -220,7 +216,7 @@ CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadMaterial(const As
return {};
}
return LoadInfo{json_data.size(), GetLastAssetWriteTime(asset_id)};
return LoadInfo{metadata_size, GetLastAssetWriteTime(asset_id)};
}
CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadMesh(const AssetID& asset_id,
@ -292,18 +288,9 @@ CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadMesh(const AssetI
return {};
}
std::string json_data;
if (!File::ReadFileToString(PathToString(metadata->second), json_data))
{
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to load the json file '{}'!", asset_id,
PathToString(metadata->second));
return {};
}
picojson::value root;
const auto error = picojson::parse(root, json_data);
if (!error.empty())
std::string error;
if (!JsonFromFile(PathToString(metadata->second), &root, &error))
{
ERROR_LOG_FMT(VIDEO,
"Asset '{}' error - failed to load the json file '{}', due to parse error: {}",
@ -362,18 +349,9 @@ CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadTexture(const Ass
return {};
}
std::string json_data;
if (!File::ReadFileToString(PathToString(metadata->second), json_data))
{
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to load the json file '{}',", asset_id,
PathToString(metadata->second));
return {};
}
picojson::value root;
const auto error = picojson::parse(root, json_data);
if (!error.empty())
std::string error;
if (!JsonFromFile(PathToString(metadata->second), &root, &error))
{
ERROR_LOG_FMT(VIDEO,
"Asset '{}' error - failed to load the json file '{}', due to parse error: {}",

View file

@ -3,6 +3,9 @@
#include "VideoCommon/Assets/TextureAsset.h"
#include <optional>
#include "Common/JsonUtil.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "VideoCommon/BPMemory.h"
@ -11,6 +14,45 @@ namespace VideoCommon
{
namespace
{
std::optional<WrapMode> ReadWrapModeFromJSON(const picojson::object& json, const std::string& uv)
{
auto uv_mode = ReadStringFromJson(json, uv).value_or("");
Common::ToLower(&uv_mode);
if (uv_mode == "clamp")
{
return WrapMode::Clamp;
}
else if (uv_mode == "repeat")
{
return WrapMode::Repeat;
}
else if (uv_mode == "mirror")
{
return WrapMode::Mirror;
}
return std::nullopt;
}
std::optional<FilterMode> ReadFilterModeFromJSON(const picojson::object& json,
const std::string& filter)
{
auto filter_mode = ReadStringFromJson(json, filter).value_or("");
Common::ToLower(&filter_mode);
if (filter_mode == "linear")
{
return FilterMode::Linear;
}
else if (filter_mode == "near")
{
return FilterMode::Near;
}
return std::nullopt;
}
bool ParseSampler(const VideoCommon::CustomAssetLibrary::AssetID& asset_id,
const picojson::object& json, SamplerState* sampler)
{
@ -19,78 +61,93 @@ bool ParseSampler(const VideoCommon::CustomAssetLibrary::AssetID& asset_id,
*sampler = RenderState::GetLinearSamplerState();
const auto sampler_state_mode_iter = json.find("texture_mode");
if (sampler_state_mode_iter == json.end())
const auto sampler_state_wrap_iter = json.find("wrap_mode");
if (sampler_state_wrap_iter != json.end())
{
ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'texture_mode' not found", asset_id);
return false;
}
if (!sampler_state_mode_iter->second.is<std::string>())
{
ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'texture_mode' is not the right type",
asset_id);
return false;
}
std::string sampler_state_mode = sampler_state_mode_iter->second.to_str();
Common::ToLower(&sampler_state_mode);
if (!sampler_state_wrap_iter->second.is<picojson::object>())
{
ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'wrap_mode' is not the right type",
asset_id);
return false;
}
const auto sampler_state_wrap_obj = sampler_state_wrap_iter->second.get<picojson::object>();
if (sampler_state_mode == "clamp")
{
sampler->tm0.wrap_u = WrapMode::Clamp;
sampler->tm0.wrap_v = WrapMode::Clamp;
}
else if (sampler_state_mode == "repeat")
{
sampler->tm0.wrap_u = WrapMode::Repeat;
sampler->tm0.wrap_v = WrapMode::Repeat;
}
else if (sampler_state_mode == "mirrored_repeat")
{
sampler->tm0.wrap_u = WrapMode::Mirror;
sampler->tm0.wrap_v = WrapMode::Mirror;
}
else
{
ERROR_LOG_FMT(VIDEO,
"Asset '{}' failed to parse json, 'texture_mode' has an invalid "
"value '{}'",
asset_id, sampler_state_mode);
return false;
if (const auto mode = ReadWrapModeFromJSON(sampler_state_wrap_obj, "u"))
{
sampler->tm0.wrap_u = *mode;
}
else
{
ERROR_LOG_FMT(VIDEO,
"Asset '{}' failed to parse json, 'wrap_mode[u]' has an invalid "
"value",
asset_id);
return false;
}
if (const auto mode = ReadWrapModeFromJSON(sampler_state_wrap_obj, "v"))
{
sampler->tm0.wrap_v = *mode;
}
else
{
ERROR_LOG_FMT(VIDEO,
"Asset '{}' failed to parse json, 'wrap_mode[v]' has an invalid "
"value",
asset_id);
return false;
}
}
const auto sampler_state_filter_iter = json.find("texture_filter");
if (sampler_state_filter_iter == json.end())
const auto sampler_state_filter_iter = json.find("filter_mode");
if (sampler_state_filter_iter != json.end())
{
ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'texture_filter' not found", asset_id);
return false;
}
if (!sampler_state_filter_iter->second.is<std::string>())
{
ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'texture_filter' is not the right type",
asset_id);
return false;
}
std::string sampler_state_filter = sampler_state_filter_iter->second.to_str();
Common::ToLower(&sampler_state_filter);
if (sampler_state_filter == "linear")
{
sampler->tm0.min_filter = FilterMode::Linear;
sampler->tm0.mag_filter = FilterMode::Linear;
sampler->tm0.mipmap_filter = FilterMode::Linear;
}
else if (sampler_state_filter == "point")
{
sampler->tm0.min_filter = FilterMode::Linear;
sampler->tm0.mag_filter = FilterMode::Linear;
sampler->tm0.mipmap_filter = FilterMode::Linear;
}
else
{
ERROR_LOG_FMT(VIDEO,
"Asset '{}' failed to parse json, 'texture_filter' has an invalid "
"value '{}'",
asset_id, sampler_state_filter);
return false;
if (!sampler_state_filter_iter->second.is<picojson::object>())
{
ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'filter_mode' is not the right type",
asset_id);
return false;
}
const auto sampler_state_filter_obj = sampler_state_filter_iter->second.get<picojson::object>();
if (const auto mode = ReadFilterModeFromJSON(sampler_state_filter_obj, "min"))
{
sampler->tm0.min_filter = *mode;
}
else
{
ERROR_LOG_FMT(VIDEO,
"Asset '{}' failed to parse json, 'filter_mode[min]' has an invalid "
"value",
asset_id);
return false;
}
if (const auto mode = ReadFilterModeFromJSON(sampler_state_filter_obj, "mag"))
{
sampler->tm0.mag_filter = *mode;
}
else
{
ERROR_LOG_FMT(VIDEO,
"Asset '{}' failed to parse json, 'filter_mode[mag]' has an invalid "
"value",
asset_id);
return false;
}
if (const auto mode = ReadFilterModeFromJSON(sampler_state_filter_obj, "mipmap"))
{
sampler->tm0.mipmap_filter = *mode;
}
else
{
ERROR_LOG_FMT(VIDEO,
"Asset '{}' failed to parse json, 'filter_mode[mipmap]' has an invalid "
"value",
asset_id);
return false;
}
}
return true;
@ -142,6 +199,61 @@ bool TextureData::FromJson(const CustomAssetLibrary::AssetID& asset_id,
return true;
}
void TextureData::ToJson(picojson::object* obj, const TextureData& data)
{
if (!obj) [[unlikely]]
return;
auto& json_obj = *obj;
switch (data.m_type)
{
case TextureData::Type::Type_Texture2D:
json_obj.emplace("type", "texture2d");
break;
case TextureData::Type::Type_TextureCube:
json_obj.emplace("type", "texturecube");
break;
case TextureData::Type::Type_Undefined:
break;
};
auto wrap_mode_to_string = [](WrapMode mode) {
switch (mode)
{
case WrapMode::Clamp:
return "clamp";
case WrapMode::Mirror:
return "mirror";
case WrapMode::Repeat:
return "repeat";
};
return "";
};
auto filter_mode_to_string = [](FilterMode mode) {
switch (mode)
{
case FilterMode::Linear:
return "linear";
case FilterMode::Near:
return "near";
};
return "";
};
picojson::object wrap_mode;
wrap_mode.emplace("u", wrap_mode_to_string(data.m_sampler.tm0.wrap_u));
wrap_mode.emplace("v", wrap_mode_to_string(data.m_sampler.tm0.wrap_v));
json_obj.emplace("wrap_mode", wrap_mode);
picojson::object filter_mode;
filter_mode.emplace("min", filter_mode_to_string(data.m_sampler.tm0.min_filter));
filter_mode.emplace("mag", filter_mode_to_string(data.m_sampler.tm0.mag_filter));
filter_mode.emplace("mipmap", filter_mode_to_string(data.m_sampler.tm0.mipmap_filter));
json_obj.emplace("filter_mode", filter_mode);
}
CustomAssetLibrary::LoadInfo GameTextureAsset::LoadImpl(const CustomAssetLibrary::AssetID& asset_id)
{
auto potential_data = std::make_shared<TextureData>();

View file

@ -17,6 +17,7 @@ struct TextureData
{
static bool FromJson(const CustomAssetLibrary::AssetID& asset_id, const picojson::object& json,
TextureData* data);
static void ToJson(picojson::object* obj, const TextureData& data);
enum class Type
{
Type_Undefined,

View file

@ -442,4 +442,4 @@ void SetInterlacingMode(const BPCmd& bp)
break;
}
}
}; // namespace BPFunctions
} // namespace BPFunctions

View file

@ -214,7 +214,7 @@ PUBLIC
PRIVATE
fmt::fmt
spng::spng
xxhash
xxhash::xxhash
imgui
implot
glslang

View file

@ -7,6 +7,7 @@
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/JsonUtil.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
@ -15,17 +16,9 @@
std::optional<GraphicsModConfig> GraphicsModConfig::Create(const std::string& file_path,
Source source)
{
std::string json_data;
if (!File::ReadFileToString(file_path, json_data))
{
ERROR_LOG_FMT(VIDEO, "Failed to load graphics mod json file '{}'", file_path);
return std::nullopt;
}
picojson::value root;
const auto error = picojson::parse(root, json_data);
if (!error.empty())
std::string error;
if (!JsonFromFile(file_path, &root, &error))
{
ERROR_LOG_FMT(VIDEO, "Failed to load graphics mod json file '{}' due to parse error: {}",
file_path, error);

View file

@ -12,6 +12,7 @@
#include "Common/CommonPaths.h"
#include "Common/FileSearch.h"
#include "Common/FileUtil.h"
#include "Common/JsonUtil.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
@ -42,17 +43,9 @@ void GraphicsModGroupConfig::Load()
std::set<std::string> known_paths;
if (File::Exists(file_path))
{
std::string json_data;
if (!File::ReadFileToString(file_path, json_data))
{
ERROR_LOG_FMT(VIDEO, "Failed to load graphics mod group json file '{}'", file_path);
return;
}
picojson::value root;
const auto error = picojson::parse(root, json_data);
if (!error.empty())
std::string error;
if (!JsonFromFile(file_path, &root, &error))
{
ERROR_LOG_FMT(VIDEO,
"Failed to load graphics mod group json file '{}' due to parse error: {}",

View file

@ -306,7 +306,7 @@ void CustomPipeline::UpdatePixelData(
if (texture_asset->m_texture)
{
g_gfx->SetTexture(sampler_index, texture_asset->m_texture.get());
g_gfx->SetSamplerState(sampler_index, RenderState::GetLinearSamplerState());
g_gfx->SetSamplerState(sampler_index, texture_data->m_sampler);
}
else
{
@ -336,17 +336,20 @@ void CustomPipeline::UpdatePixelData(
first_slice.m_levels[0].format, 0, texture_type);
texture_asset->m_texture = g_gfx->CreateTexture(
texture_config, fmt::format("Custom shader texture '{}'", property.m_code_name));
for (std::size_t slice_index = 0; slice_index < texture_data->m_texture.m_slices.size();
slice_index++)
if (texture_asset->m_texture)
{
auto& slice = texture_data->m_texture.m_slices[slice_index];
for (u32 level_index = 0; level_index < static_cast<u32>(slice.m_levels.size());
++level_index)
for (std::size_t slice_index = 0; slice_index < texture_data->m_texture.m_slices.size();
slice_index++)
{
auto& level = slice.m_levels[level_index];
texture_asset->m_texture->Load(level_index, level.width, level.height,
level.row_length, level.data.data(), level.data.size(),
static_cast<u32>(slice_index));
auto& slice = texture_data->m_texture.m_slices[slice_index];
for (u32 level_index = 0; level_index < static_cast<u32>(slice.m_levels.size());
++level_index)
{
auto& level = slice.m_levels[level_index];
texture_asset->m_texture->Load(level_index, level.width, level.height,
level.row_length, level.data.data(),
level.data.size(), static_cast<u32>(slice_index));
}
}
}
}

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/VideoConfig.h"

View file

@ -197,7 +197,7 @@ void GraphicsModManager::Load(const GraphicsModGroupConfig& config)
{
for (const GraphicsTargetGroupConfig& group : mod.m_groups)
{
if (m_groups.find(group.m_name) != m_groups.end())
if (m_groups.contains(group.m_name))
{
WARN_LOG_FMT(
VIDEO,

View file

@ -20,6 +20,7 @@
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/Assets/CustomTextureData.h"
#include "VideoCommon/TextureConfig.h"
namespace OSD
@ -36,8 +37,9 @@ static std::atomic<int> s_obscured_pixels_top = 0;
struct Message
{
Message() = default;
Message(std::string text_, u32 duration_, u32 color_, std::unique_ptr<Icon> icon_ = nullptr)
: text(std::move(text_)), duration(duration_), color(color_), icon(std::move(icon_))
Message(std::string text_, u32 duration_, u32 color_,
const VideoCommon::CustomTextureData::ArraySlice::Level* icon_ = nullptr)
: text(std::move(text_)), duration(duration_), color(color_), icon(icon_)
{
timer.Start();
}
@ -48,7 +50,7 @@ struct Message
bool ever_drawn = false;
bool should_discard = false;
u32 color = 0;
std::unique_ptr<Icon> icon;
const VideoCommon::CustomTextureData::ArraySlice::Level* icon;
std::unique_ptr<AbstractTexture> texture;
};
static std::multimap<MessageType, Message> s_messages;
@ -95,13 +97,13 @@ static float DrawMessage(int index, Message& msg, const ImVec2& position, int ti
msg.texture = g_gfx->CreateTexture(tex_config);
if (msg.texture)
{
msg.texture->Load(0, width, height, width, msg.icon->rgba_data.data(),
msg.texture->Load(0, width, height, width, msg.icon->data.data(),
sizeof(u32) * width * height);
}
else
{
// don't try again next time
msg.icon.reset();
msg.icon = nullptr;
}
}
@ -109,11 +111,13 @@ static float DrawMessage(int index, Message& msg, const ImVec2& position, int ti
{
ImGui::Image(msg.texture.get(), ImVec2(static_cast<float>(msg.icon->width),
static_cast<float>(msg.icon->height)));
ImGui::SameLine();
}
}
// Use %s in case message contains %.
ImGui::TextColored(ARGBToImVec4(msg.color), "%s", msg.text.c_str());
if (msg.text.size() > 0)
ImGui::TextColored(ARGBToImVec4(msg.color), "%s", msg.text.c_str());
window_height =
ImGui::GetWindowSize().y + (WINDOW_PADDING * ImGui::GetIO().DisplayFramebufferScale.y);
}
@ -127,7 +131,7 @@ static float DrawMessage(int index, Message& msg, const ImVec2& position, int ti
}
void AddTypedMessage(MessageType type, std::string message, u32 ms, u32 argb,
std::unique_ptr<Icon> icon)
const VideoCommon::CustomTextureData::ArraySlice::Level* icon)
{
std::lock_guard lock{s_messages_mutex};
@ -141,7 +145,8 @@ void AddTypedMessage(MessageType type, std::string message, u32 ms, u32 argb,
s_messages.emplace(type, Message(std::move(message), ms, argb, std::move(icon)));
}
void AddMessage(std::string message, u32 ms, u32 argb, std::unique_ptr<Icon> icon)
void AddMessage(std::string message, u32 ms, u32 argb,
const VideoCommon::CustomTextureData::ArraySlice::Level* icon)
{
std::lock_guard lock{s_messages_mutex};
s_messages.emplace(MessageType::Typeless, Message(std::move(message), ms, argb, std::move(icon)));

View file

@ -10,6 +10,8 @@
#include "Common/CommonTypes.h"
#include "VideoCommon/Assets/CustomTextureData.h"
namespace OSD
{
enum class MessageType
@ -29,27 +31,21 @@ constexpr u32 CYAN = 0xFF00FFFF;
constexpr u32 GREEN = 0xFF00FF00;
constexpr u32 RED = 0xFFFF0000;
constexpr u32 YELLOW = 0xFFFFFF30;
}; // namespace Color
} // namespace Color
namespace Duration
{
constexpr u32 SHORT = 2000;
constexpr u32 NORMAL = 5000;
constexpr u32 VERY_LONG = 10000;
}; // namespace Duration
struct Icon
{
std::vector<u8> rgba_data;
u32 width = 0;
u32 height = 0;
}; // struct Icon
} // namespace Duration
// On-screen message display (colored yellow by default)
void AddMessage(std::string message, u32 ms = Duration::SHORT, u32 argb = Color::YELLOW,
std::unique_ptr<Icon> icon = nullptr);
const VideoCommon::CustomTextureData::ArraySlice::Level* icon = nullptr);
void AddTypedMessage(MessageType type, std::string message, u32 ms = Duration::SHORT,
u32 argb = Color::YELLOW, std::unique_ptr<Icon> icon = nullptr);
u32 argb = Color::YELLOW,
const VideoCommon::CustomTextureData::ArraySlice::Level* icon = nullptr);
// Draw the current messages on the screen. Only call once per frame.
void DrawMessages();

View file

@ -331,55 +331,56 @@ void OnScreenUI::DrawDebugText()
ImGui::TextUnformatted(profile_output.c_str());
}
#ifdef USE_RETRO_ACHIEVEMENTS
void OnScreenUI::DrawChallengesAndLeaderboards()
{
std::lock_guard lg{AchievementManager::GetInstance().GetLock()};
const auto& challenge_icons = AchievementManager::GetInstance().GetChallengeIcons();
const auto& leaderboard_progress = AchievementManager::GetInstance().GetActiveLeaderboards();
float leaderboard_y = ImGui::GetIO().DisplaySize.y;
if (!challenge_icons.empty())
if (!Config::Get(Config::MAIN_OSD_MESSAGES))
return;
#ifdef USE_RETRO_ACHIEVEMENTS
auto& instance = AchievementManager::GetInstance();
std::lock_guard lg{instance.GetLock()};
if (instance.AreChallengesUpdated())
{
instance.ResetChallengesUpdated();
const auto& challenges = instance.GetActiveChallenges();
m_challenge_texture_map.clear();
for (const auto& name : challenges)
{
const auto& icon = instance.GetAchievementBadge(name, false);
const u32 width = icon.width;
const u32 height = icon.height;
TextureConfig tex_config(width, height, 1, 1, 1, AbstractTextureFormat::RGBA8, 0,
AbstractTextureType::Texture_2DArray);
auto res = m_challenge_texture_map.insert_or_assign(name, g_gfx->CreateTexture(tex_config));
res.first->second->Load(0, width, height, width, icon.data.data(),
sizeof(u32) * width * height);
}
}
float leaderboard_y = ImGui::GetIO().DisplaySize.y;
if (!m_challenge_texture_map.empty())
{
float scale = ImGui::GetIO().DisplaySize.y / 1024.0;
ImGui::SetNextWindowSize(ImVec2(0, 0));
ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y), 0,
ImVec2(1.0, 1.0));
ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f));
ImVec2(1, 1));
if (ImGui::Begin("Challenges", nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing))
{
for (const auto& [name, icon] : challenge_icons)
{
if (m_challenge_texture_map.find(name) != m_challenge_texture_map.end())
continue;
const u32 width = icon->width;
const u32 height = icon->height;
TextureConfig tex_config(width, height, 1, 1, 1, AbstractTextureFormat::RGBA8, 0,
AbstractTextureType::Texture_2DArray);
auto res = m_challenge_texture_map.insert_or_assign(name, g_gfx->CreateTexture(tex_config));
res.first->second->Load(0, width, height, width, icon->rgba_data.data(),
sizeof(u32) * width * height);
}
for (auto& [name, texture] : m_challenge_texture_map)
{
auto icon_itr = challenge_icons.find(name);
if (icon_itr == challenge_icons.end())
{
m_challenge_texture_map.erase(name);
continue;
}
if (texture)
{
ImGui::Image(texture.get(), ImVec2(static_cast<float>(icon_itr->second->width),
static_cast<float>(icon_itr->second->height)));
}
ImGui::Image(texture.get(), ImVec2(static_cast<float>(texture->GetWidth()) * scale,
static_cast<float>(texture->GetHeight()) * scale));
ImGui::SameLine();
}
leaderboard_y -= ImGui::GetWindowHeight();
}
leaderboard_y -= ImGui::GetWindowHeight();
ImGui::End();
}
const auto& leaderboard_progress = instance.GetActiveLeaderboards();
if (!leaderboard_progress.empty())
{
ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x, leaderboard_y), 0,
@ -392,12 +393,12 @@ void OnScreenUI::DrawChallengesAndLeaderboards()
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing))
{
for (const auto& value : leaderboard_progress)
ImGui::Text(value.data());
ImGui::TextUnformatted(value.c_str());
}
ImGui::End();
}
}
#endif // USE_RETRO_ACHIEVEMENTS
}
void OnScreenUI::Finalize()
{
@ -406,9 +407,7 @@ void OnScreenUI::Finalize()
g_perf_metrics.DrawImGuiStats(m_backbuffer_scale);
DrawDebugText();
OSD::DrawMessages();
#ifdef USE_RETRO_ACHIEVEMENTS
DrawChallengesAndLeaderboards();
#endif // USE_RETRO_ACHIEVEMENTS
ImGui::Render();
}
@ -472,8 +471,7 @@ void OnScreenUI::SetMousePos(float x, float y)
{
auto lock = GetImGuiLock();
ImGui::GetIO().MousePos.x = x;
ImGui::GetIO().MousePos.y = y;
ImGui::GetIO().AddMousePosEvent(x, y);
}
void OnScreenUI::SetMousePress(u32 button_mask)

View file

@ -61,9 +61,7 @@ public:
private:
void DrawDebugText();
#ifdef USE_RETRO_ACHIEVEMENTS
void DrawChallengesAndLeaderboards();
#endif // USE_RETRO_ACHIEVEMENTS
// ImGui resources.
std::unique_ptr<NativeVertexFormat> m_imgui_vertex_format;
@ -78,7 +76,7 @@ private:
float m_backbuffer_scale = 1.0;
#ifdef USE_RETRO_ACHIEVEMENTS
std::map<std::string, std::unique_ptr<AbstractTexture>, std::less<>> m_challenge_texture_map;
std::map<int, std::unique_ptr<AbstractTexture>, std::less<>> m_challenge_texture_map;
#endif // USE_RETRO_ACHIEVEMENTS
bool m_ready = false;

View file

@ -203,7 +203,8 @@ static DOLPHIN_FORCE_INLINE u32 RunCommand(const u8* data, u32 available, T& cal
const u32 address = Common::swap32(&data[1]);
const u32 size = Common::swap32(&data[5]);
callback.OnDisplayList(address, size);
// Force 32-byte alignment for both the address and the size.
callback.OnDisplayList(address & ~31, size & ~31);
return 9;
}

View file

@ -2,7 +2,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoCommon/PerfQueryBase.h"
#include <memory>
#include "VideoCommon/VideoConfig.h"
std::unique_ptr<PerfQueryBase> g_perf_query;

View file

@ -1315,6 +1315,23 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
WriteFog(out, uid_data);
for (std::size_t i = 0; i < custom_details.shaders.size(); i++)
{
const auto& shader_details = custom_details.shaders[i];
if (!shader_details.custom_shader.empty())
{
out.Write("\t{{\n");
out.Write("\t\tcustom_data.final_color = float4(prev.r / 255.0, prev.g / 255.0, prev.b "
"/ 255.0, prev.a / 255.0);\n");
out.Write("\t\tCustomShaderOutput custom_output = {}_{}(custom_data);\n",
CUSTOM_PIXELSHADER_COLOR_FUNC, i);
out.Write("\t\tprev = int4(custom_output.main_rt.r * 255, custom_output.main_rt.g * 255, "
"custom_output.main_rt.b * 255, custom_output.main_rt.a * 255);\n");
out.Write("\t}}\n\n");
}
}
if (uid_data->logic_op_enable)
WriteLogicOp(out, uid_data);
else if (uid_data->emulate_logic_op_with_blend)
@ -1325,31 +1342,6 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
const bool use_dual_source = !uid_data->no_dual_src || uid_data->blend_enable;
WriteColor(out, api_type, uid_data, use_dual_source);
for (std::size_t i = 0; i < custom_details.shaders.size(); i++)
{
const auto& shader_details = custom_details.shaders[i];
if (!shader_details.custom_shader.empty())
{
out.Write("\t{{\n");
if (uid_data->uint_output)
{
out.Write("\t\tcustom_data.final_color = float4(ocol0.x / 255.0, ocol0.y / 255.0, ocol0.z "
"/ 255.0, ocol0.w / 255.0);\n");
out.Write("\t\tfloat3 custom_output = {}_{}(custom_data).xyz;\n",
CUSTOM_PIXELSHADER_COLOR_FUNC, i);
out.Write("\t\tocol0.xyz = uint3(custom_output.x * 255, custom_output.y * 255, "
"custom_output.z * 255);\n");
}
else
{
out.Write("\t\tcustom_data.final_color = ocol0;\n");
out.Write("\t\tocol0.xyz = {}_{}(custom_data).xyz;\n", CUSTOM_PIXELSHADER_COLOR_FUNC, i);
}
out.Write("\t}}\n\n");
}
}
if (uid_data->blend_enable)
WriteBlend(out, uid_data);
else if (use_framebuffer_fetch)

View file

@ -290,7 +290,7 @@ void ShaderCache::LoadPipelineCache(T& cache, Common::LinearDiskCache<DiskKeyTyp
UnserializePipelineUid(key, real_uid);
// Skip those which are already compiled.
if (failed || cache.find(real_uid) != cache.end())
if (failed || cache.contains(real_uid))
return;
auto config = this_ptr->GetGXPipelineConfig(real_uid);

View file

@ -379,6 +379,11 @@ void WriteCustomShaderStructDef(ShaderCode* out, u32 numtexgens)
out->Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_SPOT = {}u;\n",
static_cast<u32>(AttenuationFunc::Spot));
out->Write("struct CustomShaderOutput\n");
out->Write("{{\n");
out->Write("\tfloat4 main_rt;\n");
out->Write("}};\n\n");
out->Write("struct CustomShaderLightData\n");
out->Write("{{\n");
out->Write("\tfloat3 position;\n");

View file

@ -665,7 +665,7 @@ void TextureCacheBase::DoSaveState(PointerWrap& p)
auto refpair1 = std::make_pair(*id1, *id2);
auto refpair2 = std::make_pair(*id2, *id1);
if (reference_pairs.count(refpair1) == 0 && reference_pairs.count(refpair2) == 0)
if (!reference_pairs.contains(refpair1) && !reference_pairs.contains(refpair2))
reference_pairs.insert(refpair1);
}
}
@ -854,7 +854,7 @@ RcTcacheEntry TextureCacheBase::DoPartialTextureUpdates(RcTcacheEntry& entry_to_
{
auto& entry = iter.first->second;
if (entry != entry_to_update && entry->IsCopy() &&
entry->references.count(entry_to_update.get()) == 0 &&
!entry->references.contains(entry_to_update.get()) &&
entry->OverlapsMemoryRange(entry_to_update->addr, entry_to_update->size_in_bytes) &&
entry->memory_stride == numBlocksX * block_size)
{
@ -1012,8 +1012,8 @@ static bool IsAnisostropicEnhancementSafe(const TexMode0& tm0)
return !(tm0.min_filter == FilterMode::Near && tm0.mag_filter == FilterMode::Near);
}
static void SetSamplerState(u32 index, float custom_tex_scale, bool custom_tex,
bool has_arbitrary_mips)
SamplerState TextureCacheBase::GetSamplerState(u32 index, float custom_tex_scale, bool custom_tex,
bool has_arbitrary_mips)
{
const TexMode0& tm0 = bpmem.tex.GetUnit(index).texMode0;
@ -1073,13 +1073,11 @@ static void SetSamplerState(u32 index, float custom_tex_scale, bool custom_tex,
state.tm0.anisotropic_filtering = false;
}
g_gfx->SetSamplerState(index, state);
auto& system = Core::System::GetInstance();
auto& pixel_shader_manager = system.GetPixelShaderManager();
pixel_shader_manager.SetSamplerState(index, state.tm0.hex, state.tm1.hex);
return state;
}
void TextureCacheBase::BindTextures(BitSet32 used_textures)
void TextureCacheBase::BindTextures(BitSet32 used_textures,
const std::array<SamplerState, 8>& samplers)
{
auto& system = Core::System::GetInstance();
auto& pixel_shader_manager = system.GetPixelShaderManager();
@ -1091,8 +1089,9 @@ void TextureCacheBase::BindTextures(BitSet32 used_textures)
g_gfx->SetTexture(i, tentry->texture.get());
pixel_shader_manager.SetTexDims(i, tentry->native_width, tentry->native_height);
const float custom_tex_scale = tentry->GetWidth() / float(tentry->native_width);
SetSamplerState(i, custom_tex_scale, tentry->is_custom_tex, tentry->has_arbitrary_mips);
auto& state = samplers[i];
g_gfx->SetSamplerState(i, state);
pixel_shader_manager.SetSamplerState(i, state.tm0.hex, state.tm1.hex);
}
}

View file

@ -33,6 +33,7 @@
class AbstractFramebuffer;
class AbstractStagingTexture;
class PointerWrap;
struct SamplerState;
struct VideoConfig;
namespace VideoCommon
@ -282,7 +283,7 @@ public:
RcTcacheEntry GetXFBTexture(u32 address, u32 width, u32 height, u32 stride,
MathUtil::Rectangle<int>* display_rect);
virtual void BindTextures(BitSet32 used_textures);
virtual void BindTextures(BitSet32 used_textures, const std::array<SamplerState, 8>& samplers);
void CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstFormat, u32 width, u32 height,
u32 dstStride, bool is_depth_copy,
const MathUtil::Rectangle<int>& srcRect, bool isIntensity,
@ -308,6 +309,10 @@ public:
static bool AllCopyFilterCoefsNeeded(const std::array<u32, 3>& coefficients);
static bool CopyFilterCanOverflow(const std::array<u32, 3>& coefficients);
// Get a new sampler state
static SamplerState GetSamplerState(u32 index, float custom_tex_scale, bool custom_tex,
bool has_arbitrary_mips);
protected:
// Decodes the specified data to the GPU texture specified by entry.
// Returns false if the configuration is not supported.

View file

@ -9,8 +9,8 @@
bool TextureConfig::operator==(const TextureConfig& o) const
{
return std::tie(width, height, levels, layers, samples, format, flags) ==
std::tie(o.width, o.height, o.levels, o.layers, o.samples, o.format, o.flags);
return std::tie(width, height, levels, layers, samples, format, flags, type) ==
std::tie(o.width, o.height, o.levels, o.layers, o.samples, o.format, o.flags, o.type);
}
bool TextureConfig::operator!=(const TextureConfig& o) const

View file

@ -1506,6 +1506,24 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
" }}\n"
"\n");
for (std::size_t i = 0; i < custom_details.shaders.size(); i++)
{
const auto& shader_details = custom_details.shaders[i];
if (!shader_details.custom_shader.empty())
{
out.Write("\t{{\n");
out.Write("\t\tcustom_data.final_color = float4(TevResult.r / 255.0, TevResult.g / 255.0, "
"TevResult.b / 255.0, TevResult.a / 255.0);\n");
out.Write("\t\tCustomShaderOutput custom_output = {}_{}(custom_data);\n",
CUSTOM_PIXELSHADER_COLOR_FUNC, i);
out.Write(
"\t\tTevResult = int4(custom_output.main_rt.r * 255, custom_output.main_rt.g * 255, "
"custom_output.main_rt.b * 255, custom_output.main_rt.a * 255);\n");
out.Write("\t}}\n\n");
}
}
if (use_framebuffer_fetch)
{
static constexpr std::array<const char*, 16> logic_op_mode{
@ -1594,31 +1612,6 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
}
}
for (std::size_t i = 0; i < custom_details.shaders.size(); i++)
{
const auto& shader_details = custom_details.shaders[i];
if (!shader_details.custom_shader.empty())
{
out.Write("\t{{\n");
if (uid_data->uint_output)
{
out.Write("\t\tcustom_data.final_color = float4(ocol0.x / 255.0, ocol0.y / 255.0, ocol0.z "
"/ 255.0, ocol0.w / 255.0);\n");
out.Write("\t\tfloat3 custom_output = {}_{}(custom_data).xyz;\n",
CUSTOM_PIXELSHADER_COLOR_FUNC, i);
out.Write("\t\tocol0.xyz = uint3(custom_output.x * 255, custom_output.y * 255, "
"custom_output.z * 255);\n");
}
else
{
out.Write("\t\tcustom_data.final_color = ocol0;\n");
out.Write("\t\tocol0.xyz = {}_{}(custom_data).xyz;\n", CUSTOM_PIXELSHADER_COLOR_FUNC, i);
}
out.Write("\t}}\n\n");
}
}
if (bounding_box)
{
out.Write(" if (bpmem_bounding_box) {{\n"

View file

@ -18,7 +18,7 @@ struct PortableVertexDeclaration;
namespace OpcodeDecoder
{
enum class Primitive : u8;
};
}
namespace VertexLoaderManager
{

View file

@ -563,13 +563,19 @@ void VertexManagerBase::Flush()
const auto used_textures = UsedTextures();
std::vector<std::string> texture_names;
Common::SmallVector<u32, 8> texture_units;
std::array<SamplerState, 8> samplers;
if (!m_cull_all)
{
if (!g_ActiveConfig.bGraphicMods)
{
for (const u32 i : used_textures)
{
g_texture_cache->Load(TextureInfo::FromStage(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);
}
}
else
@ -585,6 +591,10 @@ void VertexManagerBase::Flush()
texture_names.push_back(cache_entry->texture_info_name);
texture_units.push_back(i);
}
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);
}
}
}
@ -633,7 +643,7 @@ void VertexManagerBase::Flush()
// Texture loading can cause palettes to be applied (-> uniforms -> draws).
// Palette application does not use vertices, only a full-screen quad, so this is okay.
// Same with GPU texture decoding, which uses compute shaders.
g_texture_cache->BindTextures(used_textures);
g_texture_cache->BindTextures(used_textures, samplers);
if (PerfQueryBase::ShouldEmulate())
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);

View file

@ -45,7 +45,7 @@ enum TexelBufferFormat : u32
namespace OpcodeDecoder
{
enum class Primitive : u8;
};
}
class VertexManagerBase
{

View file

@ -66,7 +66,7 @@ void VideoConfig::Refresh()
CPUThreadConfigCallback::AddConfigChangedCallback([]() {
auto& system = Core::System::GetInstance();
const bool lock_gpu_thread = Core::IsRunningAndStarted();
const bool lock_gpu_thread = Core::IsRunning(system);
if (lock_gpu_thread)
system.GetFifo().PauseAndLock(true, false);