diff options
Diffstat (limited to 'src/video_core/gpu.cpp')
-rw-r--r-- | src/video_core/gpu.cpp | 185 |
1 files changed, 173 insertions, 12 deletions
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 88c45a423..d3d32a359 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -3,6 +3,8 @@ // Refer to the license.txt file included. #include "common/assert.h" +#include "core/core_timing.h" +#include "core/memory.h" #include "video_core/engines/fermi_2d.h" #include "video_core/engines/kepler_memory.h" #include "video_core/engines/maxwell_3d.h" @@ -102,6 +104,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { return 1; default: UNIMPLEMENTED_MSG("Unimplemented render target format {}", static_cast<u32>(format)); + return 1; } } @@ -119,12 +122,40 @@ u32 DepthFormatBytesPerPixel(DepthFormat format) { return 2; default: UNIMPLEMENTED_MSG("Unimplemented Depth format {}", static_cast<u32>(format)); + return 1; } } +// Note that, traditionally, methods are treated as 4-byte addressable locations, and hence +// their numbers are written down multiplied by 4 in Docs. Here we are not multiply by 4. +// So the values you see in docs might be multiplied by 4. enum class BufferMethods { - BindObject = 0, - CountBufferMethods = 0x40, + BindObject = 0x0, + Nop = 0x2, + SemaphoreAddressHigh = 0x4, + SemaphoreAddressLow = 0x5, + SemaphoreSequence = 0x6, + SemaphoreTrigger = 0x7, + NotifyIntr = 0x8, + WrcacheFlush = 0x9, + Unk28 = 0xA, + Unk2c = 0xB, + RefCnt = 0x14, + SemaphoreAcquire = 0x1A, + SemaphoreRelease = 0x1B, + Unk70 = 0x1C, + Unk74 = 0x1D, + Unk78 = 0x1E, + Unk7c = 0x1F, + Yield = 0x20, + NonPullerMethods = 0x40, +}; + +enum class GpuSemaphoreOperation { + AcquireEqual = 0x1, + WriteLong = 0x2, + AcquireGequal = 0x4, + AcquireMask = 0x8, }; void GPU::CallMethod(const MethodCall& method_call) { @@ -133,20 +164,78 @@ void GPU::CallMethod(const MethodCall& method_call) { ASSERT(method_call.subchannel < bound_engines.size()); - if (method_call.method == static_cast<u32>(BufferMethods::BindObject)) { - // Bind the current subchannel to the desired engine id. - LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel, - method_call.argument); - bound_engines[method_call.subchannel] = static_cast<EngineID>(method_call.argument); - return; + if (ExecuteMethodOnEngine(method_call)) { + CallEngineMethod(method_call); + } else { + CallPullerMethod(method_call); } +} - if (method_call.method < static_cast<u32>(BufferMethods::CountBufferMethods)) { - // TODO(Subv): Research and implement these methods. - LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented"); - return; +bool GPU::ExecuteMethodOnEngine(const MethodCall& method_call) { + const auto method = static_cast<BufferMethods>(method_call.method); + return method >= BufferMethods::NonPullerMethods; +} + +void GPU::CallPullerMethod(const MethodCall& method_call) { + regs.reg_array[method_call.method] = method_call.argument; + const auto method = static_cast<BufferMethods>(method_call.method); + + switch (method) { + case BufferMethods::BindObject: { + ProcessBindMethod(method_call); + break; } + case BufferMethods::Nop: + case BufferMethods::SemaphoreAddressHigh: + case BufferMethods::SemaphoreAddressLow: + case BufferMethods::SemaphoreSequence: + case BufferMethods::RefCnt: + break; + case BufferMethods::SemaphoreTrigger: { + ProcessSemaphoreTriggerMethod(); + break; + } + case BufferMethods::NotifyIntr: { + // TODO(Kmather73): Research and implement this method. + LOG_ERROR(HW_GPU, "Special puller engine method NotifyIntr not implemented"); + break; + } + case BufferMethods::WrcacheFlush: { + // TODO(Kmather73): Research and implement this method. + LOG_ERROR(HW_GPU, "Special puller engine method WrcacheFlush not implemented"); + break; + } + case BufferMethods::Unk28: { + // TODO(Kmather73): Research and implement this method. + LOG_ERROR(HW_GPU, "Special puller engine method Unk28 not implemented"); + break; + } + case BufferMethods::Unk2c: { + // TODO(Kmather73): Research and implement this method. + LOG_ERROR(HW_GPU, "Special puller engine method Unk2c not implemented"); + break; + } + case BufferMethods::SemaphoreAcquire: { + ProcessSemaphoreAcquire(); + break; + } + case BufferMethods::SemaphoreRelease: { + ProcessSemaphoreRelease(); + break; + } + case BufferMethods::Yield: { + // TODO(Kmather73): Research and implement this method. + LOG_ERROR(HW_GPU, "Special puller engine method Yield not implemented"); + break; + } + default: + LOG_ERROR(HW_GPU, "Special puller engine method {:X} not implemented", + static_cast<u32>(method)); + break; + } +} +void GPU::CallEngineMethod(const MethodCall& method_call) { const EngineID engine = bound_engines[method_call.subchannel]; switch (engine) { @@ -170,4 +259,76 @@ void GPU::CallMethod(const MethodCall& method_call) { } } +void GPU::ProcessBindMethod(const MethodCall& method_call) { + // Bind the current subchannel to the desired engine id. + LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel, + method_call.argument); + bound_engines[method_call.subchannel] = static_cast<EngineID>(method_call.argument); +} + +void GPU::ProcessSemaphoreTriggerMethod() { + const auto semaphoreOperationMask = 0xF; + const auto op = + static_cast<GpuSemaphoreOperation>(regs.semaphore_trigger & semaphoreOperationMask); + if (op == GpuSemaphoreOperation::WriteLong) { + auto address = memory_manager->GpuToCpuAddress(regs.smaphore_address.SmaphoreAddress()); + struct Block { + u32 sequence; + u32 zeros = 0; + u64 timestamp; + }; + + Block block{}; + block.sequence = regs.semaphore_sequence; + // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of + // CoreTiming + block.timestamp = CoreTiming::GetTicks(); + Memory::WriteBlock(*address, &block, sizeof(block)); + } else { + const auto address = + memory_manager->GpuToCpuAddress(regs.smaphore_address.SmaphoreAddress()); + const u32 word = Memory::Read32(*address); + if ((op == GpuSemaphoreOperation::AcquireEqual && word == regs.semaphore_sequence) || + (op == GpuSemaphoreOperation::AcquireGequal && + static_cast<s32>(word - regs.semaphore_sequence) > 0) || + (op == GpuSemaphoreOperation::AcquireMask && (word & regs.semaphore_sequence))) { + // Nothing to do in this case + } else { + regs.acquire_source = true; + regs.acquire_value = regs.semaphore_sequence; + if (op == GpuSemaphoreOperation::AcquireEqual) { + regs.acquire_active = true; + regs.acquire_mode = false; + } else if (op == GpuSemaphoreOperation::AcquireGequal) { + regs.acquire_active = true; + regs.acquire_mode = true; + } else if (op == GpuSemaphoreOperation::AcquireMask) { + // TODO(kemathe) The acquire mask operation waits for a value that, ANDed with + // semaphore_sequence, gives a non-0 result + LOG_ERROR(HW_GPU, "Invalid semaphore operation AcquireMask not implemented"); + } else { + LOG_ERROR(HW_GPU, "Invalid semaphore operation"); + } + } + } +} + +void GPU::ProcessSemaphoreRelease() { + const auto address = memory_manager->GpuToCpuAddress(regs.smaphore_address.SmaphoreAddress()); + Memory::Write32(*address, regs.semaphore_release); +} + +void GPU::ProcessSemaphoreAcquire() { + const auto address = memory_manager->GpuToCpuAddress(regs.smaphore_address.SmaphoreAddress()); + const u32 word = Memory::Read32(*address); + const auto value = regs.semaphore_acquire; + if (word != value) { + regs.acquire_active = true; + regs.acquire_value = value; + // TODO(kemathe73) figure out how to do the acquire_timeout + regs.acquire_mode = false; + regs.acquire_source = false; + } +} + } // namespace Tegra |