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 DMA {
51
56
57}
58
59namespace timer_literals {
60
69consteval uint32_t operator""_ns(unsigned long long int value) { return value / 1'000; }
70consteval uint32_t operator""_us(unsigned long long int value) { return value; }
71consteval uint32_t operator""_ms(unsigned long long int value) { return value * 1'000; }
72consteval uint32_t operator""_s(unsigned long long int value) { return value * 1'000'000; }
73consteval uint32_t operator""_ns(long double value) { return value / 1'000; }
74consteval uint32_t operator""_us(long double value) { return value; }
75consteval uint32_t operator""_ms(long double value) { return value * 1'000; }
76consteval uint32_t operator""_s(long double value) { return value * 1'000'000; }
77
78} // namespace timer_literals
79
88class GPU {
89 struct TimerAwaiter {
90 TimerAwaiter(GPU &gpu, uint32_t deadline) : m_gpu(gpu), m_deadline(deadline) {}
91 ~TimerAwaiter() {}
92 constexpr bool await_ready() const { return false; }
93 void await_suspend(std::coroutine_handle<> handle) {
94 m_gpu.armTimer(m_deadline, [handle](uint32_t) { handle.resume(); });
95 }
96 void await_resume() {}
97 GPU &m_gpu;
98 uintptr_t m_deadline;
99 };
100
101 public:
102 struct Configuration;
103 enum class Resolution { W256, W320, W368, W512, W640 };
104 enum class VideoMode { AUTO, NTSC, PAL };
105 enum class ColorMode { C15BITS, C24BITS };
108 void initialize(const Configuration &config);
109
110 static constexpr uint32_t US_PER_HBLANK = 64;
111 static constexpr unsigned c_chainThreshold = 56;
112
119 unsigned getRefreshRate() const { return m_refreshRate; }
120
133 uint32_t getFrameCount() const { return m_previousFrameCount; }
134
148 unsigned getParity() const { return m_parity; }
149
157 void clear(Color bg = {{0, 0, 0}});
158
169 void getClear(Prim::FastFill &ff, Color bg = {{0, 0, 0}}) const;
170
182 void getNextClear(Prim::FastFill &ff, Color bg = {{0, 0, 0}}) const;
183
195 void uploadToVRAM(const uint16_t *data, Rect region);
196
220 void uploadToVRAM(const uint16_t *data, Rect region, eastl::function<void()> &&callback,
222
229 template <Fragment Frag>
230 void sendFragment(const Frag &fragment) {
231 sendFragment(&fragment.head + 1, fragment.getActualFragmentSize());
232 }
233
243 template <Fragment Frag>
244 void sendFragment(const Frag &fragment, eastl::function<void()> &&callback,
246 sendFragment(&fragment.head + 1, fragment.getActualFragmentSize(), eastl::move(callback), dmaCallback);
247 }
248
252 void disableScissor();
253
260 void enableScissor();
261
269 void getScissor(Prim::Scissor &scissor);
270
279 void getNextScissor(Prim::Scissor &scissor);
280
284 void waitReady();
285
289 void waitFifo();
290
294 static void sendRaw(uint32_t data) { Hardware::GPU::Data = data; }
295
302 template <Primitive Prim>
303 void sendPrimitive(const Prim &primitive) {
304 waitReady();
305 const uint32_t *ptr = reinterpret_cast<const uint32_t *>(&primitive);
306 constexpr size_t size = sizeof(Prim) / sizeof(uint32_t);
307 for (int i = 0; i < size; i++) {
308 if constexpr (sizeof(Prim) > c_chainThreshold) waitFifo();
309 sendRaw(*ptr++);
310 }
311 }
312
326 template <Fragment Frag>
327 void chain(Frag &fragment) {
328 chain(&fragment.head, &fragment.head, fragment.getActualFragmentSize());
329 }
330
340 template <Fragment Frag1, Fragment Frag2>
341 void chain(Frag1 *first, Frag2 *last) {
342 auto count = last->getActualFragmentSize();
343 Kernel::assert(count <= (c_chainThreshold / 4), "Last element of the chain is too big");
344 chain(&first->head, &last->head, last->getActualFragmentSize());
345 }
346
355 template <size_t N, Safe safety = Safe::Yes>
357 chain(&table.m_table[N], &table.m_table[0], 0);
358 scheduleOTC(&table.m_table[N], N + 1);
359 }
360
366 void sendChain();
367
375 void sendChain(eastl::function<void()> &&callback, DMA::DmaCallback dmaCallback = DMA::FROM_MAIN_LOOP);
376
382 bool isChainIdle() const;
383
389 bool isChainTransferring() const;
390
396 bool isChainTransferred() const;
397
404 }
405
423 uint32_t now() const { return m_currentTime; }
424
442 uintptr_t armTimer(uint32_t deadline, eastl::function<void(uint32_t)> &&callback);
443
455 TimerAwaiter delay(uint32_t microseconds) { return {*this, now() + microseconds}; }
456
468 unsigned armPeriodicTimer(uint32_t period, eastl::function<void(uint32_t)> &&callback);
469
484 void changeTimerPeriod(uintptr_t id, uint32_t period, bool reset = false);
485
495 void pauseTimer(uintptr_t id);
496
506 void resumeTimer(uintptr_t id);
507
515 void cancelTimer(uintptr_t id);
516
525 void pumpCallbacks();
526
527 private:
528 GPU();
529 GPU(const GPU &) = delete;
530 GPU(GPU &&) = delete;
531 GPU &operator=(const GPU &) = delete;
532 GPU &operator=(GPU &&) = delete;
533 void sendFragment(const uint32_t *data, size_t count);
534 void sendFragment(const uint32_t *data, size_t count, eastl::function<void()> &&callback,
535 DMA::DmaCallback dmaCallback);
536 void scheduleNormalDMA(uintptr_t data, size_t count);
537 void scheduleChainedDMA(uintptr_t head);
538 void chain(uint32_t *first, uint32_t *last, size_t count);
539 void scheduleOTC(uint32_t *start, uint32_t count);
540 void checkOTCAndTriggerCallback();
541 void prepareForTakeover();
542
543 eastl::function<void(void)> m_dmaCallback = nullptr;
544 unsigned m_refreshRate = 0;
545 int m_width = 0;
546 int m_height = 0;
547 uint32_t m_currentTime = 0;
548 uint32_t m_frameCount = 0;
549 uint32_t m_previousFrameCount = 0;
550 unsigned m_parity = 0;
551 uint32_t *m_chainHead = nullptr;
552 uint32_t *m_chainTail = nullptr;
553 size_t m_chainTailCount = 0;
554 enum { CHAIN_IDLE, CHAIN_TRANSFERRING, CHAIN_TRANSFERRED } m_chainStatus = CHAIN_IDLE;
555 struct Timer {
556 eastl::function<void(uint32_t)> callback;
557 uint32_t deadline;
558 uint32_t period;
559 int32_t pausedRemaining;
560 bool periodic;
561 bool paused = false;
562 };
563 eastl::fixed_list<Timer, 32> m_timers;
564 struct ScheduledOTC {
565 uint32_t *start;
567 };
568 eastl::fixed_list<ScheduledOTC, 32> m_OTCs[2];
569 uint32_t *m_chainNext = nullptr;
570
571 uint16_t m_lastHSyncCounter = 0;
572 bool m_interlaced = false;
573 bool m_fromISR = false;
574 bool m_flushCacheAfterDMA = false;
575
576 void flip();
577 friend class Application;
579};
580
581} // namespace psyqo
582
The application class.
Definition application.hh:49
The singleton GPU class.
Definition gpu.hh:88
bool isChainIdle() const
Gets the status of the background DMA transfer operation when initiated by a frame flip.
Definition gpu.cpp:484
unsigned getParity() const
Get the index of the current display buffer.
Definition gpu.hh:148
void sendFragment(const Frag &fragment)
Immediately sends a fragment to the GPU. This is a blocking operation. See the fragments....
Definition gpu.hh:230
static constexpr uint32_t US_PER_HBLANK
Definition gpu.hh:110
void sendPrimitive(const Prim &primitive)
Sends a primitive to the GPU. This is a blocking call.
Definition gpu.hh:303
void waitChainIdle()
Waits until the background DMA transfer operation initiated by a frame flip is complete.
Definition gpu.hh:402
uint32_t getFrameCount() const
Returns the number of frames rendered by the GPU so far.
Definition gpu.hh:133
Interlace
Definition gpu.hh:106
uintptr_t armTimer(uint32_t deadline, eastl::function< void(uint32_t)> &&callback)
Creates a single-use timer.
Definition gpu.cpp:499
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:244
void disableScissor()
Immediately disables the scissoring of the VRAM.
Definition gpu.cpp:262
void getClear(Prim::FastFill &ff, Color bg={{0, 0, 0}}) const
Sets a FastFill primitive to clear the current drawing buffer.
Definition gpu.cpp:301
void chain(Frag1 *first, Frag2 *last)
Chains an already constructed DMA chain to the next DMA chain transfer.
Definition gpu.hh:341
TimerAwaiter delay(uint32_t microseconds)
Delays the coroutine for a specified amount of time.
Definition gpu.hh:455
unsigned armPeriodicTimer(uint32_t period, eastl::function< void(uint32_t)> &&callback)
Creates a periodic timer.
Definition gpu.cpp:504
void enableScissor()
Enables the scissoring of the VRAM.
Definition gpu.cpp:267
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:284
uint32_t now() const
Gets the current timestamp in microseconds.
Definition gpu.hh:423
void chain(OrderingTable< N, safety > &table)
Chains an ordering table to the next DMA chain transfer.
Definition gpu.hh:356
void initialize(const Configuration &config)
Definition gpu.cpp:54
unsigned getRefreshRate() const
Returns the refresh rate of the GPU.
Definition gpu.hh:119
MiscSetting
Definition gpu.hh:107
void sendChain()
Immediately sends the current DMA chain.
Definition gpu.cpp:440
ColorMode
Definition gpu.hh:105
void changeTimerPeriod(uintptr_t id, uint32_t period, bool reset=false)
Changes the period of a periodic timer.
Definition gpu.cpp:509
void pauseTimer(uintptr_t id)
Pauses a timer.
Definition gpu.cpp:525
void pumpCallbacks()
Runs one round of event processing.
Definition gpu.cpp:553
Resolution
Definition gpu.hh:103
void cancelTimer(uintptr_t id)
Cancels a timer.
Definition gpu.cpp:545
bool isChainTransferred() const
Gets the status of the background DMA transfer operation when initiated by a frame flip.
Definition gpu.cpp:494
VideoMode
Definition gpu.hh:104
void uploadToVRAM(const uint16_t *data, Rect region)
Uploads a buffer to the VRAM as a blocking call.
Definition gpu.cpp:317
void getNextClear(Prim::FastFill &ff, Color bg={{0, 0, 0}}) const
Sets a FastFill primitive to clear the next drawing buffer.
Definition gpu.cpp:309
static void sendRaw(uint32_t data)
Sends a raw 32 bits value to the Data register of the GPU.
Definition gpu.hh:294
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:535
bool isChainTransferring() const
Gets the status of the background DMA transfer operation when initiated by a frame flip.
Definition gpu.cpp:489
void clear(Color bg={{0, 0, 0}})
Immediately clears the drawing buffer.
Definition gpu.cpp:295
void chain(Frag &fragment)
Chains a fragment to the next DMA chain transfer.
Definition gpu.hh:327
static constexpr unsigned c_chainThreshold
Definition gpu.hh:111
void getScissor(Prim::Scissor &scissor)
Gets the current scissoring region.
Definition gpu.cpp:273
The ordering table. Used to sort fragments before sending them to the GPU.
Definition ordering-table.hh:59
volatile uint32_t * ptr
Definition cop0.c:80
DmaCallback
Definition gpu.hh:52
@ FROM_MAIN_LOOP
Definition gpu.hh:54
@ FROM_ISR
Definition gpu.hh:53
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:300
void takeOverKernel()
Takes over the kernel. Can only be called once inside the main function.
Definition kernel.cpp:135
Definition cdrom-loader.hh:39
static int size
Definition string.h:32
Definition main.c:101
Definition configuration.hh:29
A compounded Scissor primitive.
Definition control.hh:156
static int value
Definition syscalls.h:534
static const void size_t count
Definition syscalls.h:145
void void(ptr, size)
void uint32_t(classId, spec)
Definition gpu.h:109
The Color struct.
Definition common.hh:91