Browse Source

mostly performance stuff

opengl-renderer-broken
Martin Dørum 4 years ago
parent
commit
ce70c058aa

+ 1
- 1
core.mod/src/WGDefault.cc View File

@@ -31,7 +31,7 @@ void WGDefault::genChunk(Swan::WorldPlane &plane, Swan::Chunk &chunk) {

Swan::TilePos pos(tilex, tiley);
Swan::Chunk::RelPos rel(cx, cy);
chunk.setTileID(rel, genTile(pos));
chunk.setTileData(rel, genTile(pos));
}
}
}

+ 1
- 1
core.mod/src/entities/EntPlayer.cc View File

@@ -71,7 +71,7 @@ void EntPlayer::tick(const Swan::Context &ctx, float dt) {
.squareLength();

if (squared_dist < 0.5 * 0.5) {
Swan::info << "Will pick up item at " << ent->getBody().getBounds().center() << "...";
// TODO: Pick up
}
}
}

+ 7
- 8
libswan/include/swan/Chunk.h View File

@@ -19,17 +19,16 @@ public:

Chunk(ChunkPos pos): pos_(pos) {
data_.reset(new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]);
visuals_.reset(new Visuals());
}

Tile::ID *getTileData();
Tile::ID getTileID(RelPos pos);
void setTileID(RelPos pos, Tile::ID id);
void drawBlock(RelPos pos, const Tile &t);
void setTileID(RelPos pos, Tile::ID id, SDL_Texture *tex);
void setTileData(RelPos pos, Tile::ID id);
void render(const Context &ctx, SDL_Renderer *rnd);

void compress();
void decompress();
void render(const Context &ctx);
void draw(const Context &ctx, Win &win);
void tick(float dt);

@@ -42,18 +41,18 @@ private:
static constexpr float DEACTIVATE_INTERVAL = 20;
static uint8_t *renderbuf;

void renderList(SDL_Renderer *rnd);

bool isCompressed() { return compressed_size_ != -1; }

std::unique_ptr<uint8_t[]> data_;
std::vector<std::pair<RelPos, SDL_Texture *>> draw_list_;

ssize_t compressed_size_ = -1; // -1 if not compressed, a positive number if compressed
bool need_render_ = false;
float deactivate_timer_ = DEACTIVATE_INTERVAL;

struct Visuals {
CPtr<SDL_Texture, SDL_DestroyTexture> texture_;
};
std::unique_ptr<Visuals> visuals_;
CPtr<SDL_Texture, SDL_DestroyTexture> texture_;
};

}

+ 5
- 1
libswan/include/swan/Clock.h View File

@@ -29,7 +29,11 @@ public:
}

friend std::ostream &operator<<(std::ostream &os, const RTClock &clock) {
os << (double)clock.duration() << 's';
double dur = clock.duration();
if (dur > 1)
os << dur << 's';
else
os << dur * 1000.0 << "ms";
return os;
}


+ 8
- 0
libswan/include/swan/Vector2.h View File

@@ -31,6 +31,14 @@ struct Vector2 {
return Vector2<T>(x > 0 ? 1 : -1, y > 0 ? 1 : -1);
}

constexpr Vector2<T> scale(T sx, T sy) {
return Vector2<T>(x * sx, y * sy);
}

constexpr Vector2<T> scale(T s) {
return scale(s, s);
}

constexpr operator std::pair<T, T>() const {
return std::pair<T, T>(x, y);
}

+ 4
- 1
libswan/include/swan/WorldPlane.h View File

@@ -1,6 +1,7 @@
#pragma once

#include <vector>
#include <deque>
#include <utility>
#include <memory>
#include <map>
@@ -19,7 +20,7 @@ namespace Swan {
class World;
class Game;

class WorldPlane {
class WorldPlane: NonCopyable {
public:
using ID = uint16_t;

@@ -66,6 +67,8 @@ private:
std::map<std::pair<int, int>, Chunk> chunks_;
std::set<Chunk *> active_chunks_;
std::vector<std::unique_ptr<Entity>> entities_;

std::deque<Chunk *> chunk_init_list_;
std::vector<std::unique_ptr<Entity>> spawn_list_;
std::vector<Entity *> despawn_list_;
std::vector<TilePos> debug_boxes_;

+ 16
- 0
libswan/include/swan/gfxutil.h View File

@@ -12,6 +12,22 @@ inline std::ostream &operator<<(std::ostream &os, const SDL_Rect &rect) {
return os;
}

class RenderTarget: NonCopyable {
public:
RenderTarget(SDL_Renderer *rnd, SDL_Texture *tex): rnd_(rnd) {
prev_target_ = SDL_GetRenderTarget(rnd_);
SDL_SetRenderTarget(rnd_, tex);
}

~RenderTarget() {
SDL_SetRenderTarget(rnd_, prev_target_);
}

private:
SDL_Renderer *rnd_;
SDL_Texture *prev_target_;
};

class TexLock: NonCopyable {
public:
TexLock(SDL_Texture *tex, SDL_Rect *rect = nullptr);

+ 36
- 33
libswan/src/Chunk.cc View File

@@ -23,19 +23,14 @@ Tile::ID Chunk::getTileID(RelPos pos) {
return getTileData()[pos.y * CHUNK_WIDTH + pos.x];
}

void Chunk::setTileID(RelPos pos, Tile::ID id) {
void Chunk::setTileID(RelPos pos, Tile::ID id, SDL_Texture *tex) {
getTileData()[pos.y * CHUNK_WIDTH + pos.x] = id;
draw_list_.push_back({ pos, tex });
}

void Chunk::drawBlock(RelPos pos, const Tile &t) {
keepActive();

SDL_Rect lockrect{ pos.x * TILE_SIZE, pos.y * TILE_SIZE, TILE_SIZE, TILE_SIZE };
TexLock lock(visuals_->texture_.get(), &lockrect);

SDL_Rect srcrect{ 0, 0, t.image_.surface_->w, t.image_.surface_->h };
SDL_Rect destrect{ 0, 0, TILE_SIZE, TILE_SIZE };
lock.blit(&destrect, t.image_.surface_.get(), &srcrect);
void Chunk::setTileData(RelPos pos, Tile::ID id) {
getTileData()[pos.y * CHUNK_WIDTH + pos.x] = id;
need_render_ = true;
}

void Chunk::compress() {
@@ -56,7 +51,7 @@ void Chunk::compress() {
data_.reset(new uint8_t[destlen]);
memcpy(data_.get(), dest, destlen);

visuals_.reset();
texture_.reset();
compressed_size_ = destlen;

info
@@ -88,8 +83,6 @@ void Chunk::decompress() {
}

data_ = std::move(dest);

visuals_.reset(new Visuals());
need_render_ = true;

info
@@ -99,22 +92,21 @@ void Chunk::decompress() {
compressed_size_ = -1;
}

void Chunk::render(const Context &ctx) {

void Chunk::render(const Context &ctx, SDL_Renderer *rnd) {
// The texture might not be created yet
if (!visuals_->texture_) {
visuals_->texture_.reset(SDL_CreateTexture(
ctx.game.win_.renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING,
if (!texture_) {
texture_.reset(SDL_CreateTexture(
ctx.game.win_.renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET,
CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE));
}

// We wanna render directly to the texture
RenderTarget target(rnd, texture_.get());

// We're caching tiles so we don't have to world.getTileByID() every time
Tile::ID prevID = Tile::INVALID_ID;
Tile *tile = ctx.game.invalid_tile_.get();

// Locking the texture lets us write to its piexls
TexLock lock(visuals_->texture_.get());

for (int y = 0; y < CHUNK_HEIGHT; ++y) {
for (int x = 0; x < CHUNK_WIDTH; ++x) {
Tile::ID id = getTileID(RelPos(x, y));
@@ -123,31 +115,42 @@ void Chunk::render(const Context &ctx) {
tile = &ctx.world.getTileByID(id);
}

// Find the source surface and rect...
auto &srcsurf = tile->image_.surface_;
SDL_Rect srcrect{ 0, 0, srcsurf->w, srcsurf->h };

// ...and blit it to the appropriate place
SDL_Rect destrect{ x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE };
if (lock.blit(&destrect, srcsurf.get(), &srcrect) < 0)
warn << "Failed to blit surface: " << SDL_GetError();
SDL_Rect dest{x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE};
SDL_RenderCopy(rnd, tile->image_.texture_.get(), nullptr, &dest);
}
}

need_render_ = false;
}

void Chunk::renderList(SDL_Renderer *rnd) {
// Here, we know that the texture is created.
// We still wanna render directly to the target texture
RenderTarget target(rnd, texture_.get());

for (auto &[pos, tex]: draw_list_) {
SDL_Rect dest{pos.x * TILE_SIZE, pos.y * TILE_SIZE, TILE_SIZE, TILE_SIZE};
SDL_RenderCopy(rnd, tex, nullptr, &dest);
}
}

void Chunk::draw(const Context &ctx, Win &win) {
if (isCompressed())
return;

if (need_render_) {
render(ctx);
need_render_ = false;
// The world plane is responsible for managing initial renders
if (need_render_)
return;

if (draw_list_.size() > 0) {
renderList(win.renderer_);
draw_list_.clear();
}

SDL_Rect rect{ 0, 0, CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE };
win.showTexture(
pos_ * Vec2i(CHUNK_WIDTH, CHUNK_HEIGHT),
visuals_->texture_.get(), &rect);
texture_.get(), &rect);
}

void Chunk::tick(float dt) {

+ 8
- 15
libswan/src/World.cc View File

@@ -7,18 +7,11 @@

namespace Swan {

static bool chunkLine(int l, WorldPlane &plane, ChunkPos &abspos, const Vec2i &dir, RTClock &clock) {
static void chunkLine(int l, WorldPlane &plane, ChunkPos &abspos, const Vec2i &dir) {
for (int i = 0; i < l; ++i) {
plane.getChunk(abspos);

// Don't blow our frame budget on generating chunks,
// but generate as many as possible within the budget
if (clock.duration() > 1 / 120.0)
return true;
abspos += dir;
}

return false;
}

World::World(Game *game, unsigned long rand_seed):
@@ -38,11 +31,11 @@ void World::ChunkRenderer::tick(WorldPlane &plane, ChunkPos abspos) {

RTClock clock;
for (int i = 0; i < 4; ++i) {
if (chunkLine(l, plane, abspos, Vec2i(0, -1), clock)) break;
if (chunkLine(l, plane, abspos, Vec2i(1, 0), clock)) break;
chunkLine(l, plane, abspos, Vec2i(0, -1));
chunkLine(l, plane, abspos, Vec2i(1, 0));
l += 1;
if (chunkLine(l, plane, abspos, Vec2i(0, 1), clock)) break;
if (chunkLine(l, plane, abspos, Vec2i(-1, 0), clock)) break;
chunkLine(l, plane, abspos, Vec2i(0, 1));
chunkLine(l, plane, abspos, Vec2i(-1, 0));
l += 1;
}
}
@@ -97,7 +90,7 @@ WorldPlane &World::addPlane(const std::string &gen) {

WorldGen::Factory *factory = it->second;
WorldGen *g = factory->create(*this);
planes_.push_back(WorldPlane(id, this, std::shared_ptr<WorldGen>(g)));
planes_.emplace_back(id, this, std::shared_ptr<WorldGen>(g));
return planes_[id];
}

@@ -147,8 +140,8 @@ void World::tick(float dt) {

auto bounds = player_->getBody().getBounds();
chunk_renderer_.tick(
planes_[current_plane_],
ChunkPos((int)bounds.pos.x / CHUNK_WIDTH, (int)bounds.pos.y / CHUNK_HEIGHT));
planes_[current_plane_],
ChunkPos((int)bounds.pos.x / CHUNK_WIDTH, (int)bounds.pos.y / CHUNK_HEIGHT));
}

}

+ 15
- 4
libswan/src/WorldPlane.cc View File

@@ -68,9 +68,10 @@ Chunk &WorldPlane::getChunk(ChunkPos pos) {

gen_->genChunk(*this, chunk);
active_chunks_.insert(&chunk);
chunk.render(getContext());
chunk_init_list_.push_back(&chunk);
} else if (iter->second.keepActive()) {
active_chunks_.insert(&iter->second);
chunk_init_list_.push_back(&iter->second);
}

return iter->second;
@@ -79,11 +80,13 @@ Chunk &WorldPlane::getChunk(ChunkPos pos) {
void WorldPlane::setTileID(TilePos pos, Tile::ID id) {
Chunk &chunk = getChunk(chunkPos(pos));
Chunk::RelPos rp = relPos(pos);
chunk.setTileID(rp, id);
chunk.drawBlock(rp, world_->getTileByID(id));

if (active_chunks_.find(&chunk) == active_chunks_.end())
chunk.setTileID(rp, id, world_->getTileByID(id).image_.texture_.get());

if (active_chunks_.find(&chunk) == active_chunks_.end()) {
active_chunks_.insert(&chunk);
chunk_init_list_.push_back(&chunk);
}
}

void WorldPlane::setTile(TilePos pos, const std::string &name) {
@@ -156,6 +159,14 @@ void WorldPlane::draw(Win &win) {
(int)floor(pbounds.pos.x / CHUNK_WIDTH),
(int)floor(pbounds.pos.y / CHUNK_HEIGHT));

// Just init one chunk per frame
if (chunk_init_list_.size() > 0) {
Chunk *chunk = chunk_init_list_.front();
info << "render chunk " << chunk->pos_;
chunk_init_list_.pop_front();
chunk->render(getContext(), win.renderer_);
}

for (int x = -1; x <= 1; ++x) {
for (int y = -1; y <= 1; ++y) {
auto iter = chunks_.find(pcpos + ChunkPos(x, y));

+ 4
- 0
src/main.cc View File

@@ -202,6 +202,10 @@ int main(int argc, char **argv) {
slow_frames = 0;
}

if (dt > 1/59.0) {
warn << "Dropped below 60 FPS: " << 1 / dt;
}

// Simple case: we can keep up, only need one physics update
RTClock update_clock;
if (dt <= 1 / 25.0) {

Loading…
Cancel
Save