diff options
| -rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 83 |
1 files changed, 50 insertions, 33 deletions
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 8ded9b09b..f3c7b7df3 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp | |||
| @@ -66,14 +66,26 @@ static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { | |||
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | /** | 68 | /** |
| 69 | * Writes a single GSP GPU hardware registers with a single u32 value | ||
| 70 | * (For internal use.) | ||
| 71 | * | ||
| 72 | * @param base_address The address of the register in question | ||
| 73 | * @param data Data to be written | ||
| 74 | */ | ||
| 75 | static void WriteSingleHWReg(u32 base_address, u32 data) { | ||
| 76 | DEBUG_ASSERT_MSG((base_address & 3) == 0 && base_address < 0x420000, "Write address out of range or misaligned"); | ||
| 77 | HW::Write<u32>(base_address + REGS_BEGIN, data); | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 69 | * Writes sequential GSP GPU hardware registers using an array of source data | 81 | * Writes sequential GSP GPU hardware registers using an array of source data |
| 70 | * | 82 | * |
| 71 | * @param base_address The address of the first register in the sequence | 83 | * @param base_address The address of the first register in the sequence |
| 72 | * @param size_in_bytes The number of registers to update (size of data) | 84 | * @param size_in_bytes The number of registers to update (size of data) |
| 73 | * @param data A pointer to the source data | 85 | * @param data_vaddr A pointer to the source data |
| 74 | * @return RESULT_SUCCESS if the parameters are valid, error code otherwise | 86 | * @return RESULT_SUCCESS if the parameters are valid, error code otherwise |
| 75 | */ | 87 | */ |
| 76 | static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { | 88 | static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, VAddr data_vaddr) { |
| 77 | // This magic number is verified to be done by the gsp module | 89 | // This magic number is verified to be done by the gsp module |
| 78 | const u32 max_size_in_bytes = 0x80; | 90 | const u32 max_size_in_bytes = 0x80; |
| 79 | 91 | ||
| @@ -87,10 +99,10 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* da | |||
| 87 | return ERR_GSP_REGS_MISALIGNED; | 99 | return ERR_GSP_REGS_MISALIGNED; |
| 88 | } else { | 100 | } else { |
| 89 | while (size_in_bytes > 0) { | 101 | while (size_in_bytes > 0) { |
| 90 | HW::Write<u32>(base_address + REGS_BEGIN, *data); | 102 | WriteSingleHWReg(base_address, Memory::Read32(data_vaddr)); |
| 91 | 103 | ||
| 92 | size_in_bytes -= 4; | 104 | size_in_bytes -= 4; |
| 93 | ++data; | 105 | data_vaddr += 4; |
| 94 | base_address += 4; | 106 | base_address += 4; |
| 95 | } | 107 | } |
| 96 | return RESULT_SUCCESS; | 108 | return RESULT_SUCCESS; |
| @@ -112,7 +124,7 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* da | |||
| 112 | * @param masks A pointer to the masks | 124 | * @param masks A pointer to the masks |
| 113 | * @return RESULT_SUCCESS if the parameters are valid, error code otherwise | 125 | * @return RESULT_SUCCESS if the parameters are valid, error code otherwise |
| 114 | */ | 126 | */ |
| 115 | static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) { | 127 | static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr data_vaddr, VAddr masks_vaddr) { |
| 116 | // This magic number is verified to be done by the gsp module | 128 | // This magic number is verified to be done by the gsp module |
| 117 | const u32 max_size_in_bytes = 0x80; | 129 | const u32 max_size_in_bytes = 0x80; |
| 118 | 130 | ||
| @@ -131,14 +143,17 @@ static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const | |||
| 131 | u32 reg_value; | 143 | u32 reg_value; |
| 132 | HW::Read<u32>(reg_value, reg_address); | 144 | HW::Read<u32>(reg_value, reg_address); |
| 133 | 145 | ||
| 146 | u32 data = Memory::Read32(data_vaddr); | ||
| 147 | u32 mask = Memory::Read32(masks_vaddr); | ||
| 148 | |||
| 134 | // Update the current value of the register only for set mask bits | 149 | // Update the current value of the register only for set mask bits |
| 135 | reg_value = (reg_value & ~*masks) | (*data | *masks); | 150 | reg_value = (reg_value & ~mask) | (data | mask); |
| 136 | 151 | ||
| 137 | HW::Write<u32>(reg_address, reg_value); | 152 | WriteSingleHWReg(base_address, reg_value); |
| 138 | 153 | ||
| 139 | size_in_bytes -= 4; | 154 | size_in_bytes -= 4; |
| 140 | ++data; | 155 | data_vaddr += 4; |
| 141 | ++masks; | 156 | masks_vaddr += 4; |
| 142 | base_address += 4; | 157 | base_address += 4; |
| 143 | } | 158 | } |
| 144 | return RESULT_SUCCESS; | 159 | return RESULT_SUCCESS; |
| @@ -164,8 +179,7 @@ static void WriteHWRegs(Service::Interface* self) { | |||
| 164 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 179 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 165 | u32 reg_addr = cmd_buff[1]; | 180 | u32 reg_addr = cmd_buff[1]; |
| 166 | u32 size = cmd_buff[2]; | 181 | u32 size = cmd_buff[2]; |
| 167 | 182 | VAddr src = cmd_buff[4]; | |
| 168 | u32* src = (u32*)Memory::GetPointer(cmd_buff[4]); | ||
| 169 | 183 | ||
| 170 | cmd_buff[1] = WriteHWRegs(reg_addr, size, src).raw; | 184 | cmd_buff[1] = WriteHWRegs(reg_addr, size, src).raw; |
| 171 | } | 185 | } |
| @@ -186,8 +200,8 @@ static void WriteHWRegsWithMask(Service::Interface* self) { | |||
| 186 | u32 reg_addr = cmd_buff[1]; | 200 | u32 reg_addr = cmd_buff[1]; |
| 187 | u32 size = cmd_buff[2]; | 201 | u32 size = cmd_buff[2]; |
| 188 | 202 | ||
| 189 | u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]); | 203 | VAddr src_data = cmd_buff[4]; |
| 190 | u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]); | 204 | VAddr mask_data = cmd_buff[6]; |
| 191 | 205 | ||
| 192 | cmd_buff[1] = WriteHWRegsWithMask(reg_addr, size, src_data, mask_data).raw; | 206 | cmd_buff[1] = WriteHWRegsWithMask(reg_addr, size, src_data, mask_data).raw; |
| 193 | } | 207 | } |
| @@ -210,13 +224,16 @@ static void ReadHWRegs(Service::Interface* self) { | |||
| 210 | return; | 224 | return; |
| 211 | } | 225 | } |
| 212 | 226 | ||
| 213 | u32* dst = (u32*)Memory::GetPointer(cmd_buff[0x41]); | 227 | VAddr dst_vaddr = cmd_buff[0x41]; |
| 214 | 228 | ||
| 215 | while (size > 0) { | 229 | while (size > 0) { |
| 216 | HW::Read<u32>(*dst, reg_addr + REGS_BEGIN); | 230 | u32 value; |
| 231 | HW::Read<u32>(value, reg_addr + REGS_BEGIN); | ||
| 232 | |||
| 233 | Memory::Write32(dst_vaddr, value); | ||
| 217 | 234 | ||
| 218 | size -= 4; | 235 | size -= 4; |
| 219 | ++dst; | 236 | dst_vaddr += 4; |
| 220 | reg_addr += 4; | 237 | reg_addr += 4; |
| 221 | } | 238 | } |
| 222 | } | 239 | } |
| @@ -226,22 +243,22 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { | |||
| 226 | PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); | 243 | PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); |
| 227 | PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); | 244 | PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); |
| 228 | if (info.active_fb == 0) { | 245 | if (info.active_fb == 0) { |
| 229 | WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), | 246 | WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), |
| 230 | 4, &phys_address_left); | 247 | phys_address_left); |
| 231 | WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), | 248 | WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), |
| 232 | 4, &phys_address_right); | 249 | phys_address_right); |
| 233 | } else { | 250 | } else { |
| 234 | WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), | 251 | WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), |
| 235 | 4, &phys_address_left); | 252 | phys_address_left); |
| 236 | WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), | 253 | WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), |
| 237 | 4, &phys_address_right); | 254 | phys_address_right); |
| 238 | } | 255 | } |
| 239 | WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), | 256 | WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), |
| 240 | 4, &info.stride); | 257 | info.stride); |
| 241 | WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), | 258 | WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), |
| 242 | 4, &info.format); | 259 | info.format); |
| 243 | WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), | 260 | WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), |
| 244 | 4, &info.shown_fb); | 261 | info.shown_fb); |
| 245 | 262 | ||
| 246 | if (Pica::g_debug_context) | 263 | if (Pica::g_debug_context) |
| 247 | Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr); | 264 | Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr); |
| @@ -432,9 +449,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { | |||
| 432 | Memory::RasterizerFlushAndInvalidateRegion(Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), | 449 | Memory::RasterizerFlushAndInvalidateRegion(Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), |
| 433 | command.dma_request.size); | 450 | command.dma_request.size); |
| 434 | 451 | ||
| 435 | memcpy(Memory::GetPointer(command.dma_request.dest_address), | 452 | // TODO(Subv): These memory accesses should not go through the application's memory mapping. |
| 436 | Memory::GetPointer(command.dma_request.source_address), | 453 | // They should go through the GSP module's memory mapping. |
| 437 | command.dma_request.size); | 454 | Memory::CopyBlock(command.dma_request.dest_address, command.dma_request.source_address, command.dma_request.size); |
| 438 | SignalInterrupt(InterruptId::DMA); | 455 | SignalInterrupt(InterruptId::DMA); |
| 439 | break; | 456 | break; |
| 440 | } | 457 | } |