mirror of
https://github.com/yuzu-emu/yuzu-mainline.git
synced 2025-09-09 12:07:11 +00:00
Compare commits
4 commits
master
...
mainline-0
Author | SHA1 | Date | |
---|---|---|---|
|
a2f0298f75 | ||
|
7fc0679e17 | ||
|
6f02a1e7d7 | ||
|
2feed5985f |
|
@ -5,7 +5,7 @@
|
||||||
#include "core/hle/service/caps/caps_a.h"
|
#include "core/hle/service/caps/caps_a.h"
|
||||||
#include "core/hle/service/caps/caps_manager.h"
|
#include "core/hle/service/caps/caps_manager.h"
|
||||||
#include "core/hle/service/caps/caps_result.h"
|
#include "core/hle/service/caps/caps_result.h"
|
||||||
#include "core/hle/service/caps/caps_types.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
|
@ -18,9 +18,9 @@ IAlbumAccessorService::IAlbumAccessorService(Core::System& system_,
|
||||||
{0, nullptr, "GetAlbumFileCount"},
|
{0, nullptr, "GetAlbumFileCount"},
|
||||||
{1, nullptr, "GetAlbumFileList"},
|
{1, nullptr, "GetAlbumFileList"},
|
||||||
{2, nullptr, "LoadAlbumFile"},
|
{2, nullptr, "LoadAlbumFile"},
|
||||||
{3, &IAlbumAccessorService::DeleteAlbumFile, "DeleteAlbumFile"},
|
{3, C<&IAlbumAccessorService::DeleteAlbumFile>, "DeleteAlbumFile"},
|
||||||
{4, nullptr, "StorageCopyAlbumFile"},
|
{4, nullptr, "StorageCopyAlbumFile"},
|
||||||
{5, &IAlbumAccessorService::IsAlbumMounted, "IsAlbumMounted"},
|
{5, C<&IAlbumAccessorService::IsAlbumMounted>, "IsAlbumMounted"},
|
||||||
{6, nullptr, "GetAlbumUsage"},
|
{6, nullptr, "GetAlbumUsage"},
|
||||||
{7, nullptr, "GetAlbumFileSize"},
|
{7, nullptr, "GetAlbumFileSize"},
|
||||||
{8, nullptr, "LoadAlbumFileThumbnail"},
|
{8, nullptr, "LoadAlbumFileThumbnail"},
|
||||||
|
@ -33,18 +33,18 @@ IAlbumAccessorService::IAlbumAccessorService(Core::System& system_,
|
||||||
{15, nullptr, "GetAlbumUsage3"},
|
{15, nullptr, "GetAlbumUsage3"},
|
||||||
{16, nullptr, "GetAlbumMountResult"},
|
{16, nullptr, "GetAlbumMountResult"},
|
||||||
{17, nullptr, "GetAlbumUsage16"},
|
{17, nullptr, "GetAlbumUsage16"},
|
||||||
{18, &IAlbumAccessorService::Unknown18, "Unknown18"},
|
{18, C<&IAlbumAccessorService::Unknown18>, "Unknown18"},
|
||||||
{19, nullptr, "Unknown19"},
|
{19, nullptr, "Unknown19"},
|
||||||
{100, nullptr, "GetAlbumFileCountEx0"},
|
{100, nullptr, "GetAlbumFileCountEx0"},
|
||||||
{101, &IAlbumAccessorService::GetAlbumFileListEx0, "GetAlbumFileListEx0"},
|
{101, C<&IAlbumAccessorService::GetAlbumFileListEx0>, "GetAlbumFileListEx0"},
|
||||||
{202, nullptr, "SaveEditedScreenShot"},
|
{202, nullptr, "SaveEditedScreenShot"},
|
||||||
{301, nullptr, "GetLastThumbnail"},
|
{301, nullptr, "GetLastThumbnail"},
|
||||||
{302, nullptr, "GetLastOverlayMovieThumbnail"},
|
{302, nullptr, "GetLastOverlayMovieThumbnail"},
|
||||||
{401, &IAlbumAccessorService::GetAutoSavingStorage, "GetAutoSavingStorage"},
|
{401, C<&IAlbumAccessorService::GetAutoSavingStorage>, "GetAutoSavingStorage"},
|
||||||
{501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"},
|
{501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"},
|
||||||
{1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"},
|
{1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"},
|
||||||
{1002, &IAlbumAccessorService::LoadAlbumScreenShotImageEx1, "LoadAlbumScreenShotImageEx1"},
|
{1002, C<&IAlbumAccessorService::LoadAlbumScreenShotImageEx1>, "LoadAlbumScreenShotImageEx1"},
|
||||||
{1003, &IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1, "LoadAlbumScreenShotThumbnailImageEx1"},
|
{1003, C<&IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1>, "LoadAlbumScreenShotThumbnailImageEx1"},
|
||||||
{8001, nullptr, "ForceAlbumUnmounted"},
|
{8001, nullptr, "ForceAlbumUnmounted"},
|
||||||
{8002, nullptr, "ResetAlbumMountStatus"},
|
{8002, nullptr, "ResetAlbumMountStatus"},
|
||||||
{8011, nullptr, "RefreshAlbumCache"},
|
{8011, nullptr, "RefreshAlbumCache"},
|
||||||
|
@ -62,138 +62,70 @@ IAlbumAccessorService::IAlbumAccessorService(Core::System& system_,
|
||||||
|
|
||||||
IAlbumAccessorService::~IAlbumAccessorService() = default;
|
IAlbumAccessorService::~IAlbumAccessorService() = default;
|
||||||
|
|
||||||
void IAlbumAccessorService::DeleteAlbumFile(HLERequestContext& ctx) {
|
Result IAlbumAccessorService::DeleteAlbumFile(AlbumFileId file_id) {
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto file_id{rp.PopRaw<AlbumFileId>()};
|
|
||||||
|
|
||||||
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}",
|
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}",
|
||||||
file_id.application_id, file_id.storage, file_id.type);
|
file_id.application_id, file_id.storage, file_id.type);
|
||||||
|
|
||||||
Result result = manager->DeleteAlbumFile(file_id);
|
const Result result = manager->DeleteAlbumFile(file_id);
|
||||||
result = TranslateResult(result);
|
R_RETURN(TranslateResult(result));
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAlbumAccessorService::IsAlbumMounted(HLERequestContext& ctx) {
|
Result IAlbumAccessorService::IsAlbumMounted(Out<bool> out_is_mounted, AlbumStorage storage) {
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto storage{rp.PopEnum<AlbumStorage>()};
|
|
||||||
|
|
||||||
LOG_INFO(Service_Capture, "called, storage={}", storage);
|
LOG_INFO(Service_Capture, "called, storage={}", storage);
|
||||||
|
|
||||||
Result result = manager->IsAlbumMounted(storage);
|
const Result result = manager->IsAlbumMounted(storage);
|
||||||
const bool is_mounted = result.IsSuccess();
|
*out_is_mounted = result.IsSuccess();
|
||||||
result = TranslateResult(result);
|
R_RETURN(TranslateResult(result));
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(result);
|
|
||||||
rb.Push<u8>(is_mounted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAlbumAccessorService::Unknown18(HLERequestContext& ctx) {
|
Result IAlbumAccessorService::Unknown18(
|
||||||
struct UnknownBuffer {
|
Out<u32> out_buffer_size,
|
||||||
INSERT_PADDING_BYTES(0x10);
|
OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_buffer) {
|
||||||
};
|
|
||||||
static_assert(sizeof(UnknownBuffer) == 0x10, "UnknownBuffer is an invalid size");
|
|
||||||
|
|
||||||
LOG_WARNING(Service_Capture, "(STUBBED) called");
|
LOG_WARNING(Service_Capture, "(STUBBED) called");
|
||||||
|
*out_buffer_size = 0;
|
||||||
std::vector<UnknownBuffer> buffer{};
|
R_SUCCEED();
|
||||||
|
|
||||||
if (!buffer.empty()) {
|
|
||||||
ctx.WriteBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push(static_cast<u32>(buffer.size()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAlbumAccessorService::GetAlbumFileListEx0(HLERequestContext& ctx) {
|
Result IAlbumAccessorService::GetAlbumFileListEx0(
|
||||||
IPC::RequestParser rp{ctx};
|
Out<u64> out_entries_size, AlbumStorage storage, u8 flags,
|
||||||
const auto storage{rp.PopEnum<AlbumStorage>()};
|
OutArray<AlbumEntry, BufferAttr_HipcMapAlias> out_entries) {
|
||||||
const auto flags{rp.Pop<u8>()};
|
|
||||||
const auto album_entry_size{ctx.GetWriteBufferNumElements<AlbumEntry>()};
|
|
||||||
|
|
||||||
LOG_INFO(Service_Capture, "called, storage={}, flags={}", storage, flags);
|
LOG_INFO(Service_Capture, "called, storage={}, flags={}", storage, flags);
|
||||||
|
|
||||||
std::vector<AlbumEntry> entries;
|
const Result result = manager->GetAlbumFileList(out_entries, *out_entries_size, storage, flags);
|
||||||
Result result = manager->GetAlbumFileList(entries, storage, flags);
|
R_RETURN(TranslateResult(result));
|
||||||
result = TranslateResult(result);
|
|
||||||
|
|
||||||
entries.resize(std::min(album_entry_size, entries.size()));
|
|
||||||
|
|
||||||
if (!entries.empty()) {
|
|
||||||
ctx.WriteBuffer(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
|
||||||
rb.Push(result);
|
|
||||||
rb.Push<u64>(entries.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAlbumAccessorService::GetAutoSavingStorage(HLERequestContext& ctx) {
|
Result IAlbumAccessorService::GetAutoSavingStorage(Out<bool> out_is_autosaving) {
|
||||||
LOG_WARNING(Service_Capture, "(STUBBED) called");
|
LOG_WARNING(Service_Capture, "(STUBBED) called");
|
||||||
|
|
||||||
bool is_autosaving{};
|
const Result result = manager->GetAutoSavingStorage(*out_is_autosaving);
|
||||||
Result result = manager->GetAutoSavingStorage(is_autosaving);
|
R_RETURN(TranslateResult(result));
|
||||||
result = TranslateResult(result);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(result);
|
|
||||||
rb.Push<u8>(is_autosaving);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAlbumAccessorService::LoadAlbumScreenShotImageEx1(HLERequestContext& ctx) {
|
Result IAlbumAccessorService::LoadAlbumScreenShotImageEx1(
|
||||||
IPC::RequestParser rp{ctx};
|
const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options,
|
||||||
const auto file_id{rp.PopRaw<AlbumFileId>()};
|
OutLargeData<LoadAlbumScreenShotImageOutput, BufferAttr_HipcMapAlias> out_image_output,
|
||||||
const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
|
OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_image,
|
||||||
const auto image_buffer_size{ctx.GetWriteBufferSize(1)};
|
OutArray<u8, BufferAttr_HipcMapAlias> out_buffer) {
|
||||||
|
|
||||||
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
|
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
|
||||||
file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
|
file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
|
||||||
|
|
||||||
std::vector<u8> image;
|
const Result result =
|
||||||
LoadAlbumScreenShotImageOutput image_output;
|
manager->LoadAlbumScreenShotImage(*out_image_output, out_image, file_id, decoder_options);
|
||||||
Result result =
|
R_RETURN(TranslateResult(result));
|
||||||
manager->LoadAlbumScreenShotImage(image_output, image, file_id, decoder_options);
|
|
||||||
result = TranslateResult(result);
|
|
||||||
|
|
||||||
if (image.size() > image_buffer_size) {
|
|
||||||
result = ResultWorkMemoryError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
ctx.WriteBuffer(image_output, 0);
|
|
||||||
ctx.WriteBuffer(image, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx) {
|
Result IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1(
|
||||||
IPC::RequestParser rp{ctx};
|
const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options,
|
||||||
const auto file_id{rp.PopRaw<AlbumFileId>()};
|
OutLargeData<LoadAlbumScreenShotImageOutput, BufferAttr_HipcMapAlias> out_image_output,
|
||||||
const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
|
OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_image,
|
||||||
|
OutArray<u8, BufferAttr_HipcMapAlias> out_buffer) {
|
||||||
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
|
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
|
||||||
file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
|
file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
|
||||||
|
|
||||||
std::vector<u8> image(ctx.GetWriteBufferSize(1));
|
const Result result = manager->LoadAlbumScreenShotThumbnail(*out_image_output, out_image,
|
||||||
LoadAlbumScreenShotImageOutput image_output;
|
file_id, decoder_options);
|
||||||
Result result =
|
R_RETURN(TranslateResult(result));
|
||||||
manager->LoadAlbumScreenShotThumbnail(image_output, image, file_id, decoder_options);
|
|
||||||
result = TranslateResult(result);
|
|
||||||
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
ctx.WriteBuffer(image_output, 0);
|
|
||||||
ctx.WriteBuffer(image, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAlbumAccessorService::TranslateResult(Result in_result) {
|
Result IAlbumAccessorService::TranslateResult(Result in_result) {
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -19,13 +21,31 @@ public:
|
||||||
~IAlbumAccessorService() override;
|
~IAlbumAccessorService() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DeleteAlbumFile(HLERequestContext& ctx);
|
Result DeleteAlbumFile(AlbumFileId file_id);
|
||||||
void IsAlbumMounted(HLERequestContext& ctx);
|
|
||||||
void Unknown18(HLERequestContext& ctx);
|
Result IsAlbumMounted(Out<bool> out_is_mounted, AlbumStorage storage);
|
||||||
void GetAlbumFileListEx0(HLERequestContext& ctx);
|
|
||||||
void GetAutoSavingStorage(HLERequestContext& ctx);
|
Result Unknown18(
|
||||||
void LoadAlbumScreenShotImageEx1(HLERequestContext& ctx);
|
Out<u32> out_buffer_size,
|
||||||
void LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx);
|
OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure>
|
||||||
|
out_buffer);
|
||||||
|
|
||||||
|
Result GetAlbumFileListEx0(Out<u64> out_entries_size, AlbumStorage storage, u8 flags,
|
||||||
|
OutArray<AlbumEntry, BufferAttr_HipcMapAlias> out_entries);
|
||||||
|
|
||||||
|
Result GetAutoSavingStorage(Out<bool> out_is_autosaving);
|
||||||
|
|
||||||
|
Result LoadAlbumScreenShotImageEx1(
|
||||||
|
const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options,
|
||||||
|
OutLargeData<LoadAlbumScreenShotImageOutput, BufferAttr_HipcMapAlias> out_image_output,
|
||||||
|
OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_image,
|
||||||
|
OutArray<u8, BufferAttr_HipcMapAlias> out_buffer);
|
||||||
|
|
||||||
|
Result LoadAlbumScreenShotThumbnailImageEx1(
|
||||||
|
const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options,
|
||||||
|
OutLargeData<LoadAlbumScreenShotImageOutput, BufferAttr_HipcMapAlias> out_image_output,
|
||||||
|
OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_image,
|
||||||
|
OutArray<u8, BufferAttr_HipcMapAlias> out_buffer);
|
||||||
|
|
||||||
Result TranslateResult(Result in_result);
|
Result TranslateResult(Result in_result);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "core/hle/service/caps/caps_manager.h"
|
#include "core/hle/service/caps/caps_manager.h"
|
||||||
#include "core/hle/service/caps/caps_result.h"
|
#include "core/hle/service/caps/caps_result.h"
|
||||||
#include "core/hle/service/caps/caps_types.h"
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
|
@ -17,7 +18,7 @@ IAlbumControlService::IAlbumControlService(Core::System& system_,
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{1, nullptr, "CaptureRawImage"},
|
{1, nullptr, "CaptureRawImage"},
|
||||||
{2, nullptr, "CaptureRawImageWithTimeout"},
|
{2, nullptr, "CaptureRawImageWithTimeout"},
|
||||||
{33, &IAlbumControlService::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
{33, C<&IAlbumControlService::SetShimLibraryVersion>, "SetShimLibraryVersion"},
|
||||||
{1001, nullptr, "RequestTakingScreenShot"},
|
{1001, nullptr, "RequestTakingScreenShot"},
|
||||||
{1002, nullptr, "RequestTakingScreenShotWithTimeout"},
|
{1002, nullptr, "RequestTakingScreenShotWithTimeout"},
|
||||||
{1011, nullptr, "NotifyTakingScreenShotRefused"},
|
{1011, nullptr, "NotifyTakingScreenShotRefused"},
|
||||||
|
@ -42,16 +43,11 @@ IAlbumControlService::IAlbumControlService(Core::System& system_,
|
||||||
|
|
||||||
IAlbumControlService::~IAlbumControlService() = default;
|
IAlbumControlService::~IAlbumControlService() = default;
|
||||||
|
|
||||||
void IAlbumControlService::SetShimLibraryVersion(HLERequestContext& ctx) {
|
Result IAlbumControlService::SetShimLibraryVersion(ShimLibraryVersion library_version,
|
||||||
IPC::RequestParser rp{ctx};
|
ClientAppletResourceUserId aruid) {
|
||||||
const auto library_version{rp.Pop<u64>()};
|
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
|
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
|
||||||
library_version, applet_resource_user_id);
|
library_version, aruid.pid);
|
||||||
|
R_SUCCEED();
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Capture
|
} // namespace Service::Capture
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -11,6 +12,7 @@ class System;
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
class AlbumManager;
|
class AlbumManager;
|
||||||
|
enum class ShimLibraryVersion : u64;
|
||||||
|
|
||||||
class IAlbumControlService final : public ServiceFramework<IAlbumControlService> {
|
class IAlbumControlService final : public ServiceFramework<IAlbumControlService> {
|
||||||
public:
|
public:
|
||||||
|
@ -19,7 +21,8 @@ public:
|
||||||
~IAlbumControlService() override;
|
~IAlbumControlService() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetShimLibraryVersion(HLERequestContext& ctx);
|
Result SetShimLibraryVersion(ShimLibraryVersion library_version,
|
||||||
|
ClientAppletResourceUserId aruid);
|
||||||
|
|
||||||
std::shared_ptr<AlbumManager> manager = nullptr;
|
std::shared_ptr<AlbumManager> manager = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -58,8 +58,8 @@ Result AlbumManager::IsAlbumMounted(AlbumStorage storage) {
|
||||||
return is_mounted ? ResultSuccess : ResultIsNotMounted;
|
return is_mounted ? ResultSuccess : ResultIsNotMounted;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
|
Result AlbumManager::GetAlbumFileList(std::span<AlbumEntry> out_entries, u64& out_entries_count,
|
||||||
u8 flags) const {
|
AlbumStorage storage, u8 flags) const {
|
||||||
if (storage > AlbumStorage::Sd) {
|
if (storage > AlbumStorage::Sd) {
|
||||||
return ResultInvalidStorage;
|
return ResultInvalidStorage;
|
||||||
}
|
}
|
||||||
|
@ -72,51 +72,55 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu
|
||||||
if (file_id.storage != storage) {
|
if (file_id.storage != storage) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (out_entries.size() >= SdAlbumFileLimit) {
|
if (out_entries_count >= SdAlbumFileLimit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (out_entries_count >= out_entries.size()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto entry_size = Common::FS::GetSize(path);
|
const auto entry_size = Common::FS::GetSize(path);
|
||||||
out_entries.push_back({
|
out_entries[out_entries_count++] = {
|
||||||
.entry_size = entry_size,
|
.entry_size = entry_size,
|
||||||
.file_id = file_id,
|
.file_id = file_id,
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
|
Result AlbumManager::GetAlbumFileList(std::span<ApplicationAlbumFileEntry> out_entries,
|
||||||
ContentType content_type, s64 start_posix_time,
|
u64& out_entries_count, ContentType content_type,
|
||||||
s64 end_posix_time, u64 aruid) const {
|
s64 start_posix_time, s64 end_posix_time, u64 aruid) const {
|
||||||
if (!is_mounted) {
|
if (!is_mounted) {
|
||||||
return ResultIsNotMounted;
|
return ResultIsNotMounted;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ApplicationAlbumEntry> album_entries;
|
std::vector<ApplicationAlbumEntry> album_entries(out_entries.size());
|
||||||
const auto start_date = ConvertToAlbumDateTime(start_posix_time);
|
const auto start_date = ConvertToAlbumDateTime(start_posix_time);
|
||||||
const auto end_date = ConvertToAlbumDateTime(end_posix_time);
|
const auto end_date = ConvertToAlbumDateTime(end_posix_time);
|
||||||
const auto result = GetAlbumFileList(album_entries, content_type, start_date, end_date, aruid);
|
const auto result = GetAlbumFileList(album_entries, out_entries_count, content_type, start_date,
|
||||||
|
end_date, aruid);
|
||||||
|
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& album_entry : album_entries) {
|
for (std::size_t i = 0; i < out_entries_count; i++) {
|
||||||
ApplicationAlbumFileEntry entry{
|
out_entries[i] = {
|
||||||
.entry = album_entry,
|
.entry = album_entries[i],
|
||||||
.datetime = album_entry.datetime,
|
.datetime = album_entries[i].datetime,
|
||||||
.unknown = {},
|
.unknown = {},
|
||||||
};
|
};
|
||||||
out_entries.push_back(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
|
Result AlbumManager::GetAlbumFileList(std::span<ApplicationAlbumEntry> out_entries,
|
||||||
ContentType content_type, AlbumFileDateTime start_date,
|
u64& out_entries_count, ContentType content_type,
|
||||||
AlbumFileDateTime end_date, u64 aruid) const {
|
AlbumFileDateTime start_date, AlbumFileDateTime end_date,
|
||||||
|
u64 aruid) const {
|
||||||
if (!is_mounted) {
|
if (!is_mounted) {
|
||||||
return ResultIsNotMounted;
|
return ResultIsNotMounted;
|
||||||
}
|
}
|
||||||
|
@ -131,12 +135,15 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_en
|
||||||
if (file_id.date < end_date) {
|
if (file_id.date < end_date) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (out_entries.size() >= SdAlbumFileLimit) {
|
if (out_entries_count >= SdAlbumFileLimit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (out_entries_count >= out_entries.size()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto entry_size = Common::FS::GetSize(path);
|
const auto entry_size = Common::FS::GetSize(path);
|
||||||
ApplicationAlbumEntry entry{
|
out_entries[out_entries_count++] = {
|
||||||
.size = entry_size,
|
.size = entry_size,
|
||||||
.hash{},
|
.hash{},
|
||||||
.datetime = file_id.date,
|
.datetime = file_id.date,
|
||||||
|
@ -144,7 +151,6 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_en
|
||||||
.content = content_type,
|
.content = content_type,
|
||||||
.unknown = 1,
|
.unknown = 1,
|
||||||
};
|
};
|
||||||
out_entries.push_back(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
|
@ -156,8 +162,7 @@ Result AlbumManager::GetAutoSavingStorage(bool& out_is_autosaving) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
|
Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
|
||||||
std::vector<u8>& out_image,
|
std::span<u8> out_image, const AlbumFileId& file_id,
|
||||||
const AlbumFileId& file_id,
|
|
||||||
const ScreenShotDecodeOption& decoder_options) const {
|
const ScreenShotDecodeOption& decoder_options) const {
|
||||||
if (file_id.storage > AlbumStorage::Sd) {
|
if (file_id.storage > AlbumStorage::Sd) {
|
||||||
return ResultInvalidStorage;
|
return ResultInvalidStorage;
|
||||||
|
@ -176,7 +181,9 @@ Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& ou
|
||||||
.orientation = AlbumImageOrientation::None,
|
.orientation = AlbumImageOrientation::None,
|
||||||
.unknown_1{},
|
.unknown_1{},
|
||||||
.unknown_2{},
|
.unknown_2{},
|
||||||
|
.pad163{},
|
||||||
},
|
},
|
||||||
|
.pad179{},
|
||||||
};
|
};
|
||||||
|
|
||||||
std::filesystem::path path;
|
std::filesystem::path path;
|
||||||
|
@ -186,14 +193,12 @@ Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& ou
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha);
|
|
||||||
|
|
||||||
return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
|
return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
|
||||||
+static_cast<int>(out_image_output.height), decoder_options.flags);
|
+static_cast<int>(out_image_output.height), decoder_options.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AlbumManager::LoadAlbumScreenShotThumbnail(
|
Result AlbumManager::LoadAlbumScreenShotThumbnail(
|
||||||
LoadAlbumScreenShotImageOutput& out_image_output, std::vector<u8>& out_image,
|
LoadAlbumScreenShotImageOutput& out_image_output, std::span<u8> out_image,
|
||||||
const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const {
|
const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const {
|
||||||
if (file_id.storage > AlbumStorage::Sd) {
|
if (file_id.storage > AlbumStorage::Sd) {
|
||||||
return ResultInvalidStorage;
|
return ResultInvalidStorage;
|
||||||
|
@ -212,7 +217,9 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail(
|
||||||
.orientation = AlbumImageOrientation::None,
|
.orientation = AlbumImageOrientation::None,
|
||||||
.unknown_1{},
|
.unknown_1{},
|
||||||
.unknown_2{},
|
.unknown_2{},
|
||||||
|
.pad163{},
|
||||||
},
|
},
|
||||||
|
.pad179{},
|
||||||
};
|
};
|
||||||
|
|
||||||
std::filesystem::path path;
|
std::filesystem::path path;
|
||||||
|
@ -222,8 +229,6 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha);
|
|
||||||
|
|
||||||
return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
|
return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
|
||||||
+static_cast<int>(out_image_output.height), decoder_options.flags);
|
+static_cast<int>(out_image_output.height), decoder_options.flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,20 +42,20 @@ public:
|
||||||
|
|
||||||
Result DeleteAlbumFile(const AlbumFileId& file_id);
|
Result DeleteAlbumFile(const AlbumFileId& file_id);
|
||||||
Result IsAlbumMounted(AlbumStorage storage);
|
Result IsAlbumMounted(AlbumStorage storage);
|
||||||
Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
|
Result GetAlbumFileList(std::span<AlbumEntry> out_entries, u64& out_entries_count,
|
||||||
u8 flags) const;
|
AlbumStorage storage, u8 flags) const;
|
||||||
Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
|
Result GetAlbumFileList(std::span<ApplicationAlbumFileEntry> out_entries,
|
||||||
ContentType content_type, s64 start_posix_time, s64 end_posix_time,
|
u64& out_entries_count, ContentType content_type, s64 start_posix_time,
|
||||||
u64 aruid) const;
|
s64 end_posix_time, u64 aruid) const;
|
||||||
Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
|
Result GetAlbumFileList(std::span<ApplicationAlbumEntry> out_entries, u64& out_entries_count,
|
||||||
ContentType content_type, AlbumFileDateTime start_date,
|
ContentType content_type, AlbumFileDateTime start_date,
|
||||||
AlbumFileDateTime end_date, u64 aruid) const;
|
AlbumFileDateTime end_date, u64 aruid) const;
|
||||||
Result GetAutoSavingStorage(bool& out_is_autosaving) const;
|
Result GetAutoSavingStorage(bool& out_is_autosaving) const;
|
||||||
Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
|
Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
|
||||||
std::vector<u8>& out_image, const AlbumFileId& file_id,
|
std::span<u8> out_image, const AlbumFileId& file_id,
|
||||||
const ScreenShotDecodeOption& decoder_options) const;
|
const ScreenShotDecodeOption& decoder_options) const;
|
||||||
Result LoadAlbumScreenShotThumbnail(LoadAlbumScreenShotImageOutput& out_image_output,
|
Result LoadAlbumScreenShotThumbnail(LoadAlbumScreenShotImageOutput& out_image_output,
|
||||||
std::vector<u8>& out_image, const AlbumFileId& file_id,
|
std::span<u8> out_image, const AlbumFileId& file_id,
|
||||||
const ScreenShotDecodeOption& decoder_options) const;
|
const ScreenShotDecodeOption& decoder_options) const;
|
||||||
|
|
||||||
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
|
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/hle/service/caps/caps_manager.h"
|
#include "core/hle/service/caps/caps_manager.h"
|
||||||
#include "core/hle/service/caps/caps_types.h"
|
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
|
||||||
|
|
||||||
#include "core/hle/service/caps/caps_ss.h"
|
#include "core/hle/service/caps/caps_ss.h"
|
||||||
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
|
|
||||||
|
@ -17,9 +16,9 @@ IScreenShotService::IScreenShotService(Core::System& system_,
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{201, nullptr, "SaveScreenShot"},
|
{201, nullptr, "SaveScreenShot"},
|
||||||
{202, nullptr, "SaveEditedScreenShot"},
|
{202, nullptr, "SaveEditedScreenShot"},
|
||||||
{203, &IScreenShotService::SaveScreenShotEx0, "SaveScreenShotEx0"},
|
{203, C<&IScreenShotService::SaveScreenShotEx0>, "SaveScreenShotEx0"},
|
||||||
{204, nullptr, "SaveEditedScreenShotEx0"},
|
{204, nullptr, "SaveEditedScreenShotEx0"},
|
||||||
{206, &IScreenShotService::SaveEditedScreenShotEx1, "SaveEditedScreenShotEx1"},
|
{206, C<&IScreenShotService::SaveEditedScreenShotEx1>, "SaveEditedScreenShotEx1"},
|
||||||
{208, nullptr, "SaveScreenShotOfMovieEx1"},
|
{208, nullptr, "SaveScreenShotOfMovieEx1"},
|
||||||
{1000, nullptr, "Unknown1000"},
|
{1000, nullptr, "Unknown1000"},
|
||||||
};
|
};
|
||||||
|
@ -30,69 +29,38 @@ IScreenShotService::IScreenShotService(Core::System& system_,
|
||||||
|
|
||||||
IScreenShotService::~IScreenShotService() = default;
|
IScreenShotService::~IScreenShotService() = default;
|
||||||
|
|
||||||
void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) {
|
Result IScreenShotService::SaveScreenShotEx0(
|
||||||
IPC::RequestParser rp{ctx};
|
Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute,
|
||||||
struct Parameters {
|
AlbumReportOption report_option, ClientAppletResourceUserId aruid,
|
||||||
ScreenShotAttribute attribute{};
|
InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias>
|
||||||
AlbumReportOption report_option{};
|
image_data_buffer) {
|
||||||
INSERT_PADDING_BYTES(0x4);
|
|
||||||
u64 applet_resource_user_id{};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
const auto image_data_buffer = ctx.ReadBuffer();
|
|
||||||
|
|
||||||
LOG_INFO(Service_Capture,
|
LOG_INFO(Service_Capture,
|
||||||
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
||||||
parameters.report_option, image_data_buffer.size(),
|
report_option, image_data_buffer.size(), aruid.pid);
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
ApplicationAlbumEntry entry{};
|
|
||||||
manager->FlipVerticallyOnWrite(false);
|
manager->FlipVerticallyOnWrite(false);
|
||||||
const auto result =
|
R_RETURN(manager->SaveScreenShot(*out_entry, attribute, report_option, image_data_buffer,
|
||||||
manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option,
|
aruid.pid));
|
||||||
image_data_buffer, parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 10};
|
|
||||||
rb.Push(result);
|
|
||||||
rb.PushRaw(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) {
|
Result IScreenShotService::SaveEditedScreenShotEx1(
|
||||||
IPC::RequestParser rp{ctx};
|
Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute, u64 width,
|
||||||
struct Parameters {
|
u64 height, u64 thumbnail_width, u64 thumbnail_height, const AlbumFileId& file_id,
|
||||||
ScreenShotAttribute attribute;
|
const InLargeData<std::array<u8, 0x400>, BufferAttr_HipcMapAlias> application_data_buffer,
|
||||||
u64 width;
|
const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias>
|
||||||
u64 height;
|
image_data_buffer,
|
||||||
u64 thumbnail_width;
|
const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias>
|
||||||
u64 thumbnail_height;
|
thumbnail_image_data_buffer) {
|
||||||
AlbumFileId file_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x78, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
const auto application_data_buffer = ctx.ReadBuffer(0);
|
|
||||||
const auto image_data_buffer = ctx.ReadBuffer(1);
|
|
||||||
const auto thumbnail_image_data_buffer = ctx.ReadBuffer(2);
|
|
||||||
|
|
||||||
LOG_INFO(Service_Capture,
|
LOG_INFO(Service_Capture,
|
||||||
"called, width={}, height={}, thumbnail_width={}, thumbnail_height={}, "
|
"called, width={}, height={}, thumbnail_width={}, thumbnail_height={}, "
|
||||||
"application_id={:016x}, storage={}, type={}, app_data_buffer_size={}, "
|
"application_id={:016x}, storage={}, type={}, "
|
||||||
"image_data_buffer_size={}, thumbnail_image_buffer_size={}",
|
"image_data_buffer_size={}, thumbnail_image_buffer_size={}",
|
||||||
parameters.width, parameters.height, parameters.thumbnail_width,
|
width, height, thumbnail_width, thumbnail_height, file_id.application_id,
|
||||||
parameters.thumbnail_height, parameters.file_id.application_id,
|
file_id.storage, file_id.type, image_data_buffer.size(),
|
||||||
parameters.file_id.storage, parameters.file_id.type, application_data_buffer.size(),
|
thumbnail_image_data_buffer.size());
|
||||||
image_data_buffer.size(), thumbnail_image_data_buffer.size());
|
|
||||||
|
|
||||||
ApplicationAlbumEntry entry{};
|
|
||||||
manager->FlipVerticallyOnWrite(false);
|
manager->FlipVerticallyOnWrite(false);
|
||||||
const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute,
|
R_RETURN(manager->SaveEditedScreenShot(*out_entry, attribute, file_id, image_data_buffer));
|
||||||
parameters.file_id, image_data_buffer);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 10};
|
|
||||||
rb.Push(result);
|
|
||||||
rb.PushRaw(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Capture
|
} // namespace Service::Capture
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -17,8 +19,20 @@ public:
|
||||||
~IScreenShotService() override;
|
~IScreenShotService() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SaveScreenShotEx0(HLERequestContext& ctx);
|
Result SaveScreenShotEx0(
|
||||||
void SaveEditedScreenShotEx1(HLERequestContext& ctx);
|
Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute,
|
||||||
|
AlbumReportOption report_option, ClientAppletResourceUserId aruid,
|
||||||
|
InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias>
|
||||||
|
image_data_buffer);
|
||||||
|
|
||||||
|
Result SaveEditedScreenShotEx1(
|
||||||
|
Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute, u64 width,
|
||||||
|
u64 height, u64 thumbnail_width, u64 thumbnail_height, const AlbumFileId& file_id,
|
||||||
|
const InLargeData<std::array<u8, 0x400>, BufferAttr_HipcMapAlias> application_data_buffer,
|
||||||
|
const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias>
|
||||||
|
image_data_buffer,
|
||||||
|
const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias>
|
||||||
|
thumbnail_image_data_buffer);
|
||||||
|
|
||||||
std::shared_ptr<AlbumManager> manager;
|
std::shared_ptr<AlbumManager> manager;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "core/hle/service/caps/caps_manager.h"
|
#include "core/hle/service/caps/caps_manager.h"
|
||||||
#include "core/hle/service/caps/caps_su.h"
|
#include "core/hle/service/caps/caps_su.h"
|
||||||
#include "core/hle/service/caps/caps_types.h"
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
|
|
||||||
|
@ -16,10 +17,10 @@ IScreenShotApplicationService::IScreenShotApplicationService(
|
||||||
: ServiceFramework{system_, "caps:su"}, manager{album_manager} {
|
: ServiceFramework{system_, "caps:su"}, manager{album_manager} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
{32, C<&IScreenShotApplicationService::SetShimLibraryVersion>, "SetShimLibraryVersion"},
|
||||||
{201, nullptr, "SaveScreenShot"},
|
{201, nullptr, "SaveScreenShot"},
|
||||||
{203, &IScreenShotApplicationService::SaveScreenShotEx0, "SaveScreenShotEx0"},
|
{203, C<&IScreenShotApplicationService::SaveScreenShotEx0>, "SaveScreenShotEx0"},
|
||||||
{205, &IScreenShotApplicationService::SaveScreenShotEx1, "SaveScreenShotEx1"},
|
{205, C<&IScreenShotApplicationService::SaveScreenShotEx1>, "SaveScreenShotEx1"},
|
||||||
{210, nullptr, "SaveScreenShotEx2"},
|
{210, nullptr, "SaveScreenShotEx2"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -29,77 +30,40 @@ IScreenShotApplicationService::IScreenShotApplicationService(
|
||||||
|
|
||||||
IScreenShotApplicationService::~IScreenShotApplicationService() = default;
|
IScreenShotApplicationService::~IScreenShotApplicationService() = default;
|
||||||
|
|
||||||
void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) {
|
Result IScreenShotApplicationService::SetShimLibraryVersion(ShimLibraryVersion library_version,
|
||||||
IPC::RequestParser rp{ctx};
|
ClientAppletResourceUserId aruid) {
|
||||||
const auto library_version{rp.Pop<u64>()};
|
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
|
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
|
||||||
library_version, applet_resource_user_id);
|
library_version, aruid.pid);
|
||||||
|
R_SUCCEED();
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) {
|
Result IScreenShotApplicationService::SaveScreenShotEx0(
|
||||||
IPC::RequestParser rp{ctx};
|
Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute,
|
||||||
struct Parameters {
|
AlbumReportOption report_option, ClientAppletResourceUserId aruid,
|
||||||
ScreenShotAttribute attribute{};
|
InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias>
|
||||||
AlbumReportOption report_option{};
|
image_data_buffer) {
|
||||||
INSERT_PADDING_BYTES(0x4);
|
|
||||||
u64 applet_resource_user_id{};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
const auto image_data_buffer = ctx.ReadBuffer();
|
|
||||||
|
|
||||||
LOG_INFO(Service_Capture,
|
LOG_INFO(Service_Capture,
|
||||||
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
||||||
parameters.report_option, image_data_buffer.size(),
|
report_option, image_data_buffer.size(), aruid.pid);
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
ApplicationAlbumEntry entry{};
|
|
||||||
manager->FlipVerticallyOnWrite(false);
|
manager->FlipVerticallyOnWrite(false);
|
||||||
const auto result =
|
R_RETURN(manager->SaveScreenShot(*out_entry, attribute, report_option, image_data_buffer,
|
||||||
manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option,
|
aruid.pid));
|
||||||
image_data_buffer, parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 10};
|
|
||||||
rb.Push(result);
|
|
||||||
rb.PushRaw(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) {
|
Result IScreenShotApplicationService::SaveScreenShotEx1(
|
||||||
IPC::RequestParser rp{ctx};
|
Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute,
|
||||||
struct Parameters {
|
AlbumReportOption report_option, ClientAppletResourceUserId aruid,
|
||||||
ScreenShotAttribute attribute{};
|
const InLargeData<ApplicationData, BufferAttr_HipcMapAlias> app_data_buffer,
|
||||||
AlbumReportOption report_option{};
|
const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias>
|
||||||
INSERT_PADDING_BYTES(0x4);
|
image_data_buffer) {
|
||||||
u64 applet_resource_user_id{};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
const auto app_data_buffer = ctx.ReadBuffer(0);
|
|
||||||
const auto image_data_buffer = ctx.ReadBuffer(1);
|
|
||||||
|
|
||||||
LOG_INFO(Service_Capture,
|
LOG_INFO(Service_Capture,
|
||||||
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
||||||
parameters.report_option, image_data_buffer.size(),
|
report_option, image_data_buffer.size(), aruid.pid);
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
ApplicationAlbumEntry entry{};
|
|
||||||
ApplicationData app_data{};
|
|
||||||
std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData));
|
|
||||||
manager->FlipVerticallyOnWrite(false);
|
manager->FlipVerticallyOnWrite(false);
|
||||||
const auto result =
|
R_RETURN(manager->SaveScreenShot(*out_entry, attribute, report_option, *app_data_buffer,
|
||||||
manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, app_data,
|
image_data_buffer, aruid.pid));
|
||||||
image_data_buffer, parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 10};
|
|
||||||
rb.Push(result);
|
|
||||||
rb.PushRaw(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption report_option) {
|
void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption report_option) {
|
||||||
|
@ -112,6 +76,7 @@ void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption r
|
||||||
.orientation = Capture::AlbumImageOrientation::None,
|
.orientation = Capture::AlbumImageOrientation::None,
|
||||||
.unknown_1{},
|
.unknown_1{},
|
||||||
.unknown_2{},
|
.unknown_2{},
|
||||||
|
.pad163{},
|
||||||
};
|
};
|
||||||
|
|
||||||
renderer.RequestScreenshot(
|
renderer.RequestScreenshot(
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -26,9 +28,19 @@ private:
|
||||||
static constexpr std::size_t screenshot_height = 720;
|
static constexpr std::size_t screenshot_height = 720;
|
||||||
static constexpr std::size_t bytes_per_pixel = 4;
|
static constexpr std::size_t bytes_per_pixel = 4;
|
||||||
|
|
||||||
void SetShimLibraryVersion(HLERequestContext& ctx);
|
Result SetShimLibraryVersion(ShimLibraryVersion library_version,
|
||||||
void SaveScreenShotEx0(HLERequestContext& ctx);
|
ClientAppletResourceUserId aruid);
|
||||||
void SaveScreenShotEx1(HLERequestContext& ctx);
|
Result SaveScreenShotEx0(
|
||||||
|
Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute,
|
||||||
|
AlbumReportOption report_option, ClientAppletResourceUserId aruid,
|
||||||
|
InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias>
|
||||||
|
image_data_buffer);
|
||||||
|
Result SaveScreenShotEx1(
|
||||||
|
Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute,
|
||||||
|
AlbumReportOption report_option, ClientAppletResourceUserId aruid,
|
||||||
|
const InLargeData<ApplicationData, BufferAttr_HipcMapAlias> app_data_buffer,
|
||||||
|
const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias>
|
||||||
|
image_data_buffer);
|
||||||
|
|
||||||
std::array<u8, screenshot_width * screenshot_height * bytes_per_pixel> image_data;
|
std::array<u8, screenshot_width * screenshot_height * bytes_per_pixel> image_data;
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,10 @@ enum class ScreenShotDecoderFlag : u64 {
|
||||||
EnableBlockSmoothing = 1 << 1,
|
EnableBlockSmoothing = 1 << 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ShimLibraryVersion : u64 {
|
||||||
|
Version1 = 1,
|
||||||
|
};
|
||||||
|
|
||||||
// This is nn::capsrv::AlbumFileDateTime
|
// This is nn::capsrv::AlbumFileDateTime
|
||||||
struct AlbumFileDateTime {
|
struct AlbumFileDateTime {
|
||||||
s16 year{};
|
s16 year{};
|
||||||
|
@ -144,19 +148,23 @@ static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
|
||||||
"ApplicationAlbumFileEntry has incorrect size.");
|
"ApplicationAlbumFileEntry has incorrect size.");
|
||||||
|
|
||||||
struct ApplicationData {
|
struct ApplicationData {
|
||||||
std::array<u8, 0x400> data{};
|
std::array<u8, 0x400> data;
|
||||||
u32 data_size{};
|
u32 data_size;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ApplicationData) == 0x404, "ApplicationData is an invalid size");
|
static_assert(sizeof(ApplicationData) == 0x404, "ApplicationData is an invalid size");
|
||||||
|
static_assert(std::is_trivial_v<ApplicationData>,
|
||||||
|
"ApplicationData type must be trivially copyable.");
|
||||||
|
|
||||||
struct ScreenShotAttribute {
|
struct ScreenShotAttribute {
|
||||||
u32 unknown_0{};
|
u32 unknown_0;
|
||||||
AlbumImageOrientation orientation{};
|
AlbumImageOrientation orientation;
|
||||||
u32 unknown_1{};
|
u32 unknown_1;
|
||||||
u32 unknown_2{};
|
u32 unknown_2;
|
||||||
INSERT_PADDING_BYTES(0x30);
|
INSERT_PADDING_BYTES_NOINIT(0x30);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ScreenShotAttribute) == 0x40, "ScreenShotAttribute is an invalid size");
|
static_assert(sizeof(ScreenShotAttribute) == 0x40, "ScreenShotAttribute is an invalid size");
|
||||||
|
static_assert(std::is_trivial_v<ScreenShotAttribute>,
|
||||||
|
"ScreenShotAttribute type must be trivially copyable.");
|
||||||
|
|
||||||
struct ScreenShotDecodeOption {
|
struct ScreenShotDecodeOption {
|
||||||
ScreenShotDecoderFlag flags{};
|
ScreenShotDecoderFlag flags{};
|
||||||
|
@ -165,13 +173,15 @@ struct ScreenShotDecodeOption {
|
||||||
static_assert(sizeof(ScreenShotDecodeOption) == 0x20, "ScreenShotDecodeOption is an invalid size");
|
static_assert(sizeof(ScreenShotDecodeOption) == 0x20, "ScreenShotDecodeOption is an invalid size");
|
||||||
|
|
||||||
struct LoadAlbumScreenShotImageOutput {
|
struct LoadAlbumScreenShotImageOutput {
|
||||||
s64 width{};
|
s64 width;
|
||||||
s64 height{};
|
s64 height;
|
||||||
ScreenShotAttribute attribute{};
|
ScreenShotAttribute attribute;
|
||||||
INSERT_PADDING_BYTES(0x400);
|
INSERT_PADDING_BYTES_NOINIT(0x400);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(LoadAlbumScreenShotImageOutput) == 0x450,
|
static_assert(sizeof(LoadAlbumScreenShotImageOutput) == 0x450,
|
||||||
"LoadAlbumScreenShotImageOutput is an invalid size");
|
"LoadAlbumScreenShotImageOutput is an invalid size");
|
||||||
|
static_assert(std::is_trivial_v<LoadAlbumScreenShotImageOutput>,
|
||||||
|
"LoadAlbumScreenShotImageOutput type must be trivially copyable.");
|
||||||
|
|
||||||
struct LoadAlbumScreenShotImageOutputForApplication {
|
struct LoadAlbumScreenShotImageOutputForApplication {
|
||||||
s64 width{};
|
s64 width{};
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "core/hle/service/caps/caps_manager.h"
|
#include "core/hle/service/caps/caps_manager.h"
|
||||||
#include "core/hle/service/caps/caps_types.h"
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
#include "core/hle/service/caps/caps_u.h"
|
#include "core/hle/service/caps/caps_u.h"
|
||||||
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
|
@ -14,8 +15,8 @@ IAlbumApplicationService::IAlbumApplicationService(Core::System& system_,
|
||||||
: ServiceFramework{system_, "caps:u"}, manager{album_manager} {
|
: ServiceFramework{system_, "caps:u"}, manager{album_manager} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{32, &IAlbumApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
{32, C<&IAlbumApplicationService::SetShimLibraryVersion>, "SetShimLibraryVersion"},
|
||||||
{102, &IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated, "GetAlbumFileList0AafeAruidDeprecated"},
|
{102, C<&IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated>, "GetAlbumFileList0AafeAruidDeprecated"},
|
||||||
{103, nullptr, "DeleteAlbumFileByAruid"},
|
{103, nullptr, "DeleteAlbumFileByAruid"},
|
||||||
{104, nullptr, "GetAlbumFileSizeByAruid"},
|
{104, nullptr, "GetAlbumFileSizeByAruid"},
|
||||||
{105, nullptr, "DeleteAlbumFileByAruidForDebug"},
|
{105, nullptr, "DeleteAlbumFileByAruidForDebug"},
|
||||||
|
@ -24,7 +25,7 @@ IAlbumApplicationService::IAlbumApplicationService(Core::System& system_,
|
||||||
{130, nullptr, "PrecheckToCreateContentsByAruid"},
|
{130, nullptr, "PrecheckToCreateContentsByAruid"},
|
||||||
{140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"},
|
{140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"},
|
||||||
{141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
|
{141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
|
||||||
{142, &IAlbumApplicationService::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
|
{142, C<&IAlbumApplicationService::GetAlbumFileList3AaeAruid>, "GetAlbumFileList3AaeAruid"},
|
||||||
{143, nullptr, "GetAlbumFileList4AaeUidAruid"},
|
{143, nullptr, "GetAlbumFileList4AaeUidAruid"},
|
||||||
{144, nullptr, "GetAllAlbumFileList3AaeAruid"},
|
{144, nullptr, "GetAllAlbumFileList3AaeAruid"},
|
||||||
{60002, nullptr, "OpenAccessorSessionForApplication"},
|
{60002, nullptr, "OpenAccessorSessionForApplication"},
|
||||||
|
@ -36,101 +37,40 @@ IAlbumApplicationService::IAlbumApplicationService(Core::System& system_,
|
||||||
|
|
||||||
IAlbumApplicationService::~IAlbumApplicationService() = default;
|
IAlbumApplicationService::~IAlbumApplicationService() = default;
|
||||||
|
|
||||||
void IAlbumApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) {
|
Result IAlbumApplicationService::SetShimLibraryVersion(ShimLibraryVersion library_version,
|
||||||
IPC::RequestParser rp{ctx};
|
ClientAppletResourceUserId aruid) {
|
||||||
const auto library_version{rp.Pop<u64>()};
|
|
||||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
|
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
|
||||||
library_version, applet_resource_user_id);
|
library_version, aruid.pid);
|
||||||
|
R_SUCCEED();
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx) {
|
Result IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(
|
||||||
IPC::RequestParser rp{ctx};
|
Out<u64> out_entries_count, ContentType content_type, s64 start_posix_time, s64 end_posix_time,
|
||||||
struct Parameters {
|
ClientAppletResourceUserId aruid,
|
||||||
ContentType content_type;
|
OutArray<ApplicationAlbumFileEntry, BufferAttr_HipcMapAlias> out_entries) {
|
||||||
INSERT_PADDING_BYTES(7);
|
|
||||||
s64 start_posix_time;
|
|
||||||
s64 end_posix_time;
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_Capture,
|
LOG_WARNING(Service_Capture,
|
||||||
"(STUBBED) called. content_type={}, start_posix_time={}, end_posix_time={}, "
|
"(STUBBED) called. content_type={}, start_posix_time={}, end_posix_time={}, "
|
||||||
"applet_resource_user_id={}",
|
"applet_resource_user_id={}",
|
||||||
parameters.content_type, parameters.start_posix_time, parameters.end_posix_time,
|
content_type, start_posix_time, end_posix_time, aruid.pid);
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
Result result = ResultSuccess;
|
R_TRY(manager->IsAlbumMounted(AlbumStorage::Sd));
|
||||||
|
R_RETURN(manager->GetAlbumFileList(out_entries, *out_entries_count, content_type,
|
||||||
if (result.IsSuccess()) {
|
start_posix_time, end_posix_time, aruid.pid));
|
||||||
result = manager->IsAlbumMounted(AlbumStorage::Sd);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ApplicationAlbumFileEntry> entries;
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
result = manager->GetAlbumFileList(entries, parameters.content_type,
|
|
||||||
parameters.start_posix_time, parameters.end_posix_time,
|
|
||||||
parameters.applet_resource_user_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entries.empty()) {
|
|
||||||
ctx.WriteBuffer(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
|
||||||
rb.Push(result);
|
|
||||||
rb.Push<u64>(entries.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) {
|
Result IAlbumApplicationService::GetAlbumFileList3AaeAruid(
|
||||||
IPC::RequestParser rp{ctx};
|
Out<u64> out_entries_count, ContentType content_type, AlbumFileDateTime start_date_time,
|
||||||
struct Parameters {
|
AlbumFileDateTime end_date_time, ClientAppletResourceUserId aruid,
|
||||||
ContentType content_type;
|
OutArray<ApplicationAlbumEntry, BufferAttr_HipcMapAlias> out_entries) {
|
||||||
INSERT_PADDING_BYTES(1);
|
|
||||||
AlbumFileDateTime start_date_time;
|
|
||||||
AlbumFileDateTime end_date_time;
|
|
||||||
INSERT_PADDING_BYTES(6);
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_WARNING(Service_Capture,
|
LOG_WARNING(Service_Capture,
|
||||||
"(STUBBED) called. content_type={}, start_date={}/{}/{}, "
|
"(STUBBED) called. content_type={}, start_date={}/{}/{}, "
|
||||||
"end_date={}/{}/{}, applet_resource_user_id={}",
|
"end_date={}/{}/{}, applet_resource_user_id={}",
|
||||||
parameters.content_type, parameters.start_date_time.year,
|
content_type, start_date_time.year, start_date_time.month, start_date_time.day,
|
||||||
parameters.start_date_time.month, parameters.start_date_time.day,
|
end_date_time.year, end_date_time.month, end_date_time.day, aruid.pid);
|
||||||
parameters.end_date_time.year, parameters.end_date_time.month,
|
|
||||||
parameters.end_date_time.day, parameters.applet_resource_user_id);
|
|
||||||
|
|
||||||
Result result = ResultSuccess;
|
R_TRY(manager->IsAlbumMounted(AlbumStorage::Sd));
|
||||||
|
R_RETURN(manager->GetAlbumFileList(out_entries, *out_entries_count, content_type,
|
||||||
if (result.IsSuccess()) {
|
start_date_time, end_date_time, aruid.pid));
|
||||||
result = manager->IsAlbumMounted(AlbumStorage::Sd);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ApplicationAlbumEntry> entries;
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
result =
|
|
||||||
manager->GetAlbumFileList(entries, parameters.content_type, parameters.start_date_time,
|
|
||||||
parameters.end_date_time, parameters.applet_resource_user_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entries.empty()) {
|
|
||||||
ctx.WriteBuffer(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
|
||||||
rb.Push(result);
|
|
||||||
rb.Push<u64>(entries.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Capture
|
} // namespace Service::Capture
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -19,9 +20,18 @@ public:
|
||||||
~IAlbumApplicationService() override;
|
~IAlbumApplicationService() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetShimLibraryVersion(HLERequestContext& ctx);
|
Result SetShimLibraryVersion(ShimLibraryVersion library_version,
|
||||||
void GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx);
|
ClientAppletResourceUserId aruid);
|
||||||
void GetAlbumFileList3AaeAruid(HLERequestContext& ctx);
|
|
||||||
|
Result GetAlbumFileList0AafeAruidDeprecated(
|
||||||
|
Out<u64> out_entries_count, ContentType content_type, s64 start_posix_time,
|
||||||
|
s64 end_posix_time, ClientAppletResourceUserId aruid,
|
||||||
|
OutArray<ApplicationAlbumFileEntry, BufferAttr_HipcMapAlias> out_entries);
|
||||||
|
|
||||||
|
Result GetAlbumFileList3AaeAruid(
|
||||||
|
Out<u64> out_entries_count, ContentType content_type, AlbumFileDateTime start_date_time,
|
||||||
|
AlbumFileDateTime end_date_time, ClientAppletResourceUserId aruid,
|
||||||
|
OutArray<ApplicationAlbumEntry, BufferAttr_HipcMapAlias> out_entries);
|
||||||
|
|
||||||
std::shared_ptr<AlbumManager> manager = nullptr;
|
std::shared_ptr<AlbumManager> manager = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1546,7 +1546,10 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
|
||||||
std::span<const u8> upload_span;
|
std::span<const u8> upload_span;
|
||||||
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
|
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
|
||||||
if (IsRangeGranular(device_addr, copy.size)) {
|
if (IsRangeGranular(device_addr, copy.size)) {
|
||||||
upload_span = std::span(device_memory.GetPointer<u8>(device_addr), copy.size);
|
auto* const ptr = device_memory.GetPointer<u8>(device_addr);
|
||||||
|
if (ptr != nullptr) {
|
||||||
|
upload_span = std::span(ptr, copy.size);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (immediate_buffer.empty()) {
|
if (immediate_buffer.empty()) {
|
||||||
immediate_buffer = ImmediateBuffer(largest_copy);
|
immediate_buffer = ImmediateBuffer(largest_copy);
|
||||||
|
|
|
@ -111,6 +111,20 @@ void Bilinear(std::span<const f32> input, std::span<f32> output, size_t src_widt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool unpack>
|
||||||
|
void ProcessPitchLinear(std::span<const u8> input, std::span<u8> output, size_t extent_x,
|
||||||
|
size_t extent_y, u32 pitch, u32 x0, u32 y0, size_t bpp) {
|
||||||
|
const size_t base_offset = x0 * bpp;
|
||||||
|
const size_t copy_size = extent_x * bpp;
|
||||||
|
for (size_t y = 0; y < extent_y; y++) {
|
||||||
|
const size_t first_offset = (y + y0) * pitch + base_offset;
|
||||||
|
const size_t second_offset = y * extent_x * bpp;
|
||||||
|
u8* write_to = unpack ? &output[first_offset] : &output[second_offset];
|
||||||
|
const u8* read_from = unpack ? &input[second_offset] : &input[first_offset];
|
||||||
|
std::memcpy(write_to, read_from, copy_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
struct SoftwareBlitEngine::BlitEngineImpl {
|
struct SoftwareBlitEngine::BlitEngineImpl {
|
||||||
|
@ -138,19 +152,6 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
|
||||||
}
|
}
|
||||||
return static_cast<size_t>(surface.pitch * surface.height);
|
return static_cast<size_t>(surface.pitch * surface.height);
|
||||||
};
|
};
|
||||||
const auto process_pitch_linear = [](bool unpack, std::span<const u8> input,
|
|
||||||
std::span<u8> output, u32 extent_x, u32 extent_y,
|
|
||||||
u32 pitch, u32 x0, u32 y0, size_t bpp) {
|
|
||||||
const size_t base_offset = x0 * bpp;
|
|
||||||
const size_t copy_size = extent_x * bpp;
|
|
||||||
for (u32 y = y0; y < extent_y; y++) {
|
|
||||||
const size_t first_offset = y * pitch + base_offset;
|
|
||||||
const size_t second_offset = y * extent_x * bpp;
|
|
||||||
u8* write_to = unpack ? &output[first_offset] : &output[second_offset];
|
|
||||||
const u8* read_from = unpack ? &input[second_offset] : &input[first_offset];
|
|
||||||
std::memcpy(write_to, read_from, copy_size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const u32 src_extent_x = config.src_x1 - config.src_x0;
|
const u32 src_extent_x = config.src_x1 - config.src_x0;
|
||||||
const u32 src_extent_y = config.src_y1 - config.src_y0;
|
const u32 src_extent_y = config.src_y1 - config.src_y0;
|
||||||
|
@ -205,8 +206,8 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
|
||||||
src.depth, config.src_x0, config.src_y0, src_extent_x, src_extent_y,
|
src.depth, config.src_x0, config.src_y0, src_extent_x, src_extent_y,
|
||||||
src.block_height, src.block_depth, src_extent_x * src_bytes_per_pixel);
|
src.block_height, src.block_depth, src_extent_x * src_bytes_per_pixel);
|
||||||
} else {
|
} else {
|
||||||
process_pitch_linear(false, tmp_buffer, impl->src_buffer, src_extent_x, src_extent_y,
|
ProcessPitchLinear<false>(tmp_buffer, impl->src_buffer, src_extent_x, src_extent_y,
|
||||||
src.pitch, config.src_x0, config.src_y0, src_bytes_per_pixel);
|
src.pitch, config.src_x0, config.src_y0, src_bytes_per_pixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conversion Phase
|
// Conversion Phase
|
||||||
|
@ -229,9 +230,9 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
|
||||||
dst.depth, config.dst_x0, config.dst_y0, dst_extent_x, dst_extent_y,
|
dst.depth, config.dst_x0, config.dst_y0, dst_extent_x, dst_extent_y,
|
||||||
dst.block_height, dst.block_depth, dst_extent_x * dst_bytes_per_pixel);
|
dst.block_height, dst.block_depth, dst_extent_x * dst_bytes_per_pixel);
|
||||||
} else {
|
} else {
|
||||||
process_pitch_linear(true, impl->dst_buffer, tmp_buffer2, dst_extent_x, dst_extent_y,
|
ProcessPitchLinear<true>(impl->dst_buffer, tmp_buffer2, dst_extent_x, dst_extent_y,
|
||||||
dst.pitch, config.dst_x0, config.dst_y0,
|
dst.pitch, config.dst_x0, config.dst_y0,
|
||||||
static_cast<size_t>(dst_bytes_per_pixel));
|
static_cast<size_t>(dst_bytes_per_pixel));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1064,8 +1064,6 @@ public:
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
auto* ptr = device_memory.GetPointer<u8>(new_query->dependant_address);
|
|
||||||
ASSERT(ptr != nullptr);
|
|
||||||
|
|
||||||
new_query->dependant_manage = must_manage_dependance;
|
new_query->dependant_manage = must_manage_dependance;
|
||||||
pending_flush_queries.push_back(index);
|
pending_flush_queries.push_back(index);
|
||||||
|
@ -1104,9 +1102,11 @@ public:
|
||||||
tfb_streamer.Free(query->dependant_index);
|
tfb_streamer.Free(query->dependant_index);
|
||||||
} else {
|
} else {
|
||||||
u8* pointer = device_memory.GetPointer<u8>(query->dependant_address);
|
u8* pointer = device_memory.GetPointer<u8>(query->dependant_address);
|
||||||
u32 result;
|
if (pointer != nullptr) {
|
||||||
std::memcpy(&result, pointer, sizeof(u32));
|
u32 result;
|
||||||
num_vertices = static_cast<u64>(result) / query->stride;
|
std::memcpy(&result, pointer, sizeof(u32));
|
||||||
|
num_vertices = static_cast<u64>(result) / query->stride;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
query->value = [&]() -> u64 {
|
query->value = [&]() -> u64 {
|
||||||
switch (query->topology) {
|
switch (query->topology) {
|
||||||
|
@ -1360,7 +1360,9 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku
|
||||||
const auto check_value = [&](DAddr address) {
|
const auto check_value = [&](DAddr address) {
|
||||||
u8* ptr = impl->device_memory.GetPointer<u8>(address);
|
u8* ptr = impl->device_memory.GetPointer<u8>(address);
|
||||||
u64 value{};
|
u64 value{};
|
||||||
std::memcpy(&value, ptr, sizeof(value));
|
if (ptr != nullptr) {
|
||||||
|
std::memcpy(&value, ptr, sizeof(value));
|
||||||
|
}
|
||||||
return value == 0;
|
return value == 0;
|
||||||
};
|
};
|
||||||
std::array<VideoCommon::LookupData*, 2> objects{&object_1, &object_2};
|
std::array<VideoCommon::LookupData*, 2> objects{&object_1, &object_2};
|
||||||
|
|
|
@ -1045,37 +1045,16 @@ void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||||
regs.zeta.format == Tegra::DepthFormat::X8Z24_UNORM ||
|
regs.zeta.format == Tegra::DepthFormat::X8Z24_UNORM ||
|
||||||
regs.zeta.format == Tegra::DepthFormat::S8Z24_UNORM ||
|
regs.zeta.format == Tegra::DepthFormat::S8Z24_UNORM ||
|
||||||
regs.zeta.format == Tegra::DepthFormat::V8Z24_UNORM;
|
regs.zeta.format == Tegra::DepthFormat::V8Z24_UNORM;
|
||||||
bool force_unorm = ([&] {
|
if (is_d24 && !device.SupportsD24DepthBuffer() &&
|
||||||
if (!is_d24 || device.SupportsD24DepthBuffer()) {
|
Settings::values.renderer_amdvlk_depth_bias_workaround) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (device.IsExtDepthBiasControlSupported()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!Settings::values.renderer_amdvlk_depth_bias_workaround) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// the base formulas can be obtained from here:
|
// the base formulas can be obtained from here:
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-output-merger-stage-depth-bias
|
// https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-output-merger-stage-depth-bias
|
||||||
const double rescale_factor =
|
const double rescale_factor =
|
||||||
static_cast<double>(1ULL << (32 - 24)) / (static_cast<double>(0x1.ep+127));
|
static_cast<double>(1ULL << (32 - 24)) / (static_cast<double>(0x1.ep+127));
|
||||||
units = static_cast<float>(static_cast<double>(units) * rescale_factor);
|
units = static_cast<float>(static_cast<double>(units) * rescale_factor);
|
||||||
return false;
|
}
|
||||||
})();
|
|
||||||
scheduler.Record([constant = units, clamp = regs.depth_bias_clamp,
|
scheduler.Record([constant = units, clamp = regs.depth_bias_clamp,
|
||||||
factor = regs.slope_scale_depth_bias, force_unorm,
|
factor = regs.slope_scale_depth_bias](vk::CommandBuffer cmdbuf) {
|
||||||
precise = device.HasExactDepthBiasControl()](vk::CommandBuffer cmdbuf) {
|
|
||||||
if (force_unorm) {
|
|
||||||
VkDepthBiasRepresentationInfoEXT info{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.depthBiasRepresentation =
|
|
||||||
VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT,
|
|
||||||
.depthBiasExact = precise ? VK_TRUE : VK_FALSE,
|
|
||||||
};
|
|
||||||
cmdbuf.SetDepthBias(constant, clamp, factor, &info);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cmdbuf.SetDepthBias(constant, clamp, factor);
|
cmdbuf.SetDepthBias(constant, clamp, factor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1135,13 +1135,6 @@ void Device::RemoveUnsuitableExtensions() {
|
||||||
RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
|
RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
|
||||||
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
||||||
|
|
||||||
// VK_EXT_depth_bias_control
|
|
||||||
extensions.depth_bias_control =
|
|
||||||
features.depth_bias_control.depthBiasControl &&
|
|
||||||
features.depth_bias_control.leastRepresentableValueForceUnormRepresentation;
|
|
||||||
RemoveExtensionFeatureIfUnsuitable(extensions.depth_bias_control, features.depth_bias_control,
|
|
||||||
VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME);
|
|
||||||
|
|
||||||
// VK_EXT_depth_clip_control
|
// VK_EXT_depth_clip_control
|
||||||
extensions.depth_clip_control = features.depth_clip_control.depthClipControl;
|
extensions.depth_clip_control = features.depth_clip_control.depthClipControl;
|
||||||
RemoveExtensionFeatureIfUnsuitable(extensions.depth_clip_control, features.depth_clip_control,
|
RemoveExtensionFeatureIfUnsuitable(extensions.depth_clip_control, features.depth_clip_control,
|
||||||
|
|
|
@ -41,7 +41,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||||
// Define all features which may be used by the implementation and require an extension here.
|
// Define all features which may be used by the implementation and require an extension here.
|
||||||
#define FOR_EACH_VK_FEATURE_EXT(FEATURE) \
|
#define FOR_EACH_VK_FEATURE_EXT(FEATURE) \
|
||||||
FEATURE(EXT, CustomBorderColor, CUSTOM_BORDER_COLOR, custom_border_color) \
|
FEATURE(EXT, CustomBorderColor, CUSTOM_BORDER_COLOR, custom_border_color) \
|
||||||
FEATURE(EXT, DepthBiasControl, DEPTH_BIAS_CONTROL, depth_bias_control) \
|
|
||||||
FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \
|
FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \
|
||||||
FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \
|
FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \
|
||||||
FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \
|
FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \
|
||||||
|
@ -97,7 +96,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||||
#define FOR_EACH_VK_RECOMMENDED_EXTENSION(EXTENSION_NAME) \
|
#define FOR_EACH_VK_RECOMMENDED_EXTENSION(EXTENSION_NAME) \
|
||||||
EXTENSION_NAME(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME) \
|
EXTENSION_NAME(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME) \
|
||||||
EXTENSION_NAME(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME) \
|
EXTENSION_NAME(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME) \
|
||||||
EXTENSION_NAME(VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME) \
|
|
||||||
EXTENSION_NAME(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME) \
|
EXTENSION_NAME(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME) \
|
||||||
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) \
|
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) \
|
||||||
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME) \
|
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME) \
|
||||||
|
@ -150,9 +148,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||||
// Define features where the absence of the feature may result in a degraded experience.
|
// Define features where the absence of the feature may result in a degraded experience.
|
||||||
#define FOR_EACH_VK_RECOMMENDED_FEATURE(FEATURE_NAME) \
|
#define FOR_EACH_VK_RECOMMENDED_FEATURE(FEATURE_NAME) \
|
||||||
FEATURE_NAME(custom_border_color, customBorderColors) \
|
FEATURE_NAME(custom_border_color, customBorderColors) \
|
||||||
FEATURE_NAME(depth_bias_control, depthBiasControl) \
|
|
||||||
FEATURE_NAME(depth_bias_control, leastRepresentableValueForceUnormRepresentation) \
|
|
||||||
FEATURE_NAME(depth_bias_control, depthBiasExact) \
|
|
||||||
FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \
|
FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \
|
||||||
FEATURE_NAME(format_a4b4g4r4, formatA4B4G4R4) \
|
FEATURE_NAME(format_a4b4g4r4, formatA4B4G4R4) \
|
||||||
FEATURE_NAME(index_type_uint8, indexTypeUint8) \
|
FEATURE_NAME(index_type_uint8, indexTypeUint8) \
|
||||||
|
@ -479,11 +474,6 @@ public:
|
||||||
return extensions.depth_clip_control;
|
return extensions.depth_clip_control;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports VK_EXT_depth_bias_control.
|
|
||||||
bool IsExtDepthBiasControlSupported() const {
|
|
||||||
return extensions.depth_bias_control;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the device supports VK_EXT_shader_viewport_index_layer.
|
/// Returns true if the device supports VK_EXT_shader_viewport_index_layer.
|
||||||
bool IsExtShaderViewportIndexLayerSupported() const {
|
bool IsExtShaderViewportIndexLayerSupported() const {
|
||||||
return extensions.shader_viewport_index_layer;
|
return extensions.shader_viewport_index_layer;
|
||||||
|
@ -649,10 +639,6 @@ public:
|
||||||
return features.robustness2.nullDescriptor;
|
return features.robustness2.nullDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasExactDepthBiasControl() const {
|
|
||||||
return features.depth_bias_control.depthBiasExact;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetMaxVertexInputAttributes() const {
|
u32 GetMaxVertexInputAttributes() const {
|
||||||
return properties.properties.limits.maxVertexInputAttributes;
|
return properties.properties.limits.maxVertexInputAttributes;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue