Nugget
Loading...
Searching...
No Matches
gpu.hh
Go to the documentation of this file.
1/*
2
3MIT License
4
5Copyright (c) 2022 PCSX-Redux authors
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26
27#pragma once
28
29#include <EASTL/array.h>
30#include <EASTL/atomic.h>
31#include <EASTL/fixed_list.h>
32#include <EASTL/functional.h>
33#include <EASTL/utility.h>
34#include <stdint.h>
35
36#include <coroutine>
37
39#include "psyqo/hardware/gpu.hh"
40#include "psyqo/kernel.hh"
46#include "psyqo/shared.hh"
47
48namespace psyqo {
49
50namespace timer_literals {
51
60consteval uint32_t operator""_ns(unsigned long long int value) { return value / 1'000; }
61consteval uint32_t operator""_us(unsigned long long int value) { return value; }
62consteval uint32_t operator""_ms(unsigned long long int value) { return value * 1'000; }
63consteval uint32_t operator""_s(unsigned long long int value) { return value * 1'000'000; }
64consteval uint32_t operator""_ns(long double value) { return value / 1'000; }
65consteval uint32_t operator""_us(long double value) { return value; }
66consteval uint32_t operator""_ms(long double value) { return value * 1'000; }
67consteval uint32_t operator""_s(long double value) { return value * 1'000'000; }
68
69} // namespace timer_literals
70
79class GPU {
80 struct TimerAwaiter {
81 TimerAwaiter(GPU &gpu, uint32_t deadline) : m_gpu(gpu), m_deadline(deadline) {}
82 ~TimerAwaiter() {}
83 constexpr bool await_ready() const { return false; }
84 void await_suspend(std::coroutine_handle<> handle) {
85 m_gpu.armTimer(m_deadline, [handle](uint32_t) { handle.resume(); });
86 }
87 void await_resume() {}
88 GPU &m_gpu;
89 uintptr_t m_deadline;
90 };
91
92 public:
93 struct Configuration;
94 enum class Resolution { W256, W320, W368, W512, W640 };
95 enum class VideoMode { AUTO, NTSC, PAL };
96 enum class ColorMode { C15BITS, C24BITS };
99 void initialize(const Configuration &config);
100 void reinitialize(const Configuration &config);
101
102 static constexpr uint32_t US_PER_HBLANK = 64;
103 static constexpr unsigned c_chainThreshold = 56;
104
111 unsigned getRefreshRate() const { return m_refreshRate; }
112
125 uint32_t getFrameCount() const { return m_previousFrameCount; }
126
140 unsigned getParity() const { return m_parity; }
141
149 void clear(Color bg = {{0, 0, 0}});
150
161 void getClear(Prim::FastFill &ff, Color bg = {{0, 0, 0}}) const;
162
174 void getNextClear(Prim::FastFill &ff, Color bg = {{0, 0, 0}}) const;
175
187 void uploadToVRAM(const uint16_t *data, Rect region);
188
212 void uploadToVRAM(const uint16_t *data, Rect region, eastl::function<void()> &&callback,
214
221 template <Fragment Frag>
222 void sendFragment(const Frag &fragment) {
223 sendFragment(reinterpret_cast<const uint32_t *>(&fragment.head + 1), fragment.getActualFragmentSize());
224 }
225
235 template <Fragment Frag>
236 void sendFragment(const Frag &fragment, eastl::function<void()> &&callback,
238 sendFragment(reinterpret_cast<const uint32_t *>(&fragment.head + 1), fragment.getActualFragmentSize(),
239 eastl::move(callback), dmaCallback);
240 }
241
245 void disableScissor();
246
253 void enableScissor();
254
262 void getScissor(Prim::Scissor &scissor);
263
272 void getNextScissor(Prim::Scissor &scissor);
273
277 void waitReady();
278
282 void waitFifo();
283
287 static void sendRaw(uint32_t data) { Hardware::GPU::Data = data; }
288
295 template <Primitive Prim>
296 void sendPrimitive(const Prim &primitive) {
297 waitReady();
298 const uint32_t *ptr = reinterpret_cast<const uint32_t *>(&primitive);
299 constexpr size_t size = sizeof(Prim) / sizeof(uint32_t);
300 for (int i = 0; i < size; i++) {
301 if constexpr (sizeof(Prim) > c_chainThreshold) waitFifo();
302 sendRaw(*ptr++);
303 }
304 }
305
319 template <Fragment Frag>
320 void chain(Frag &fragment) {
321 chain(&fragment.head, &fragment.head, fragment.getActualFragmentSize());
322 }
323
333 template <Fragment Frag1, Fragment Frag2>
334 void chain(Frag1 *first, Frag2 *last) {
335 auto count = last->getActualFragmentSize();
336 Kernel::assert(count <= (c_chainThreshold / 4), "Last element of the chain is too big");
337 chain(&first->head, &last->head, last->getActualFragmentSize());
338 }
339
348 template <size_t N, Safe safety = Safe::Yes>
350 chain(&table.m_table[N].head, &table.m_table[0].head, 0);
351 scheduleOTC(&table.m_table[N].head, N + 1);
352 }
353
359 void sendChain();
360
368 void sendChain(eastl::function<void()> &&callback, DMA::DmaCallback dmaCallback = DMA::FROM_MAIN_LOOP);
369
375 bool isChainIdle() const;
376
382 bool isChainTransferring() const;
383
389 bool isChainTransferred() const;
390
397 }
398
416 uint32_t now() const { return m_currentTime; }
417
435 uintptr_t armTimer(uint32_t deadline, eastl::function<void(uint32_t)> &&callback);
436
448 TimerAwaiter delay(uint32_t microseconds) { return {*this, now() + microseconds}; }
449
461 unsigned armPeriodicTimer(uint32_t period, eastl::function<void(uint32_t)> &&callback);
462
477 void changeTimerPeriod(uintptr_t id, uint32_t period, bool reset = false);
478
488 void pauseTimer(uintptr_t id);
489
499 void resumeTimer(uintptr_t id);
500
508 void cancelTimer(uintptr_t id);
509
518 void pumpCallbacks();
519
520 private:
521 GPU();
522 GPU(const GPU &) = delete;
523 GPU(GPU &&) = delete;
524 GPU &operator=(const GPU &) = delete;
525 GPU &operator=(GPU &&) = delete;
526 void sendFragment(const uint32_t *data, size_t count);
527 void sendFragment(const uint32_t *data, size_t count, eastl::function<void()> &&callback,
528 DMA::DmaCallback dmaCallback);
529 void scheduleNormalDMA(uintptr_t data, size_t count);
530 void scheduleChainedDMA(uintptr_t head);
531 void chain(uintptr_t *first, uintptr_t *last, size_t count);
532 void scheduleOTC(uintptr_t *start, uint32_t count);
533 void checkOTCAndTriggerCallback();
534 void prepareForTakeover();
535
536 eastl::function<void(void)> m_dmaCallback = nullptr;
537 unsigned m_refreshRate = 0;
538 int m_width = 0;
539 int m_height = 0;
540 uint32_t m_currentTime = 0;
541 uint32_t m_frameCount = 0;
542 uint32_t m_previousFrameCount = 0;
543 unsigned m_parity = 0;
544 uintptr_t *m_chainHead = nullptr;
545 uintptr_t *m_chainTail = nullptr;
546 size_t m_chainTailCount = 0;
547 enum { CHAIN_IDLE, CHAIN_TRANSFERRING, CHAIN_TRANSFERRED } m_chainStatus = CHAIN_IDLE;
548 struct Timer {
549 eastl::function<void(uint32_t)> callback;
550 uint32_t deadline;
551 uint32_t period;
552 int32_t pausedRemaining;
553 bool periodic;
554 bool paused = false;
555 };
556 eastl::fixed_list<Timer, 32> m_timers;
557 struct ScheduledOTC {
558 uintptr_t *start;
560 };
561 eastl::fixed_list<ScheduledOTC, 32> m_OTCs[2];
562 uintptr_t *m_chainNext = nullptr;
563
564 uint16_t m_lastHSyncCounter = 0;
565 bool m_interlaced = false;
566 bool m_fromISR = false;
567 bool m_flushCacheAfterDMA = false;
568
569 void flip();
570 friend class Application;
572};
573
574} // namespace psyqo
575
The application class.
Definition application.hh:49
The singleton GPU class.
Definition gpu.hh:79
bool isChainIdle() const
Gets the status of the background DMA transfer operation when initiated by a frame flip.
Definition gpu.cpp:488
unsigned getParity() const
Get the index of the current display buffer.
Definition gpu.hh:140
void sendFragment(const Frag &fragment)
Immediately sends a fragment to the GPU. This is a blocking operation. See the fragments....
Definition gpu.hh:222
static constexpr uint32_t US_PER_HBLANK
Definition gpu.hh:102
void sendPrimitive(const Prim &primitive)
Sends a primitive to the GPU. This is a blocking call.
Definition gpu.hh:296
void waitChainIdle()
Waits until the background DMA transfer operation initiated by a frame flip is complete.
Definition gpu.hh:395
uint32_t getFrameCount() const
Returns the number of frames rendered by the GPU so far.
Definition gpu.hh:125
Interlace
Definition gpu.hh:97
uintptr_t armTimer(uint32_t deadline, eastl::function< void(uint32_t)> &&callback)
Creates a single-use timer.
Definition gpu.cpp:503
void sendFragment(const Frag &fragment, eastl::function< void()> &&callback, DMA::DmaCallback dmaCallback=DMA::FROM_MAIN_LOOP)
Sends a fragment to the GPU as a non-blocking call.
Definition gpu.hh:236
void disableScissor()
Immediately disables the scissoring of the VRAM.
Definition gpu.cpp:266
void getClear(Prim::FastFill &ff, Color bg={{0, 0, 0}}) const
Sets a FastFill primitive to clear the current drawing buffer.
Definition gpu.cpp:305
void chain(Frag1 *first, Frag2 *last)
Chains an already constructed DMA chain to the next DMA chain transfer.
Definition gpu.hh:334
TimerAwaiter delay(uint32_t microseconds)
Delays the coroutine for a specified amount of time.
Definition gpu.hh:448
unsigned armPeriodicTimer(uint32_t period, eastl::function< void(uint32_t)> &&callback)
Creates a periodic timer.
Definition gpu.cpp:508
void enableScissor()
Enables the scissoring of the VRAM.
Definition gpu.cpp:271
void waitReady()
Waits until the GPU is ready to send a command.
Definition gpu.cpp:42
void getNextScissor(Prim::Scissor &scissor)
Gets the next scissoring region.
Definition gpu.cpp:288
void reinitialize(const Configuration &config)
Definition gpu.cpp:54
uint32_t now() const
Gets the current timestamp in microseconds.
Definition gpu.hh:416
void chain(OrderingTable< N, safety > &table)
Chains an ordering table to the next DMA chain transfer.
Definition gpu.hh:349
void initialize(const Configuration &config)
Definition gpu.cpp:110
unsigned getRefreshRate() const
Returns the refresh rate of the GPU.
Definition gpu.hh:111
MiscSetting
Definition gpu.hh:98
void sendChain()
Immediately sends the current DMA chain.
Definition gpu.cpp:444
ColorMode
Definition gpu.hh:96
void changeTimerPeriod(uintptr_t id, uint32_t period, bool reset=false)
Changes the period of a periodic timer.
Definition gpu.cpp:513
void pauseTimer(uintptr_t id)
Pauses a timer.
Definition gpu.cpp:529
void pumpCallbacks()
Runs one round of event processing.
Definition gpu.cpp:557
Resolution
Definition gpu.hh:94
void cancelTimer(uintptr_t id)
Cancels a timer.
Definition gpu.cpp:549
bool isChainTransferred() const
Gets the status of the background DMA transfer operation when initiated by a frame flip.
Definition gpu.cpp:498
VideoMode
Definition gpu.hh:95
void uploadToVRAM(const uint16_t *data, Rect region)
Uploads a buffer to the VRAM as a blocking call.
Definition gpu.cpp:321
void getNextClear(Prim::FastFill &ff, Color bg={{0, 0, 0}}) const
Sets a FastFill primitive to clear the next drawing buffer.
Definition gpu.cpp:313
static void sendRaw(uint32_t data)
Sends a raw 32 bits value to the Data register of the GPU.
Definition gpu.hh:287
void waitFifo()
Waits until the GPU's FIFO is ready to receive data.
Definition gpu.cpp:48
void resumeTimer(uintptr_t id)
Resumes a paused timer.
Definition gpu.cpp:539
bool isChainTransferring() const
Gets the status of the background DMA transfer operation when initiated by a frame flip.
Definition gpu.cpp:493
void clear(Color bg={{0, 0, 0}})
Immediately clears the drawing buffer.
Definition gpu.cpp:299
void chain(Frag &fragment)
Chains a fragment to the next DMA chain transfer.
Definition gpu.hh:320
static constexpr unsigned c_chainThreshold
Definition gpu.hh:103
void getScissor(Prim::Scissor &scissor)
Gets the current scissoring region.
Definition gpu.cpp:277
The ordering table. Used to sort fragments before sending them to the GPU.
Definition ordering-table.hh:60
psyqo::Fragments::ChainEntry m_table[N+1]
Definition ordering-table.hh:102
volatile uint32_t * ptr
Definition cop0.c:80
int i
Definition gte-regio.c:287
DmaCallback
Definition kernel.hh:38
@ FROM_MAIN_LOOP
Definition kernel.hh:40
Register< 0x0810 > Data
Definition gpu.cpp:29
void assert(bool condition, const char *message, std::source_location location=std::source_location::current())
A simple assert macro.
Definition kernel.hh:357
void takeOverKernel()
Takes over the kernel. Can only be called once inside the main function.
Definition kernel.cpp:140
Definition lua.hh:38
#define head
Definition alloc.c:109
static int size
Definition string.h:32
Definition main.c:100
uintptr_t head
Definition fragments.hh:89
Definition configuration.hh:29
A compounded Scissor primitive.
Definition control.hh:156
static int value
Definition syscalls.h:535
static const void size_t count
Definition syscalls.h:146
void void(ptr, size)
void uint32_t(classId, spec)
Definition gpu.h:109
The Color struct.
Definition common.hh:91