Skip to content

Commit

Permalink
28ms -> 8ms. Rendering board directly to a texture, instead of using …
Browse files Browse the repository at this point in the history
…SDL pixel functions (#1)

- moved from a 500x500 to 2560x1440 grid for more accurate scores
- remove the SDL pixel position calculations and instead just map the memory address to RGB
  • Loading branch information
Jumbub committed Oct 2, 2021
1 parent d55a8fe commit cda613a
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 49 deletions.
4 changes: 2 additions & 2 deletions results/benchmark.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
----------------------------------------------------------------------------
Benchmark Time CPU Iterations
----------------------------------------------------------------------------
BM_NextBoard/min_time:5.000 23.1 ms 23.1 ms 301
BM_RenderNextBoard/min_time:5.000 25.3 ms 25.2 ms 275
BM_NextBoard/min_time:5.000 356 ms 356 ms 20
BM_RenderNextBoard/min_time:5.000 362 ms 362 ms 19
7 changes: 6 additions & 1 deletion src/board/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
#include <tuple>
#include <array>
#include <memory>
#include <SDL2/SDL.h>

using Board = std::tuple<std::shared_ptr<bool[]>, int, int>;
using Cell = Uint32;
const Cell ALIVE = SDL_MAX_UINT32;
const Cell DEAD = 0;

using Board = std::tuple<std::shared_ptr<Cell[]>, int, int>;
using NeighbourPositions = std::array<int, 8>;
14 changes: 7 additions & 7 deletions src/board/generate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
#include <tuple>

Board randomBoard(int width, int height) {
auto board = std::shared_ptr<bool[]>(new bool[width * height]);
auto board = std::shared_ptr<Cell[]>(new Cell[width * height]);
for (int i = 0; i < height * width; ++i)
board[i] = rand() % 2;
board[i] = rand() % 2 ? ALIVE : DEAD;
return {board, width, height};
}

Expand All @@ -25,22 +25,22 @@ Board benchmarkBoard(int width, int height) {
"Did not meet minimum height required for the benchmark board");

srand(0);
auto board = std::shared_ptr<bool[]>(new bool[width * height]);
auto board = std::shared_ptr<Cell[]>(new Cell[width * height]);
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
const int i = y * width + x;
if (y > height / 2) {
if (x < width / 2)
board[i] = rand() % 2;
board[i] = rand() % 2 ? ALIVE : DEAD;
if (x >= width / 2)
board[i] = (x / 8) % 2 != (y / 8) % 2;
board[i] = (x / 8) % 2 != (y / 8) % 2 ? ALIVE : DEAD;
} else {
const int breederMarginY = (height / 2 - BREEDER_HEIGHT) / 2;
const int breederY = y - breederMarginY;
if (breederY > 0 && breederY < BREEDER_HEIGHT && x < BREEDER_WIDTH) {
board[i] = BREEDER[breederY][x];
board[i] = BREEDER[breederY][x] ? ALIVE : DEAD;
} else {
board[i] = false;
board[i] = DEAD;
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/board/next.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ Board nextBoard(Board board) {
if (width == 0)
return board;

auto output = std::shared_ptr<bool[]>(new bool[width*height]);
auto output = std::shared_ptr<Cell[]>(new Cell[width*height]);

for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
const int i = y * width + x;

auto alive = input[i];
auto state = input[i];

int neighboursCount = 0;
for (int y2 = -1; y2 <= 1; y2++)
Expand All @@ -43,12 +43,12 @@ Board nextBoard(Board board) {
}
}

if (alive && (neighboursCount < 2 || neighboursCount > 3))
output[i] = false;
else if (!alive && neighboursCount == 3)
output[i] = true;
if (state && (neighboursCount < 2 || neighboursCount > 3))
output[i] = DEAD;
else if (!state && neighboursCount == 3)
output[i] = ALIVE;
else
output[i] = alive;
output[i] = state;
}
}

Expand Down
18 changes: 4 additions & 14 deletions src/board/sdl.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "sdl.h"
#include "../util/profile.h"
#include "generate.h"
#include <vector>

Expand All @@ -8,22 +9,11 @@ Board boardForSdlWindow(SDL_Window *window) {
return benchmarkBoard(width, height);
}

void renderBoardSdl(Board board, SDL_Renderer *renderer) {
void renderBoardSdl(Board board, SDL_Renderer *renderer, SDL_Texture *texture) {
const auto &[input, width, height] = board;

auto points = std::unique_ptr<SDL_Point[]>(new SDL_Point[width * height]);
int count = 0;
for (int i = 0; i < width * height; i++)
if (input[i]) {
points[count] = {i % width, i / width};
count++;
}

SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);

SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawPoints(renderer, &points[0], count);
SDL_UpdateTexture(texture, NULL, &input[0], width * sizeof(Uint32));

SDL_RenderCopy(renderer, texture, nullptr, nullptr);
SDL_RenderPresent(renderer);
}
2 changes: 1 addition & 1 deletion src/board/sdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

Board boardForSdlWindow(SDL_Window *window);

void renderBoardSdl(Board board, SDL_Renderer *renderer);
void renderBoardSdl(Board board, SDL_Renderer *renderer, SDL_Texture *texture);
20 changes: 10 additions & 10 deletions src/entrypoints/benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,35 @@
#include <SDL2/SDL.h>
#include <benchmark/benchmark.h>

static void BM_NextBoard(benchmark::State &state) {
const int width = 500;
const int height = 500;
const int TEST_WIDTH = 2560;
const int TEST_HEIGHT = 1440;

auto board = benchmarkBoard(width, height);
static void BM_NextBoard(benchmark::State &state) {
auto board = benchmarkBoard(TEST_WIDTH, TEST_HEIGHT);

for (auto _ : state) {
board = nextBoard(board);
}
}

static void BM_RenderNextBoard(benchmark::State &state) {
const int width = 500;
const int height = 500;

auto board = benchmarkBoard(width, height);
auto board = benchmarkBoard(TEST_WIDTH, TEST_HEIGHT);

// Initialize graphics
SDL_Init(SDL_INIT_VIDEO);
SDL_Renderer *renderer;
SDL_Window *window;
SDL_CreateWindowAndRenderer(width, height, 0, &window, &renderer);
SDL_CreateWindowAndRenderer(TEST_WIDTH, TEST_HEIGHT, 0, &window, &renderer);
auto texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC, TEST_WIDTH, TEST_HEIGHT);

for (auto _ : state) {
board = nextBoard(board);
renderBoardSdl(board, renderer);
renderBoardSdl(board, renderer, texture);
}

// Destroy graphics
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
Expand Down
18 changes: 16 additions & 2 deletions src/entrypoints/interactive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ int main() {
SDL_CreateWindowAndRenderer(500, 500, SDL_WINDOW_RESIZABLE, &window,
&renderer);

// Window texture
int width, height;
SDL_GetWindowSize(window, &width, &height);
auto texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC, width, height);

// Generate initial board
auto p1 = startProfiling();
auto board = boardForSdlWindow(window);
Expand All @@ -33,19 +39,27 @@ int main() {
running = false;
// Re-create board when Enter is pressed
else if (event.type == SDL_KEYDOWN &&
event.key.keysym.scancode == SDL_SCANCODE_RETURN)
event.key.keysym.scancode == SDL_SCANCODE_RETURN) {

board = boardForSdlWindow(window);
int width, height;
SDL_GetWindowSize(window, &width, &height);
SDL_DestroyTexture(texture);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC, width, height);
}
}

auto p2 = startProfiling();
board = nextBoard(board);
stopProfiling(p2, "Calculated next board");

auto p3 = startProfiling();
renderBoardSdl(board, renderer);
renderBoardSdl(board, renderer, texture);
stopProfiling(p3, "Rendered next board");
}

SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
Expand Down
10 changes: 5 additions & 5 deletions src/entrypoints/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
#include "../board/next.h"
#include <catch2/catch.hpp>

Board generate(std::vector<std::vector<bool>> input) {
Board generate(std::vector<std::vector<Cell>> input) {
const auto height = (int)input.size();
const auto width = (int)input[0].size();

auto board = std::shared_ptr<bool[]>(new bool[width * height]);
auto board = std::shared_ptr<Cell[]>(new Cell[width * height]);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
board[y * width + x] = input[y][x];
board[y * width + x] = input[y][x] ? ALIVE : DEAD;

return {board, width, height};
}

std::vector<std::vector<bool>> ungenerate(Board board) {
std::vector<std::vector<Cell>> ungenerate(Board board) {
const auto &[input, width, height] = board;

std::vector<std::vector<bool>> output(height, std::vector<bool>(width));
std::vector<std::vector<Cell>> output(height, std::vector<Cell>(width));
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
output[y][x] = input[y * width + x];
Expand Down

0 comments on commit cda613a

Please sign in to comment.