mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-18 06:10:35 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 64a4908ea6 |
@@ -1,54 +0,0 @@
|
|||||||
name: update-deps
|
|
||||||
|
|
||||||
on:
|
|
||||||
# saturday at noon
|
|
||||||
schedule:
|
|
||||||
- cron: '0 12 * * 6'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
tx-update:
|
|
||||||
runs-on: source
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Update deps
|
|
||||||
run: |
|
|
||||||
git config --local user.name "Eden CI"
|
|
||||||
git config --local user.email "ci@eden-emu.dev"
|
|
||||||
git config --local user.signingkey "D57652791BB25D2A"
|
|
||||||
git config --local push.autoSetupRemote true
|
|
||||||
|
|
||||||
git remote set-url origin ci:eden-emu/eden.git
|
|
||||||
|
|
||||||
DATE=$(date +"%b %d")
|
|
||||||
echo "DATE=$DATE" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
git switch -c update-deps-$DATE
|
|
||||||
tools/cpmutil.sh package update -ac
|
|
||||||
git push
|
|
||||||
|
|
||||||
- name: Create PR
|
|
||||||
run: |
|
|
||||||
TITLE="[externals] Dependency update for $DATE"
|
|
||||||
BODY="$(git show -s --format='%b')"
|
|
||||||
BASE=master
|
|
||||||
HEAD=update-deps-$DATE
|
|
||||||
|
|
||||||
cat << EOF > data.json
|
|
||||||
{
|
|
||||||
"base": "$BASE",
|
|
||||||
"body": "$BODY",
|
|
||||||
"head": "$HEAD",
|
|
||||||
"title": "$TITLE"
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
curl -X 'POST' \
|
|
||||||
'https://git.eden-emu.dev/api/v1/repos/eden-emu/eden/pulls' \
|
|
||||||
-H 'accept: application/json' \
|
|
||||||
-H 'Authorization: Bearer ${{ secrets.CI_FJ_TOKEN }}' \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d "@data.json" --fail
|
|
||||||
@@ -35,8 +35,7 @@
|
|||||||
namespace Service::News {
|
namespace Service::News {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// TODO(crueter): COMPILE DEFINITION
|
constexpr const char* GitHubAPI_EdenReleases = "/repos/eden-emulator/Releases/releases";
|
||||||
constexpr const char* GitHubAPI_EdenReleases = "/api/v1/repos/eden-emu/eden/releases";
|
|
||||||
|
|
||||||
// Cached logo data
|
// Cached logo data
|
||||||
std::vector<u8> default_logo_small;
|
std::vector<u8> default_logo_small;
|
||||||
@@ -228,58 +227,22 @@ void WriteCachedJson(std::string_view json) {
|
|||||||
|
|
||||||
std::optional<std::string> DownloadReleasesJson() {
|
std::optional<std::string> DownloadReleasesJson() {
|
||||||
try {
|
try {
|
||||||
#ifdef YUZU_BUNDLED_OPENSSL
|
httplib::SSLClient cli{"api.github.com", 443};
|
||||||
const auto url = "https://git.eden-emu.dev";
|
cli.set_connection_timeout(10);
|
||||||
#else
|
cli.set_read_timeout(10);
|
||||||
const auto url = "git.eden-emu.dev";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO(crueter): This is duplicated between frontend and here.
|
httplib::Headers headers{
|
||||||
constexpr auto path = GitHubAPI_EdenReleases;
|
{"User-Agent", "Eden"},
|
||||||
|
{"Accept", "application/vnd.github+json"},
|
||||||
constexpr std::size_t timeout_seconds = 15;
|
|
||||||
|
|
||||||
std::unique_ptr<httplib::Client> client = std::make_unique<httplib::Client>(url);
|
|
||||||
client->set_connection_timeout(timeout_seconds);
|
|
||||||
client->set_read_timeout(timeout_seconds);
|
|
||||||
client->set_write_timeout(timeout_seconds);
|
|
||||||
|
|
||||||
#ifdef YUZU_BUNDLED_OPENSSL
|
|
||||||
client->load_ca_cert_store(kCert, sizeof(kCert));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (client == nullptr) {
|
|
||||||
LOG_ERROR(Service_BCAT, "Invalid URL {}{}", url, path);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
httplib::Request request{
|
|
||||||
.method = "GET",
|
|
||||||
.path = path,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
client->set_follow_location(true);
|
// TODO(crueter): automate this in some way...
|
||||||
httplib::Result result = client->send(request);
|
#ifdef YUZU_BUNDLED_OPENSSL
|
||||||
|
cli.load_ca_cert_store(kCert, sizeof(kCert));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!result) {
|
if (auto res = cli.Get(GitHubAPI_EdenReleases, headers); res && res->status < 400) {
|
||||||
LOG_ERROR(Service_BCAT, "GET to {}{} returned null", url, path);
|
return res->body;
|
||||||
return {};
|
|
||||||
} else if (result->status < 400) {
|
|
||||||
return result->body;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result->status >= 400) {
|
|
||||||
LOG_ERROR(Service_BCAT,
|
|
||||||
"GET to {}{} returned error status code: {}",
|
|
||||||
url,
|
|
||||||
path,
|
|
||||||
result->status);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result->headers.contains("content-type")) {
|
|
||||||
LOG_ERROR(Service_BCAT, "GET to {}{} returned no content", url, path);
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
LOG_WARNING(Service_BCAT, " failed to download releases");
|
LOG_WARNING(Service_BCAT, " failed to download releases");
|
||||||
@@ -369,7 +332,7 @@ std::string FormatBody(const nlohmann::json& release, std::string_view title) {
|
|||||||
body.pop_back();
|
body.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
body += "\n\n... View more on Forgejo";
|
body += "\n\n... View more on GitHub";
|
||||||
}
|
}
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
@@ -526,7 +489,7 @@ std::vector<u8> BuildMsgpack(std::string_view title, std::string_view body,
|
|||||||
w.WriteString("");
|
w.WriteString("");
|
||||||
|
|
||||||
w.WriteKey("allow_domains");
|
w.WriteKey("allow_domains");
|
||||||
w.WriteString("^https?://git.eden-emu.dev(/|$)");
|
w.WriteString("^https?://github.com(/|$)");
|
||||||
|
|
||||||
// More link
|
// More link
|
||||||
w.WriteKey("more");
|
w.WriteKey("more");
|
||||||
@@ -536,7 +499,7 @@ std::vector<u8> BuildMsgpack(std::string_view title, std::string_view body,
|
|||||||
w.WriteKey("url");
|
w.WriteKey("url");
|
||||||
w.WriteString(html_url);
|
w.WriteString(html_url);
|
||||||
w.WriteKey("text");
|
w.WriteKey("text");
|
||||||
w.WriteString("Open Forgejo");
|
w.WriteString("Open GitHub");
|
||||||
|
|
||||||
// Body
|
// Body
|
||||||
w.WriteKey("body");
|
w.WriteKey("body");
|
||||||
@@ -573,7 +536,7 @@ void EnsureBuiltinNewsLoaded() {
|
|||||||
if (const auto fresh = DownloadReleasesJson()) {
|
if (const auto fresh = DownloadReleasesJson()) {
|
||||||
WriteCachedJson(*fresh);
|
WriteCachedJson(*fresh);
|
||||||
ImportReleases(*fresh);
|
ImportReleases(*fresh);
|
||||||
LOG_DEBUG(Service_BCAT, "news: {} entries updated from Forgejo", NewsStorage::Instance().ListAll().size());
|
LOG_DEBUG(Service_BCAT, "news: {} entries updated from GitHub", NewsStorage::Instance().ListAll().size());
|
||||||
}
|
}
|
||||||
}).detach();
|
}).detach();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -81,7 +81,9 @@ std::optional<std::string> UpdateChecker::GetResponse(std::string url, std::stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<UpdateChecker::Update> UpdateChecker::GetLatestRelease(bool include_prereleases) {
|
std::optional<UpdateChecker::Update> UpdateChecker::GetLatestRelease(bool include_prereleases) {
|
||||||
#ifdef YUZU_BUNDLED_OPENSSL
|
// For some unbeknownst reason, only Android likes when https is specified.
|
||||||
|
// Consider dropping support for this radioactive platform.
|
||||||
|
#ifdef __ANDROID__
|
||||||
const auto update_check_url = fmt::format("https://{}", Common::g_build_auto_update_api);
|
const auto update_check_url = fmt::format("https://{}", Common::g_build_auto_update_api);
|
||||||
#else
|
#else
|
||||||
const auto update_check_url = std::string{Common::g_build_auto_update_api};
|
const auto update_check_url = std::string{Common::g_build_auto_update_api};
|
||||||
|
|||||||
@@ -236,34 +236,10 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
|
|||||||
size_t streamer_id = static_cast<size_t>(counter_type);
|
size_t streamer_id = static_cast<size_t>(counter_type);
|
||||||
auto* streamer = impl->streamers[streamer_id];
|
auto* streamer = impl->streamers[streamer_id];
|
||||||
if (streamer == nullptr) [[unlikely]] {
|
if (streamer == nullptr) [[unlikely]] {
|
||||||
auto cpu_addr_opt = gpu_memory->GpuToCpuAddress(addr);
|
counter_type = QueryType::Payload;
|
||||||
if (!cpu_addr_opt) [[unlikely]] {
|
payload = 1U;
|
||||||
return;
|
streamer_id = static_cast<size_t>(counter_type);
|
||||||
}
|
streamer = impl->streamers[streamer_id];
|
||||||
const DAddr cpu_addr = *cpu_addr_opt;
|
|
||||||
u8* pointer = impl->device_memory.template GetPointer<u8>(cpu_addr);
|
|
||||||
u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8);
|
|
||||||
if (pointer == nullptr || (has_timestamp && pointer_timestamp == nullptr)) [[unlikely]] {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const u64 fallback_value = counter_type == QueryType::Payload ? static_cast<u64>(payload) : 0;
|
|
||||||
std::function<void()> operation([this, has_timestamp, fallback_value, pointer,
|
|
||||||
pointer_timestamp] {
|
|
||||||
if (has_timestamp) {
|
|
||||||
const u64 timestamp = impl->gpu.GetTicks();
|
|
||||||
std::memcpy(pointer_timestamp, ×tamp, sizeof(timestamp));
|
|
||||||
std::memcpy(pointer, &fallback_value, sizeof(fallback_value));
|
|
||||||
} else {
|
|
||||||
const u32 value = static_cast<u32>(fallback_value);
|
|
||||||
std::memcpy(pointer, &value, sizeof(value));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (is_fence) {
|
|
||||||
impl->rasterizer.SignalFence(std::move(operation));
|
|
||||||
} else {
|
|
||||||
impl->rasterizer.SyncOperation(std::move(operation));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
auto cpu_addr_opt = gpu_memory->GpuToCpuAddress(addr);
|
auto cpu_addr_opt = gpu_memory->GpuToCpuAddress(addr);
|
||||||
if (!cpu_addr_opt) [[unlikely]] {
|
if (!cpu_addr_opt) [[unlikely]] {
|
||||||
@@ -461,10 +437,8 @@ bool QueryCacheBase<Traits>::AccelerateHostConditionalRendering() {
|
|||||||
impl->runtime.EndHostConditionalRendering();
|
impl->runtime.EndHostConditionalRendering();
|
||||||
return false;
|
return false;
|
||||||
case ComparisonMode::Conditional: {
|
case ComparisonMode::Conditional: {
|
||||||
// Guest conditional mode expects both initial_sequence and initial_mode to be non-zero
|
VideoCommon::LookupData object_1{gen_lookup(address)};
|
||||||
// fall back to software eval
|
return impl->runtime.HostConditionalRenderingCompareValue(object_1, qc_dirty);
|
||||||
impl->runtime.EndHostConditionalRendering();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
case ComparisonMode::IfEqual: {
|
case ComparisonMode::IfEqual: {
|
||||||
VideoCommon::LookupData object_1{gen_lookup(address)};
|
VideoCommon::LookupData object_1{gen_lookup(address)};
|
||||||
|
|||||||
@@ -1457,13 +1457,11 @@ VideoCommon::StreamerInterface* QueryCacheRuntime::GetStreamerInterface(QueryTyp
|
|||||||
return &impl->sample_streamer;
|
return &impl->sample_streamer;
|
||||||
case QueryType::StreamingByteCount:
|
case QueryType::StreamingByteCount:
|
||||||
return &impl->tfb_streamer;
|
return &impl->tfb_streamer;
|
||||||
case QueryType::PrimitivesGenerated:
|
|
||||||
case QueryType::StreamingPrimitivesNeeded:
|
case QueryType::StreamingPrimitivesNeeded:
|
||||||
case QueryType::VtgPrimitivesOut:
|
case QueryType::VtgPrimitivesOut:
|
||||||
case QueryType::StreamingPrimitivesSucceeded:
|
case QueryType::StreamingPrimitivesSucceeded:
|
||||||
return &impl->primitives_succeeded_streamer;
|
return &impl->primitives_succeeded_streamer;
|
||||||
case QueryType::StreamingPrimitivesNeededMinusSucceeded:
|
case QueryType::StreamingPrimitivesNeededMinusSucceeded:
|
||||||
case QueryType::TotalStreamingPrimitivesNeededMinusSucceeded:
|
|
||||||
return &impl->primitives_needed_minus_succeeded_streamer;
|
return &impl->primitives_needed_minus_succeeded_streamer;
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@@ -607,6 +607,10 @@ void RasterizerVulkan::DispatchCompute() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerVulkan::ResetCounter(VideoCommon::QueryType type) {
|
void RasterizerVulkan::ResetCounter(VideoCommon::QueryType type) {
|
||||||
|
if (type != VideoCommon::QueryType::ZPassPixelCount64) {
|
||||||
|
LOG_DEBUG(Render_Vulkan, "Unimplemented counter reset={}", type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
query_cache.CounterReset(type);
|
query_cache.CounterReset(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -264,6 +264,12 @@ template <class P>
|
|||||||
typename P::ImageView& TextureCache<P>::GetImageView(u32 index) noexcept {
|
typename P::ImageView& TextureCache<P>::GetImageView(u32 index) noexcept {
|
||||||
const auto image_view_id = VisitImageView(channel_state->graphics_image_table,
|
const auto image_view_id = VisitImageView(channel_state->graphics_image_table,
|
||||||
channel_state->graphics_image_view_ids, index);
|
channel_state->graphics_image_view_ids, index);
|
||||||
|
if (image_view_id != NULL_IMAGE_VIEW_ID) {
|
||||||
|
const ImageViewBase& image_view = slot_image_views[image_view_id];
|
||||||
|
if (!image_view.IsBuffer()) {
|
||||||
|
PrepareImage(image_view.image_id, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
return slot_image_views[image_view_id];
|
return slot_image_views[image_view_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,20 +625,88 @@ template <bool has_blacklists>
|
|||||||
void TextureCache<P>::FillImageViews(DescriptorTable<TICEntry>& table,
|
void TextureCache<P>::FillImageViews(DescriptorTable<TICEntry>& table,
|
||||||
std::span<ImageViewId> cached_image_view_ids,
|
std::span<ImageViewId> cached_image_view_ids,
|
||||||
std::span<ImageViewInOut> views) {
|
std::span<ImageViewInOut> views) {
|
||||||
|
if (views.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool has_blacklisted = false;
|
bool has_blacklisted = false;
|
||||||
do {
|
do {
|
||||||
has_deleted_images = false;
|
has_deleted_images = false;
|
||||||
if constexpr (has_blacklists) {
|
if constexpr (has_blacklists) {
|
||||||
has_blacklisted = false;
|
has_blacklisted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// descriptors often reuse TIC indices in one bind pass
|
||||||
|
// use a tiny size cache to avoid expensive descriptor repeat reads
|
||||||
|
constexpr size_t RECENT_VIEW_CACHE_SIZE = 8;
|
||||||
|
std::array<std::pair<u32, ImageViewId>, RECENT_VIEW_CACHE_SIZE> recent_indices{};
|
||||||
|
std::array<bool, RECENT_VIEW_CACHE_SIZE> recent_valid{};
|
||||||
|
size_t recent_insert = 0;
|
||||||
|
boost::container::small_vector<ImageId, 16> prepared_image_ids;
|
||||||
|
[[maybe_unused]] boost::container::small_vector<ImageId, 16> blacklisted_image_ids;
|
||||||
|
|
||||||
for (ImageViewInOut& view : views) {
|
for (ImageViewInOut& view : views) {
|
||||||
view.id = VisitImageView(table, cached_image_view_ids, view.index);
|
bool found_cached = false;
|
||||||
|
for (size_t cache_index = 0; cache_index < RECENT_VIEW_CACHE_SIZE; ++cache_index) {
|
||||||
|
if (recent_valid[cache_index] &&
|
||||||
|
recent_indices[cache_index].first == view.index) {
|
||||||
|
view.id = recent_indices[cache_index].second;
|
||||||
|
found_cached = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found_cached) {
|
||||||
|
view.id = VisitImageView(table, cached_image_view_ids, view.index);
|
||||||
|
recent_indices[recent_insert] = {view.index, view.id};
|
||||||
|
recent_valid[recent_insert] = true;
|
||||||
|
recent_insert = (recent_insert + 1) % RECENT_VIEW_CACHE_SIZE;
|
||||||
|
}
|
||||||
|
if (has_deleted_images) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (view.id != NULL_IMAGE_VIEW_ID) {
|
||||||
|
const ImageViewBase& image_view{slot_image_views[view.id]};
|
||||||
|
if (!image_view.IsBuffer()) {
|
||||||
|
const ImageId image_id = image_view.image_id;
|
||||||
|
const bool already_queued =
|
||||||
|
std::ranges::find(prepared_image_ids, image_id) != prepared_image_ids.end();
|
||||||
|
if (!already_queued) {
|
||||||
|
prepared_image_ids.push_back(image_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if constexpr (has_blacklists) {
|
if constexpr (has_blacklists) {
|
||||||
if (view.blacklist && view.id != NULL_IMAGE_VIEW_ID) {
|
if (view.blacklist && view.id != NULL_IMAGE_VIEW_ID) {
|
||||||
const ImageViewBase& image_view{slot_image_views[view.id]};
|
const ImageViewBase& image_view{slot_image_views[view.id]};
|
||||||
auto& image = slot_images[image_view.image_id];
|
const ImageId image_id = image_view.image_id;
|
||||||
|
const bool already_queued =
|
||||||
|
std::ranges::find(blacklisted_image_ids, image_id) !=
|
||||||
|
blacklisted_image_ids.end();
|
||||||
|
if (!already_queued) {
|
||||||
|
blacklisted_image_ids.push_back(image_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_deleted_images) {
|
||||||
|
for (const ImageId image_id : prepared_image_ids) {
|
||||||
|
PrepareImage(image_id, false, false);
|
||||||
|
if (has_deleted_images) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (has_blacklists) {
|
||||||
|
if (!has_deleted_images) {
|
||||||
|
for (const ImageId image_id : blacklisted_image_ids) {
|
||||||
|
auto& image = slot_images[image_id];
|
||||||
has_blacklisted |= ScaleDown(image);
|
has_blacklisted |= ScaleDown(image);
|
||||||
image.scale_rating = 0;
|
image.scale_rating = 0;
|
||||||
|
if (has_deleted_images) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -652,9 +726,6 @@ ImageViewId TextureCache<P>::VisitImageView(DescriptorTable<TICEntry>& table,
|
|||||||
if (is_new) {
|
if (is_new) {
|
||||||
image_view_id = FindImageView(descriptor);
|
image_view_id = FindImageView(descriptor);
|
||||||
}
|
}
|
||||||
if (image_view_id != NULL_IMAGE_VIEW_ID) {
|
|
||||||
PrepareImageView(image_view_id, false, false);
|
|
||||||
}
|
|
||||||
return image_view_id;
|
return image_view_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user