54 const int kIterations = 10000;
55 const int kBitmapSize = 128;
57 auto test_data = CreateTestBitmapData(kBitmapSize, kBitmapSize);
58 auto test_palette = CreateTestPalette();
60 Bitmap bitmap(kBitmapSize, kBitmapSize, 8, test_data, test_palette);
63 auto start = std::chrono::high_resolution_clock::now();
65 for (
int i = 0; i < kIterations; ++i) {
66 SnesColor test_color(i % 16, (i + 1) % 16, (i + 2) % 16);
71 auto end = std::chrono::high_resolution_clock::now();
72 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
74 double avg_time_us =
static_cast<double>(duration.count()) / kIterations;
77 EXPECT_LT(avg_time_us, 1.0) <<
"Palette lookup should be optimized to < 1μs";
79 std::cout <<
"Palette lookup average time: " << avg_time_us <<
" μs" << std::endl;
84 const int kBitmapSize = 256;
85 const int kPixelUpdates = 1000;
87 auto test_data = CreateTestBitmapData(kBitmapSize, kBitmapSize);
88 auto test_palette = CreateTestPalette();
90 Bitmap bitmap(kBitmapSize, kBitmapSize, 8, test_data, test_palette);
93 auto start = std::chrono::high_resolution_clock::now();
95 for (
int i = 0; i < kPixelUpdates; ++i) {
96 int x = i % kBitmapSize;
97 int y = (i * 7) % kBitmapSize;
98 SnesColor color(i % 16, (i + 1) % 16, (i + 2) % 16);
102 auto end = std::chrono::high_resolution_clock::now();
103 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
105 double avg_time_us =
static_cast<double>(duration.count()) / kPixelUpdates;
108 EXPECT_LT(avg_time_us, 10.0) <<
"Pixel updates should be < 10μs with dirty region tracking";
110 std::cout <<
"Pixel update average time: " << avg_time_us <<
" μs" << std::endl;
115 const int kAllocations = 10000;
116 const size_t kAllocationSize = 1024;
120 std::vector<void*> allocations;
121 allocations.reserve(kAllocations);
124 auto start = std::chrono::high_resolution_clock::now();
126 for (
int i = 0; i < kAllocations; ++i) {
127 void* ptr = memory_pool.Allocate(kAllocationSize);
128 allocations.push_back(ptr);
131 auto end = std::chrono::high_resolution_clock::now();
132 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
134 double avg_time_us =
static_cast<double>(duration.count()) / kAllocations;
137 EXPECT_LT(avg_time_us, 1.0) <<
"Memory pool allocation should be < 1μs";
139 std::cout <<
"Memory pool allocation average time: " << avg_time_us <<
" μs" << std::endl;
142 start = std::chrono::high_resolution_clock::now();
144 for (
void* ptr : allocations) {
145 memory_pool.Deallocate(ptr);
148 end = std::chrono::high_resolution_clock::now();
149 duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
151 avg_time_us =
static_cast<double>(duration.count()) / kAllocations;
153 EXPECT_LT(avg_time_us, 1.0) <<
"Memory pool deallocation should be < 1μs";
155 std::cout <<
"Memory pool deallocation average time: " << avg_time_us <<
" μs" << std::endl;
160 const int kTextureUpdates = 100;
161 const int kBitmapSize = 64;
163 auto test_data = CreateTestBitmapData(kBitmapSize, kBitmapSize);
164 auto test_palette = CreateTestPalette();
166 std::vector<Bitmap> bitmaps;
167 bitmaps.reserve(kTextureUpdates);
170 for (
int i = 0; i < kTextureUpdates; ++i) {
171 bitmaps.emplace_back(kBitmapSize, kBitmapSize, 8, test_data, test_palette);
177 auto start = std::chrono::high_resolution_clock::now();
179 for (
auto& bitmap : bitmaps) {
184 auto end = std::chrono::high_resolution_clock::now();
185 auto individual_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
188 start = std::chrono::high_resolution_clock::now();
190 for (
auto& bitmap : bitmaps) {
196 end = std::chrono::high_resolution_clock::now();
197 auto batch_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
200 double individual_avg =
static_cast<double>(individual_duration.count()) / kTextureUpdates;
201 double batch_avg =
static_cast<double>(batch_duration.count()) / kTextureUpdates;
203 EXPECT_LT(batch_avg, individual_avg) <<
"Batch updates should be faster than individual updates";
205 std::cout <<
"Individual texture update average: " << individual_avg <<
" μs" << std::endl;
206 std::cout <<
"Batch texture update average: " << batch_avg <<
" μs" << std::endl;
207 std::cout <<
"Speedup: " << (individual_avg / batch_avg) <<
"x" << std::endl;
212 const int kBitmaps = 50;
213 const int kBitmapSize = 32;
215 auto test_data = CreateTestBitmapData(kBitmapSize, kBitmapSize);
216 auto test_palette = CreateTestPalette();
218 std::vector<Bitmap> bitmaps;
219 bitmaps.reserve(kBitmaps);
222 for (
int i = 0; i < kBitmaps; ++i) {
223 bitmaps.emplace_back(kBitmapSize, kBitmapSize, 8, test_data, test_palette);
227 atlas_renderer.Initialize(
nullptr, 512);
230 std::vector<int> atlas_ids;
231 for (
auto& bitmap : bitmaps) {
232 int atlas_id = atlas_renderer.AddBitmap(bitmap);
234 atlas_ids.push_back(atlas_id);
239 std::vector<RenderCommand> render_commands;
240 for (
size_t i = 0; i < atlas_ids.size(); ++i) {
241 render_commands.emplace_back(atlas_ids[i], i * 10.0f, i * 10.0f);
245 auto start = std::chrono::high_resolution_clock::now();
247 for (
int i = 0; i < 1000; ++i) {
248 atlas_renderer.RenderBatch(render_commands);
251 auto end = std::chrono::high_resolution_clock::now();
252 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
254 double avg_time_us =
static_cast<double>(duration.count()) / 1000.0;
257 EXPECT_LT(avg_time_us, 100.0) <<
"Atlas rendering should be < 100μs per batch";
259 std::cout <<
"Atlas rendering average time: " << avg_time_us <<
" μs per batch" << std::endl;
262 auto stats = atlas_renderer.GetStats();
263 std::cout <<
"Atlas utilization: " << stats.utilization_percent <<
"%" << std::endl;
268 const int kOperations = 100000;
273 auto start = std::chrono::high_resolution_clock::now();
275 for (
int i = 0; i < kOperations; ++i) {
277 volatile int result = i * i;
281 auto end = std::chrono::high_resolution_clock::now();
282 auto no_profiling_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
285 start = std::chrono::high_resolution_clock::now();
287 for (
int i = 0; i < kOperations; ++i) {
288 profiler.StartTimer(
"test_operation");
290 volatile int result = i * i;
292 profiler.EndTimer(
"test_operation");
295 end = std::chrono::high_resolution_clock::now();
296 auto with_profiling_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
299 double no_profiling_avg =
static_cast<double>(no_profiling_duration.count()) / kOperations;
300 double with_profiling_avg =
static_cast<double>(with_profiling_duration.count()) / kOperations;
301 double overhead = with_profiling_avg - no_profiling_avg;
304 EXPECT_LT(overhead, 1.0) <<
"Profiling overhead should be < 1μs per operation";
306 std::cout <<
"No profiling average: " << no_profiling_avg <<
" μs" << std::endl;
307 std::cout <<
"With profiling average: " << with_profiling_avg <<
" μs" << std::endl;
308 std::cout <<
"Profiling overhead: " << overhead <<
" μs" << std::endl;
313 const int kNumTiles = 100;
314 const int kTileSize = 16;
320 std::vector<Bitmap> test_tiles;
321 std::vector<int> atlas_ids;
323 for (
int i = 0; i < kNumTiles; ++i) {
324 auto tile_data = CreateTestBitmapData(kTileSize, kTileSize);
325 auto tile_palette = CreateTestPalette();
327 test_tiles.emplace_back(kTileSize, kTileSize, 8, tile_data, tile_palette);
330 int atlas_id = atlas_renderer.AddBitmap(test_tiles.back());
332 atlas_ids.push_back(atlas_id);
337 auto start = std::chrono::high_resolution_clock::now();
339 for (
int i = 0; i < kNumTiles; ++i) {
340 if (i < atlas_ids.size()) {
341 atlas_renderer.RenderBitmap(atlas_ids[i], i * 20.0f, 0.0f);
345 auto end = std::chrono::high_resolution_clock::now();
346 auto individual_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
349 std::vector<RenderCommand> render_commands;
350 for (
size_t i = 0; i < atlas_ids.size(); ++i) {
351 render_commands.emplace_back(atlas_ids[i], i * 20.0f, 100.0f);
354 start = std::chrono::high_resolution_clock::now();
355 atlas_renderer.RenderBatch(render_commands);
356 end = std::chrono::high_resolution_clock::now();
357 auto batch_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
360 EXPECT_LT(batch_duration.count(), individual_duration.count())
361 <<
"Batch rendering should be faster than individual rendering";
364 auto stats = atlas_renderer.GetStats();
365 EXPECT_GT(stats.total_entries, 0) <<
"Atlas should contain entries";
366 EXPECT_GT(stats.used_entries, 0) <<
"Atlas should have used entries";
368 std::cout <<
"Individual rendering: " << individual_duration.count() <<
" μs" << std::endl;
369 std::cout <<
"Batch rendering: " << batch_duration.count() <<
" μs" << std::endl;
370 std::cout <<
"Atlas entries: " << stats.used_entries <<
"/" << stats.total_entries << std::endl;
371 std::cout <<
"Atlas utilization: " << stats.utilization_percent <<
"%" << std::endl;
376 const int kGraphicsSheets = 10;
377 const int kTilesPerSheet = 100;
378 const int kTileSize = 16;
385 auto start = std::chrono::high_resolution_clock::now();
387 std::vector<Bitmap> graphics_sheets;
388 for (
int sheet = 0; sheet < kGraphicsSheets; ++sheet) {
389 auto sheet_data = CreateTestBitmapData(kTileSize * 10, kTileSize * 10);
390 auto sheet_palette = CreateTestPalette();
392 graphics_sheets.emplace_back(kTileSize * 10, kTileSize * 10, 8, sheet_data, sheet_palette);
395 auto end = std::chrono::high_resolution_clock::now();
396 auto load_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
399 start = std::chrono::high_resolution_clock::now();
401 for (
int sheet = 0; sheet < kGraphicsSheets; ++sheet) {
402 for (
int tile = 0; tile < kTilesPerSheet; ++tile) {
403 int x = (tile % 10) * kTileSize;
404 int y = (tile / 10) * kTileSize;
406 SnesColor color(tile % 16, (tile + 1) % 16, (tile + 2) % 16);
407 graphics_sheets[sheet].SetPixel(x, y, color);
411 end = std::chrono::high_resolution_clock::now();
412 auto tile_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
415 start = std::chrono::high_resolution_clock::now();
417 for (
auto& sheet : graphics_sheets) {
420 arena.ProcessTextureQueue(
nullptr);
422 end = std::chrono::high_resolution_clock::now();
423 auto batch_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
426 double load_time_ms =
static_cast<double>(load_duration.count()) / 1000.0;
427 double tile_time_ms =
static_cast<double>(tile_duration.count()) / 1000.0;
428 double batch_time_ms =
static_cast<double>(batch_duration.count()) / 1000.0;
430 EXPECT_LT(load_time_ms, 100.0) <<
"Graphics sheet loading should be < 100ms";
431 EXPECT_LT(tile_time_ms, 50.0) <<
"Tile operations should be < 50ms";
432 EXPECT_LT(batch_time_ms, 10.0) <<
"Batch updates should be < 10ms";
434 std::cout <<
"Graphics sheet loading: " << load_time_ms <<
" ms" << std::endl;
435 std::cout <<
"Tile operations: " << tile_time_ms <<
" ms" << std::endl;
436 std::cout <<
"Batch updates: " << batch_time_ms <<
" ms" << std::endl;
440 std::cout <<
"Optimization score: " << summary.
optimization_score <<
"/100" << std::endl;
441 std::cout <<
"Status: " << summary.status_message << std::endl;