Commit 075fe798 authored by Florian Oetke's avatar Florian Oetke
Browse files

fixed transfer_manager bug and better model loading

parent 6a32b809
......@@ -46,8 +46,8 @@ void main() {
out_color = vec4(textureLod(mat_data_sampler, vertex_out.tex_coords, pcs.prev_projection[2][3]).rgb, 1.0);
}
out_color = vec4(decode_normal(textureLod(mat_data_sampler, vertex_out.tex_coords, 0).rg), 1.0);
out_color = vec4(textureLod(albedo_sampler, vertex_out.tex_coords, 0).rgb, 1.0);
// out_color = vec4(decode_normal(textureLod(mat_data_sampler, vertex_out.tex_coords, 0).rg), 1.0);
// out_color = vec4(textureLod(albedo_sampler, vertex_out.tex_coords, 0).rgb, 1.0);
// out_color = vec4(texture(ao_sampler, vertex_out.tex_coords).rrr, 1.0);
}
......@@ -32,10 +32,10 @@ vec3 decode_tangent_normal(vec2 tn);
vec3 tangent_space_to_world(vec3 N);
void main() {
vec4 albedo = textureLod(albedo_sampler, vertex_out.tex_coords, 3);
vec4 albedo = texture(albedo_sampler, vertex_out.tex_coords);
// if(albedo.a < 0.1)
// discard;
if(albedo.a < 0.1)
discard;
vec4 mat_data = texture(mat_data_sampler, vertex_out.tex_coords); // TODO: LOD bias?
......
......@@ -2,13 +2,15 @@
#include <mirrage/ecs/components/transform_comp.hpp>
#include <mirrage/renderer/deferred_renderer.hpp>
#include <mirrage/renderer/loading_system.hpp>
namespace lux {
Meta_system::Meta_system(Game_engine& engine)
: _entities(engine.assets(), this)
, _renderer(engine.renderer_factory().create_renderer(_entities, *this)) {
, _renderer(engine.renderer_factory().create_renderer(_entities, *this))
, _model_loading(std::make_unique<renderer::Loading_system>(_entities, _renderer->model_loader())) {
_entities.register_component_type<ecs::components::Transform_comp>();
}
......@@ -20,6 +22,7 @@ namespace lux {
void Meta_system::update(util::Time dt) {
_entities.process_queued_actions();
_model_loading->update(dt);
_renderer->update(dt);
}
void Meta_system::draw() {
......
......@@ -7,6 +7,8 @@
namespace lux {
namespace renderer {class Deferred_renderer;}
namespace renderer {class Loading_system;}
class Meta_system {
public:
......@@ -24,6 +26,7 @@ namespace lux {
private:
ecs::Entity_manager _entities;
std::unique_ptr<renderer::Deferred_renderer> _renderer;
std::unique_ptr<renderer::Loading_system> _model_loading;
};
}
......@@ -65,15 +65,6 @@ namespace lux {
_sun = _meta_system.entities().emplace("sun");
// WORKAROUND until I've rewritten the transfer_manager/model loading
for(auto& model : _meta_system.entities().list<renderer::Model_comp>()) {
if(!model.model()) {
model.model(_meta_system.renderer().model_loader().load(model.model_aid()));
}
}
_meta_system.renderer().device().wait_idle();
// END WORKAROUND
_set_preset(1);
_mailbox.subscribe_to([&](input::Once_action& e){
......
......@@ -45,7 +45,6 @@ namespace lux {
};
auto mip_levels = std::floor(std::log2(std::min(width, height))) + 1;
mip_levels = 1;
auto texture = gli::texture2d(srgb ? gli::FORMAT_RGBA8_SRGB_PACK8
: gli::FORMAT_RGBA8_UNORM_PACK8,
......
......@@ -69,6 +69,10 @@ namespace ecs {
* Any component C may provide the following additional ADL functions for serialisation:
* - void load_component(ecs::Deserializer& state, C& v)
* - void save_component(ecs::Serializer& state, const C& v)
*
* The static constexpr methods name_save_as() may also be "overriden" replaced
* in a component to implement more complex compontent behaviour (e.g. a Live- and a Storage-
* Component that share the same name when storead but gets always loaded as a Storage-Component).
*/
template<class T, class Index_policy=Sparse_index_policy, class Storage_policy=Pool_storage_policy<32, T>>
class Component {
......@@ -94,6 +98,7 @@ namespace ecs {
using storage_policy = Storage_policy;
using Pool = Component_container<T>;
// static constexpr auto name() {return "Component";}
static constexpr const char* name_save_as() {return T::name();}
Component() : _manager(nullptr), _owner(invalid_entity) {}
Component(Entity_manager& manager, Entity_handle owner)
......
......@@ -145,7 +145,7 @@ namespace ecs {
bool save(Entity_handle owner, Serializer& serializer)override {
return find(owner).process(false, [&](T& comp) {
serializer.write_value(T::name());
serializer.write_value(T::name_save_as());
save_component(serializer, comp);
return true;
});
......
......@@ -138,8 +138,8 @@ namespace graphic {
return _delete_queue.destroy_later(std::forward<T>(obj));
}
auto finish_frame() -> std::tuple<vk::Fence, util::maybe<vk::Semaphore>> {
auto semaphore = _transfer_manager.next_frame();
auto finish_frame(vk::CommandBuffer transfer_barriers) -> std::tuple<vk::Fence, util::maybe<vk::Semaphore>> {
auto semaphore = _transfer_manager.next_frame(transfer_barriers);
return std::make_tuple(_delete_queue.start_new_frame(), std::move(semaphore));
}
......
......@@ -42,8 +42,6 @@ namespace graphic {
std::function<void(char*)> write_vertices, std::function<void(char*)> write_indices);
void generate_barriers(const Command_buffer&);
void bind(vk::CommandBuffer, std::uint32_t vertex_binding);
auto index_count()const noexcept {return _indices;}
......
......@@ -27,7 +27,6 @@ namespace graphic {
auto view()const noexcept {return *_image_view;}
auto image()const noexcept {return _image.image();}
void generate_barrier(const Command_buffer&);
auto width()const noexcept {return _image.width();}
auto height()const noexcept {return _image.height();}
......
......@@ -11,6 +11,7 @@
#include <memory>
#include <cstdint>
#include <tuple>
namespace lux {
......@@ -19,33 +20,29 @@ namespace graphic {
class Device;
// TODO: wrapper classes (Static_buffer/Static_image) are not realy required anymore and we
// 'could' just return Backed_buffer/Backed_image
class Static_buffer {
public:
Static_buffer(Backed_buffer buffer, std::uint32_t new_owner,
util::maybe<std::uint32_t> last_owner=util::nothing)
: _buffer(std::move(buffer)), _new_owner(new_owner), _last_owner(last_owner) {}
Static_buffer(Backed_buffer buffer)
: _buffer(std::move(buffer)) {}
Static_buffer(Static_buffer&&)noexcept ;
Static_buffer& operator=(Static_buffer&&)noexcept;
auto buffer()const noexcept {return *_buffer;}
void generate_barrier(const Command_buffer&, vk::PipelineStageFlags, vk::AccessFlags);
private:
Backed_buffer _buffer;
std::uint32_t _new_owner;
util::maybe<std::uint32_t> _last_owner;
};
class Static_image {
public:
Static_image(Backed_image image, std::uint32_t mip_count, bool generate_mips,
Image_dimensions dimensions,
std::uint32_t new_owner, util::maybe<std::uint32_t> last_owner=util::nothing)
Image_dimensions dimensions)
: _image(std::move(image)), _mip_count(mip_count), _generate_mips(generate_mips)
, _dimensions(dimensions), _new_owner(new_owner), _last_owner(last_owner) {}
, _dimensions(dimensions) {}
Static_image(Static_image&&)noexcept;
auto image()const noexcept {return *_image;}
void generate_barrier(const Command_buffer&);
auto mip_level_count()const noexcept {return _mip_count;}
auto width()const noexcept {return _dimensions.width;}
......@@ -58,8 +55,6 @@ namespace graphic {
std::uint32_t _mip_count;
bool _generate_mips;
Image_dimensions _dimensions;
std::uint32_t _new_owner;
util::maybe<std::uint32_t> _last_owner;
};
class Dynamic_buffer {
......@@ -190,9 +185,11 @@ namespace graphic {
/**
* @brief has to be called exacly once per frame, executes the transfer operations
* @arg The command buffer that will be filled with all required barriers (should be
* submitted before anything else in this frame)
* @return the semaphore that all draw operations have to wait on
*/
auto next_frame() -> util::maybe<vk::Semaphore>;
auto next_frame(vk::CommandBuffer) -> util::maybe<vk::Semaphore>;
private:
struct Transfer_buffer_req {
......
......@@ -186,9 +186,9 @@ namespace graphic {
const vk::Device& _device;
std::uint32_t _type;
Device_memory_pool<4L*1024, 256L*1024*1024> _temporary_pool;
Device_memory_pool<512L, 256L*1024*1024> _normal_pool;
Device_memory_pool<512L, 256L*1024*1024> _persistent_pool;
Device_memory_pool<1024L*1024, 256L*1024*1024> _temporary_pool;
Device_memory_pool<1024L*1024, 256L*1024*1024> _normal_pool;
Device_memory_pool<1024L*1024, 256L*1024*1024> _persistent_pool;
};
......@@ -285,13 +285,6 @@ namespace graphic {
for(auto id : pool_ids) {
if(type_mask & (1u<<id)) {
auto alloc_info = vk::MemoryAllocateInfo{size, id};
auto mem = _device.allocateMemoryUnique(alloc_info);
return Device_memory{this, +[](void* self, std::uint32_t,
std::uint32_t, vk::DeviceMemory memory) {
static_cast<Device_memory_allocator*>(self)->_device.freeMemory(memory);
}, 0, 0, mem.release(), 0};
/*
auto& pool = _pools[id];
if(!pool) {
pool.reset(new Device_heap(_device, id));
......@@ -307,7 +300,7 @@ namespace graphic {
if(e.code()==vk::Result::eErrorOutOfDeviceMemory && shrink_to_fit()>0) {
return pool->alloc(size, alignment, lifetime);
}
}*/
}
}
}
......
......@@ -20,11 +20,6 @@ namespace graphic {
, _indices(index_count / sizeof(std::uint32_t)) {
}
void Mesh::generate_barriers(const Command_buffer& cb) {
_buffer.generate_barrier(cb, vk::PipelineStageFlagBits::eVertexInput,
vk::AccessFlagBits::eIndexRead|vk::AccessFlagBits::eVertexAttributeRead);
}
void Mesh::bind(vk::CommandBuffer cb, std::uint32_t vertex_binding) {
cb.bindVertexBuffers(vertex_binding, {_buffer.buffer()}, {0});
cb.bindIndexBuffer(_buffer.buffer(), _index_offset, vk::IndexType::eUint32);
......
......@@ -80,7 +80,7 @@ namespace graphic {
vk::Extent3D{dim.width, dim.height, dim.depth},
clamp_mip_levels(dim.width, dim.height, mip_levels),
dim.layers, vk::SampleCountFlagBits::e1, vk::ImageTiling::eOptimal,
usage}, false, Memory_lifetime::normal, dedicated), mip_levels, false, dim, 0)
usage}, false, Memory_lifetime::normal, dedicated), mip_levels, false, dim)
, _image_view(device.create_image_view(_image.image(), format, 0, _image.mip_level_count(), aspects)) {
}
......@@ -101,9 +101,6 @@ namespace graphic {
: _image(std::move(image))
, _image_view(device.create_image_view(this->image(), format, 0, _image.mip_level_count())) {
}
void Base_texture::generate_barrier(const Command_buffer& cb) {
_image.generate_barrier(cb);
}
auto build_mip_views(Device& device, std::uint32_t mip_levels,
vk::Image image, vk::Format format,
......
......@@ -8,77 +8,17 @@ namespace graphic {
Static_buffer::Static_buffer(Static_buffer&& rhs)noexcept
: _buffer(std::move(rhs._buffer)), _new_owner(std::move(rhs._new_owner))
, _last_owner(std::move(rhs._last_owner)) {
: _buffer(std::move(rhs._buffer)) {
}
Static_buffer& Static_buffer::operator=(Static_buffer&& rhs)noexcept {
_buffer = std::move(rhs._buffer);
_new_owner = std::move(rhs._new_owner);
_last_owner = std::move(rhs._last_owner);
return *this;
}
void Static_buffer::generate_barrier(const Command_buffer& command_buffer,
vk::PipelineStageFlags pipeline_stage, vk::AccessFlags access) {
if(_last_owner.is_nothing() || _last_owner.get_or_throw()==_new_owner)
return;
// queue family release operation
auto buffer_barrier = vk::BufferMemoryBarrier {
vk::AccessFlags{}, access, _last_owner.get_or_throw(), _new_owner,
*_buffer, 0, VK_WHOLE_SIZE
};
// srcStageMask should be 0 (based on the spec) but validation layer complains
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, pipeline_stage,
vk::DependencyFlags{}, {}, {buffer_barrier}, {});
_last_owner = util::nothing;
}
Static_image::Static_image(Static_image&& rhs)noexcept
: _image(std::move(rhs._image))
, _mip_count(std::move(rhs._mip_count))
, _dimensions(std::move(rhs._dimensions))
, _new_owner(std::move(rhs._new_owner))
, _last_owner(std::move(rhs._last_owner)) {
}
void Static_image::generate_barrier(const Command_buffer& command_buffer) {
if(_last_owner.is_some()) {
// queue family release operation
auto subresource = vk::ImageSubresourceRange {
vk::ImageAspectFlagBits::eColor, 0, _mip_count, 0, _dimensions.layers
};
auto barrier = vk::ImageMemoryBarrier {
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead
| vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferWrite,
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferDstOptimal,
_last_owner.get_or_throw(), _new_owner, *_image, subresource
};
// srcStageMask should be 0 (based on the spec) but validation layer complains
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlags{}, {}, {}, {barrier});
if(!_generate_mips) {
image_layout_transition(command_buffer, *_image,
vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eShaderReadOnlyOptimal,
vk::ImageAspectFlagBits::eColor,
0, _mip_count);
}
if(_generate_mips) {
_generate_mips = false;
// generate complete mip chain
generate_mipmaps(command_buffer, *_image, vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eShaderReadOnlyOptimal,
_dimensions.width, _dimensions.height, _mip_count);
}
_last_owner = util::nothing;
}
, _dimensions(std::move(rhs._dimensions)) {
}
void Dynamic_buffer::update(const Command_buffer& cb, vk::DeviceSize offset,
......@@ -166,7 +106,7 @@ namespace graphic {
std::function<void(char*)> write_data,
bool dedicated) -> Static_image {
mip_levels=0;
mip_levels=0; // TODO: test code: delete
auto stored_mip_levels = std::max(1u, mip_levels);
auto actual_mip_levels = mip_levels;
......@@ -231,7 +171,7 @@ namespace graphic {
real_dimensions, std::move(mip_image_sizes));
return {std::move(final_image), actual_mip_levels, mip_levels==0,
real_dimensions, owner, _queue_family};
real_dimensions};
}
auto Transfer_manager::upload_buffer(vk::BufferUsageFlags usage, std::uint32_t owner,
......@@ -250,7 +190,7 @@ namespace graphic {
if(_device.is_unified_memory_architecture()) {
// no transfer required
return {std::move(staging_buffer), owner};
return {std::move(staging_buffer)};
}
......@@ -260,7 +200,7 @@ namespace graphic {
_buffer_transfers.emplace_back(std::move(staging_buffer), *final_buffer, size, owner);
return {std::move(final_buffer), owner, _queue_family};
return {std::move(final_buffer)};
}
auto Transfer_manager::_create_staging_buffer(vk::BufferUsageFlags usage,
......@@ -300,10 +240,13 @@ namespace graphic {
latest_usage, latest_usage_access};
}
auto Transfer_manager::next_frame() -> util::maybe<vk::Semaphore> {
auto Transfer_manager::next_frame(vk::CommandBuffer main_queue_commands) -> util::maybe<vk::Semaphore> {
if(_buffer_transfers.empty() && _image_transfers.empty())
return util::nothing;
main_queue_commands.begin(vk::CommandBufferBeginInfo{vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
auto& command_buffer = *_command_buffers.current();
command_buffer.begin(vk::CommandBufferBeginInfo{vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
......@@ -317,11 +260,22 @@ namespace graphic {
t.dst, 0, VK_WHOLE_SIZE
};
// dstStageMask should be 0 (based on the spec) but validation layer complains
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlags{}, {}, {buffer_barrier}, {});
_device.destroy_after_frame(std::move(t.src));
// executed in graphics queue
// queue family aquire operation
auto aq_buffer_barrier = vk::BufferMemoryBarrier {
vk::AccessFlags{}, vk::AccessFlags{}, _queue_family, t.owner,
t.dst, 0, VK_WHOLE_SIZE
};
// srcStageMask should be 0 (based on the spec) but validation layer complains
main_queue_commands.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlags{}, {}, {aq_buffer_barrier}, {});
}
_buffer_transfers.clear();
......@@ -345,11 +299,48 @@ namespace graphic {
vk::DependencyFlags{}, {}, {}, {barrier});
_device.destroy_after_frame(std::move(t.src));
// executed in graphics queue
{
// queue family aquire operation
auto subresource = vk::ImageSubresourceRange {
vk::ImageAspectFlagBits::eColor, 0, t.mip_count_actual, 0, t.dimensions.layers
};
auto barrier = vk::ImageMemoryBarrier {
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead
| vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferWrite,
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferDstOptimal,
_queue_family, t.owner, t.dst, subresource
};
// srcStageMask should be 0 (based on the spec) but validation layer complains
main_queue_commands.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlags{}, {}, {}, {barrier});
if(t.generate_mips) {
// generate complete mip chain
generate_mipmaps(main_queue_commands, t.dst, vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eShaderReadOnlyOptimal,
t.dimensions.width, t.dimensions.height, t.mip_count_actual);
} else {
image_layout_transition(main_queue_commands, t.dst,
vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eShaderReadOnlyOptimal,
vk::ImageAspectFlagBits::eColor,
0, t.mip_count_actual);
}
}
}
_image_transfers.clear();
command_buffer.end();
main_queue_commands.end();
auto submit_info = vk::SubmitInfo {
0, nullptr, nullptr,
1, &command_buffer,
......
......@@ -27,6 +27,7 @@ add_library(mirrage_renderer STATIC
src/deferred_renderer.cpp
src/gbuffer.cpp
src/light_comp.cpp
src/loading_system.cpp
src/model_comp.cpp
src/model.cpp
......
#pragma once
#include <mirrage/renderer/model.hpp>
#include <mirrage/renderer/model_comp.hpp>
#include <mirrage/ecs/ecs.hpp>
#include <mirrage/utils/units.hpp>
namespace lux {
namespace renderer {
/**
* Handles the loading and unloading of models.
* Has to be instantiated and updated for ANY model components to be loaded and rendered!
*
* This implementation always loads all model components as soon as they are added and never
* unloads anything automatically.
* Subclasses may implement a different behaviour by overriding _update() and NOT calling
* the base class implementation but _load(...) and _unload(...) themself.
*/
class Loading_system {
public:
Loading_system(ecs::Entity_manager& ecs, Model_loader&);
virtual ~Loading_system() = default;
void update(util::Time);
protected:
Model_comp::Pool& _loaded_models;
Model_unloaded_comp::Pool& _unloaded_models;
Model_loading_comp::Pool& _loading_models;
void _load (Model_unloaded_comp&);
void _unload(Model_comp&);
virtual void _update(util::Time);
private:
Model_loader& _loader;
void _finish_loading();
};
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment