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 void reinitialize(const Configuration &config);
110
111 static constexpr uint32_t US_PER_HBLANK = 64;
112 static constexpr unsigned c_chainThreshold = 56;
113
120 unsigned getRefreshRate() const { return m_refreshRate; }
121
134 uint32_t getFrameCount() const { return m_previousFrameCount; }
135
149 unsigned getParity() const { return m_parity; }
150
158 void clear(Color bg = {{0, 0, 0}});
159
170 void getClear(Prim::FastFill &ff, Color bg = {{0, 0, 0}}) const;
171
183 void getNextClear(Prim::FastFill &ff, Color bg = {{0, 0, 0}}) const;
184
196 void uploadToVRAM(const uint16_t *data, Rect region);
197
221 void uploadToVRAM(const uint16_t *data, Rect region, eastl::function<void()> &&callback,
223
230 template <Fragment Frag>
231 void sendFragment(const Frag &fragment) {
232 sendFragment(reinterpret_cast<const uint32_t *>(&fragment.head + 1), fragment.getActualFragmentSize());
233 }
234
244 template <Fragment Frag>
245 void sendFragment(const Frag &fragment, eastl::function<void()> &&callback,
247 sendFragment(reinterpret_cast<const uint32_t *>(&fragment.head + 1), fragment.getActualFragmentSize(),
248 eastl::move(callback), dmaCallback);
249 }
250
254 void disableScissor();
255
262 void enableScissor();
263
271 void getScissor(Prim::Scissor &scissor);
272
281 void getNextScissor(Prim::Scissor &scissor);
282
286 void waitReady();
287
291 void waitFifo();
292
296 static void sendRaw(uint32_t data) { Hardware::GPU::Data = data; }
297
304 template <Primitive Prim>
305 void sendPrimitive(const Prim &primitive) {
306 waitReady();
307 const uint32_t *ptr = reinterpret_cast<const uint32_t *>(&primitive);
308 constexpr size_t size = sizeof(Prim) / sizeof(uint32_t);
309 for (int i = 0; i < size; i++) {
310 if constexpr (sizeof(Prim) > c_chainThreshold) waitFifo();
311 sendRaw(*ptr++);
312 }
313 }
314
328 template <Fragment Frag>
329 void chain(Frag &fragment) {
330 chain(&fragment.head, &fragment.head, fragment.getActualFragmentSize());
331 }
332
342 template <Fragment Frag1, Fragment Frag2>
343 void chain(Frag1 *first, Frag2 *last) {
344 auto count = last->getActualFragmentSize();
345 Kernel::assert(count <= (c_chainThreshold / 4), "Last element of the chain is too big");
346 chain(&first->head, &last->head, last->getActualFragmentSize());
347 }
348
357 template <size_t N, Safe safety = Safe::Yes>
359 chain(&table.m_table[N].head, &table.m_table[0].head, 0);
360 scheduleOTC(&table.m_table[N].head, N + 1);
361 }
362
368 void sendChain();
369
377 void sendChain(eastl::function<void()> &&callback, DMA::DmaCallback dmaCallback = DMA::FROM_MAIN_LOOP);
378
384 bool isChainIdle() const;
385
391 bool isChainTransferring() const;
392
398 bool isChainTransferred() const;
399
406 }
407
425 uint32_t now() const { return m_currentTime; }
426
444 uintptr_t armTimer(uint32_t deadline, eastl::function<void(uint32_t)> &&callback);
445
457 TimerAwaiter delay(uint32_t microseconds) { return {*this, now() + microseconds}; }
458
470 unsigned armPeriodicTimer(uint32_t period, eastl::function<void(uint32_t)> &&callback);
471
486 void changeTimerPeriod(uintptr_t id, uint32_t period, bool reset = false);
487
497 void pauseTimer(uintptr_t id);
498
508 void resumeTimer(uintptr_t id);
509
517 void cancelTimer(uintptr_t id);
518
527 void pumpCallbacks();
528
529 private:
530 GPU();
531 GPU(const GPU &) = delete;
532 GPU(GPU &&) = delete;
533 GPU &operator=(const GPU &) = delete;
534 GPU &operator=(GPU &&) = delete;
535 void sendFragment(const uint32_t *data, size_t count);
536 void sendFragment(const uint32_t *data, size_t count, eastl::function<void()> &&callback,
537 DMA::DmaCallback dmaCallback);
538 void scheduleNormalDMA(uintptr_t data, size_t count);
539 void scheduleChainedDMA(uintptr_t head);
540 void chain(uintptr_t *first, uintptr_t *last, size_t count);
541 void scheduleOTC(uintptr_t *start, uint32_t count);
542 void checkOTCAndTriggerCallback();
543 void prepareForTakeover();
544
545 eastl::function<void(void)> m_dmaCallback = nullptr;
546 unsigned m_refreshRate = 0;
547 int m_width = 0;
548 int m_height = 0;
549 uint32_t m_currentTime = 0;
550 uint32_t m_frameCount = 0;
551 uint32_t m_previousFrameCount = 0;
552 unsigned m_parity = 0;
553 uintptr_t *m_chainHead = nullptr;
554 uintptr_t *m_chainTail = nullptr;
555 size_t m_chainTailCount = 0;
556 enum { CHAIN_IDLE, CHAIN_TRANSFERRING, CHAIN_TRANSFERRED } m_chainStatus = CHAIN_IDLE;
557 struct Timer {
558 eastl::function<void(uint32_t)> callback;
559 uint32_t deadline;
560 uint32_t period;
561 int32_t pausedRemaining;
562 bool periodic;
563 bool paused = false;
564 };
565 eastl::fixed_list<Timer, 32> m_timers;
566 struct ScheduledOTC {
567 uintptr_t *start;
569 };
570 eastl::fixed_list<ScheduledOTC, 32> m_OTCs[2];
571 uintptr_t *m_chainNext = nullptr;
572
573 uint16_t m_lastHSyncCounter = 0;
574 bool m_interlaced = false;
575 bool m_fromISR = false;
576 bool m_flushCacheAfterDMA = false;
577
578 void flip();
579 friend class Application;
581};
582
583} // namespace psyqo
584
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:488
unsigned getParity() const
Get the index of the current display buffer.
Definition gpu.hh:149
void sendFragment(const Frag &fragment)
Immediately sends a fragment to the GPU. This is a blocking operation. See the fragments....
Definition gpu.hh:231
static constexpr uint32_t US_PER_HBLANK
Definition gpu.hh:111
void sendPrimitive(const Prim &primitive)
Sends a primitive to the GPU. This is a blocking call.
Definition gpu.hh:305
void waitChainIdle()
Waits until the background DMA transfer operation initiated by a frame flip is complete.
Definition gpu.hh:404
uint32_t getFrameCount() const
Returns the number of frames rendered by the GPU so far.
Definition gpu.hh:134
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: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:245
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:343
TimerAwaiter delay(uint32_t microseconds)
Delays the coroutine for a specified amount of time.
Definition gpu.hh:457
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:425
void chain(OrderingTable< N, safety > &table)
Chains an ordering table to the next DMA chain transfer.
Definition gpu.hh:358
void initialize(const Configuration &config)
Definition gpu.cpp:110
unsigned getRefreshRate() const
Returns the refresh rate of the GPU.
Definition gpu.hh:120
MiscSetting
Definition gpu.hh:107
void sendChain()
Immediately sends the current DMA chain.
Definition gpu.cpp:444
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: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:103
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:104
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:296
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:329
static constexpr unsigned c_chainThreshold
Definition gpu.hh:112
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 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:335
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