summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/gsp_gpu.cpp97
1 files changed, 91 insertions, 6 deletions
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 4c3ac845b..dcc1b6942 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -48,20 +48,42 @@ static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
48 return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); 48 return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr));
49} 49}
50 50
51static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { 51/**
52 * Checks if the parameters in a register write call are valid and logs in the case that
53 * they are not
54 * @param base_address The first address in the sequence of registers that will be written
55 * @param size_in_bytes The number of registers that will be written
56 * @return true if the parameters are valid, false otherwise
57 */
58static bool CheckWriteParameters(u32 base_address, u32 size_in_bytes) {
52 // TODO: Return proper error codes 59 // TODO: Return proper error codes
53 if (base_address + size_in_bytes >= 0x420000) { 60 if (base_address + size_in_bytes >= 0x420000) {
54 LOG_ERROR(Service_GSP, "Write address out of range! (address=0x%08x, size=0x%08x)", 61 LOG_ERROR(Service_GSP, "Write address out of range! (address=0x%08x, size=0x%08x)",
55 base_address, size_in_bytes); 62 base_address, size_in_bytes);
56 return; 63 return false;
57 } 64 }
58 65
59 // size should be word-aligned 66 // size should be word-aligned
60 if ((size_in_bytes % 4) != 0) { 67 if ((size_in_bytes % 4) != 0) {
61 LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size_in_bytes); 68 LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size_in_bytes);
62 return; 69 return false;
63 } 70 }
64 71
72 return true;
73}
74
75/**
76 * Writes sequential GSP GPU hardware registers using an array of source data
77 *
78 * @param base_address The address of the first register in the sequence
79 * @param size_in_bytes The number of registers to update (size of data)
80 * @param data A pointer to the source data
81 */
82static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
83 // TODO: Return proper error codes
84 if (!CheckWriteParameters(base_address, size_in_bytes))
85 return;
86
65 while (size_in_bytes > 0) { 87 while (size_in_bytes > 0) {
66 GPU::Write<u32>(base_address + 0x1EB00000, *data); 88 GPU::Write<u32>(base_address + 0x1EB00000, *data);
67 89
@@ -71,17 +93,80 @@ static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
71 } 93 }
72} 94}
73 95
74/// Write a GSP GPU hardware register 96/**
97 * GSP_GPU::WriteHWRegs service function
98 *
99 * Writes sequential GSP GPU hardware registers
100 *
101 * Inputs:
102 * 1 : address of first GPU register
103 * 2 : number of registers to write sequentially
104 * 4 : pointer to source data array
105 */
75static void WriteHWRegs(Service::Interface* self) { 106static void WriteHWRegs(Service::Interface* self) {
76 u32* cmd_buff = Kernel::GetCommandBuffer(); 107 u32* cmd_buff = Kernel::GetCommandBuffer();
77 u32 reg_addr = cmd_buff[1]; 108 u32 reg_addr = cmd_buff[1];
78 u32 size = cmd_buff[2]; 109 u32 size = cmd_buff[2];
79 110
80 u32* src = (u32*)Memory::GetPointer(cmd_buff[0x4]); 111 u32* src = (u32*)Memory::GetPointer(cmd_buff[4]);
81 112
82 WriteHWRegs(reg_addr, size, src); 113 WriteHWRegs(reg_addr, size, src);
83} 114}
84 115
116/**
117 * Updates sequential GSP GPU hardware registers using parallel arrays of source data and masks.
118 * For each register, the value is updated only where the mask is high
119 *
120 * @param base_address The address of the first register in the sequence
121 * @param size_in_bytes The number of registers to update (size of data)
122 * @param data A pointer to the source data to use for updates
123 * @param masks A pointer to the masks
124 */
125static void WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) {
126 // TODO: Return proper error codes
127 if (!CheckWriteParameters(base_address, size_in_bytes))
128 return;
129
130 while (size_in_bytes > 0) {
131 const u32 reg_address = base_address + 0x1EB00000;
132
133 u32 reg_value;
134 GPU::Read<u32>(reg_value, reg_address);
135
136 // Update the current value of the register only for set mask bits
137 reg_value = (reg_value & ~*masks) | (*data | *masks);
138
139 GPU::Write<u32>(reg_address, reg_value);
140
141 size_in_bytes -= 4;
142 ++data;
143 ++masks;
144 base_address += 4;
145 }
146}
147
148/**
149 * GSP_GPU::WriteHWRegsWithMask service function
150 *
151 * Updates sequential GSP GPU hardware registers using masks
152 *
153 * Inputs:
154 * 1 : address of first GPU register
155 * 2 : number of registers to update sequentially
156 * 4 : pointer to source data array
157 * 6 : pointer to mask array
158 */
159static void WriteHWRegsWithMask(Service::Interface* self) {
160 u32* cmd_buff = Kernel::GetCommandBuffer();
161 u32 reg_addr = cmd_buff[1];
162 u32 size = cmd_buff[2];
163
164 u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
165 u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
166
167 WriteHWRegsWithMask(reg_addr, size, src_data, mask_data);
168}
169
85/// Read a GSP GPU hardware register 170/// Read a GSP GPU hardware register
86static void ReadHWRegs(Service::Interface* self) { 171static void ReadHWRegs(Service::Interface* self) {
87 u32* cmd_buff = Kernel::GetCommandBuffer(); 172 u32* cmd_buff = Kernel::GetCommandBuffer();
@@ -350,7 +435,7 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
350 435
351const Interface::FunctionInfo FunctionTable[] = { 436const Interface::FunctionInfo FunctionTable[] = {
352 {0x00010082, WriteHWRegs, "WriteHWRegs"}, 437 {0x00010082, WriteHWRegs, "WriteHWRegs"},
353 {0x00020084, nullptr, "WriteHWRegsWithMask"}, 438 {0x00020084, WriteHWRegsWithMask, "WriteHWRegsWithMask"},
354 {0x00030082, nullptr, "WriteHWRegRepeat"}, 439 {0x00030082, nullptr, "WriteHWRegRepeat"},
355 {0x00040080, ReadHWRegs, "ReadHWRegs"}, 440 {0x00040080, ReadHWRegs, "ReadHWRegs"},
356 {0x00050200, SetBufferSwap, "SetBufferSwap"}, 441 {0x00050200, SetBufferSwap, "SetBufferSwap"},