fix: put all opengl things on main thread to render chunks correctly
This commit is contained in:
parent
5e0bae610e
commit
6d4d9394f4
4 changed files with 127 additions and 67 deletions
79
src/main.zig
79
src/main.zig
|
|
@ -10,6 +10,7 @@ const chunks = @import("world/chunk.zig");
|
|||
const WorldState = @import("world/world_state.zig").WorldState;
|
||||
const CameraChunkloader = @import("world/world_state.zig").CameraChunkloader;
|
||||
const chunk_generators = @import("world/chunk_generators.zig");
|
||||
const GraphicsTaskManager = @import("util/task_manager.zig").GraphicsTaskManager;
|
||||
|
||||
const TILE_TEXTURE_RESOLUTION = 16;
|
||||
|
||||
|
|
@ -52,6 +53,15 @@ var time: struct {
|
|||
}
|
||||
} = .{};
|
||||
|
||||
pub const ChunkGraphicsResources = struct {
|
||||
tile_rows: u32,
|
||||
tile_columns: u32,
|
||||
texture: raylib.Texture,
|
||||
ambient_occlusion_texture: raylib.Texture,
|
||||
shader: raylib.Shader,
|
||||
graphics_task_manager: *GraphicsTaskManager,
|
||||
};
|
||||
|
||||
pub fn drawCameraPosition(camera: raylib.Camera3D, x: i32, y: i32) !void {
|
||||
var buf: [256:0]u8 = undefined;
|
||||
|
||||
|
|
@ -128,24 +138,22 @@ pub fn main() !void {
|
|||
try thread_pool.init(.{.allocator = allocator});
|
||||
defer thread_pool.deinit();
|
||||
|
||||
var global_graphics_mutex: std.Thread.Mutex = undefined;
|
||||
var graphics_task_manager: GraphicsTaskManager = GraphicsTaskManager.init(allocator);
|
||||
defer graphics_task_manager.deinit();
|
||||
|
||||
const chunk_graphics_resources: chunks.ChunkGraphicsResources = .{
|
||||
const chunk_graphics_resources: ChunkGraphicsResources = .{
|
||||
.tile_rows = tile_rows,
|
||||
.tile_columns = tile_columns,
|
||||
.texture = texture,
|
||||
.ambient_occlusion_texture = ambient_occlusion_texture,
|
||||
.shader = shader,
|
||||
.global_graphics_mutex = &global_graphics_mutex
|
||||
.graphics_task_manager = &graphics_task_manager,
|
||||
};
|
||||
|
||||
var world_state: WorldState = WorldState.init(&thread_pool, allocator, chunk_graphics_resources);
|
||||
defer world_state.deinit();
|
||||
|
||||
// for (0..10) |x| for (0..10) |z| {
|
||||
// try world_state.queueLoadChunk(.{@intCast(x), 0, @intCast(z)});
|
||||
// };
|
||||
var chunkloader = CameraChunkloader.init(allocator, 3);
|
||||
var chunkloader = CameraChunkloader.init(allocator, 10);
|
||||
try chunkloader.update(&world_state, .{0, 0, 0});
|
||||
defer chunkloader.deinit();
|
||||
|
||||
|
|
@ -182,47 +190,40 @@ pub fn main() !void {
|
|||
}
|
||||
}
|
||||
|
||||
raylib.ClearBackground(raylib.BLACK);
|
||||
|
||||
{
|
||||
global_graphics_mutex.lock();
|
||||
defer global_graphics_mutex.unlock();
|
||||
raylib.MakeContextCurrent();
|
||||
defer raylib.DropContextCurrent();
|
||||
|
||||
raylib.ClearBackground(raylib.BLACK);
|
||||
raylib.BeginDrawing();
|
||||
defer raylib.EndDrawing();
|
||||
|
||||
var chunk_count: u32 = 0;
|
||||
var shown_count: u32 = 0;
|
||||
|
||||
{
|
||||
raylib.BeginDrawing();
|
||||
defer raylib.EndDrawing();
|
||||
raylib.BeginMode3D(camera);
|
||||
defer raylib.EndMode3D();
|
||||
|
||||
var chunk_count: u32 = 0;
|
||||
var shown_count: u32 = 0;
|
||||
world_state.chunks_access_mutex.lock();
|
||||
defer world_state.chunks_access_mutex.unlock();
|
||||
|
||||
{
|
||||
raylib.BeginMode3D(camera);
|
||||
defer raylib.EndMode3D();
|
||||
|
||||
world_state.chunks_access_mutex.lock();
|
||||
defer world_state.chunks_access_mutex.unlock();
|
||||
|
||||
var chunks_iterator = world_state.chunks.valueIterator();
|
||||
while (chunks_iterator.next()) |entry_ptr| {
|
||||
const entry = entry_ptr.*;
|
||||
if (entry.*.model) |model| {
|
||||
const model_position = v3.new(@floatFromInt(entry.position[0]*16), @floatFromInt(entry.position[1]*16), @floatFromInt(entry.position[2]*16));
|
||||
raylib.DrawChunkModel(model, model_position, 0.5, raylib.WHITE);
|
||||
shown_count += 1;
|
||||
}
|
||||
chunk_count += 1;
|
||||
var chunks_iterator = world_state.chunks.valueIterator();
|
||||
while (chunks_iterator.next()) |entry_ptr| {
|
||||
const entry = entry_ptr.*;
|
||||
if (entry.*.model) |model| {
|
||||
const model_position = v3.new(@floatFromInt(entry.position[0]*16), @floatFromInt(entry.position[1]*16), @floatFromInt(entry.position[2]*16));
|
||||
raylib.DrawChunkModel(model, model_position, 0.5, raylib.WHITE);
|
||||
shown_count += 1;
|
||||
}
|
||||
chunk_count += 1;
|
||||
}
|
||||
|
||||
try drawFmtText("fps: {d:.0}", .{time.fps()}, 10, 10);
|
||||
try drawCameraPosition(camera, 10, 30);
|
||||
try drawFmtText("chunks shown: {}, chunks total: {}", .{shown_count, chunk_count}, 10, 50);
|
||||
}
|
||||
|
||||
raylib.SwapScreenBuffer();
|
||||
|
||||
try drawFmtText("fps: {d:.0}", .{time.fps()}, 10, 10);
|
||||
try drawCameraPosition(camera, 10, 30);
|
||||
try drawFmtText("chunks shown: {}, chunks total: {}", .{shown_count, chunk_count}, 10, 50);
|
||||
}
|
||||
raylib.SwapScreenBuffer();
|
||||
try graphics_task_manager.executeAll();
|
||||
time.update();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
75
src/util/task_manager.zig
Normal file
75
src/util/task_manager.zig
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Mutex = std.Thread.Mutex;
|
||||
const Condition = std.Thread.Condition;
|
||||
const ArrayList = std.ArrayList;
|
||||
|
||||
const ChunkGraphicsResources = @import("../main.zig").ChunkGraphicsResources;
|
||||
|
||||
const raylib_helper = @import("../lib_helpers/raylib_helper.zig");
|
||||
const raylib = raylib_helper.raylib;
|
||||
|
||||
pub const GraphicsTaskManager = struct {
|
||||
pub const Task = union(enum) {
|
||||
upload_chunk_mesh: *raylib.ChunkMesh,
|
||||
set_chunk_ambient_occlusion: struct {model: *raylib.ChunkModel, resources: ChunkGraphicsResources},
|
||||
signal: *Condition,
|
||||
print: []const u8,
|
||||
};
|
||||
|
||||
allocator: Allocator,
|
||||
tasks: ArrayList(Task),
|
||||
mutex: Mutex = .{},
|
||||
|
||||
pub fn init(allocator: Allocator) GraphicsTaskManager {
|
||||
var self: GraphicsTaskManager = undefined;
|
||||
self.allocator = allocator;
|
||||
self.tasks = ArrayList(Task).init(allocator);
|
||||
return self;
|
||||
}
|
||||
pub fn deinit(self: *GraphicsTaskManager) void{
|
||||
self.tasks.deinit();
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn executeAll(self: *GraphicsTaskManager) !void {
|
||||
self.mutex.lock();
|
||||
const tasks = try self.tasks.toOwnedSlice();
|
||||
defer self.allocator.free(tasks);
|
||||
self.mutex.unlock();
|
||||
|
||||
for(tasks) |task| {
|
||||
switch (task) {
|
||||
Task.upload_chunk_mesh => |mesh_ptr| {
|
||||
raylib.UploadChunkMesh(mesh_ptr, false);
|
||||
},
|
||||
Task.set_chunk_ambient_occlusion => |args| {
|
||||
args.model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1] = raylib.GetShaderLocation(args.resources.shader, "occlusionMap");
|
||||
raylib.SetShaderValueTexture(args.resources.shader, args.model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1], args.resources.ambient_occlusion_texture);
|
||||
args.model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE+1].texture = args.resources.ambient_occlusion_texture;
|
||||
},
|
||||
Task.signal => |condition| {
|
||||
condition.signal();
|
||||
},
|
||||
Task.print => |str| {
|
||||
std.debug.print("{s}", .{str});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn submit(self: *GraphicsTaskManager, task: Task) !void {
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
try self.tasks.append(task);
|
||||
}
|
||||
|
||||
pub fn wait(self: *GraphicsTaskManager) !void {
|
||||
var mutex: Mutex = .{};
|
||||
var condition: Condition = .{};
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
try self.submit(.{.signal = &condition});
|
||||
condition.wait(&mutex);
|
||||
}
|
||||
};
|
||||
|
|
@ -54,16 +54,6 @@ comptime {
|
|||
}
|
||||
}
|
||||
|
||||
pub const ChunkGraphicsResources = struct {
|
||||
tile_rows: u32,
|
||||
tile_columns: u32,
|
||||
texture: raylib.Texture,
|
||||
ambient_occlusion_texture: raylib.Texture,
|
||||
shader: raylib.Shader,
|
||||
global_graphics_mutex: *std.Thread.Mutex
|
||||
};
|
||||
|
||||
|
||||
pub const Chunk = struct {
|
||||
tiles: []u32,
|
||||
allocator: Allocator,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const AutoHashMap = std.AutoHashMap;
|
|||
const ArrayList = std.ArrayList;
|
||||
|
||||
const Chunk = @import("chunk.zig").Chunk;
|
||||
const ChunkGraphicsResources = @import("chunk.zig").ChunkGraphicsResources;
|
||||
const ChunkGraphicsResources = @import("../main.zig").ChunkGraphicsResources;
|
||||
const chunk_generators = @import("chunk_generators.zig");
|
||||
|
||||
const raylib_helper = @import("../lib_helpers/raylib_helper.zig");
|
||||
|
|
@ -42,7 +42,7 @@ pub const CameraChunkloader = struct {
|
|||
if(self.loaded.contains(position)){
|
||||
return;
|
||||
}
|
||||
if(@reduce(.Add, (position-self.current_position)*(position-self.current_position)) > self.render_distance*self.render_distance){
|
||||
if(@reduce(.Add, (position-self.current_position)*(position-self.current_position)) >= self.render_distance*self.render_distance){
|
||||
try self.to_load.put(position, {});
|
||||
return;
|
||||
}
|
||||
|
|
@ -135,7 +135,7 @@ pub const WorldState = struct {
|
|||
return chunk;
|
||||
}
|
||||
|
||||
pub fn generateChunkModel(self: *WorldState, pos: @Vector(3, i64)) !raylib.ChunkModel {
|
||||
pub fn generateChunkModel(self: *WorldState, pos: @Vector(3, i64)) !void {
|
||||
const resources = self.chunk_graphics_resources;
|
||||
self.chunks_access_mutex.lock();
|
||||
const chunk_entry = blk: {
|
||||
|
|
@ -152,25 +152,19 @@ pub const WorldState = struct {
|
|||
const chunk = chunk_entry.chunk;
|
||||
if(chunk == null) return WorldStateError.ChunkNotGeneratedError;
|
||||
|
||||
// TODO: we wait twice here for a frame. perhaps we can do something different and wait just once or not wait at all?
|
||||
|
||||
var mesh = try chunk.?.createMesh(resources.tile_rows, resources.tile_columns);
|
||||
const model = blk: {
|
||||
resources.global_graphics_mutex.lock();
|
||||
defer resources.global_graphics_mutex.unlock();
|
||||
raylib.MakeContextCurrent();
|
||||
defer raylib.DropContextCurrent();
|
||||
try resources.graphics_task_manager.submit(.{.upload_chunk_mesh = &mesh});
|
||||
try resources.graphics_task_manager.wait();
|
||||
|
||||
raylib.UploadChunkMesh(@ptrCast(&mesh), false);
|
||||
var model = raylib.LoadChunkModelFromMesh(mesh);
|
||||
model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE].texture = resources.texture;
|
||||
model.materials[0].shader = resources.shader;
|
||||
|
||||
const model = raylib.LoadChunkModelFromMesh(mesh);
|
||||
model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE].texture = resources.texture;
|
||||
model.materials[0].shader = resources.shader;
|
||||
try resources.graphics_task_manager.submit(.{.set_chunk_ambient_occlusion = .{.model = &model, .resources = resources}});
|
||||
try resources.graphics_task_manager.wait();
|
||||
|
||||
model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1] = raylib.GetShaderLocation(resources.shader, "occlusionMap");
|
||||
raylib.SetShaderValueTexture(resources.shader, model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1], resources.ambient_occlusion_texture);
|
||||
model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE+1].texture = resources.ambient_occlusion_texture;
|
||||
break :blk model;
|
||||
};
|
||||
chunk_entry.model = model;
|
||||
return model;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue