VideoCommon: instead of using 'CustomTextureData' directly, use 'TextureData' for texture assets, this allows us to provide additional metadata for textures. Such as a sampler or type information (to distinguish cube maps)
This commit is contained in:
parent
1b7a590b4b
commit
0e8f8ea930
|
@ -6,7 +6,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "VideoCommon/Assets/CustomTextureData.h"
|
||||
#include "VideoCommon/Assets/TextureAsset.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
|
@ -26,16 +26,26 @@ std::size_t GetAssetSize(const CustomTextureData& data)
|
|||
}
|
||||
} // namespace
|
||||
CustomAssetLibrary::LoadInfo CustomAssetLibrary::LoadGameTexture(const AssetID& asset_id,
|
||||
CustomTextureData* data)
|
||||
TextureData* data)
|
||||
{
|
||||
const auto load_info = LoadTexture(asset_id, data);
|
||||
if (load_info.m_bytes_loaded == 0)
|
||||
return {};
|
||||
|
||||
// Note: 'LoadTexture()' ensures we have a level loaded
|
||||
for (std::size_t slice_index = 0; slice_index < data->m_slices.size(); slice_index++)
|
||||
if (data->m_type != TextureData::Type::Type_Texture2D)
|
||||
{
|
||||
auto& slice = data->m_slices[slice_index];
|
||||
ERROR_LOG_FMT(
|
||||
VIDEO,
|
||||
"Custom asset '{}' is not a valid game texture, it is expected to be a 2d texture "
|
||||
"but was a '{}'.",
|
||||
asset_id, data->m_type);
|
||||
return {};
|
||||
}
|
||||
|
||||
// Note: 'LoadTexture()' ensures we have a level loaded
|
||||
for (std::size_t slice_index = 0; slice_index < data->m_texture.m_slices.size(); slice_index++)
|
||||
{
|
||||
auto& slice = data->m_texture.m_slices[slice_index];
|
||||
const auto& first_mip = slice.m_levels[0];
|
||||
|
||||
// Verify that each mip level is the correct size (divide by 2 each time).
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
namespace VideoCommon
|
||||
{
|
||||
class CustomTextureData;
|
||||
struct MaterialData;
|
||||
struct PixelShaderData;
|
||||
struct TextureData;
|
||||
|
||||
// This class provides functionality to load
|
||||
// specific data (like textures). Where this data
|
||||
|
@ -32,14 +32,14 @@ public:
|
|||
};
|
||||
|
||||
// Loads a texture, if there are no levels, bytes loaded will be empty
|
||||
virtual LoadInfo LoadTexture(const AssetID& asset_id, CustomTextureData* data) = 0;
|
||||
virtual LoadInfo LoadTexture(const AssetID& asset_id, TextureData* data) = 0;
|
||||
|
||||
// Gets the last write time for a given asset id
|
||||
virtual TimeType GetLastAssetWriteTime(const AssetID& asset_id) const = 0;
|
||||
|
||||
// Loads a texture as a game texture, providing additional checks like confirming
|
||||
// each mip level size is correct and that the format is consistent across the data
|
||||
LoadInfo LoadGameTexture(const AssetID& asset_id, CustomTextureData* data);
|
||||
LoadInfo LoadGameTexture(const AssetID& asset_id, TextureData* data);
|
||||
|
||||
// Loads a pixel shader
|
||||
virtual LoadInfo LoadPixelShader(const AssetID& asset_id, PixelShaderData* data) = 0;
|
||||
|
|
|
@ -77,13 +77,6 @@ void CustomAssetLoader ::Shutdown()
|
|||
m_total_bytes_loaded = 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<RawTextureAsset>
|
||||
CustomAssetLoader::LoadTexture(const CustomAssetLibrary::AssetID& asset_id,
|
||||
std::shared_ptr<CustomAssetLibrary> library)
|
||||
{
|
||||
return LoadOrCreateAsset<RawTextureAsset>(asset_id, m_textures, std::move(library));
|
||||
}
|
||||
|
||||
std::shared_ptr<GameTextureAsset>
|
||||
CustomAssetLoader::LoadGameTexture(const CustomAssetLibrary::AssetID& asset_id,
|
||||
std::shared_ptr<CustomAssetLibrary> library)
|
||||
|
|
|
@ -38,9 +38,6 @@ public:
|
|||
// Loads happen asynchronously where the data will be set now or in the future
|
||||
// Callees are expected to query the underlying data with 'GetData()'
|
||||
// from the 'CustomLoadableAsset' class to determine if the data is ready for use
|
||||
std::shared_ptr<RawTextureAsset> LoadTexture(const CustomAssetLibrary::AssetID& asset_id,
|
||||
std::shared_ptr<CustomAssetLibrary> library);
|
||||
|
||||
std::shared_ptr<GameTextureAsset> LoadGameTexture(const CustomAssetLibrary::AssetID& asset_id,
|
||||
std::shared_ptr<CustomAssetLibrary> library);
|
||||
|
||||
|
@ -80,7 +77,6 @@ private:
|
|||
|
||||
static constexpr auto TIME_BETWEEN_ASSET_MONITOR_CHECKS = std::chrono::milliseconds{500};
|
||||
|
||||
std::map<CustomAssetLibrary::AssetID, std::weak_ptr<RawTextureAsset>> m_textures;
|
||||
std::map<CustomAssetLibrary::AssetID, std::weak_ptr<GameTextureAsset>> m_game_textures;
|
||||
std::map<CustomAssetLibrary::AssetID, std::weak_ptr<PixelShaderAsset>> m_pixel_shaders;
|
||||
std::map<CustomAssetLibrary::AssetID, std::weak_ptr<MaterialAsset>> m_materials;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "Common/StringUtil.h"
|
||||
#include "VideoCommon/Assets/MaterialAsset.h"
|
||||
#include "VideoCommon/Assets/ShaderAsset.h"
|
||||
#include "VideoCommon/Assets/TextureAsset.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
|
@ -219,66 +220,126 @@ CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadMaterial(const As
|
|||
}
|
||||
|
||||
CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadTexture(const AssetID& asset_id,
|
||||
CustomTextureData* data)
|
||||
TextureData* data)
|
||||
{
|
||||
const auto asset_map = GetAssetMapForID(asset_id);
|
||||
|
||||
// Raw texture is expected to have one asset mapped
|
||||
if (asset_map.empty() || asset_map.size() > 1)
|
||||
// Texture can optionally have a metadata file as well
|
||||
if (asset_map.empty() || asset_map.size() > 2)
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - raw texture expected to have one file mapped!",
|
||||
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - raw texture expected to have one or two files mapped!",
|
||||
asset_id);
|
||||
return {};
|
||||
}
|
||||
const auto& asset_path = asset_map.begin()->second;
|
||||
|
||||
std::error_code ec;
|
||||
const auto last_loaded_time = std::filesystem::last_write_time(asset_path, ec);
|
||||
if (ec)
|
||||
const auto metadata = asset_map.find("metadata");
|
||||
const auto texture_path = asset_map.find("texture");
|
||||
|
||||
if (texture_path == asset_map.end())
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to get last write time with error '{}'!",
|
||||
asset_id, ec);
|
||||
ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have a texture entry mapped!", asset_id);
|
||||
return {};
|
||||
}
|
||||
auto ext = PathToString(asset_path.extension());
|
||||
|
||||
std::size_t metadata_size = 0;
|
||||
if (metadata != asset_map.end())
|
||||
{
|
||||
std::error_code ec;
|
||||
metadata_size = std::filesystem::file_size(metadata->second, ec);
|
||||
if (ec)
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO,
|
||||
"Asset '{}' error - failed to get texture metadata file size with error '{}'!",
|
||||
asset_id, ec);
|
||||
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())
|
||||
{
|
||||
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(
|
||||
VIDEO,
|
||||
"Asset '{}' error - failed to load the json file '{}', due to root not being an object!",
|
||||
asset_id, PathToString(metadata->second));
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto& root_obj = root.get<picojson::object>();
|
||||
if (!TextureData::FromJson(asset_id, root_obj, data))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data->m_type = TextureData::Type::Type_Texture2D;
|
||||
}
|
||||
|
||||
auto ext = PathToString(texture_path->second.extension());
|
||||
Common::ToLower(&ext);
|
||||
if (ext == ".dds")
|
||||
{
|
||||
if (!LoadDDSTexture(data, PathToString(asset_path)))
|
||||
if (!LoadDDSTexture(&data->m_texture, PathToString(texture_path->second)))
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - could not load dds texture!", asset_id);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (data->m_slices.empty()) [[unlikely]]
|
||||
data->m_slices.push_back({});
|
||||
if (data->m_texture.m_slices.empty()) [[unlikely]]
|
||||
data->m_texture.m_slices.push_back({});
|
||||
|
||||
if (!LoadMips(asset_path, &data->m_slices[0]))
|
||||
if (!LoadMips(texture_path->second, &data->m_texture.m_slices[0]))
|
||||
return {};
|
||||
|
||||
return LoadInfo{GetAssetSize(*data), FileTimeToSysTime(last_loaded_time)};
|
||||
return LoadInfo{GetAssetSize(data->m_texture) + metadata_size, GetLastAssetWriteTime(asset_id)};
|
||||
}
|
||||
else if (ext == ".png")
|
||||
{
|
||||
// If we have no slices, create one
|
||||
if (data->m_slices.empty())
|
||||
data->m_slices.push_back({});
|
||||
// PNG could support more complicated texture types in the future
|
||||
// but for now just error
|
||||
if (data->m_type != TextureData::Type::Type_Texture2D)
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - PNG is not supported for texture type '{}'!",
|
||||
asset_id, data->m_type);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto& slice = data->m_slices[0];
|
||||
// If we have no slices, create one
|
||||
if (data->m_texture.m_slices.empty())
|
||||
data->m_texture.m_slices.push_back({});
|
||||
|
||||
auto& slice = data->m_texture.m_slices[0];
|
||||
// If we have no levels, create one to pass into LoadPNGTexture
|
||||
if (slice.m_levels.empty())
|
||||
slice.m_levels.push_back({});
|
||||
|
||||
if (!LoadPNGTexture(&slice.m_levels[0], PathToString(asset_path)))
|
||||
if (!LoadPNGTexture(&slice.m_levels[0], PathToString(texture_path->second)))
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - could not load png texture!", asset_id);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!LoadMips(asset_path, &slice))
|
||||
if (!LoadMips(texture_path->second, &slice))
|
||||
return {};
|
||||
|
||||
return LoadInfo{GetAssetSize(*data), FileTimeToSysTime(last_loaded_time)};
|
||||
return LoadInfo{GetAssetSize(data->m_texture) + metadata_size, GetLastAssetWriteTime(asset_id)};
|
||||
}
|
||||
|
||||
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - extension '{}' unknown!", asset_id, ext);
|
||||
|
|
|
@ -20,7 +20,7 @@ class DirectFilesystemAssetLibrary final : public CustomAssetLibrary
|
|||
public:
|
||||
using AssetMap = std::map<std::string, std::filesystem::path>;
|
||||
|
||||
LoadInfo LoadTexture(const AssetID& asset_id, CustomTextureData* data) override;
|
||||
LoadInfo LoadTexture(const AssetID& asset_id, TextureData* data) override;
|
||||
LoadInfo LoadPixelShader(const AssetID& asset_id, PixelShaderData* data) override;
|
||||
LoadInfo LoadMaterial(const AssetID& asset_id, MaterialData* data) override;
|
||||
|
||||
|
|
|
@ -97,20 +97,6 @@ bool ParseSampler(const VideoCommon::CustomAssetLibrary::AssetID& asset_id,
|
|||
return true;
|
||||
}
|
||||
} // namespace
|
||||
CustomAssetLibrary::LoadInfo RawTextureAsset::LoadImpl(const CustomAssetLibrary::AssetID& asset_id)
|
||||
{
|
||||
auto potential_data = std::make_shared<CustomTextureData>();
|
||||
const auto loaded_info = m_owning_library->LoadTexture(asset_id, potential_data.get());
|
||||
if (loaded_info.m_bytes_loaded == 0)
|
||||
return {};
|
||||
{
|
||||
std::lock_guard lk(m_data_lock);
|
||||
m_loaded = true;
|
||||
m_data = std::move(potential_data);
|
||||
}
|
||||
return loaded_info;
|
||||
}
|
||||
|
||||
bool TextureData::FromJson(const CustomAssetLibrary::AssetID& asset_id,
|
||||
const picojson::object& json, TextureData* data)
|
||||
{
|
||||
|
@ -160,7 +146,7 @@ bool TextureData::FromJson(const CustomAssetLibrary::AssetID& asset_id,
|
|||
|
||||
CustomAssetLibrary::LoadInfo GameTextureAsset::LoadImpl(const CustomAssetLibrary::AssetID& asset_id)
|
||||
{
|
||||
auto potential_data = std::make_shared<CustomTextureData>();
|
||||
auto potential_data = std::make_shared<TextureData>();
|
||||
const auto loaded_info = m_owning_library->LoadGameTexture(asset_id, potential_data.get());
|
||||
if (loaded_info.m_bytes_loaded == 0)
|
||||
return {};
|
||||
|
@ -184,7 +170,7 @@ bool GameTextureAsset::Validate(u32 native_width, u32 native_height) const
|
|||
return false;
|
||||
}
|
||||
|
||||
if (m_data->m_slices.empty())
|
||||
if (m_data->m_texture.m_slices.empty())
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO,
|
||||
"Game texture can't be validated for asset '{}' because no data was available.",
|
||||
|
@ -192,7 +178,7 @@ bool GameTextureAsset::Validate(u32 native_width, u32 native_height) const
|
|||
return false;
|
||||
}
|
||||
|
||||
if (m_data->m_slices.size() > 1)
|
||||
if (m_data->m_texture.m_slices.size() > 1)
|
||||
{
|
||||
ERROR_LOG_FMT(
|
||||
VIDEO,
|
||||
|
@ -201,7 +187,7 @@ bool GameTextureAsset::Validate(u32 native_width, u32 native_height) const
|
|||
return false;
|
||||
}
|
||||
|
||||
const auto& slice = m_data->m_slices[0];
|
||||
const auto& slice = m_data->m_texture.m_slices[0];
|
||||
if (slice.m_levels.empty())
|
||||
{
|
||||
ERROR_LOG_FMT(
|
||||
|
|
|
@ -3,23 +3,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <picojson.h>
|
||||
|
||||
#include "Common/EnumFormatter.h"
|
||||
#include "VideoCommon/Assets/CustomAsset.h"
|
||||
#include "VideoCommon/Assets/CustomTextureData.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
class RawTextureAsset final : public CustomLoadableAsset<CustomTextureData>
|
||||
{
|
||||
public:
|
||||
using CustomLoadableAsset::CustomLoadableAsset;
|
||||
|
||||
private:
|
||||
CustomAssetLibrary::LoadInfo LoadImpl(const CustomAssetLibrary::AssetID& asset_id) override;
|
||||
};
|
||||
|
||||
struct TextureData
|
||||
{
|
||||
static bool FromJson(const CustomAssetLibrary::AssetID& asset_id, const picojson::object& json,
|
||||
|
@ -32,11 +25,11 @@ struct TextureData
|
|||
Type_Max = Type_TextureCube
|
||||
};
|
||||
Type m_type;
|
||||
CustomTextureData m_data;
|
||||
CustomTextureData m_texture;
|
||||
SamplerState m_sampler;
|
||||
};
|
||||
|
||||
class GameTextureAsset final : public CustomLoadableAsset<CustomTextureData>
|
||||
class GameTextureAsset final : public CustomLoadableAsset<TextureData>
|
||||
{
|
||||
public:
|
||||
using CustomLoadableAsset::CustomLoadableAsset;
|
||||
|
@ -49,3 +42,10 @@ private:
|
|||
CustomAssetLibrary::LoadInfo LoadImpl(const CustomAssetLibrary::AssetID& asset_id) override;
|
||||
};
|
||||
} // namespace VideoCommon
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<VideoCommon::TextureData::Type>
|
||||
: EnumFormatter<VideoCommon::TextureData::Type::Type_Max>
|
||||
{
|
||||
constexpr formatter() : EnumFormatter({"Undefined", "Texture2D", "TextureCube"}) {}
|
||||
};
|
||||
|
|
|
@ -423,7 +423,7 @@ void CustomPipelineAction::OnTextureCreate(GraphicsModActionData::TextureCreate*
|
|||
auto data = game_texture.m_asset->GetData();
|
||||
if (data)
|
||||
{
|
||||
if (data->m_slices.empty() || data->m_slices[0].m_levels.empty())
|
||||
if (data->m_texture.m_slices.empty() || data->m_texture.m_slices[0].m_levels.empty())
|
||||
{
|
||||
ERROR_LOG_FMT(
|
||||
VIDEO,
|
||||
|
@ -431,15 +431,16 @@ void CustomPipelineAction::OnTextureCreate(GraphicsModActionData::TextureCreate*
|
|||
create->texture_name, game_texture.m_asset->GetAssetId());
|
||||
m_valid = false;
|
||||
}
|
||||
else if (create->texture_width != data->m_slices[0].m_levels[0].width ||
|
||||
create->texture_height != data->m_slices[0].m_levels[0].height)
|
||||
else if (create->texture_width != data->m_texture.m_slices[0].m_levels[0].width ||
|
||||
create->texture_height != data->m_texture.m_slices[0].m_levels[0].height)
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO,
|
||||
"Custom pipeline for texture '{}' has asset '{}' that does not match "
|
||||
"the width/height of the texture loaded. Texture {}x{} vs asset {}x{}",
|
||||
create->texture_name, game_texture.m_asset->GetAssetId(),
|
||||
create->texture_width, create->texture_height,
|
||||
data->m_slices[0].m_levels[0].width, data->m_slices[0].m_levels[0].height);
|
||||
data->m_texture.m_slices[0].m_levels[0].width,
|
||||
data->m_texture.m_slices[0].m_levels[0].height);
|
||||
m_valid = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,8 +130,8 @@ void HiresTexture::Update()
|
|||
{
|
||||
// Since this is just a texture (single file) the mapper doesn't really matter
|
||||
// just provide a string
|
||||
s_file_library->SetAssetIDMapData(
|
||||
filename, std::map<std::string, std::filesystem::path>{{"", StringToPath(path)}});
|
||||
s_file_library->SetAssetIDMapData(filename, std::map<std::string, std::filesystem::path>{
|
||||
{"texture", StringToPath(path)}});
|
||||
|
||||
if (g_ActiveConfig.bCacheHiresTextures)
|
||||
{
|
||||
|
|
|
@ -1606,7 +1606,7 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
|
|||
}
|
||||
|
||||
std::vector<VideoCommon::CachedAsset<VideoCommon::GameTextureAsset>> cached_game_assets;
|
||||
std::vector<std::shared_ptr<VideoCommon::CustomTextureData>> data_for_assets;
|
||||
std::vector<VideoCommon::CustomTextureData*> data_for_assets;
|
||||
bool has_arbitrary_mipmaps = false;
|
||||
bool skip_texture_dump = false;
|
||||
std::shared_ptr<HiresTexture> hires_texture;
|
||||
|
@ -1640,12 +1640,12 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
|
|||
auto data = asset->GetData();
|
||||
if (data)
|
||||
{
|
||||
if (!data->m_slices.empty())
|
||||
if (!data->m_texture.m_slices.empty())
|
||||
{
|
||||
if (!data->m_slices[0].m_levels.empty())
|
||||
if (!data->m_texture.m_slices[0].m_levels.empty())
|
||||
{
|
||||
height = data->m_slices[0].m_levels[0].height;
|
||||
width = data->m_slices[0].m_levels[0].width;
|
||||
height = data->m_texture.m_slices[0].m_levels[0].height;
|
||||
width = data->m_texture.m_slices[0].m_levels[0].width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1667,7 +1667,7 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
|
|||
{
|
||||
if (cached_asset.m_asset->Validate(texture_info.GetRawWidth(), texture_info.GetRawHeight()))
|
||||
{
|
||||
data_for_assets.push_back(std::move(data));
|
||||
data_for_assets.push_back(&data->m_texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1687,8 +1687,7 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
|
|||
// expected because each texture is loaded into a texture array
|
||||
RcTcacheEntry TextureCacheBase::CreateTextureEntry(
|
||||
const TextureCreationInfo& creation_info, const TextureInfo& texture_info,
|
||||
const int safety_color_sample_size,
|
||||
std::vector<std::shared_ptr<VideoCommon::CustomTextureData>> assets_data,
|
||||
const int safety_color_sample_size, std::vector<VideoCommon::CustomTextureData*> assets_data,
|
||||
const bool custom_arbitrary_mipmaps, bool skip_texture_dump)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
|
@ -1705,7 +1704,7 @@ RcTcacheEntry TextureCacheBase::CreateTextureEntry(
|
|||
assets_data.begin(), assets_data.end(), [](const auto& lhs, const auto& rhs) {
|
||||
return lhs->m_slices[0].m_levels.size() < rhs->m_slices[0].m_levels.size();
|
||||
});
|
||||
return max_element->get()->m_slices[0].m_levels.size();
|
||||
return (*max_element)->m_slices[0].m_levels.size();
|
||||
};
|
||||
const u32 texLevels = no_mips ? 1 : (u32)calculate_max_levels();
|
||||
const auto& first_level = assets_data[0]->m_slices[0].m_levels[0];
|
||||
|
|
|
@ -346,11 +346,10 @@ private:
|
|||
|
||||
void SetBackupConfig(const VideoConfig& config);
|
||||
|
||||
RcTcacheEntry
|
||||
CreateTextureEntry(const TextureCreationInfo& creation_info, const TextureInfo& texture_info,
|
||||
int safety_color_sample_size,
|
||||
std::vector<std::shared_ptr<VideoCommon::CustomTextureData>> assets_data,
|
||||
bool custom_arbitrary_mipmaps, bool skip_texture_dump);
|
||||
RcTcacheEntry CreateTextureEntry(const TextureCreationInfo& creation_info,
|
||||
const TextureInfo& texture_info, int safety_color_sample_size,
|
||||
std::vector<VideoCommon::CustomTextureData*> assets_data,
|
||||
bool custom_arbitrary_mipmaps, bool skip_texture_dump);
|
||||
|
||||
RcTcacheEntry GetXFBFromCache(u32 address, u32 width, u32 height, u32 stride);
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ A full example is given below:
|
|||
"name": "normal_texture",
|
||||
"data":
|
||||
{
|
||||
"": "normal_texture.png"
|
||||
"texture": "normal_texture.png"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue