diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 34 | ||||
| -rw-r--r-- | src/core/hle/service/gsp_gpu.h | 4 | ||||
| -rw-r--r-- | src/core/hw/gpu.cpp | 41 | ||||
| -rw-r--r-- | src/core/hw/gpu.h | 32 |
4 files changed, 78 insertions, 33 deletions
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 31e61391f..c23cfa3c8 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp | |||
| @@ -368,28 +368,28 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { | |||
| 368 | case CommandId::SET_MEMORY_FILL: | 368 | case CommandId::SET_MEMORY_FILL: |
| 369 | { | 369 | { |
| 370 | auto& params = command.memory_fill; | 370 | auto& params = command.memory_fill; |
| 371 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)), | 371 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)), |
| 372 | Memory::VirtualToPhysicalAddress(params.start1) >> 3); | 372 | Memory::VirtualToPhysicalAddress(params.start1) >> 3); |
| 373 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)), | 373 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)), |
| 374 | Memory::VirtualToPhysicalAddress(params.end1) >> 3); | 374 | Memory::VirtualToPhysicalAddress(params.end1) >> 3); |
| 375 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].size)), params.end1 - params.start1); | 375 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1); |
| 376 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value)), params.value1); | 376 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1); |
| 377 | 377 | ||
| 378 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)), | 378 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)), |
| 379 | Memory::VirtualToPhysicalAddress(params.start2) >> 3); | 379 | Memory::VirtualToPhysicalAddress(params.start2) >> 3); |
| 380 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)), | 380 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)), |
| 381 | Memory::VirtualToPhysicalAddress(params.end2) >> 3); | 381 | Memory::VirtualToPhysicalAddress(params.end2) >> 3); |
| 382 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].size)), params.end2 - params.start2); | 382 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2); |
| 383 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value)), params.value2); | 383 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2); |
| 384 | break; | 384 | break; |
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | case CommandId::SET_DISPLAY_TRANSFER: | 387 | case CommandId::SET_DISPLAY_TRANSFER: |
| 388 | { | 388 | { |
| 389 | auto& params = command.image_copy; | 389 | auto& params = command.image_copy; |
| 390 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)), | 390 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)), |
| 391 | Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3); | 391 | Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3); |
| 392 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)), | 392 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)), |
| 393 | Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3); | 393 | Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3); |
| 394 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_size)), params.in_buffer_size); | 394 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_size)), params.in_buffer_size); |
| 395 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_size)), params.out_buffer_size); | 395 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_size)), params.out_buffer_size); |
| @@ -402,9 +402,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { | |||
| 402 | case CommandId::SET_TEXTURE_COPY: | 402 | case CommandId::SET_TEXTURE_COPY: |
| 403 | { | 403 | { |
| 404 | auto& params = command.image_copy; | 404 | auto& params = command.image_copy; |
| 405 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)), | 405 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)), |
| 406 | Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3); | 406 | Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3); |
| 407 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)), | 407 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)), |
| 408 | Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3); | 408 | Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3); |
| 409 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_size)), params.in_buffer_size); | 409 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_size)), params.in_buffer_size); |
| 410 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_size)), params.out_buffer_size); | 410 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_size)), params.out_buffer_size); |
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h index 65abb194a..a435d418a 100644 --- a/src/core/hle/service/gsp_gpu.h +++ b/src/core/hle/service/gsp_gpu.h | |||
| @@ -109,9 +109,13 @@ struct Command { | |||
| 109 | u32 start1; | 109 | u32 start1; |
| 110 | u32 value1; | 110 | u32 value1; |
| 111 | u32 end1; | 111 | u32 end1; |
| 112 | |||
| 112 | u32 start2; | 113 | u32 start2; |
| 113 | u32 value2; | 114 | u32 value2; |
| 114 | u32 end2; | 115 | u32 end2; |
| 116 | |||
| 117 | u16 control1; | ||
| 118 | u16 control2; | ||
| 115 | } memory_fill; | 119 | } memory_fill; |
| 116 | 120 | ||
| 117 | struct { | 121 | struct { |
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index aad0e5d0d..bd7d92cd1 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp | |||
| @@ -67,23 +67,38 @@ inline void Write(u32 addr, const T data) { | |||
| 67 | switch (index) { | 67 | switch (index) { |
| 68 | 68 | ||
| 69 | // Memory fills are triggered once the fill value is written. | 69 | // Memory fills are triggered once the fill value is written. |
| 70 | // NOTE: This is not verified. | 70 | case GPU_REG_INDEX_WORKAROUND(memory_fill_config[0].trigger, 0x00004 + 0x3): |
| 71 | case GPU_REG_INDEX_WORKAROUND(memory_fill_config[0].value, 0x00004 + 0x3): | 71 | case GPU_REG_INDEX_WORKAROUND(memory_fill_config[1].trigger, 0x00008 + 0x3): |
| 72 | case GPU_REG_INDEX_WORKAROUND(memory_fill_config[1].value, 0x00008 + 0x3): | ||
| 73 | { | 72 | { |
| 74 | const bool is_second_filler = (index != GPU_REG_INDEX(memory_fill_config[0].value)); | 73 | const bool is_second_filler = (index != GPU_REG_INDEX(memory_fill_config[0].trigger)); |
| 75 | const auto& config = g_regs.memory_fill_config[is_second_filler]; | 74 | auto& config = g_regs.memory_fill_config[is_second_filler]; |
| 76 | 75 | ||
| 77 | // TODO: Not sure if this check should be done at GSP level instead | 76 | if (config.address_start && config.trigger) { |
| 78 | if (config.address_start) { | 77 | u8* start = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetStartAddress())); |
| 79 | // TODO: Not sure if this algorithm is correct, particularly because it doesn't use the size member at all | 78 | u8* end = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetEndAddress())); |
| 80 | u32* start = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetStartAddress())); | 79 | |
| 81 | u32* end = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetEndAddress())); | 80 | if (config.fill_24bit) { |
| 82 | for (u32* ptr = start; ptr < end; ++ptr) | 81 | // fill with 24-bit values |
| 83 | *ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation | 82 | for (u8* ptr = start; ptr < end; ptr += 3) { |
| 83 | ptr[0] = config.value_24bit_b; | ||
| 84 | ptr[1] = config.value_24bit_g; | ||
| 85 | ptr[2] = config.value_24bit_r; | ||
| 86 | } | ||
| 87 | } else if (config.fill_32bit) { | ||
| 88 | // fill with 32-bit values | ||
| 89 | for (u32* ptr = (u32*)start; ptr < (u32*)end; ++ptr) | ||
| 90 | *ptr = config.value_32bit; | ||
| 91 | } else { | ||
| 92 | // fill with 16-bit values | ||
| 93 | for (u16* ptr = (u16*)start; ptr < (u16*)end; ++ptr) | ||
| 94 | *ptr = config.value_16bit; | ||
| 95 | } | ||
| 84 | 96 | ||
| 85 | LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress()); | 97 | LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress()); |
| 86 | 98 | ||
| 99 | config.trigger = 0; | ||
| 100 | config.finished = 1; | ||
| 101 | |||
| 87 | if (!is_second_filler) { | 102 | if (!is_second_filler) { |
| 88 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0); | 103 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0); |
| 89 | } else { | 104 | } else { |
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index 9fd694f65..df9aa0d71 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h | |||
| @@ -84,9 +84,35 @@ struct Regs { | |||
| 84 | 84 | ||
| 85 | struct { | 85 | struct { |
| 86 | u32 address_start; | 86 | u32 address_start; |
| 87 | u32 address_end; // ? | 87 | u32 address_end; |
| 88 | u32 size; | 88 | |
| 89 | u32 value; // ? | 89 | union { |
| 90 | u32 value_32bit; | ||
| 91 | |||
| 92 | BitField<0, 16, u32> value_16bit; | ||
| 93 | |||
| 94 | // TODO: Verify component order | ||
| 95 | BitField< 0, 8, u32> value_24bit_r; | ||
| 96 | BitField< 8, 8, u32> value_24bit_g; | ||
| 97 | BitField<16, 8, u32> value_24bit_b; | ||
| 98 | }; | ||
| 99 | |||
| 100 | union { | ||
| 101 | u32 control; | ||
| 102 | |||
| 103 | // Setting this field to 1 triggers the memory fill. | ||
| 104 | // This field also acts as a status flag, and gets reset to 0 upon completion. | ||
| 105 | BitField<0, 1, u32> trigger; | ||
| 106 | |||
| 107 | // Set to 1 upon completion. | ||
| 108 | BitField<0, 1, u32> finished; | ||
| 109 | |||
| 110 | // 0: fill with 16- or 32-bit wide values; 1: fill with 24-bit wide values | ||
| 111 | BitField<8, 1, u32> fill_24bit; | ||
| 112 | |||
| 113 | // 0: fill with 16-bit wide values; 1: fill with 32-bit wide values | ||
| 114 | BitField<9, 1, u32> fill_32bit; | ||
| 115 | }; | ||
| 90 | 116 | ||
| 91 | inline u32 GetStartAddress() const { | 117 | inline u32 GetStartAddress() const { |
| 92 | return DecodeAddressRegister(address_start); | 118 | return DecodeAddressRegister(address_start); |