diff options
| author | 2014-06-04 18:30:23 +0200 | |
|---|---|---|
| committer | 2014-07-23 00:33:08 +0200 | |
| commit | baf0aa04f50dff257b57fa78786e53b97c1e6abb (patch) | |
| tree | 3dc92a276f58d1099eb19dd2b5fcb52c69a8da9a /src | |
| parent | GPU: Add proper framebuffer register handling. (diff) | |
| download | yuzu-baf0aa04f50dff257b57fa78786e53b97c1e6abb.tar.gz yuzu-baf0aa04f50dff257b57fa78786e53b97c1e6abb.tar.xz yuzu-baf0aa04f50dff257b57fa78786e53b97c1e6abb.zip | |
GPU: Emulate memory fills.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/gsp.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/service/gsp.h | 2 | ||||
| -rw-r--r-- | src/core/hw/gpu.cpp | 56 | ||||
| -rw-r--r-- | src/core/hw/gpu.h | 26 |
4 files changed, 89 insertions, 3 deletions
diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index fea521891..5baa7a7a2 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp | |||
| @@ -174,6 +174,14 @@ void TriggerCmdReqQueue(Service::Interface* self) { | |||
| 174 | break; | 174 | break; |
| 175 | 175 | ||
| 176 | case GXCommandId::SET_MEMORY_FILL: | 176 | case GXCommandId::SET_MEMORY_FILL: |
| 177 | GPU::Write<u32>(GPU::Registers::MemoryFillStart1, cmd_buff[1] >> 3); | ||
| 178 | GPU::Write<u32>(GPU::Registers::MemoryFillEnd1, cmd_buff[3] >> 3); | ||
| 179 | GPU::Write<u32>(GPU::Registers::MemoryFillSize1, cmd_buff[3] - cmd_buff[1]); | ||
| 180 | GPU::Write<u32>(GPU::Registers::MemoryFillValue1, cmd_buff[2]); | ||
| 181 | GPU::Write<u32>(GPU::Registers::MemoryFillStart2, cmd_buff[4] >> 3); | ||
| 182 | GPU::Write<u32>(GPU::Registers::MemoryFillEnd2, cmd_buff[6] >> 3); | ||
| 183 | GPU::Write<u32>(GPU::Registers::MemoryFillSize2, cmd_buff[6] - cmd_buff[4]); | ||
| 184 | GPU::Write<u32>(GPU::Registers::MemoryFillValue2, cmd_buff[5]); | ||
| 177 | break; | 185 | break; |
| 178 | 186 | ||
| 179 | // TODO: Check if texture copies are implemented correctly.. | 187 | // TODO: Check if texture copies are implemented correctly.. |
diff --git a/src/core/hle/service/gsp.h b/src/core/hle/service/gsp.h index 214de140f..fb50a928a 100644 --- a/src/core/hle/service/gsp.h +++ b/src/core/hle/service/gsp.h | |||
| @@ -14,7 +14,7 @@ namespace GSP_GPU { | |||
| 14 | enum class GXCommandId : u32 { | 14 | enum class GXCommandId : u32 { |
| 15 | REQUEST_DMA = 0x00000000, | 15 | REQUEST_DMA = 0x00000000, |
| 16 | SET_COMMAND_LIST_LAST = 0x00000001, | 16 | SET_COMMAND_LIST_LAST = 0x00000001, |
| 17 | SET_MEMORY_FILL = 0x00000002, // TODO: Confirm? (lictru uses 0x01000102) | 17 | SET_MEMORY_FILL = 0x01000102, // TODO: Confirm? |
| 18 | SET_DISPLAY_TRANSFER = 0x00000003, | 18 | SET_DISPLAY_TRANSFER = 0x00000003, |
| 19 | SET_TEXTURE_COPY = 0x00000004, | 19 | SET_TEXTURE_COPY = 0x00000004, |
| 20 | SET_COMMAND_LIST_FIRST = 0x00000005, | 20 | SET_COMMAND_LIST_FIRST = 0x00000005, |
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index fad3439c8..230a12d46 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp | |||
| @@ -84,6 +84,26 @@ const u8* GetFramebufferPointer(const u32 address) { | |||
| 84 | template <typename T> | 84 | template <typename T> |
| 85 | inline void Read(T &var, const u32 addr) { | 85 | inline void Read(T &var, const u32 addr) { |
| 86 | switch (addr) { | 86 | switch (addr) { |
| 87 | case Registers::MemoryFillStart1: | ||
| 88 | case Registers::MemoryFillStart2: | ||
| 89 | var = g_regs.memory_fill[(addr - Registers::MemoryFillStart1) / 0x10].address_start; | ||
| 90 | break; | ||
| 91 | |||
| 92 | case Registers::MemoryFillEnd1: | ||
| 93 | case Registers::MemoryFillEnd2: | ||
| 94 | var = g_regs.memory_fill[(addr - Registers::MemoryFillEnd1) / 0x10].address_end; | ||
| 95 | break; | ||
| 96 | |||
| 97 | case Registers::MemoryFillSize1: | ||
| 98 | case Registers::MemoryFillSize2: | ||
| 99 | var = g_regs.memory_fill[(addr - Registers::MemoryFillSize1) / 0x10].size; | ||
| 100 | break; | ||
| 101 | |||
| 102 | case Registers::MemoryFillValue1: | ||
| 103 | case Registers::MemoryFillValue2: | ||
| 104 | var = g_regs.memory_fill[(addr - Registers::MemoryFillValue1) / 0x10].value; | ||
| 105 | break; | ||
| 106 | |||
| 87 | case Registers::FramebufferTopSize: | 107 | case Registers::FramebufferTopSize: |
| 88 | var = g_regs.top_framebuffer.size; | 108 | var = g_regs.top_framebuffer.size; |
| 89 | break; | 109 | break; |
| @@ -194,6 +214,40 @@ inline void Read(T &var, const u32 addr) { | |||
| 194 | template <typename T> | 214 | template <typename T> |
| 195 | inline void Write(u32 addr, const T data) { | 215 | inline void Write(u32 addr, const T data) { |
| 196 | switch (static_cast<Registers::Id>(addr)) { | 216 | switch (static_cast<Registers::Id>(addr)) { |
| 217 | case Registers::MemoryFillStart1: | ||
| 218 | case Registers::MemoryFillStart2: | ||
| 219 | g_regs.memory_fill[(addr - Registers::MemoryFillStart1) / 0x10].address_start = data; | ||
| 220 | break; | ||
| 221 | |||
| 222 | case Registers::MemoryFillEnd1: | ||
| 223 | case Registers::MemoryFillEnd2: | ||
| 224 | g_regs.memory_fill[(addr - Registers::MemoryFillEnd1) / 0x10].address_end = data; | ||
| 225 | break; | ||
| 226 | |||
| 227 | case Registers::MemoryFillSize1: | ||
| 228 | case Registers::MemoryFillSize2: | ||
| 229 | g_regs.memory_fill[(addr - Registers::MemoryFillSize1) / 0x10].size = data; | ||
| 230 | break; | ||
| 231 | |||
| 232 | case Registers::MemoryFillValue1: | ||
| 233 | case Registers::MemoryFillValue2: | ||
| 234 | { | ||
| 235 | Registers::MemoryFillConfig& config = g_regs.memory_fill[(addr - Registers::MemoryFillValue1) / 0x10]; | ||
| 236 | config.value = data; | ||
| 237 | |||
| 238 | // TODO: Not sure if this check should be done at GSP level instead | ||
| 239 | if (config.address_start) { | ||
| 240 | // TODO: Not sure if this algorithm is correct, particularly because it doesn't use the size member at all | ||
| 241 | u32* start = (u32*)Memory::GetPointer(config.GetStartAddress()); | ||
| 242 | u32* end = (u32*)Memory::GetPointer(config.GetEndAddress()); | ||
| 243 | for (u32* ptr = start; ptr < end; ++ptr) | ||
| 244 | *ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation | ||
| 245 | |||
| 246 | DEBUG_LOG(GPU, "MemoryFill from %x to %x", config.GetStartAddress(), config.GetEndAddress()); | ||
| 247 | } | ||
| 248 | break; | ||
| 249 | } | ||
| 250 | |||
| 197 | // TODO: Framebuffer registers!! | 251 | // TODO: Framebuffer registers!! |
| 198 | case Registers::FramebufferTopSwapBuffers: | 252 | case Registers::FramebufferTopSwapBuffers: |
| 199 | g_regs.top_framebuffer.active_fb = data; | 253 | g_regs.top_framebuffer.active_fb = data; |
| @@ -240,8 +294,6 @@ inline void Write(u32 addr, const T data) { | |||
| 240 | g_regs.display_transfer.output_width * 4); | 294 | g_regs.display_transfer.output_width * 4); |
| 241 | } | 295 | } |
| 242 | 296 | ||
| 243 | // Clear previous contents until we implement proper buffer clearing | ||
| 244 | memset(source_pointer, 0x20, g_regs.display_transfer.input_width*g_regs.display_transfer.input_height*4); | ||
| 245 | DEBUG_LOG(GPU, "DisplayTriggerTransfer: %x bytes from %x(%xx%x)-> %x(%xx%x), dst format %x", | 297 | DEBUG_LOG(GPU, "DisplayTriggerTransfer: %x bytes from %x(%xx%x)-> %x(%xx%x), dst format %x", |
| 246 | g_regs.display_transfer.output_height * g_regs.display_transfer.output_width * 4, | 298 | g_regs.display_transfer.output_height * g_regs.display_transfer.output_width * 4, |
| 247 | g_regs.display_transfer.GetPhysicalInputAddress(), (int)g_regs.display_transfer.input_width, (int)g_regs.display_transfer.input_height, | 299 | g_regs.display_transfer.GetPhysicalInputAddress(), (int)g_regs.display_transfer.input_width, (int)g_regs.display_transfer.input_height, |
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index 50c360814..47d7fcb26 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h | |||
| @@ -14,6 +14,15 @@ static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of i | |||
| 14 | 14 | ||
| 15 | struct Registers { | 15 | struct Registers { |
| 16 | enum Id : u32 { | 16 | enum Id : u32 { |
| 17 | MemoryFillStart1 = 0x1EF00010, | ||
| 18 | MemoryFillEnd1 = 0x1EF00014, | ||
| 19 | MemoryFillSize1 = 0x1EF00018, | ||
| 20 | MemoryFillValue1 = 0x1EF0001C, | ||
| 21 | MemoryFillStart2 = 0x1EF00020, | ||
| 22 | MemoryFillEnd2 = 0x1EF00024, | ||
| 23 | MemoryFillSize2 = 0x1EF00028, | ||
| 24 | MemoryFillValue2 = 0x1EF0002C, | ||
| 25 | |||
| 17 | FramebufferTopSize = 0x1EF0045C, | 26 | FramebufferTopSize = 0x1EF0045C, |
| 18 | FramebufferTopLeft1 = 0x1EF00468, // Main LCD, first framebuffer for 3D left | 27 | FramebufferTopLeft1 = 0x1EF00468, // Main LCD, first framebuffer for 3D left |
| 19 | FramebufferTopLeft2 = 0x1EF0046C, // Main LCD, second framebuffer for 3D left | 28 | FramebufferTopLeft2 = 0x1EF0046C, // Main LCD, second framebuffer for 3D left |
| @@ -53,6 +62,23 @@ struct Registers { | |||
| 53 | RGBA4 = 4, | 62 | RGBA4 = 4, |
| 54 | }; | 63 | }; |
| 55 | 64 | ||
| 65 | struct MemoryFillConfig { | ||
| 66 | u32 address_start; | ||
| 67 | u32 address_end; // ? | ||
| 68 | u32 size; | ||
| 69 | u32 value; // ? | ||
| 70 | |||
| 71 | inline u32 GetStartAddress() const { | ||
| 72 | return address_start * 8; | ||
| 73 | } | ||
| 74 | |||
| 75 | inline u32 GetEndAddress() const { | ||
| 76 | return address_end * 8; | ||
| 77 | } | ||
| 78 | }; | ||
| 79 | |||
| 80 | MemoryFillConfig memory_fill[2]; | ||
| 81 | |||
| 56 | // TODO: Move these into the framebuffer struct | 82 | // TODO: Move these into the framebuffer struct |
| 57 | u32 framebuffer_top_left_1; | 83 | u32 framebuffer_top_left_1; |
| 58 | u32 framebuffer_top_left_2; | 84 | u32 framebuffer_top_left_2; |