#include "graphics/host_gpu/renderer/sync.h" #include "common/assert.h" #include "graphics/host_gpu/renderer/cache/bufferCache.h" #include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/presentation/videoOut.h" #include "kernel/eventQueue.h" #include "kernel/pthread.h" #include "libs/errno.h" #include #include namespace Libs::Graphics::Sync { constexpr uint64_t GRAPHICS_REFERENCE_CLOCK_FREQUENCY = 100000000; bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t& value) { if (host_frequency == 0) { return false; } const auto whole_seconds = host_ticks / host_frequency; const auto remainder = host_ticks % host_frequency; constexpr auto MAX_VALUE = std::numeric_limits::max(); if (whole_seconds > MAX_VALUE / GRAPHICS_REFERENCE_CLOCK_FREQUENCY || remainder > MAX_VALUE / GRAPHICS_REFERENCE_CLOCK_FREQUENCY) { return false; } const auto whole_value = whole_seconds * GRAPHICS_REFERENCE_CLOCK_FREQUENCY; const auto fractional_value = (remainder * GRAPHICS_REFERENCE_CLOCK_FREQUENCY) / host_frequency; if (whole_value > MAX_VALUE - fractional_value) { return false; } value = whole_value + fractional_value; return true; } uint64_t ReadReferenceClock() { const auto host_frequency = LibKernel::KernelGetTscFrequency(); const auto host_ticks = LibKernel::KernelReadTsc(); uint64_t value = 0; if (!ScaleReferenceClock(host_ticks, host_frequency, value)) { EXIT("cannot scale host clock, ticks=0x%016" PRIx64 " frequency=%" PRIu64 "\n", host_ticks, host_frequency); } return value; } uint64_t PrepareVideoOutFlip(CommandBuffer& buffer, int handle, int index, int flip_mode, int64_t flip_arg) { for (;;) { uint64_t request_id = 0; auto& video_out = buffer.GetContext().GetVideoOut(); const auto result = video_out.SubmitFlipFromGpu(buffer, handle, index, flip_mode, flip_arg, request_id); if (result == OK) { EXIT_IF(request_id == 0); return request_id; } if (result != VideoOut::VIDEO_OUT_ERROR_FLIP_QUEUE_FULL) { EXIT("GPU flip submission failed, result=%d handle=%d index=%d mode=%d arg=%" PRId64 "\n", result, handle, index, flip_mode, flip_arg); } video_out.WaitForSubmitSlot(handle); } } static void InterruptEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) { EXIT_IF(event == nullptr); event->triggered = false; event->event.fflags = 0; event->event.data = 0; } static void InterruptEventTriggerFunc(LibKernel::EventQueue::KernelEqueueEvent* event, void* trigger_data) { EXIT_IF(event == nullptr); auto triggered_event = event->event; triggered_event.fflags++; triggered_event.data = reinterpret_cast(trigger_data); if (event->triggered) { event->pending_events.push_back(triggered_event); } else { event->event = triggered_event; event->triggered = true; } } int AddEqEvent(RenderContext& renderer, LibKernel::EventQueue::KernelEqueue eq, int id, void* udata) { LibKernel::EventQueue::KernelEqueueEvent event; event.triggered = false; event.event.ident = static_cast(id); event.event.filter = LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS; event.event.udata = udata; event.event.fflags = 0; event.event.data = id; event.filter.reset_func = InterruptEventResetFunc; event.filter.trigger_func = InterruptEventTriggerFunc; int result = LibKernel::EventQueue::KernelAddEvent(eq, event); if (result == 0) { renderer.AddInterruptEq(eq, id); } return result; } int DeleteEqEvent(RenderContext& renderer, LibKernel::EventQueue::KernelEqueue eq, int id) { int result = LibKernel::EventQueue::KernelDeleteEvent( eq, static_cast(id), LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS); if (result == OK || result == LibKernel::KERNEL_ERROR_ENOENT) { renderer.DeleteInterruptEq(eq, id); } return result; } void ReadGds(const Buffer& gds, uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) { const auto offset = uint64_t {dw_offset} * sizeof(uint32_t); const auto size = uint64_t {dw_size} * sizeof(uint32_t); EXIT_IF(dst == nullptr || offset > gds.Size() || size > gds.Size() - offset || gds.Mapped().empty()); std::memcpy(dst, gds.Mapped().data() + offset, static_cast(size)); } } // namespace Libs::Graphics::Sync