Skip to content

Commit

Permalink
Merge pull request #1303 from nicolasnoble/lets-hold-more-hands
Browse files Browse the repository at this point in the history
Creating the psyqo's paths helpers library.
  • Loading branch information
nicolasnoble committed May 9, 2023
2 parents 3607ec4 + e9ac1ad commit cfd7856
Show file tree
Hide file tree
Showing 13 changed files with 305 additions and 5 deletions.
11 changes: 11 additions & 0 deletions src/mips/psyqo-paths/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PSYQOPATHSDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))

TARGET = psyqo-paths
TYPE = library

SRCS = \
src/cdrom-loader.cpp \

EXTRA_DEPS += $(PSYQOPATHSDIR)Makefile

include ../psyqo/psyqo.mk
9 changes: 9 additions & 0 deletions src/mips/psyqo-paths/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
While the [PSYQo](../psyqo) library is still very light, and not really opinionated on how to process certain operations, it means it can be tedious and verbose to write certain things. This is where the PSYQo Paths library comes in: it provides a set of functions called "Paths" to help with common operations, such as loading a file from CD-Rom.

The point is to provide a set of functions that are easy to use, but are also too generic to be included in the PSYQo library itself. Using them comes with the caveat that they are not optimized for any specific use case, and may not be the best solution for your specific problem. However, they should be good enough for most cases, and can be used as a starting point for more specific implementations.

## Loading a file from CD-Rom

This Path will allow you to load a file from CD-Rom, and return a vector containing the file's data. As with the rest of PSYQo, the loading is still going to be done asynchronously, so you will need to either pass a callback to the class' method, or use the `schedule` version of the method using the task scheduler.

See [the example](examples/cdrom-loader) for a full usage example.
79 changes: 79 additions & 0 deletions src/mips/psyqo-paths/cdrom-loader.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
MIT License
Copyright (c) 2023 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.
*/

#pragma once

#include <EASTL/string_view.h>
#include <EASTL/vector.h>
#include <stdint.h>

#include "psyqo/gpu.hh"
#include "psyqo/iso9660-parser.hh"
#include "psyqo/task.hh"

namespace psyqo::paths {

/**
* @brief A class that reads files from the CDRom.
*
* @details This class provides a PSYQo path to read files from the CDRom.
* The way to use it is to instantiate the class somewhere persistent, and
* then call readFile() with a callback. The callback will be called with
* the data of the file, or an empty vector if the file could not be read.
* This is going to allocate memory in different places. Only one file can
* be read at a time, but it is safe to call readFile() again from the
* callback.
*/

class CDRomLoader {
public:
/**
* @brief Reads a file from the CDRom.
*
* @param path The path to the file to read. The view must be persistent
* until the callback is called.
* @param gpu The GPU class used by the application, in order to set timers.
* @param parser The ISO9660Parser to use for reading the file.
* @param callback The callback to call when the file is read. The callback
* will be called with the data of the file, or an empty vector if the file
* could not be read.
*/
void readFile(eastl::string_view path, GPU& gpu, ISO9660Parser& parser,
eastl::function<void(eastl::vector<uint8_t>&&)>&& callback) {
setupQueue(path, gpu, parser, eastl::move(callback));
m_queue.run();
}

private:
void setupQueue(eastl::string_view path, GPU& gpu, ISO9660Parser& parser, eastl::function<void(eastl::vector<uint8_t> &&)> &&callback);
eastl::function<void(eastl::vector<uint8_t> &&)> m_callback;
psyqo::TaskQueue m_queue;
ISO9660Parser::ReadRequest m_request;
eastl::vector<uint8_t> m_data;
bool m_pending = false;
};

}
7 changes: 7 additions & 0 deletions src/mips/psyqo-paths/compile_flags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-m32
-std=c++20
-fcoroutines-ts
-I.
-I..
-I../../../third_party/EASTL/include
-I../../../third_party/EABase/include/Common
10 changes: 10 additions & 0 deletions src/mips/psyqo-paths/examples/cdrom-loader/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
TARGET = cdrom-loader
TYPE = ps-exe

SRCS = \
cdrom-loader.cpp \

CPPFLAGS = -Werror
CXXFLAGS = -std=c++20

include ../../psyqo-paths.mk
90 changes: 90 additions & 0 deletions src/mips/psyqo-paths/examples/cdrom-loader/cdrom-loader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
MIT License
Copyright (c) 2023 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/cdrom-device.hh"
#include "psyqo/font.hh"
#include "psyqo/gpu.hh"
#include "psyqo/iso9660-parser.hh"
#include "psyqo/scene.hh"
#include "psyqo-paths/cdrom-loader.hh"

namespace {

class CDRomLoaderExample final : public psyqo::Application {
void prepare() override;
void createScene() override;

public:
psyqo::Font<> m_font;
psyqo::CDRomDevice m_cdrom;
psyqo::ISO9660Parser m_isoParser = psyqo::ISO9660Parser(&m_cdrom);
psyqo::paths::CDRomLoader m_cdromLoader;
eastl::vector<uint8_t> m_buffer;
bool m_callbackCalled = false;
};

class CDRomLoaderExampleScene final : public psyqo::Scene {
void frame() override;
};

CDRomLoaderExample cdromLoaderExample;
CDRomLoaderExampleScene cdromLoaderExampleScene;

} // namespace

void CDRomLoaderExample::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);
m_cdrom.prepare();
}

void CDRomLoaderExample::createScene() {
m_font.uploadSystemFont(gpu());
pushScene(&cdromLoaderExampleScene);
m_cdromLoader.readFile("SYSTEM.CNF;1", cdromLoaderExample.gpu(), cdromLoaderExample.m_isoParser,
[this](const eastl::vector<uint8_t>& buffer) {
m_buffer = buffer;
m_callbackCalled = true;
});
}

void CDRomLoaderExampleScene::frame() {
auto& gpu = cdromLoaderExample.gpu();
gpu.clear({{.r = 0, .g = 64, .b = 91}});
if (cdromLoaderExample.m_callbackCalled) {
cdromLoaderExample.m_font.printf(gpu, {{.x = 16, .y = 32}}, {{.r = 255, .g = 255, .b = 255}}, "Read %i bytes",
cdromLoaderExample.m_buffer.size());
} else {
cdromLoaderExample.m_font.printf(gpu, {{.x = 16, .y = 32}}, {{.r = 255, .g = 255, .b = 255}}, "Loading...");
}
}

int main() { return cdromLoaderExample.run(); }
15 changes: 15 additions & 0 deletions src/mips/psyqo-paths/psyqo-paths.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
PSYQOPATHSDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))

LIBRARIES += $(PSYQOPATHSDIR)libpsyqo-paths.a

EXTRA_CLEAN += clean-psyqo-paths

include $(PSYQOPATHSDIR)../psyqo/psyqo.mk

$(PSYQOPATHSDIR)libpsyqo-paths.a:
$(MAKE) -C $(PSYQOPATHSDIR) BUILD=$(BUILD)

clean-psyqo-paths:
$(MAKE) -C $(PSYQOPATHSDIR) clean

.PHONY: clean-psyqo-paths $(PSYQOPATHSDIR)libpsyqo-paths.a
57 changes: 57 additions & 0 deletions src/mips/psyqo-paths/src/cdrom-loader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
MIT License
Copyright (c) 2023 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-paths/cdrom-loader.hh"

#include "psyqo/kernel.hh"

void psyqo::paths::CDRomLoader::setupQueue(eastl::string_view path, GPU& gpu, psyqo::ISO9660Parser& parser,
eastl::function<void(eastl::vector<uint8_t>&&)>&& callback) {
Kernel::assert(!m_pending, "Only one file can be read at a time");
m_pending = true;
m_callback = eastl::move(callback);
m_queue.startWith([](auto task) { task->resolve(); });
if (!parser.initialized()) {
m_queue.then(parser.scheduleInitialize());
}
m_queue.then(parser.scheduleGetDirentry(path, &m_request.entry))
.then([this](auto task) {
uint32_t size = (m_request.entry.size + 2047) & ~2048;
m_data.resize(size);
m_request.buffer = m_data.data();
task->resolve();
})
.then(parser.scheduleReadRequest(&m_request))
.butCatch([this](auto task) {
m_request.entry.size = 0;
})
.finally([this](auto task) {
m_pending = false;
m_data.resize(m_request.entry.size);
m_callback(eastl::move(m_data));
m_callback = nullptr;
});
}
2 changes: 1 addition & 1 deletion src/mips/psyqo/GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ The computer might need to be rebooted after the installation of this script.
Next, run the following command to install the proper toolchain and its dependencies:

```cmd
mips install 12.2.0
mips install 13.1.0
```

## Docker
Expand Down
23 changes: 22 additions & 1 deletion src/mips/psyqo/iso9660-parser.hh
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ class ISO9660Parser {
*
* @details This struct serves as a persistent storage for an asynchronous read
* request. Its purpose is to be embedded outside of the parser, so it can
* keep track of the current state of the request.
* keep track of the current state of the request. IMPORTANT: The buffer
* pointer needs to hold at least enough sectors to hold the file. Even if the
* file size isn't a multiple of 2048, the buffer needs to be a multiple of
* 2048. The buffer is not owned by the parser, and it's the user's
* responsibility to ensure it's valid during the whole request.
*/
struct ReadRequest {
struct DirEntry entry;
Expand Down Expand Up @@ -120,6 +124,23 @@ class ISO9660Parser {
*/
TaskQueue::Task scheduleReadRequest(ReadRequest* request);

/**
* @brief Returns the state of the parser.
*
* @details This method returns true if the parser was initialized successfully,
* and false otherwise.
*
* @return The root directory entry.
*/
bool initialized() { return m_initialized; }

/**
* @brief Returns the CDRom object used by the parser.
*
* @return The CDRom object.
*/
CDRom* getCDRom() { return m_cdrom; }

private:
void parseDirEntry(const uint8_t* data, DirEntry* entry);
eastl::string_view getEntryName(const uint8_t* data);
Expand Down
3 changes: 2 additions & 1 deletion src/mips/psyqo/src/iso9660-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ void psyqo::ISO9660Parser::findDirEntry() {
while (offset < 2048) {
auto entry = &m_buffer[offset];
if (entry[0] == 0) break;
if (getEntryName(entry) == name) {
auto entryName = getEntryName(entry);
if (entryName == name) {
if (m_path.empty()) {
parseDirEntry(entry, m_dirEntry);
auto callback = eastl::move(m_callback);
Expand Down
2 changes: 1 addition & 1 deletion src/mips/psyqo/src/task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void psyqo::TaskQueue::runNext() {
void psyqo::TaskQueue::runCatch() {
m_running = false;
if (m_catch && m_finally) {
auto finally = m_finally;
auto finally = eastl::move(m_finally);
m_catch(this);
finally(this);
} else {
Expand Down
2 changes: 1 addition & 1 deletion third_party/EASTL/include/EASTL/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ namespace eastl
return;

typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
memset(first, 0, sizeof(value_type) * n);
__builtin_memset(first, 0, sizeof(value_type) * n);
}
}

Expand Down

0 comments on commit cfd7856

Please sign in to comment.