mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-28 05:50:05 +00:00
209 lines
5.9 KiB
C++
209 lines
5.9 KiB
C++
// Copyright 2014 Citra Emulator Project
|
|
// Licensed under GPLv2 or any later version
|
|
// Refer to the license.txt file included.
|
|
|
|
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <string>
|
|
|
|
#include "common/bit_field.h"
|
|
#include "common/common_types.h"
|
|
|
|
#include "core/hle/result.h"
|
|
#include "core/hle/service/service.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Namespace GSP_GPU
|
|
|
|
namespace GSP_GPU {
|
|
|
|
/// GSP interrupt ID
|
|
enum class InterruptId : u8 {
|
|
PSC0 = 0x00,
|
|
PSC1 = 0x01,
|
|
PDC0 = 0x02, // Seems called every vertical screen line
|
|
PDC1 = 0x03, // Seems called every frame
|
|
PPF = 0x04,
|
|
P3D = 0x05,
|
|
DMA = 0x06,
|
|
};
|
|
|
|
/// GSP command ID
|
|
enum class CommandId : u32 {
|
|
REQUEST_DMA = 0x00,
|
|
/// Submits a commandlist for execution by the GPU.
|
|
SUBMIT_GPU_CMDLIST = 0x01,
|
|
|
|
// Fills a given memory range with a particular value
|
|
SET_MEMORY_FILL = 0x02,
|
|
|
|
// Copies an image and optionally performs color-conversion or scaling.
|
|
// This is highly similar to the GameCube's EFB copy feature
|
|
SET_DISPLAY_TRANSFER = 0x03,
|
|
|
|
// Conceptionally similar to SET_DISPLAY_TRANSFER and presumable uses the same hardware path
|
|
SET_TEXTURE_COPY = 0x04,
|
|
/// Flushes up to 3 cache regions in a single command.
|
|
CACHE_FLUSH = 0x05,
|
|
};
|
|
|
|
/// GSP thread interrupt relay queue
|
|
struct InterruptRelayQueue {
|
|
// Index of last interrupt in the queue
|
|
u8 index;
|
|
// Number of interrupts remaining to be processed by the userland code
|
|
u8 number_interrupts;
|
|
// Error code - zero on success, otherwise an error has occurred
|
|
u8 error_code;
|
|
u8 padding1;
|
|
|
|
u32 missed_PDC0;
|
|
u32 missed_PDC1;
|
|
|
|
InterruptId slot[0x34]; ///< Interrupt ID slots
|
|
};
|
|
static_assert(sizeof(InterruptRelayQueue) == 0x40,
|
|
"InterruptRelayQueue struct has incorrect size");
|
|
|
|
struct FrameBufferInfo {
|
|
BitField<0, 1, u32> active_fb; // 0 = first, 1 = second
|
|
|
|
u32 address_left;
|
|
u32 address_right;
|
|
u32 stride; // maps to 0x1EF00X90 ?
|
|
u32 format; // maps to 0x1EF00X70 ?
|
|
u32 shown_fb; // maps to 0x1EF00X78 ?
|
|
u32 unknown;
|
|
};
|
|
static_assert(sizeof(FrameBufferInfo) == 0x1c, "Struct has incorrect size");
|
|
|
|
struct FrameBufferUpdate {
|
|
BitField<0, 1, u8> index; // Index used for GSP::SetBufferSwap
|
|
BitField<0, 1, u8> is_dirty; // true if GSP should update GPU framebuffer registers
|
|
u16 pad1;
|
|
|
|
FrameBufferInfo framebuffer_info[2];
|
|
|
|
u32 pad2;
|
|
};
|
|
static_assert(sizeof(FrameBufferUpdate) == 0x40, "Struct has incorrect size");
|
|
// TODO: Not sure if this padding is correct.
|
|
// Chances are the second block is stored at offset 0x24 rather than 0x20.
|
|
#ifndef _MSC_VER
|
|
static_assert(offsetof(FrameBufferUpdate, framebuffer_info[1]) == 0x20, "FrameBufferInfo element has incorrect alignment");
|
|
#endif
|
|
|
|
/// GSP command
|
|
struct Command {
|
|
BitField<0, 8, CommandId> id;
|
|
|
|
union {
|
|
struct {
|
|
u32 source_address;
|
|
u32 dest_address;
|
|
u32 size;
|
|
} dma_request;
|
|
|
|
struct {
|
|
u32 address;
|
|
u32 size;
|
|
u32 flags;
|
|
u32 unused[3];
|
|
u32 do_flush;
|
|
} submit_gpu_cmdlist;
|
|
|
|
struct {
|
|
u32 start1;
|
|
u32 value1;
|
|
u32 end1;
|
|
|
|
u32 start2;
|
|
u32 value2;
|
|
u32 end2;
|
|
|
|
u16 control1;
|
|
u16 control2;
|
|
} memory_fill;
|
|
|
|
struct {
|
|
u32 in_buffer_address;
|
|
u32 out_buffer_address;
|
|
u32 in_buffer_size;
|
|
u32 out_buffer_size;
|
|
u32 flags;
|
|
} display_transfer;
|
|
|
|
struct {
|
|
u32 in_buffer_address;
|
|
u32 out_buffer_address;
|
|
u32 size;
|
|
u32 in_width_gap;
|
|
u32 out_width_gap;
|
|
u32 flags;
|
|
} texture_copy;
|
|
|
|
struct {
|
|
struct {
|
|
u32 address;
|
|
u32 size;
|
|
} regions[3];
|
|
} cache_flush;
|
|
|
|
u8 raw_data[0x1C];
|
|
};
|
|
};
|
|
static_assert(sizeof(Command) == 0x20, "Command struct has incorrect size");
|
|
|
|
/// GSP shared memory GX command buffer header
|
|
struct CommandBuffer {
|
|
union {
|
|
u32 hex;
|
|
|
|
// Current command index. This index is updated by GSP module after loading the command
|
|
// data, right before the command is processed. When this index is updated by GSP module,
|
|
// the total commands field is decreased by one as well.
|
|
BitField<0,8,u32> index;
|
|
|
|
// Total commands to process, must not be value 0 when GSP module handles commands. This
|
|
// must be <=15 when writing a command to shared memory. This is incremented by the
|
|
// application when writing a command to shared memory, after increasing this value
|
|
// TriggerCmdReqQueue is only used if this field is value 1.
|
|
BitField<8,8,u32> number_commands;
|
|
};
|
|
|
|
u32 unk[7];
|
|
|
|
Command commands[0xF];
|
|
};
|
|
static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size");
|
|
|
|
/// Interface to "srv:" service
|
|
class Interface : public Service::Interface {
|
|
public:
|
|
Interface();
|
|
~Interface() override;
|
|
|
|
std::string GetPortName() const override {
|
|
return "gsp::Gpu";
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Signals that the specified interrupt type has occurred to userland code
|
|
* @param interrupt_id ID of interrupt that is being signalled
|
|
*/
|
|
void SignalInterrupt(InterruptId interrupt_id);
|
|
|
|
ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
|
|
|
|
/**
|
|
* Retrieves the framebuffer info stored in the GSP shared memory for the
|
|
* specified screen index and thread id.
|
|
* @param thread_id GSP thread id of the process that accesses the structure that we are requesting.
|
|
* @param screen_index Index of the screen we are requesting (Top = 0, Bottom = 1).
|
|
* @returns FramebufferUpdate Information about the specified framebuffer.
|
|
*/
|
|
FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index);
|
|
} // namespace
|