From 4ea1b823d6ef72a9142cfaca209930743aa30b0f Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 4 Oct 2024 20:55:20 -0700 Subject: [PATCH] Fixing chainprint, and adding a chain example. --- .../psyqo/examples/hello-chained/Makefile | 12 ++ .../examples/hello-chained/hello-chained.cpp | 119 ++++++++++++++++++ src/mips/psyqo/font.hh | 12 +- src/mips/psyqo/src/font.cpp | 58 ++++----- 4 files changed, 166 insertions(+), 35 deletions(-) create mode 100644 src/mips/psyqo/examples/hello-chained/Makefile create mode 100644 src/mips/psyqo/examples/hello-chained/hello-chained.cpp diff --git a/src/mips/psyqo/examples/hello-chained/Makefile b/src/mips/psyqo/examples/hello-chained/Makefile new file mode 100644 index 000000000..43509784b --- /dev/null +++ b/src/mips/psyqo/examples/hello-chained/Makefile @@ -0,0 +1,12 @@ +TARGET = hello-chained +TYPE = ps-exe + +SRCS = \ +hello-chained.cpp \ + +ifeq ($(TEST),true) +CPPFLAGS = -Werror +endif +CXXFLAGS = -std=c++20 + +include ../../psyqo.mk diff --git a/src/mips/psyqo/examples/hello-chained/hello-chained.cpp b/src/mips/psyqo/examples/hello-chained/hello-chained.cpp new file mode 100644 index 000000000..524642559 --- /dev/null +++ b/src/mips/psyqo/examples/hello-chained/hello-chained.cpp @@ -0,0 +1,119 @@ +/* + +MIT License + +Copyright (c) 2024 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "psyqo/application.hh" +#include "psyqo/font.hh" +#include "psyqo/fragments.hh" +#include "psyqo/gpu.hh" +#include "psyqo/primitives/misc.hh" +#include "psyqo/scene.hh" + +namespace { + +// This is the same hello world example, but using chained DMA calls +// instead of the normal immediate calls. Only the difference is +// going to be documented throughout this file. +class HelloChained final : public psyqo::Application { + void prepare() override; + void createScene() override; + + public: + psyqo::Font<> m_systemFont; + psyqo::Font<> m_romFont; +}; + +class HelloChainedScene final : public psyqo::Scene { + void frame() override; + + uint8_t m_anim = 0; + bool m_direction = true; + + // We need two FastFill fragments to hold our clear commands + // while double buffering. We can't use the same fragment + // for two frames in a row, because the GPU will still be + // processing the previous frame's commands. + psyqo::Fragments::SimpleFragment m_clear[2]; +}; + +HelloChained helloChained; +HelloChainedScene helloChainedScene; + +} // namespace + +void HelloChained::prepare() { + psyqo::GPU::Configuration config; + config.set(psyqo::GPU::Resolution::W320) + .set(psyqo::GPU::VideoMode::AUTO) + .set(psyqo::GPU::ColorMode::C15BITS) + .set(psyqo::GPU::Interlace::PROGRESSIVE); + gpu().initialize(config); +} + +void HelloChained::createScene() { + m_systemFont.uploadSystemFont(gpu()); + m_romFont.uploadKromFont(gpu(), {{.x = 960, .y = int16_t(512 - 48 - 90)}}); + pushScene(&helloChainedScene); +} + +void HelloChainedScene::frame() { + if (m_anim == 0) { + m_direction = true; + } else if (m_anim == 255) { + m_direction = false; + } + psyqo::Color bg{{.r = 0, .g = 64, .b = 91}}; + bg.r = m_anim; + // We need to get the current parity to know which fragment to use + // from our double buffer. + auto parity = gpu().getParity(); + // Get a reference to the fragment we're going to use this frame + // to clear the screen. + auto& clear = m_clear[parity]; + // We're currently computing the next frame that'll be drawn by + // the GPU, while the GPU is still processing the previous frame. + // Therefore, we need to grab the next clear command from the GPU + // and chain it. + gpu().getNextClear(clear.primitive, bg); + gpu().chain(clear); + + if (m_direction) { + m_anim++; + } else { + m_anim--; + } + + psyqo::Color c = {{.r = 255, .g = 255, .b = uint8_t(255 - m_anim)}}; + // Finally, chain some text to be printed on the screen. Each + // Font<> object has its own set of fragments. The default is 16, + // which means 8 text fragments can be displayed per frame. If + // more than 8 fragments are chained, there will be corruption. + // More fragments can be added by increasing the template parameter + // of the Font<> object. + helloChained.m_systemFont.chainprint(gpu(), "Hello World!", {{.x = 16, .y = 32}}, c); + helloChained.m_romFont.chainprint(gpu(), "Hello World!", {{.x = 16, .y = 64}}, c); +} + +int main() { return helloChained.run(); } diff --git a/src/mips/psyqo/font.hh b/src/mips/psyqo/font.hh index b9ddb4edc..138de16e9 100644 --- a/src/mips/psyqo/font.hh +++ b/src/mips/psyqo/font.hh @@ -158,12 +158,12 @@ class FontBase { Prim::TPage tpage; }; typedef Fragments::FixedFragmentWithPrologue GlyphsFragment; - virtual GlyphsFragment& getGlyphFragment(bool increment) = 0; + virtual GlyphsFragment* getGlyphFragment(bool increment) = 0; virtual void forEach(eastl::function&& cb) = 0; - void innerprint(GlyphsFragment& fragment, GPU& gpu, eastl::string_view text, Vertex pos, Color color); - void innerprint(GlyphsFragment& fragment, GPU& gpu, const char* text, Vertex pos, Color color); - void innervprintf(GlyphsFragment& fragment, GPU& gpu, Vertex pos, Color color, const char* format, va_list ap); + void innerprint(GlyphsFragment* fragment, GPU& gpu, eastl::string_view text, Vertex pos, Color color); + void innerprint(GlyphsFragment* fragment, GPU& gpu, const char* text, Vertex pos, Color color); + void innervprintf(GlyphsFragment* fragment, GPU& gpu, Vertex pos, Color color, const char* format, va_list ap); private: struct XPrintfInfo; @@ -180,8 +180,8 @@ class Font : public FontBase { virtual ~Font() { static_assert(N > 0, "Needs to have at least one fragment"); } private: - virtual GlyphsFragment& getGlyphFragment(bool increment) override { - auto& fragment = m_fragments[m_index]; + virtual GlyphsFragment* getGlyphFragment(bool increment) override { + auto fragment = &m_fragments[m_index]; if (increment) { if (++m_index == N) { m_index = 0; diff --git a/src/mips/psyqo/src/font.cpp b/src/mips/psyqo/src/font.cpp index 0fcc78479..d02a0f23d 100644 --- a/src/mips/psyqo/src/font.cpp +++ b/src/mips/psyqo/src/font.cpp @@ -291,34 +291,34 @@ void psyqo::FontBase::print(GPU& gpu, const char* text, Vertex pos, Color color) void psyqo::FontBase::print(GPU& gpu, eastl::string_view text, Vertex pos, Color color, eastl::function&& callback, DMA::DmaCallback dmaCallback) { - auto& fragment = getGlyphFragment(false); + auto fragment = getGlyphFragment(false); innerprint(fragment, gpu, text, pos, color); - gpu.sendFragment(fragment, eastl::move(callback), dmaCallback); + gpu.sendFragment(*fragment, eastl::move(callback), dmaCallback); } void psyqo::FontBase::print(GPU& gpu, const char* text, Vertex pos, Color color, eastl::function&& callback, DMA::DmaCallback dmaCallback) { - auto& fragment = getGlyphFragment(false); + auto fragment = getGlyphFragment(false); innerprint(fragment, gpu, text, pos, color); - gpu.sendFragment(fragment, eastl::move(callback), dmaCallback); + gpu.sendFragment(*fragment, eastl::move(callback), dmaCallback); } void psyqo::FontBase::chainprint(GPU& gpu, eastl::string_view text, Vertex pos, Color color) { - auto& fragment = getGlyphFragment(true); + auto fragment = getGlyphFragment(true); innerprint(fragment, gpu, text, pos, color); - gpu.chain(fragment); + gpu.chain(*fragment); } void psyqo::FontBase::chainprint(GPU& gpu, const char* text, Vertex pos, Color color) { - auto& fragment = getGlyphFragment(true); + auto fragment = getGlyphFragment(true); innerprint(fragment, gpu, text, pos, color); - gpu.chain(fragment); + gpu.chain(*fragment); } -void psyqo::FontBase::innerprint(GlyphsFragment& fragment, GPU& gpu, eastl::string_view text, Vertex pos, Color color) { +void psyqo::FontBase::innerprint(GlyphsFragment* fragment, GPU& gpu, eastl::string_view text, Vertex pos, Color color) { auto size = m_glyphSize; unsigned i = 0; - auto maxSize = fragment.primitives.size(); + auto maxSize = fragment->primitives.size(); for (auto c : text) { if (i >= maxSize) break; @@ -329,24 +329,24 @@ void psyqo::FontBase::innerprint(GlyphsFragment& fragment, GPU& gpu, eastl::stri pos.x += size.w; continue; } - auto& f = fragment.primitives[i++]; + auto& f = fragment->primitives[i++]; auto p = m_lut[c - 32]; f.position = pos; f.texInfo = p; pos.x += size.w; } - fragment.count = i; + fragment->count = i; color.r >>= 3; color.g >>= 3; color.b >>= 3; uint32_t pixel = color.r | (color.g << 5) | (color.b << 10); - fragment.prologue.pixel = pixel << 16; + fragment->prologue.pixel = pixel << 16; } -void psyqo::FontBase::innerprint(GlyphsFragment& fragment, GPU& gpu, const char* text, Vertex pos, Color color) { +void psyqo::FontBase::innerprint(GlyphsFragment* fragment, GPU& gpu, const char* text, Vertex pos, Color color) { auto size = m_glyphSize; unsigned i; - auto maxSize = fragment.primitives.size(); + auto maxSize = fragment->primitives.size(); for (i = 0; i < maxSize; pos.x += size.w) { uint8_t c = *text++; @@ -357,17 +357,17 @@ void psyqo::FontBase::innerprint(GlyphsFragment& fragment, GPU& gpu, const char* if (c == ' ') { continue; } - auto& f = fragment.primitives[i++]; + auto& f = fragment->primitives[i++]; auto p = m_lut[c - 32]; f.position = pos; f.texInfo = p; } - fragment.count = i; + fragment->count = i; color.r >>= 3; color.g >>= 3; color.b >>= 3; uint32_t pixel = color.r | (color.g << 5) | (color.b << 10); - fragment.prologue.pixel = pixel << 16; + fragment->prologue.pixel = pixel << 16; } void psyqo::FontBase::vprintf(GPU& gpu, Vertex pos, Color color, const char* format, va_list ap) { @@ -387,19 +387,19 @@ void psyqo::FontBase::vprintf(GPU& gpu, Vertex pos, Color color, const char* for void psyqo::FontBase::vprintf(GPU& gpu, Vertex pos, Color color, eastl::function&& callback, DMA::DmaCallback dmaCallback, const char* format, va_list ap) { - auto& fragment = getGlyphFragment(false); + auto fragment = getGlyphFragment(false); innervprintf(fragment, gpu, pos, color, format, ap); - gpu.sendFragment(fragment, eastl::move(callback), dmaCallback); + gpu.sendFragment(*fragment, eastl::move(callback), dmaCallback); } void psyqo::FontBase::chainvprintf(GPU& gpu, Vertex pos, Color color, const char* format, va_list ap) { - auto& fragment = getGlyphFragment(true); + auto fragment = getGlyphFragment(true); innervprintf(fragment, gpu, pos, color, format, ap); - gpu.chain(fragment); + gpu.chain(*fragment); } struct psyqo::FontBase::XPrintfInfo { - GlyphsFragment& fragment; + GlyphsFragment* fragment; GPU& gpu; Vertex pos; FontBase* self; @@ -407,26 +407,26 @@ struct psyqo::FontBase::XPrintfInfo { extern "C" int vxprintf(void (*func)(const char*, int, void*), void* arg, const char* format, va_list ap); -void psyqo::FontBase::innervprintf(GlyphsFragment& fragment, GPU& gpu, Vertex pos, Color color, const char* format, +void psyqo::FontBase::innervprintf(GlyphsFragment* fragment, GPU& gpu, Vertex pos, Color color, const char* format, va_list ap) { - fragment.count = 0; + fragment->count = 0; color.r >>= 3; color.g >>= 3; color.b >>= 3; uint32_t pixel = color.r | (color.g << 5) | (color.b << 10); - fragment.prologue.pixel = pixel << 16; + fragment->prologue.pixel = pixel << 16; XPrintfInfo info{fragment, gpu, pos, this}; vxprintf( [](const char* str, int len, void* info_) { auto& info = *static_cast(info_); auto& fragment = info.fragment; - auto& primitives = info.fragment.primitives; + auto& primitives = info.fragment->primitives; auto maxSize = primitives.size(); auto& pos = info.pos; auto self = info.self; unsigned i; for (i = 0; i < len; i++) { - if (fragment.count >= maxSize) break; + if (fragment->count >= maxSize) break; auto c = str[i]; if (c < 32 || c > 127) { c = '?'; @@ -435,7 +435,7 @@ void psyqo::FontBase::innervprintf(GlyphsFragment& fragment, GPU& gpu, Vertex po pos.x += self->m_glyphSize.w; continue; } - auto& f = primitives[fragment.count++]; + auto& f = primitives[fragment->count++]; auto p = self->m_lut[c - 32]; f.position = pos; f.texInfo = p;