mirror of
https://github.com/PabloMK7/citra.git
synced 2025-10-11 20:10:03 +00:00
service/gsp: Implement saving of framebuffers in SaveVramSysArea. (#6821)
* service/gsp: Implement saving of framebuffers in SaveVramSysArea. * Address review comments. * service/apt: Separate capture info and capture buffer info. The former is used with the RequestForSysApplet message and GetCaptureInfo. The latter is used with SendCaptureBufferInfo and ReceiveCaptureBufferInfo.
This commit is contained in:
parent
bb364d9bc0
commit
964f9ee3cf
4 changed files with 157 additions and 35 deletions
|
@ -704,18 +704,73 @@ void GSP_GPU::ImportDisplayCaptureInfo(Kernel::HLERequestContext& ctx) {
|
|||
LOG_WARNING(Service_GSP, "called");
|
||||
}
|
||||
|
||||
static void CopyFrameBuffer(Core::System& system, VAddr dst, VAddr src, u32 stride, u32 lines) {
|
||||
auto dst_ptr = system.Memory().GetPointer(dst);
|
||||
const auto src_ptr = system.Memory().GetPointer(src);
|
||||
if (!dst_ptr || !src_ptr) {
|
||||
LOG_WARNING(Service_GSP,
|
||||
"Could not resolve pointers for framebuffer capture, skipping screen.");
|
||||
return;
|
||||
}
|
||||
|
||||
Memory::RasterizerFlushVirtualRegion(src, stride * lines, Memory::FlushMode::Flush);
|
||||
std::memcpy(dst_ptr, src_ptr, stride * lines);
|
||||
Memory::RasterizerFlushVirtualRegion(dst, stride * lines, Memory::FlushMode::Invalidate);
|
||||
}
|
||||
|
||||
void GSP_GPU::SaveVramSysArea(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
if (active_thread_id == std::numeric_limits<u32>::max()) {
|
||||
LOG_WARNING(Service_GSP, "Called without an active thread.");
|
||||
|
||||
// TODO: Find the right error code.
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO(Service_GSP, "called");
|
||||
|
||||
// TODO: This should also DMA framebuffers into VRAM and save LCD register state.
|
||||
// TODO: This should also save LCD register state.
|
||||
Memory::RasterizerFlushVirtualRegion(Memory::VRAM_VADDR, Memory::VRAM_SIZE,
|
||||
Memory::FlushMode::Flush);
|
||||
auto vram = system.Memory().GetPointer(Memory::VRAM_VADDR);
|
||||
const auto vram = system.Memory().GetPointer(Memory::VRAM_VADDR);
|
||||
saved_vram.emplace(std::vector<u8>(Memory::VRAM_SIZE));
|
||||
std::memcpy(saved_vram.get().data(), vram, Memory::VRAM_SIZE);
|
||||
|
||||
const auto top_screen = GetFrameBufferInfo(active_thread_id, 0);
|
||||
if (top_screen) {
|
||||
const auto top_fb = top_screen->framebuffer_info[top_screen->index];
|
||||
if (top_fb.address_left) {
|
||||
CopyFrameBuffer(system, FRAMEBUFFER_SAVE_AREA_TOP_LEFT, top_fb.address_left,
|
||||
top_fb.stride, TOP_FRAMEBUFFER_HEIGHT);
|
||||
} else {
|
||||
LOG_WARNING(Service_GSP, "No framebuffer bound to top left screen, skipping capture.");
|
||||
}
|
||||
if (top_fb.address_right) {
|
||||
CopyFrameBuffer(system, FRAMEBUFFER_SAVE_AREA_TOP_RIGHT, top_fb.address_right,
|
||||
top_fb.stride, TOP_FRAMEBUFFER_HEIGHT);
|
||||
} else {
|
||||
LOG_WARNING(Service_GSP, "No framebuffer bound to top right screen, skipping capture.");
|
||||
}
|
||||
} else {
|
||||
LOG_WARNING(Service_GSP, "No top screen bound, skipping capture.");
|
||||
}
|
||||
|
||||
const auto bottom_screen = GetFrameBufferInfo(active_thread_id, 1);
|
||||
if (bottom_screen) {
|
||||
const auto bottom_fb = bottom_screen->framebuffer_info[bottom_screen->index];
|
||||
if (bottom_fb.address_left) {
|
||||
CopyFrameBuffer(system, FRAMEBUFFER_SAVE_AREA_BOTTOM, bottom_fb.address_left,
|
||||
bottom_fb.stride, BOTTOM_FRAMEBUFFER_HEIGHT);
|
||||
} else {
|
||||
LOG_WARNING(Service_GSP, "No framebuffer bound to bottom screen, skipping capture.");
|
||||
}
|
||||
} else {
|
||||
LOG_WARNING(Service_GSP, "No bottom screen bound, skipping capture.");
|
||||
}
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
@ -819,7 +874,7 @@ SessionData* GSP_GPU::FindRegisteredThreadData(u32 thread_id) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 2), system(system) {
|
||||
GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 4), system(system) {
|
||||
static const FunctionInfo functions[] = {
|
||||
// clang-format off
|
||||
{0x0001, &GSP_GPU::WriteHWRegs, "WriteHWRegs"},
|
||||
|
|
|
@ -186,6 +186,17 @@ struct CommandBuffer {
|
|||
};
|
||||
static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size");
|
||||
|
||||
constexpr u32 FRAMEBUFFER_WIDTH = 240;
|
||||
constexpr u32 FRAMEBUFFER_WIDTH_POW2 = 256;
|
||||
constexpr u32 TOP_FRAMEBUFFER_HEIGHT = 400;
|
||||
constexpr u32 BOTTOM_FRAMEBUFFER_HEIGHT = 320;
|
||||
constexpr u32 FRAMEBUFFER_HEIGHT_POW2 = 512;
|
||||
|
||||
// These are the VRAM addresses that GSP copies framebuffers to in SaveVramSysArea.
|
||||
constexpr VAddr FRAMEBUFFER_SAVE_AREA_TOP_LEFT = Memory::VRAM_VADDR + 0x273000;
|
||||
constexpr VAddr FRAMEBUFFER_SAVE_AREA_TOP_RIGHT = Memory::VRAM_VADDR + 0x2B9800;
|
||||
constexpr VAddr FRAMEBUFFER_SAVE_AREA_BOTTOM = Memory::VRAM_VADDR + 0x4C7800;
|
||||
|
||||
class GSP_GPU;
|
||||
|
||||
class SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue