Skip to content

Commit 941a284

Browse files
authored
Merge pull request #11 from Stovent/renderer
Merge the new Renderer
2 parents 62ae04e + 452ebc6 commit 941a284

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+4625
-1449
lines changed

.github/workflows/build-macos-x86_64.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ jobs:
66
build-x86_64:
77
runs-on: macos-latest
88
steps:
9-
- uses: actions/checkout@v4
9+
- uses: actions/checkout@v5
10+
with:
11+
submodules: recursive
1012

11-
- name: Install wxWidgets
12-
run: brew install wxwidgets dylibbundler create-dmg
13+
- name: Install dependencies
14+
run: brew install wxwidgets@3.2 dylibbundler create-dmg llvm
1315

1416
- name: Generate Makefile
15-
run: cmake . -DCMAKE_BUILD_TYPE=Release
17+
run: CXX=$(brew --prefix llvm)/bin/clang++ cmake . -DCMAKE_BUILD_TYPE=Release -DCEDIMU_ENABLE_LTO=OFF
1618

1719
- name: Build
1820
run: make -j$(sysctl -n hw.physicalcpu)
@@ -36,3 +38,6 @@ jobs:
3638
with:
3739
name: CeDImu-Installer-x86_64.dmg
3840
path: ./CeDImu-Installer.dmg
41+
42+
- name: Run tests
43+
run: ./tests/tests

.github/workflows/build-ubuntu-lastest.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ jobs:
66
build:
77
runs-on: ubuntu-24.04
88
steps:
9-
- uses: actions/checkout@v4
9+
- uses: actions/checkout@v5
10+
with:
11+
submodules: recursive
1012

1113
- name: Install wxWidgets
1214
run: |
@@ -15,6 +17,8 @@ jobs:
1517
1618
- name: Configure
1719
run: cmake -B build -DCMAKE_BUILD_TYPE=Release
20+
env:
21+
CXX: g++-14
1822

1923
- name: Build
2024
run: cmake --build build -j$(nproc --all)
@@ -23,3 +27,6 @@ jobs:
2327
with:
2428
name: CeDImu-ubuntu-x86_64
2529
path: build/CeDImu
30+
31+
- name: Run tests
32+
run: ./build/tests/tests

.github/workflows/build-windows.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ jobs:
66
build:
77
runs-on: windows-latest
88
steps:
9-
- uses: actions/checkout@v4
9+
- uses: actions/checkout@v5
10+
with:
11+
submodules: recursive
1012

1113
- name: Cache vcpkg
1214
id: cache-vcpkg
@@ -30,3 +32,6 @@ jobs:
3032
with:
3133
name: CeDImu-windows-x86_64
3234
path: ./build/Release/CeDImu.exe
35+
36+
- name: Run tests
37+
run: ./build/tests/Release/tests.exe

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
!.git-blame-ignore-revs
55
!.gitattributes
66
!.gitignore
7+
!.gitmodules
78
!CMakeLists.txt
89
!Doxyfile
910
!MANUAL.md
1011
!README.md
1112

1213
!/.github
14+
!/benchmarks
1315
!/cditool
16+
!/externals
1417
!/resources
1518
!/src
19+
!/tests

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "externals/Catch2"]
2+
path = externals/Catch2
3+
url = https://github.com/catchorg/Catch2.git

CMakeLists.txt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
11
cmake_minimum_required(VERSION 3.15)
22

33
if(POLICY CMP0091)
4-
cmake_policy(SET CMP0091 NEW)
4+
cmake_policy(SET CMP0091 NEW)
55
endif()
66

77
project(CeDImu)
88

99
option(CEDIMU_BUILD_CDITOOL "Build cditool" OFF)
10-
1110
if(CEDIMU_BUILD_CDITOOL)
1211
add_subdirectory(cditool)
1312
endif()
1413

14+
option(CEDIMU_BENCHMARKS "Compile the benchmarks" OFF)
15+
if(CEDIMU_BENCHMARKS)
16+
add_subdirectory(benchmarks)
17+
endif()
18+
19+
option(CEDIMU_TESTS "Compile the tests" ON)
20+
21+
add_subdirectory(externals)
1522
add_subdirectory(src)
23+
24+
if(CEDIMU_TESTS)
25+
add_subdirectory(tests)
26+
endif()

README.md

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,20 +78,40 @@ Compatible means it is capable of playing discs.
7878

7979
## How to build
8080

81-
You need a compiler that supports C++20 and wxWidgets 3.1.
81+
You need a compiler that supports C++23 and wxWidgets 3.2.
82+
83+
When cloning the repo, make sure you clone the submodules too (`git clone --recurse-submodules https://github.com/Stovent/CeDImu`).
8284

8385
### Build macros
8486

85-
`ENABLE_LOG`: if defined, allows the library to print some messages in the console and the use of OnLogMemoryAccess callback (default: `OFF`).
87+
CeDImu (the frontend) and libCeDImu (the emulation core) accepts the following macros:
88+
89+
`LIBCEDIMU_ENABLE_LOG`: if defined, allows the library to print some messages in the console and the use of OnLogMemoryAccess callback.
8690

87-
The official build of CeDImu always enables it.
91+
`LIBCEDIMU_ENABLE_RENDERERSIMD`: if on, uses the hardware-accelerated SIMD renderer. Requires the C++ header `<experimental/simd>`.
8892

8993
### CMake
9094

9195
#### CMake options
9296

97+
The CMake options below controls how to build CeDImu and the build macros listed upper.
98+
99+
`LIBCEDIMU_ENABLE_LOG`: see section `Build macros` (default: `ON`). The official build of CeDImu always enables it.
100+
101+
`LIBCEDIMU_ENABLE_RENDERERSIMD`: builds and uses the SIMD renderer, see section `Build macros` (default: `OFF`).
102+
103+
`LIBCEDIMU_PROFILE_GNU`: if true, adds profiling arguments to GCC (clang/MSVC not supported) (default: `OFF`).
104+
105+
`LIBCEDIMU_ENABLE_ASAN`: if true, uses address sanitizer for GCC and clang (MSVC not yet supported) (default: `OFF`).
106+
93107
`CEDIMU_BUILD_CDITOOL`: If ON, builds the little `cditool` program (Linux only, requires libcdio) (default: `OFF`).
94108

109+
`CEDIMU_BENCHMARKS`: if ON, builds the benchmarks (default: `OFF`).
110+
111+
`CEDIMU_TESTS`: If ON, builds the unit tests (requires Catch2 cloned) (default: `ON`).
112+
113+
`CEDIMU_TESTS_ASAN`: If ON, builds the unit tests with address sanitizer options (default: `OFF`).
114+
95115
`CEDIMU_ENABLE_LTO`: If ON, compiles the executable with link-time optimisations (default: `ON`).
96116

97117
#### Windows
@@ -118,7 +138,7 @@ First install cmake and wxWidgets-3.1 (or later).
118138

119139
With apt the command is: `sudo apt install cmake libwxgtk3.2-dev`
120140

121-
Install the dependency, then open a terminal in the root directory of the git and type:
141+
Install the dependency, then open a terminal in the root directory of the repo and type:
122142

123143
```sh
124144
cmake -B build -DCMAKE_BUILD_TYPE=Release
@@ -129,16 +149,18 @@ The executable will be in the `build` directory.
129149

130150
#### macOS
131151

132-
Package dependency: `wxwidgets` and `cmake` (e.g. if using brew run: `brew install wxwidgets cmake`). Also make sure to have Xcode or just it's Command Line Tools installed.
152+
Package dependency: `wxwidgets`, `cmake` and `llvm` (e.g. if using brew run: `brew install wxwidgets cmake llvm`). Also make sure to have Xcode or just it's Command Line Tools installed.
153+
154+
LLVM clang is used to build because AppleClang lacks recent features.
133155

134156
For keyboard input to work properly, enable 'Keyboard Navigation' in macOS. See this [support article](https://support.apple.com/en-us/HT204434#fullkeyboard).
135157

136-
Open a terminal in the root directory of the git and type:
158+
Open a terminal in the root directory of the repo and type:
137159

138160
```sh
139161
mkdir build
140162
cd build
141-
cmake .. -DCMAKE_BUILD_TYPE=Release
163+
CXX=$(brew --prefix llvm)/bin/clang++ cmake .. -DCMAKE_BUILD_TYPE=Release
142164
make -j$(sysctl -n hw.physicalcpu)
143165
```
144166

benchmarks/CMakeLists.txt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# TODO: use a specific benchmarking tool like google benchmark?
2+
cmake_minimum_required(VERSION 3.25)
3+
4+
project(CeDImu-benchmarks)
5+
6+
set(CMAKE_CXX_STANDARD 23)
7+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
8+
9+
if(NOT CMAKE_BUILD_TYPE)
10+
set(CMAKE_BUILD_TYPE Release)
11+
endif()
12+
13+
add_executable(benchmarkRenderers benchmarkRenderers.cpp)
14+
target_link_libraries(benchmarkRenderers CeDImu)
15+
16+
add_executable(benchmarkVideoDecoders benchmarkVideoDecoders.cpp)
17+
target_link_libraries(benchmarkVideoDecoders CeDImu)
18+
19+
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
20+
target_compile_options(benchmarkRenderers PUBLIC -Wall -Wextra -pedantic -march=native)
21+
target_compile_options(benchmarkVideoDecoders PUBLIC -Wall -Wextra -pedantic -march=native)
22+
23+
if(WIN32)
24+
target_link_options(benchmarkRenderers PUBLIC -static-libgcc -static-libstdc++)
25+
target_link_options(benchmarkVideoDecoders PUBLIC -static-libgcc -static-libstdc++)
26+
endif()
27+
endif()
28+
29+
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
30+
if(WIN32)
31+
# GCC does not support 32-byte aligned stack https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412
32+
target_compile_options(benchmarkRenderers PRIVATE -Wa,-muse-unaligned-vector-move)
33+
target_compile_options(benchmarkVideoDecoders PRIVATE -Wa,-muse-unaligned-vector-move)
34+
endif()
35+
36+
# target_compile_options(benchmarkVideoDecoders PRIVATE -fsanitize=address)
37+
# target_link_options(benchmarkVideoDecoders PUBLIC -fsanitize=address -static-libasan)
38+
endif()
39+
40+
include(CheckIPOSupported)
41+
check_ipo_supported(RESULT ipoAvailable)
42+
if(ipoAvailable)
43+
set_property(TARGET benchmarkRenderers PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
44+
set_property(TARGET benchmarkVideoDecoders PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
45+
endif()

benchmarks/benchmarkRenderers.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#include <Video/RendererSIMD.hpp>
2+
#include <Video/RendererSoftware.hpp>
3+
4+
#include <array>
5+
#include <chrono>
6+
#include <print>
7+
#include <string_view>
8+
9+
static constexpr size_t WIDTH = 768;
10+
static constexpr size_t HEIGHT = 280;
11+
static constexpr size_t FRAMES = 10000;
12+
static constexpr size_t FRAMES_CURSOR = 10'000'000;
13+
14+
static constexpr std::array<uint8_t, WIDTH> LINEA{};
15+
static constexpr std::array<uint8_t, WIDTH> LINEB{};
16+
17+
static constexpr Video::Renderer::ImagePlane A = Video::Renderer::A;
18+
static constexpr Video::Renderer::ImagePlane B = Video::Renderer::B;
19+
20+
template<typename RENDERER, Video::Renderer::BitsPerPixel BPS, Video::ImageCodingMethod CODINGA, Video::ImageCodingMethod CODINGB>
21+
static void benchmarkRenderer(std::string_view name)
22+
{
23+
RENDERER renderer;
24+
renderer.m_codingMethod[A] = CODINGA;
25+
renderer.m_codingMethod[B] = CODINGB;
26+
renderer.m_bps[A] = BPS;
27+
renderer.m_bps[B] = BPS;
28+
renderer.SetDisplayFormat(Video::Renderer::DisplayFormat::PAL, false, false);
29+
renderer.m_mix = true;
30+
31+
uint16_t lineNumber = 0;
32+
33+
// Benchmark
34+
const std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
35+
for(size_t f = 0; f < FRAMES; ++f)
36+
{
37+
for(size_t y = 0; y < HEIGHT; ++y)
38+
{
39+
renderer.DrawLine(LINEA.data(), LINEB.data(), lineNumber++);
40+
}
41+
lineNumber = 0;
42+
renderer.RenderFrame();
43+
}
44+
const std::chrono::high_resolution_clock::time_point finish = std::chrono::high_resolution_clock::now();
45+
const std::chrono::nanoseconds delta = finish - start;
46+
47+
std::println("{} {} {} {}/f {}",
48+
name,
49+
delta,
50+
std::chrono::duration_cast<std::chrono::microseconds>(delta),
51+
std::chrono::duration_cast<std::chrono::microseconds>(delta / FRAMES),
52+
std::chrono::duration_cast<std::chrono::milliseconds>(delta)
53+
);
54+
}
55+
56+
template<typename RENDERER>
57+
static void benchmarkRendererCursor(std::string_view name)
58+
{
59+
RENDERER renderer;
60+
renderer.SetCursorEnabled(true);
61+
renderer.SetDisplayFormat(Video::Renderer::DisplayFormat::PAL, false, false);
62+
63+
// Benchmark
64+
const std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
65+
for(size_t f = 0; f < FRAMES_CURSOR; ++f)
66+
{
67+
renderer.RenderFrame();
68+
}
69+
const std::chrono::high_resolution_clock::time_point finish = std::chrono::high_resolution_clock::now();
70+
const std::chrono::nanoseconds delta = finish - start;
71+
72+
std::println("{} {} {} {}/f {}",
73+
name,
74+
delta,
75+
std::chrono::duration_cast<std::chrono::microseconds>(delta),
76+
delta / FRAMES_CURSOR,
77+
std::chrono::duration_cast<std::chrono::milliseconds>(delta)
78+
);
79+
}
80+
81+
int main()
82+
{
83+
constexpr Video::Renderer::BitsPerPixel NORMAL_8 = Video::Renderer::BitsPerPixel::Normal8;
84+
constexpr Video::Renderer::BitsPerPixel DOUBLE_4 = Video::Renderer::BitsPerPixel::Double4;
85+
// constexpr Video::Renderer::BitsPerPixel HIGH_8 = Video::Renderer::BitsPerPixel::High8;
86+
87+
benchmarkRendererCursor<Video::RendererSoftware>("Cursor Soft");
88+
benchmarkRendererCursor<Video::RendererSIMD>("Cursor SIMD");
89+
90+
benchmarkRenderer<Video::RendererSoftware, NORMAL_8, ICM(OFF), ICM(RGB555)>("Normal Soft RGB555");
91+
benchmarkRenderer<Video::RendererSIMD, NORMAL_8, ICM(OFF), ICM(RGB555)>("Normal SIMD RGB555");
92+
93+
benchmarkRenderer<Video::RendererSoftware, NORMAL_8, ICM(DYUV), ICM(DYUV)>("Normal Soft DYUV");
94+
benchmarkRenderer<Video::RendererSIMD, NORMAL_8, ICM(DYUV), ICM(DYUV)>("Normal SIMD DYUV");
95+
96+
benchmarkRenderer<Video::RendererSoftware, DOUBLE_4, ICM(DYUV), ICM(DYUV)>("Double Soft DYUV");
97+
benchmarkRenderer<Video::RendererSIMD, DOUBLE_4, ICM(DYUV), ICM(DYUV)>("Double SIMD DYUV");
98+
99+
benchmarkRenderer<Video::RendererSoftware, DOUBLE_4, ICM(CLUT4), ICM(CLUT4)>("Double Soft CLUT4");
100+
benchmarkRenderer<Video::RendererSIMD, DOUBLE_4, ICM(CLUT4), ICM(CLUT4)>("Double SIMD CLUT4");
101+
102+
benchmarkRenderer<Video::RendererSoftware, NORMAL_8, ICM(CLUT8), ICM(CLUT7)>("Normal Soft CLUT8/CLUT7");
103+
benchmarkRenderer<Video::RendererSIMD, NORMAL_8, ICM(CLUT8), ICM(CLUT7)>("Normal SIMD CLUT8/CLUT7");
104+
105+
benchmarkRenderer<Video::RendererSoftware, DOUBLE_4, ICM(CLUT8), ICM(CLUT7)>("Double Soft CLUT8/CLUT7");
106+
benchmarkRenderer<Video::RendererSIMD, DOUBLE_4, ICM(CLUT8), ICM(CLUT7)>("Double SIMD CLUT8/CLUT7");
107+
}

0 commit comments

Comments
 (0)