mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-14 16:09:06 +07:00
Merge remote-tracking branch 'origin/master' into feature/debug_hierarchy
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include "input.hpp"
|
||||
#include "network.hpp"
|
||||
#include "platform.hpp"
|
||||
#include "profiler.hpp"
|
||||
#include "render.hpp"
|
||||
#include "render.inl"
|
||||
#include "vfs.hpp"
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include <curly.hpp/curly.hpp>
|
||||
|
||||
#include <promise.hpp/invoke.hpp>
|
||||
#include <promise.hpp/jobber.hpp>
|
||||
#include <promise.hpp/promise.hpp>
|
||||
#include <promise.hpp/scheduler.hpp>
|
||||
@@ -26,7 +25,6 @@ namespace e2d
|
||||
|
||||
namespace stdex
|
||||
{
|
||||
using namespace invoke_hpp;
|
||||
using namespace jobber_hpp;
|
||||
using namespace promise_hpp;
|
||||
using namespace scheduler_hpp;
|
||||
@@ -44,6 +42,7 @@ namespace e2d
|
||||
class input;
|
||||
class network;
|
||||
class platform;
|
||||
class profiler;
|
||||
class render;
|
||||
class shader;
|
||||
class texture;
|
||||
|
||||
@@ -83,12 +83,9 @@ namespace e2d
|
||||
audio(debug& d);
|
||||
~audio() noexcept;
|
||||
|
||||
[[nodiscard]] sound_stream_ptr preload_stream(
|
||||
[[nodiscard]] sound_stream_ptr create_stream(
|
||||
buffer_view sound_data);
|
||||
|
||||
[[nodiscard]] sound_stream_ptr preload_stream(
|
||||
const input_stream_uptr& file_stream);
|
||||
|
||||
[[nodiscard]] sound_stream_ptr create_stream(
|
||||
input_stream_uptr file_stream);
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ namespace e2d
|
||||
|
||||
template < typename T >
|
||||
void active_safe_wait_promise(const stdex::promise<T>& promise) noexcept;
|
||||
|
||||
void frame_tick() noexcept;
|
||||
private:
|
||||
stdex::jobber worker_;
|
||||
stdex::scheduler scheduler_;
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
#include "_core.hpp"
|
||||
|
||||
#include "window.hpp"
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class mouse final : private noncopyable {
|
||||
@@ -120,16 +118,4 @@ namespace e2d
|
||||
class internal_state;
|
||||
std::unique_ptr<internal_state> state_;
|
||||
};
|
||||
|
||||
class window_input_source : public window::event_listener {
|
||||
public:
|
||||
window_input_source(input& input) noexcept;
|
||||
void on_input_char(char32_t uchar) noexcept final;
|
||||
void on_move_cursor(const v2f& pos) noexcept final;
|
||||
void on_mouse_scroll(const v2f& delta) noexcept final;
|
||||
void on_mouse_button(mouse_button btn, mouse_button_action act) noexcept final;
|
||||
void on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept final;
|
||||
private:
|
||||
input& input_;
|
||||
};
|
||||
}
|
||||
|
||||
221
headers/enduro2d/core/profiler.hpp
Normal file
221
headers/enduro2d/core/profiler.hpp
Normal file
@@ -0,0 +1,221 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "_core.hpp"
|
||||
|
||||
#include "deferrer.hpp"
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class profiler final : public module<profiler> {
|
||||
public:
|
||||
using args_t = flat_map<str, str>;
|
||||
|
||||
struct begin_scope_info {
|
||||
str name;
|
||||
args_t args;
|
||||
std::thread::id tid;
|
||||
std::chrono::microseconds tp;
|
||||
};
|
||||
|
||||
struct end_scope_info {
|
||||
std::thread::id tid;
|
||||
std::chrono::microseconds tp;
|
||||
};
|
||||
|
||||
struct thread_event_info {
|
||||
str name;
|
||||
args_t args;
|
||||
std::thread::id tid;
|
||||
std::chrono::microseconds tp;
|
||||
};
|
||||
|
||||
struct global_event_info {
|
||||
str name;
|
||||
args_t args;
|
||||
std::thread::id tid;
|
||||
std::chrono::microseconds tp;
|
||||
};
|
||||
|
||||
using event_info = std::variant<
|
||||
begin_scope_info,
|
||||
end_scope_info,
|
||||
thread_event_info,
|
||||
global_event_info>;
|
||||
public:
|
||||
class sink : private e2d::noncopyable {
|
||||
public:
|
||||
virtual ~sink() noexcept = default;
|
||||
virtual void on_event(const event_info& event) noexcept = 0;
|
||||
};
|
||||
using sink_uptr = std::unique_ptr<sink>;
|
||||
public:
|
||||
class auto_scope final : private e2d::noncopyable {
|
||||
public:
|
||||
auto_scope(profiler* profiler, str name);
|
||||
auto_scope(profiler* profiler, str name, args_t args);
|
||||
~auto_scope() noexcept;
|
||||
private:
|
||||
profiler* profiler_ = nullptr;
|
||||
};
|
||||
public:
|
||||
profiler(deferrer& d);
|
||||
~profiler() noexcept final;
|
||||
|
||||
void begin_scope(str name) noexcept;
|
||||
void begin_scope(str name, args_t args) noexcept;
|
||||
void end_scope() noexcept;
|
||||
|
||||
void thread_event(str name) noexcept;
|
||||
void thread_event(str name, args_t args) noexcept;
|
||||
|
||||
void global_event(str name) noexcept;
|
||||
void global_event(str name, args_t args) noexcept;
|
||||
public:
|
||||
struct recording_info {
|
||||
vector<event_info> events;
|
||||
};
|
||||
|
||||
template < typename Rep, typename Period >
|
||||
stdex::promise<recording_info> record_for(
|
||||
const std::chrono::duration<Rep, Period>& timeout_duration);
|
||||
|
||||
template < typename Clock, typename Duration >
|
||||
stdex::promise<recording_info> record_until(
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time);
|
||||
public:
|
||||
template < typename T, typename... Args >
|
||||
T& register_sink(Args&&... args);
|
||||
sink& register_sink(sink_uptr sink);
|
||||
void unregister_sink(const sink& sink) noexcept;
|
||||
private:
|
||||
deferrer& deferrer_;
|
||||
std::size_t depth_{0u};
|
||||
vector<sink_uptr> sinks_;
|
||||
std::recursive_mutex rmutex_;
|
||||
};
|
||||
}
|
||||
|
||||
#define E2D_PROFILER_SCOPE(name)\
|
||||
auto E2D_PP_CAT(e2d_generated_profiler_auto_scope_, __LINE__) =\
|
||||
::e2d::profiler::auto_scope(\
|
||||
modules::is_initialized<profiler>() ? &the<profiler>() : nullptr,\
|
||||
name);
|
||||
|
||||
#define E2D_PROFILER_SCOPE_EX(name, ...)\
|
||||
auto E2D_PP_CAT(e2d_generated_profiler_auto_scope_, __LINE__) =\
|
||||
::e2d::profiler::auto_scope(\
|
||||
modules::is_initialized<profiler>() ? &the<profiler>() : nullptr,\
|
||||
name,\
|
||||
__VA_ARGS__);
|
||||
|
||||
#define E2D_PROFILER_THREAD_EVENT(name)\
|
||||
if ( modules::is_initialized<profiler>() ) {\
|
||||
the<profiler>().thread_event(name);\
|
||||
}
|
||||
|
||||
#define E2D_PROFILER_THREAD_EVENT_EX(name, ...)\
|
||||
if ( modules::is_initialized<profiler>() ) {\
|
||||
the<profiler>().thread_event(name, __VA_ARGS___);\
|
||||
}
|
||||
|
||||
#define E2D_PROFILER_GLOBAL_EVENT(name)\
|
||||
if ( modules::is_initialized<profiler>() ) {\
|
||||
the<profiler>().global_event(name);\
|
||||
}
|
||||
|
||||
#define E2D_PROFILER_GLOBAL_EVENT_EX(name, ...)\
|
||||
if ( modules::is_initialized<profiler>() ) {\
|
||||
the<profiler>().global_event(name, __VA_ARGS__);\
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
template < typename Rep, typename Period >
|
||||
stdex::promise<profiler::recording_info> profiler::record_for(
|
||||
const std::chrono::duration<Rep, Period>& timeout_duration)
|
||||
{
|
||||
return record_until(std::chrono::steady_clock::now() + timeout_duration);
|
||||
}
|
||||
|
||||
template < typename Clock, typename Duration >
|
||||
stdex::promise<profiler::recording_info> profiler::record_until(
|
||||
const std::chrono::time_point<Clock, Duration>& timeout_time)
|
||||
{
|
||||
using promise_t = stdex::promise<recording_info>;
|
||||
using time_point_t = std::chrono::time_point<Clock, Duration>;
|
||||
|
||||
class temp_sink final : public sink {
|
||||
public:
|
||||
temp_sink(std::size_t depth, time_point_t time_point)
|
||||
: depth_(depth)
|
||||
, time_point_(time_point) {}
|
||||
|
||||
void on_event(const event_info& event) noexcept final {
|
||||
const bool skip = info_.events.empty() && depth_;
|
||||
|
||||
if ( std::holds_alternative<begin_scope_info>(event) ) {
|
||||
++depth_;
|
||||
} else if ( std::holds_alternative<end_scope_info>(event) ) {
|
||||
E2D_ASSERT(depth_);
|
||||
--depth_;
|
||||
}
|
||||
|
||||
try {
|
||||
if ( !skip ) {
|
||||
info_.events.push_back(event);
|
||||
}
|
||||
|
||||
if ( !depth_ && time_point_ <= Clock::now() ) {
|
||||
promise_.resolve(std::move(info_));
|
||||
}
|
||||
} catch (...) {
|
||||
promise_.reject(std::current_exception());
|
||||
}
|
||||
}
|
||||
|
||||
promise_t& promise() noexcept {
|
||||
return promise_;
|
||||
}
|
||||
|
||||
const promise_t& promise() const noexcept {
|
||||
return promise_;
|
||||
}
|
||||
private:
|
||||
promise_t promise_;
|
||||
recording_info info_;
|
||||
std::size_t depth_{0u};
|
||||
time_point_t time_point_;
|
||||
};
|
||||
|
||||
temp_sink& s = register_sink<temp_sink>(depth_, timeout_time);
|
||||
return s.promise().then([&s, this](auto&& info){
|
||||
return deferrer_.do_in_main_thread([&s, this](auto&& info){
|
||||
unregister_sink(s);
|
||||
return std::forward<decltype(info)>(info);
|
||||
}, std::forward<decltype(info)>(info));
|
||||
});
|
||||
}
|
||||
|
||||
template < typename T, typename... Args >
|
||||
T& profiler::register_sink(Args&&... args) {
|
||||
return static_cast<T&>(
|
||||
register_sink(std::make_unique<T>(std::forward<Args>(args)...)));
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d::profilers
|
||||
{
|
||||
bool try_save_recording_info(
|
||||
const profiler::recording_info& src,
|
||||
buffer& dst) noexcept;
|
||||
|
||||
bool try_save_recording_info(
|
||||
const profiler::recording_info& src,
|
||||
const output_stream_uptr& dst) noexcept;
|
||||
}
|
||||
@@ -908,15 +908,12 @@ namespace e2d
|
||||
str_view fragment_source);
|
||||
|
||||
shader_ptr create_shader(
|
||||
const input_stream_uptr& vertex_stream,
|
||||
const input_stream_uptr& fragment_stream);
|
||||
buffer_view vertex_source,
|
||||
buffer_view fragment_source);
|
||||
|
||||
texture_ptr create_texture(
|
||||
const image& image);
|
||||
|
||||
texture_ptr create_texture(
|
||||
const input_stream_uptr& image_stream);
|
||||
|
||||
texture_ptr create_texture(
|
||||
const v2u& size,
|
||||
const pixel_declaration& decl);
|
||||
|
||||
@@ -25,9 +25,6 @@ namespace e2d
|
||||
|
||||
class vfs final : public module<vfs> {
|
||||
public:
|
||||
vfs();
|
||||
~vfs() noexcept final;
|
||||
|
||||
class file_source : private e2d::noncopyable {
|
||||
public:
|
||||
virtual ~file_source() noexcept = default;
|
||||
@@ -38,6 +35,12 @@ namespace e2d
|
||||
virtual bool trace(str_view path, filesystem::trace_func func) const = 0;
|
||||
};
|
||||
using file_source_uptr = std::unique_ptr<file_source>;
|
||||
public:
|
||||
vfs();
|
||||
~vfs() noexcept final;
|
||||
|
||||
stdex::jobber& worker() noexcept;
|
||||
const stdex::jobber& worker() const noexcept;
|
||||
|
||||
template < typename T, typename... Args >
|
||||
bool register_scheme(str_view scheme, Args&&... args);
|
||||
@@ -52,10 +55,10 @@ namespace e2d
|
||||
input_stream_uptr read(const url& url) const;
|
||||
output_stream_uptr write(const url& url, bool append) const;
|
||||
|
||||
bool load(const url& url, buffer& dst) const;
|
||||
std::optional<buffer> load(const url& url) const;
|
||||
stdex::promise<buffer> load_async(const url& url) const;
|
||||
|
||||
bool load_as_string(const url& url, str& dst) const;
|
||||
std::optional<str> load_as_string(const url& url) const;
|
||||
stdex::promise<str> load_as_string_async(const url& url) const;
|
||||
|
||||
template < typename Iter >
|
||||
|
||||
@@ -89,9 +89,9 @@ namespace e2d
|
||||
std::unique_ptr<state> state_;
|
||||
};
|
||||
|
||||
class window_trace_event_listener final : public window::event_listener {
|
||||
class window_event_tracer final : public window::event_listener {
|
||||
public:
|
||||
window_trace_event_listener(debug& debug) noexcept;
|
||||
window_event_tracer(debug& debug) noexcept;
|
||||
void on_input_char(char32_t uchar) noexcept final;
|
||||
void on_move_cursor(const v2f& pos) noexcept final;
|
||||
void on_mouse_scroll(const v2f& delta) noexcept final;
|
||||
@@ -105,6 +105,18 @@ namespace e2d
|
||||
private:
|
||||
debug& debug_;
|
||||
};
|
||||
|
||||
class window_input_source final : public window::event_listener {
|
||||
public:
|
||||
window_input_source(input& input) noexcept;
|
||||
void on_input_char(char32_t uchar) noexcept final;
|
||||
void on_move_cursor(const v2f& pos) noexcept final;
|
||||
void on_mouse_scroll(const v2f& delta) noexcept final;
|
||||
void on_mouse_button(mouse_button btn, mouse_button_action act) noexcept final;
|
||||
void on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept final;
|
||||
private:
|
||||
input& input_;
|
||||
};
|
||||
}
|
||||
|
||||
ENUM_HPP_REGISTER_TRAITS(e2d::window::cursor_shapes)
|
||||
|
||||
@@ -24,8 +24,8 @@ namespace e2d
|
||||
template < typename F >
|
||||
decltype(auto) with_state(F&& f) const;
|
||||
|
||||
std::optional<script> load_script(str_view src);
|
||||
std::optional<script> load_script(buffer_view src);
|
||||
std::optional<script> load_script(const input_stream_uptr& src);
|
||||
private:
|
||||
sol::state state_;
|
||||
};
|
||||
|
||||
@@ -27,9 +27,6 @@ namespace e2d
|
||||
template < typename T >
|
||||
buffer_view(const vector<T>& buffer) noexcept;
|
||||
|
||||
template < typename Char >
|
||||
buffer_view(const basic_string<Char>& buffer) noexcept;
|
||||
|
||||
template < typename T, std::size_t N >
|
||||
buffer_view(const std::array<T,N>& buffer) noexcept;
|
||||
|
||||
@@ -60,11 +57,6 @@ namespace e2d
|
||||
: data_(buffer.data())
|
||||
, size_(buffer.size() * sizeof(T)) {}
|
||||
|
||||
template < typename Char >
|
||||
buffer_view::buffer_view(const basic_string<Char>& buffer) noexcept
|
||||
: data_(buffer.data())
|
||||
, size_(buffer.size() * sizeof(Char)) {}
|
||||
|
||||
template < typename T, std::size_t N >
|
||||
buffer_view::buffer_view(const std::array<T,N>& buffer) noexcept
|
||||
: data_(buffer.data())
|
||||
|
||||
@@ -13,27 +13,16 @@ namespace e2d
|
||||
namespace impl
|
||||
{
|
||||
template < typename F >
|
||||
class defer_impl {
|
||||
class defer_impl final : noncopyable {
|
||||
public:
|
||||
defer_impl() = delete;
|
||||
defer_impl(const defer_impl&) = delete;
|
||||
defer_impl& operator=(const defer_impl&) = delete;
|
||||
|
||||
explicit defer_impl(F f)
|
||||
: f_(std::move(f)) {}
|
||||
|
||||
~defer_impl() noexcept(std::is_nothrow_invocable_v<F>) {
|
||||
if ( !cancelled_ ) {
|
||||
f_();
|
||||
}
|
||||
}
|
||||
|
||||
void cancel() noexcept {
|
||||
cancelled_ = true;
|
||||
}
|
||||
private:
|
||||
F f_;
|
||||
bool cancelled_{false};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,4 +33,4 @@ namespace e2d
|
||||
}
|
||||
|
||||
#define E2D_DEFER(lambda)\
|
||||
auto E2D_PP_CAT(e2d_defer_, __LINE__) = ::e2d::make_defer(lambda)
|
||||
auto E2D_PP_CAT(e2d_generated_defer_, __LINE__) = ::e2d::make_defer(lambda)
|
||||
|
||||
@@ -76,6 +76,7 @@ namespace e2d::filesystem
|
||||
|
||||
bool try_read_all(str& dst, str_view path) noexcept;
|
||||
bool try_read_all(buffer& dst, str_view path) noexcept;
|
||||
bool try_write_all(str_view src, str_view path, bool append) noexcept;
|
||||
bool try_write_all(buffer_view src, str_view path, bool append) noexcept;
|
||||
|
||||
ENUM_HPP_CLASS_DECL(predef_path, u8,
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace e2d
|
||||
|
||||
output_sequence& seek(std::ptrdiff_t offset, bool relative) noexcept;
|
||||
output_sequence& write(const void* src, std::size_t size) noexcept;
|
||||
output_sequence& write_all(str_view src) noexcept;
|
||||
output_sequence& write_all(buffer_view src) noexcept;
|
||||
|
||||
output_sequence& flush() noexcept;
|
||||
@@ -113,6 +114,10 @@ namespace e2d::streams
|
||||
buffer& dst,
|
||||
const input_stream_uptr& stream) noexcept;
|
||||
|
||||
bool try_write_tail(
|
||||
str_view src,
|
||||
const output_stream_uptr& stream) noexcept;
|
||||
|
||||
bool try_write_tail(
|
||||
buffer_view src,
|
||||
const output_stream_uptr& stream) noexcept;
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace e2d
|
||||
const str& scheme() const noexcept;
|
||||
const str& path() const noexcept;
|
||||
|
||||
str schemepath() const;
|
||||
|
||||
url& operator+=(str_view path);
|
||||
url& operator/=(str_view path);
|
||||
private:
|
||||
|
||||
Submodule modules/promise.hpp updated: 8ed2aad253...22380ff930
@@ -97,12 +97,19 @@ namespace
|
||||
"ships",
|
||||
url("piratepack://PNG/Retina/Ships"));
|
||||
|
||||
shader_ = the<render>().create_shader(
|
||||
vs_source_cstr, fs_source_cstr);
|
||||
texture1_ = the<render>().create_texture(
|
||||
the<vfs>().read(url("ships://ship (2).png")));
|
||||
texture2_ = the<render>().create_texture(
|
||||
the<vfs>().read(url("ships://ship (19).png")));
|
||||
image texture1_image;
|
||||
if ( !images::try_load_image(texture1_image, the<vfs>().read(url("ships://ship (2).png"))) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
image texture2_image;
|
||||
if ( !images::try_load_image(texture2_image, the<vfs>().read(url("ships://ship (19).png"))) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
shader_ = the<render>().create_shader(vs_source_cstr, fs_source_cstr);
|
||||
texture1_ = the<render>().create_texture(texture1_image);
|
||||
texture2_ = the<render>().create_texture(texture2_image);
|
||||
|
||||
if ( !shader_ || !texture1_ || !texture2_ ) {
|
||||
return false;
|
||||
|
||||
@@ -157,11 +157,13 @@ namespace
|
||||
"ships",
|
||||
url("piratepack://PNG/Retina/Ships"));
|
||||
|
||||
shader_ = the<render>().create_shader(
|
||||
vs_source_cstr, fs_source_cstr);
|
||||
image texture_image;
|
||||
if ( !images::try_load_image(texture_image, the<vfs>().read(url("ships://ship (3).png"))) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
texture_ = the<render>().create_texture(
|
||||
the<vfs>().read(url("ships://ship (3).png")));
|
||||
shader_ = the<render>().create_shader(vs_source_cstr, fs_source_cstr);
|
||||
texture_ = the<render>().create_texture(texture_image);
|
||||
|
||||
if ( !shader_ || !texture_ ) {
|
||||
return false;
|
||||
|
||||
@@ -112,11 +112,13 @@ namespace
|
||||
"ships",
|
||||
url("piratepack://PNG/Retina/Ships"));
|
||||
|
||||
shader_ = the<render>().create_shader(
|
||||
vs_source_cstr, fs_source_cstr);
|
||||
image texture_image;
|
||||
if ( !images::try_load_image(texture_image, the<vfs>().read(url("ships://ship (3).png"))) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
texture_ = the<render>().create_texture(
|
||||
the<vfs>().read(url("ships://ship (3).png")));
|
||||
shader_ = the<render>().create_shader(vs_source_cstr, fs_source_cstr);
|
||||
texture_ = the<render>().create_texture(texture_image);
|
||||
|
||||
if ( !shader_ || !texture_ ) {
|
||||
return false;
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace
|
||||
"audio",
|
||||
url("rpgaudio://Audio"));
|
||||
|
||||
auto sstream1 = the<audio>().preload_stream(the<vfs>().read(url("audio://chop.ogg")));
|
||||
auto sstream2 = the<audio>().create_stream(the<vfs>().read(url("audio://footstep00.ogg")));
|
||||
auto sstream1 = the<audio>().create_stream(the<vfs>().read(url("audio://chop.ogg")));
|
||||
auto sstream2 = the<audio>().create_stream(*the<vfs>().load(url("audio://footstep00.ogg")));
|
||||
|
||||
if ( !sstream1 || !sstream2 ) {
|
||||
return false;
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <enduro2d/core/debug.hpp>
|
||||
#include <enduro2d/core/audio.hpp>
|
||||
#include <enduro2d/core/debug.hpp>
|
||||
#include <enduro2d/core/profiler.hpp>
|
||||
|
||||
#define E2D_AUDIO_MODE_NONE 1
|
||||
#define E2D_AUDIO_MODE_BASS 2
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace e2d
|
||||
audio::~audio() noexcept {
|
||||
}
|
||||
|
||||
sound_stream_ptr audio::preload_stream(
|
||||
sound_stream_ptr audio::create_stream(
|
||||
buffer_view sound_data)
|
||||
{
|
||||
if ( !state_->initialized() ) {
|
||||
@@ -156,6 +156,8 @@ namespace e2d
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
E2D_PROFILER_SCOPE("audio.create_stream");
|
||||
|
||||
HSAMPLE sample = BASS_SampleLoad(
|
||||
TRUE,
|
||||
sound_data.data(),
|
||||
@@ -176,23 +178,6 @@ namespace e2d
|
||||
state_->dbg(), sample, nullptr));
|
||||
}
|
||||
|
||||
sound_stream_ptr audio::preload_stream(
|
||||
const input_stream_uptr& file_stream)
|
||||
{
|
||||
if ( !state_->initialized() ) {
|
||||
state_->dbg().error("AUDIO: Not initialized");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
buffer file_data;
|
||||
if ( !streams::try_read_tail(file_data, file_stream) ) {
|
||||
state_->dbg().error("AUDIO: Failed to read file");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return preload_stream(buffer_view(file_data));
|
||||
}
|
||||
|
||||
sound_stream_ptr audio::create_stream(
|
||||
input_stream_uptr file_stream)
|
||||
{
|
||||
@@ -206,6 +191,8 @@ namespace e2d
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
E2D_PROFILER_SCOPE("audio.create_stream");
|
||||
|
||||
BASS_FILEPROCS file_procs = {
|
||||
sound_stream_close_proc,
|
||||
sound_stream_length_proc,
|
||||
@@ -243,6 +230,8 @@ namespace e2d
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
E2D_PROFILER_SCOPE("audio.create_source");
|
||||
|
||||
HCHANNEL channel = stream->state().stream()
|
||||
? stream->state().sound()
|
||||
: BASS_SampleGetChannel(stream->state().sound(), FALSE);
|
||||
|
||||
@@ -119,20 +119,13 @@ namespace e2d
|
||||
audio::~audio() noexcept {
|
||||
}
|
||||
|
||||
sound_stream_ptr audio::preload_stream(
|
||||
sound_stream_ptr audio::create_stream(
|
||||
buffer_view sound_data)
|
||||
{
|
||||
E2D_UNUSED(sound_data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sound_stream_ptr audio::preload_stream(
|
||||
const input_stream_uptr& file_stream)
|
||||
{
|
||||
E2D_UNUSED(file_stream);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sound_stream_ptr audio::create_stream(
|
||||
input_stream_uptr file_stream)
|
||||
{
|
||||
|
||||
@@ -101,9 +101,9 @@ namespace e2d
|
||||
io.DisplaySize =
|
||||
window_.real_size().cast_to<f32>();
|
||||
|
||||
io.DisplayFramebufferScale =
|
||||
window_.framebuffer_size().cast_to<f32>() /
|
||||
window_.real_size().cast_to<f32>();
|
||||
io.DisplayFramebufferScale = io.DisplaySize.x > 0.f && io.DisplaySize.y > 0.f
|
||||
? window_.framebuffer_size().cast_to<f32>() / v2f(io.DisplaySize)
|
||||
: v2f(1.f, 1.f);
|
||||
|
||||
window_.set_cursor_shape(
|
||||
imgui::convert_mouse_cursor(
|
||||
@@ -436,6 +436,7 @@ namespace e2d
|
||||
}
|
||||
|
||||
void dbgui::frame_tick() {
|
||||
E2D_PROFILER_SCOPE("dbgui.frame_tick");
|
||||
state_->frame_tick();
|
||||
|
||||
if ( visible() ) {
|
||||
@@ -444,6 +445,7 @@ namespace e2d
|
||||
}
|
||||
|
||||
void dbgui::frame_render() {
|
||||
E2D_PROFILER_SCOPE("dbgui.frame_render");
|
||||
state_->frame_render();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <enduro2d/core/debug.hpp>
|
||||
#include <enduro2d/core/engine.hpp>
|
||||
#include <enduro2d/core/input.hpp>
|
||||
#include <enduro2d/core/profiler.hpp>
|
||||
#include <enduro2d/core/render.hpp>
|
||||
#include <enduro2d/core/window.hpp>
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <enduro2d/core/deferrer.hpp>
|
||||
|
||||
#include <enduro2d/core/profiler.hpp>
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
deferrer::deferrer()
|
||||
@@ -26,4 +28,9 @@ namespace e2d
|
||||
const stdex::scheduler& deferrer::scheduler() const noexcept {
|
||||
return scheduler_;
|
||||
}
|
||||
|
||||
void deferrer::frame_tick() noexcept {
|
||||
E2D_PROFILER_SCOPE("deferrer.frame_tick");
|
||||
scheduler_.process_all_tasks();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <enduro2d/core/input.hpp>
|
||||
#include <enduro2d/core/network.hpp>
|
||||
#include <enduro2d/core/platform.hpp>
|
||||
#include <enduro2d/core/profiler.hpp>
|
||||
#include <enduro2d/core/render.hpp>
|
||||
#include <enduro2d/core/vfs.hpp>
|
||||
#include <enduro2d/core/window.hpp>
|
||||
@@ -319,6 +320,8 @@ namespace e2d
|
||||
}
|
||||
public:
|
||||
void calculate_end_frame_timers() noexcept {
|
||||
E2D_PROFILER_SCOPE("engine.wait_for_target_fps");
|
||||
|
||||
const auto second_us = time::second_us<u64>();
|
||||
|
||||
const auto minimal_delta_time_us =
|
||||
@@ -382,6 +385,11 @@ namespace e2d
|
||||
|
||||
safe_module_initialize<deferrer>();
|
||||
|
||||
// setup profiler
|
||||
|
||||
safe_module_initialize<profiler>(
|
||||
the<deferrer>());
|
||||
|
||||
// setup debug
|
||||
|
||||
safe_module_initialize<debug>();
|
||||
@@ -477,6 +485,7 @@ namespace e2d
|
||||
modules::shutdown<input>();
|
||||
modules::shutdown<vfs>();
|
||||
modules::shutdown<debug>();
|
||||
modules::shutdown<profiler>();
|
||||
modules::shutdown<deferrer>();
|
||||
modules::shutdown<platform>();
|
||||
}
|
||||
@@ -492,7 +501,7 @@ namespace e2d
|
||||
while ( true ) {
|
||||
try {
|
||||
the<dbgui>().frame_tick();
|
||||
the<deferrer>().scheduler().process_all_tasks();
|
||||
the<deferrer>().frame_tick();
|
||||
|
||||
if ( !app->frame_tick() ) {
|
||||
break;
|
||||
@@ -510,8 +519,11 @@ namespace e2d
|
||||
app->shutdown();
|
||||
throw;
|
||||
}
|
||||
|
||||
the<input>().frame_tick();
|
||||
window::poll_events();
|
||||
|
||||
E2D_PROFILER_GLOBAL_EVENT("engine.end_of_frame");
|
||||
}
|
||||
|
||||
app->shutdown();
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <enduro2d/core/input.hpp>
|
||||
|
||||
#include <enduro2d/core/profiler.hpp>
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
//
|
||||
@@ -364,35 +366,8 @@ namespace e2d
|
||||
}
|
||||
|
||||
void input::frame_tick() noexcept {
|
||||
E2D_PROFILER_SCOPE("input.frame_tick");
|
||||
state_->mouse.state_->frame_tick();
|
||||
state_->keyboard.state_->frame_tick();
|
||||
}
|
||||
|
||||
//
|
||||
// class window_input_source
|
||||
//
|
||||
|
||||
window_input_source::window_input_source(input& input) noexcept
|
||||
: input_(input) {}
|
||||
|
||||
void window_input_source::on_input_char(char32_t uchar) noexcept {
|
||||
input_.post_event(input::input_char_event{uchar});
|
||||
}
|
||||
|
||||
void window_input_source::on_move_cursor(const v2f& pos) noexcept {
|
||||
input_.post_event(input::move_cursor_event{pos});
|
||||
}
|
||||
|
||||
void window_input_source::on_mouse_scroll(const v2f& delta) noexcept {
|
||||
input_.post_event(input::mouse_scroll_event{delta});
|
||||
}
|
||||
|
||||
void window_input_source::on_mouse_button(mouse_button btn, mouse_button_action act) noexcept {
|
||||
input_.post_event(input::mouse_button_event{btn, act});
|
||||
}
|
||||
|
||||
void window_input_source::on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept {
|
||||
E2D_UNUSED(scancode);
|
||||
input_.post_event(input::keyboard_key_event{key, act});
|
||||
}
|
||||
}
|
||||
|
||||
248
sources/enduro2d/core/profiler.cpp
Normal file
248
sources/enduro2d/core/profiler.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <enduro2d/core/profiler.hpp>
|
||||
|
||||
#include <enduro2d/core/engine.hpp>
|
||||
#include <enduro2d/core/vfs.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
|
||||
str recording_args_to_json(const profiler::args_t& args) {
|
||||
str dst = "{";
|
||||
for ( auto iter = args.begin(); iter != args.end(); ) {
|
||||
dst += strings::rformat("\"%0\":\"%1\"", iter->first, iter->second);
|
||||
if ( ++iter != args.end() ) {
|
||||
dst += ",";
|
||||
}
|
||||
}
|
||||
dst += "}";
|
||||
return dst;
|
||||
}
|
||||
|
||||
str recording_info_to_json(const profiler::recording_info& src) {
|
||||
str dst("{\"traceEvents\":[\n");
|
||||
|
||||
dst += strings::rformat(
|
||||
" {\"name\":\"thread_name\",\"ph\":\"M\",\"tid\":%0,\"pid\":0,\"args\":{\"name\":\"%1\"}},\n",
|
||||
std::hash<std::thread::id>()(the<engine>().main_thread()),
|
||||
"Main");
|
||||
|
||||
for ( std::thread::id tid : the<vfs>().worker().thread_ids() ) {
|
||||
dst += strings::rformat(
|
||||
" {\"name\":\"thread_name\",\"ph\":\"M\",\"tid\":%0,\"pid\":0,\"args\":{\"name\":\"%1\"}},\n",
|
||||
std::hash<std::thread::id>()(tid),
|
||||
"VFS");
|
||||
}
|
||||
|
||||
for ( std::thread::id tid : the<deferrer>().worker().thread_ids() ) {
|
||||
dst += strings::rformat(
|
||||
" {\"name\":\"thread_name\",\"ph\":\"M\",\"tid\":%0,\"pid\":0,\"args\":{\"name\":\"%1\"}},\n",
|
||||
std::hash<std::thread::id>()(tid),
|
||||
"Worker");
|
||||
}
|
||||
|
||||
for ( auto iter = src.events.begin(); iter != src.events.end(); ) {
|
||||
std::visit(utils::overloaded {
|
||||
[&dst](const profiler::begin_scope_info& e){
|
||||
char buf[512] = {'\0'};
|
||||
strings::format(buf, std::size(buf),
|
||||
" {\"name\":\"%0\",\"ph\":\"B\",\"ts\":%1,\"tid\":%2,\"pid\":0,\"cat\":\"\",\"args\":%3}",
|
||||
e.name,
|
||||
e.tp.count(),
|
||||
std::hash<std::thread::id>()(e.tid),
|
||||
recording_args_to_json(e.args));
|
||||
dst += buf;
|
||||
},
|
||||
[&dst](const profiler::end_scope_info& e){
|
||||
char buf[512] = {'\0'};
|
||||
strings::format(buf, std::size(buf),
|
||||
" {\"ph\":\"E\",\"ts\":%0,\"tid\":%1,\"pid\":0,\"cat\":\"\"}",
|
||||
e.tp.count(),
|
||||
std::hash<std::thread::id>()(e.tid));
|
||||
dst += buf;
|
||||
},
|
||||
[&dst](const profiler::thread_event_info& e){
|
||||
char buf[512] = {'\0'};
|
||||
strings::format(buf, std::size(buf),
|
||||
" {\"name\":\"%0\",\"ph\":\"i\",\"s\":\"t\",\"ts\":%1,\"tid\":%2,\"pid\":0,\"cat\":\"\",\"args\":%3}",
|
||||
e.name,
|
||||
e.tp.count(),
|
||||
std::hash<std::thread::id>()(e.tid),
|
||||
recording_args_to_json(e.args));
|
||||
dst += buf;
|
||||
},
|
||||
[&dst](const profiler::global_event_info& e){
|
||||
char buf[512] = {'\0'};
|
||||
strings::format(buf, std::size(buf),
|
||||
" {\"name\":\"%0\",\"ph\":\"i\",\"s\":\"g\",\"ts\":%1,\"tid\":%2,\"pid\":0,\"cat\":\"\",\"args\":%3}",
|
||||
e.name,
|
||||
e.tp.count(),
|
||||
std::hash<std::thread::id>()(e.tid),
|
||||
recording_args_to_json(e.args));
|
||||
dst += buf;
|
||||
}
|
||||
}, *iter);
|
||||
|
||||
if ( ++iter != src.events.end() ) {
|
||||
dst += ",\n";
|
||||
}
|
||||
}
|
||||
|
||||
dst += "\n]}";
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
profiler::auto_scope::auto_scope(profiler* profiler, str name)
|
||||
: profiler_(profiler) {
|
||||
if ( profiler_ ) {
|
||||
profiler_->begin_scope(std::move(name));
|
||||
}
|
||||
}
|
||||
|
||||
profiler::auto_scope::auto_scope(profiler* profiler, str name, args_t args)
|
||||
: profiler_(profiler) {
|
||||
if ( profiler_ ) {
|
||||
profiler_->begin_scope(std::move(name), std::move(args));
|
||||
}
|
||||
}
|
||||
|
||||
profiler::auto_scope::~auto_scope() noexcept {
|
||||
if ( profiler_ ) {
|
||||
profiler_->end_scope();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
profiler::profiler(deferrer& d)
|
||||
: deferrer_(d) {}
|
||||
profiler::~profiler() noexcept = default;
|
||||
|
||||
profiler::sink& profiler::register_sink(sink_uptr sink) {
|
||||
E2D_ASSERT(sink);
|
||||
std::lock_guard guard(rmutex_);
|
||||
sinks_.push_back(std::move(sink));
|
||||
return *sinks_.back();
|
||||
}
|
||||
|
||||
void profiler::unregister_sink(const sink& sink) noexcept {
|
||||
std::lock_guard guard(rmutex_);
|
||||
for ( auto iter = sinks_.begin(); iter != sinks_.end(); ) {
|
||||
if ( iter->get() == &sink ) {
|
||||
iter = sinks_.erase(iter);
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void profiler::begin_scope(str name) noexcept {
|
||||
return begin_scope(std::move(name), {});
|
||||
}
|
||||
|
||||
void profiler::begin_scope(str name, args_t args) noexcept {
|
||||
++depth_;
|
||||
|
||||
begin_scope_info event{
|
||||
std::move(name),
|
||||
std::move(args),
|
||||
std::this_thread::get_id(),
|
||||
time::to_chrono(time::now_us())};
|
||||
|
||||
std::lock_guard guard(rmutex_);
|
||||
for ( const auto& sink : sinks_ ) {
|
||||
if ( sink ) {
|
||||
sink->on_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void profiler::end_scope() noexcept {
|
||||
E2D_ASSERT(depth_);
|
||||
--depth_;
|
||||
|
||||
end_scope_info event{
|
||||
std::this_thread::get_id(),
|
||||
time::to_chrono(time::now_us())};
|
||||
|
||||
std::lock_guard guard(rmutex_);
|
||||
for ( const auto& sink : sinks_ ) {
|
||||
if ( sink ) {
|
||||
sink->on_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void profiler::thread_event(str name) noexcept {
|
||||
return thread_event(std::move(name), {});
|
||||
}
|
||||
|
||||
void profiler::thread_event(str name, args_t args) noexcept {
|
||||
thread_event_info event{
|
||||
std::move(name),
|
||||
std::move(args),
|
||||
std::this_thread::get_id(),
|
||||
time::to_chrono(time::now_us())};
|
||||
|
||||
std::lock_guard guard(rmutex_);
|
||||
for ( const auto& sink : sinks_ ) {
|
||||
if ( sink ) {
|
||||
sink->on_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void profiler::global_event(str name) noexcept {
|
||||
return global_event(std::move(name), {});
|
||||
}
|
||||
|
||||
void profiler::global_event(str name, args_t args) noexcept {
|
||||
global_event_info event{
|
||||
std::move(name),
|
||||
std::move(args),
|
||||
std::this_thread::get_id(),
|
||||
time::to_chrono(time::now_us())};
|
||||
|
||||
std::lock_guard guard(rmutex_);
|
||||
for ( const auto& sink : sinks_ ) {
|
||||
if ( sink ) {
|
||||
sink->on_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d::profilers
|
||||
{
|
||||
bool try_save_recording_info(
|
||||
const profiler::recording_info& src,
|
||||
buffer& dst) noexcept
|
||||
{
|
||||
try {
|
||||
str json = recording_info_to_json(src);
|
||||
dst.assign(json.data(), json.size());
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool try_save_recording_info(
|
||||
const profiler::recording_info& src,
|
||||
const output_stream_uptr& dst) noexcept
|
||||
{
|
||||
buffer file_data;
|
||||
return try_save_recording_info(src, file_data)
|
||||
&& streams::try_write_tail(file_data, dst);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <enduro2d/core/debug.hpp>
|
||||
#include <enduro2d/core/profiler.hpp>
|
||||
#include <enduro2d/core/render.hpp>
|
||||
#include <enduro2d/core/window.hpp>
|
||||
|
||||
|
||||
@@ -181,10 +181,10 @@ namespace e2d
|
||||
}
|
||||
|
||||
shader_ptr render::create_shader(
|
||||
const input_stream_uptr& vertex_stream,
|
||||
const input_stream_uptr& fragment_stream)
|
||||
buffer_view vertex_source,
|
||||
buffer_view fragment_source)
|
||||
{
|
||||
E2D_UNUSED(vertex_stream, fragment_stream);
|
||||
E2D_UNUSED(vertex_source, fragment_source);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -193,11 +193,6 @@ namespace e2d
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
texture_ptr render::create_texture(const input_stream_uptr& image_stream) {
|
||||
E2D_UNUSED(image_stream);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
texture_ptr render::create_texture(const v2u& size, const pixel_declaration& decl) {
|
||||
E2D_UNUSED(size, decl);
|
||||
return nullptr;
|
||||
|
||||
@@ -497,7 +497,12 @@ namespace e2d
|
||||
{
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
|
||||
gl_shader_id vs = gl_compile_shader(
|
||||
gl_shader_id vs(state_->dbg());
|
||||
|
||||
{
|
||||
E2D_PROFILER_SCOPE("render.compile_vertex_shader");
|
||||
|
||||
vs = gl_compile_shader(
|
||||
state_->dbg(),
|
||||
vertex_shader_header_cstr(device_capabilities().profile),
|
||||
vertex_source,
|
||||
@@ -506,8 +511,14 @@ namespace e2d
|
||||
if ( vs.empty() ) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gl_shader_id fs = gl_compile_shader(
|
||||
gl_shader_id fs(state_->dbg());
|
||||
|
||||
{
|
||||
E2D_PROFILER_SCOPE("render.compile_fragment_shader");
|
||||
|
||||
fs = gl_compile_shader(
|
||||
state_->dbg(),
|
||||
fragment_shader_header_cstr(device_capabilities().profile),
|
||||
fragment_source,
|
||||
@@ -516,8 +527,14 @@ namespace e2d
|
||||
if ( fs.empty() ) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gl_program_id ps = gl_link_program(
|
||||
gl_program_id ps(state_->dbg());
|
||||
|
||||
{
|
||||
E2D_PROFILER_SCOPE("render.link_shader_program");
|
||||
|
||||
ps = gl_link_program(
|
||||
state_->dbg(),
|
||||
std::move(vs),
|
||||
std::move(fs));
|
||||
@@ -525,6 +542,7 @@ namespace e2d
|
||||
if ( ps.empty() ) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_shared<shader>(
|
||||
std::make_unique<shader::internal_state>(
|
||||
@@ -532,16 +550,14 @@ namespace e2d
|
||||
}
|
||||
|
||||
shader_ptr render::create_shader(
|
||||
const input_stream_uptr& vertex,
|
||||
const input_stream_uptr& fragment)
|
||||
buffer_view vertex_source,
|
||||
buffer_view fragment_source)
|
||||
{
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
|
||||
str vertex_source, fragment_source;
|
||||
return streams::try_read_tail(vertex_source, vertex)
|
||||
&& streams::try_read_tail(fragment_source, fragment)
|
||||
? create_shader(vertex_source, fragment_source)
|
||||
: nullptr;
|
||||
return create_shader(
|
||||
str_view(reinterpret_cast<const char*>(vertex_source.data()), vertex_source.size()),
|
||||
str_view(reinterpret_cast<const char*>(fragment_source.data()), fragment_source.size()));
|
||||
}
|
||||
|
||||
texture_ptr render::create_texture(
|
||||
@@ -585,6 +601,11 @@ namespace e2d
|
||||
}
|
||||
}
|
||||
|
||||
E2D_PROFILER_SCOPE_EX("render.create_texture_from_image", {
|
||||
{"size", strings::rformat("%0", image.size())},
|
||||
{"format", strings::rformat("%0", image.format())}
|
||||
});
|
||||
|
||||
gl_texture_id id = gl_texture_id::create(state_->dbg(), GL_TEXTURE_2D);
|
||||
if ( id.empty() ) {
|
||||
state_->dbg().error("RENDER: Failed to create texture:\n"
|
||||
@@ -622,18 +643,6 @@ namespace e2d
|
||||
state_->dbg(), std::move(id), image.size(), decl));
|
||||
}
|
||||
|
||||
texture_ptr render::create_texture(
|
||||
const input_stream_uptr& image_stream)
|
||||
{
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
|
||||
image image;
|
||||
if ( !images::try_load_image(image, image_stream) ) {
|
||||
return nullptr;
|
||||
}
|
||||
return create_texture(image);
|
||||
}
|
||||
|
||||
texture_ptr render::create_texture(
|
||||
const v2u& size,
|
||||
const pixel_declaration& decl)
|
||||
@@ -673,6 +682,11 @@ namespace e2d
|
||||
}
|
||||
}
|
||||
|
||||
E2D_PROFILER_SCOPE_EX("render.create_empty_texture", {
|
||||
{"size", strings::rformat("%0", size)},
|
||||
{"format", strings::rformat("%0", decl.type())}
|
||||
});
|
||||
|
||||
gl_texture_id id = gl_texture_id::create(state_->dbg(), GL_TEXTURE_2D);
|
||||
if ( id.empty() ) {
|
||||
state_->dbg().error("RENDER: Failed to create texture:\n"
|
||||
@@ -737,6 +751,8 @@ namespace e2d
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
E2D_PROFILER_SCOPE("render.create_index_buffer");
|
||||
|
||||
gl_buffer_id id = gl_buffer_id::create(state_->dbg(), GL_ELEMENT_ARRAY_BUFFER);
|
||||
if ( id.empty() ) {
|
||||
state_->dbg().error("RENDER: Failed to create index buffer:\n"
|
||||
@@ -771,6 +787,8 @@ namespace e2d
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
E2D_PROFILER_SCOPE("render.create_vertex_buffer");
|
||||
|
||||
gl_buffer_id id = gl_buffer_id::create(state_->dbg(), GL_ARRAY_BUFFER);
|
||||
if ( id.empty() ) {
|
||||
state_->dbg().error("RENDER: Failed to create vertex buffer:\n"
|
||||
@@ -827,6 +845,8 @@ namespace e2d
|
||||
}
|
||||
}
|
||||
|
||||
E2D_PROFILER_SCOPE("render.create_render_target");
|
||||
|
||||
gl_framebuffer_id id = gl_framebuffer_id::create(state_->dbg(), GL_FRAMEBUFFER);
|
||||
if ( id.empty() ) {
|
||||
state_->dbg().error("RENDER: Failed to create framebuffer:\n",
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <enduro2d/core/vfs.hpp>
|
||||
|
||||
#include <enduro2d/core/profiler.hpp>
|
||||
|
||||
#include <3rdparty/miniz/miniz.h>
|
||||
|
||||
namespace
|
||||
@@ -108,9 +110,18 @@ namespace e2d
|
||||
|
||||
vfs::vfs()
|
||||
: state_(new state()){}
|
||||
|
||||
vfs::~vfs() noexcept = default;
|
||||
|
||||
stdex::jobber& vfs::worker() noexcept {
|
||||
std::lock_guard<std::mutex> guard(state_->mutex);
|
||||
return state_->worker;
|
||||
}
|
||||
|
||||
const stdex::jobber& vfs::worker() const noexcept {
|
||||
std::lock_guard<std::mutex> guard(state_->mutex);
|
||||
return state_->worker;
|
||||
}
|
||||
|
||||
bool vfs::register_scheme(str_view scheme, file_source_uptr source) {
|
||||
std::lock_guard<std::mutex> guard(state_->mutex);
|
||||
return (source && source->valid())
|
||||
@@ -163,16 +174,20 @@ namespace e2d
|
||||
}, output_stream_uptr());
|
||||
}
|
||||
|
||||
bool vfs::load(const url& url, buffer& dst) const {
|
||||
return load_async(url)
|
||||
.then([&dst](auto&& src){
|
||||
dst = std::forward<decltype(src)>(src);
|
||||
return true;
|
||||
}).get_or_default(false);
|
||||
std::optional<buffer> vfs::load(const url& url) const {
|
||||
E2D_PROFILER_SCOPE_EX("vfs.sync_load", {
|
||||
{"url", url.schemepath()}
|
||||
});
|
||||
return load_async(url).then([](auto&& src){
|
||||
return std::optional<buffer>(std::forward<decltype(src)>(src));
|
||||
}).get_or_default(std::nullopt);
|
||||
}
|
||||
|
||||
stdex::promise<buffer> vfs::load_async(const url& url) const {
|
||||
return state_->worker.async([this, url](){
|
||||
E2D_PROFILER_SCOPE_EX("vfs.load_async", {
|
||||
{"url", url.schemepath()}
|
||||
});
|
||||
buffer content;
|
||||
const input_stream_uptr stream = read(url);
|
||||
if ( !stream || !streams::try_read_tail(content, stream) ) {
|
||||
@@ -182,16 +197,20 @@ namespace e2d
|
||||
});
|
||||
}
|
||||
|
||||
bool vfs::load_as_string(const url& url, str& dst) const {
|
||||
return load_as_string_async(url)
|
||||
.then([&dst](auto&& src){
|
||||
dst = std::forward<decltype(src)>(src);
|
||||
return true;
|
||||
}).get_or_default(false);
|
||||
std::optional<str> vfs::load_as_string(const url& url) const {
|
||||
E2D_PROFILER_SCOPE_EX("vfs.sync_load_as_string", {
|
||||
{"url", url.schemepath()}
|
||||
});
|
||||
return load_as_string_async(url).then([](auto&& src){
|
||||
return std::optional<str>(std::forward<decltype(src)>(src));
|
||||
}).get_or_default(std::nullopt);
|
||||
}
|
||||
|
||||
stdex::promise<str> vfs::load_as_string_async(const url& url) const {
|
||||
return state_->worker.async([this, url](){
|
||||
E2D_PROFILER_SCOPE_EX("vfs.load_as_string_async", {
|
||||
{"url", url.schemepath()}
|
||||
});
|
||||
str content;
|
||||
const input_stream_uptr stream = read(url);
|
||||
if ( !stream || !streams::try_read_tail(content, stream) ) {
|
||||
|
||||
@@ -7,13 +7,10 @@
|
||||
#include <enduro2d/core/window.hpp>
|
||||
|
||||
#include <enduro2d/core/debug.hpp>
|
||||
#include <enduro2d/core/input.hpp>
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
//
|
||||
// class window::event_listener
|
||||
//
|
||||
|
||||
void window::event_listener::on_input_char(char32_t uchar) noexcept {
|
||||
E2D_UNUSED(uchar);
|
||||
}
|
||||
@@ -52,56 +49,77 @@ namespace e2d
|
||||
void window::event_listener::on_window_minimize(bool minimized) noexcept {
|
||||
E2D_UNUSED(minimized);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// class trace_window_event_listener
|
||||
//
|
||||
|
||||
window_trace_event_listener::window_trace_event_listener(debug& debug) noexcept
|
||||
namespace e2d
|
||||
{
|
||||
window_event_tracer::window_event_tracer(debug& debug) noexcept
|
||||
: debug_(debug) {}
|
||||
|
||||
void window_trace_event_listener::on_input_char(char32_t uchar) noexcept {
|
||||
void window_event_tracer::on_input_char(char32_t uchar) noexcept {
|
||||
debug_.trace("WINDOW: on_input_char(uchar: %0)", str32_view(&uchar, 1));
|
||||
}
|
||||
|
||||
void window_trace_event_listener::on_move_cursor(const v2f& pos) noexcept {
|
||||
void window_event_tracer::on_move_cursor(const v2f& pos) noexcept {
|
||||
debug_.trace("WINDOW: on_move_cursor(pos: %0)", pos);
|
||||
}
|
||||
|
||||
void window_trace_event_listener::on_mouse_scroll(const v2f& delta) noexcept {
|
||||
void window_event_tracer::on_mouse_scroll(const v2f& delta) noexcept {
|
||||
debug_.trace("WINDOW: on_scroll(delta: %0)", delta);
|
||||
}
|
||||
|
||||
void window_trace_event_listener::on_mouse_button(mouse_button btn, mouse_button_action act) noexcept {
|
||||
debug_.trace("WINDOW: on_mouse_button(btn: %0 act: %1)",
|
||||
btn,
|
||||
act);
|
||||
void window_event_tracer::on_mouse_button(mouse_button btn, mouse_button_action act) noexcept {
|
||||
debug_.trace("WINDOW: on_mouse_button(btn: %0 act: %1)", btn, act);
|
||||
}
|
||||
|
||||
void window_trace_event_listener::on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept {
|
||||
debug_.trace("WINDOW: on_keyboard_key(key: %0 scancode: %1 act: %2)",
|
||||
key,
|
||||
scancode,
|
||||
act);
|
||||
void window_event_tracer::on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept {
|
||||
debug_.trace("WINDOW: on_keyboard_key(key: %0 scancode: %1 act: %2)", key, scancode, act);
|
||||
}
|
||||
|
||||
void window_trace_event_listener::on_window_size(const v2u& size) noexcept {
|
||||
void window_event_tracer::on_window_size(const v2u& size) noexcept {
|
||||
debug_.trace("WINDOW: on_window_size(size: %0)", size);
|
||||
}
|
||||
|
||||
void window_trace_event_listener::on_framebuffer_size(const v2u& size) noexcept {
|
||||
void window_event_tracer::on_framebuffer_size(const v2u& size) noexcept {
|
||||
debug_.trace("WINDOW: on_framebuffer_size(size: %0)", size);
|
||||
}
|
||||
|
||||
void window_trace_event_listener::on_window_close() noexcept {
|
||||
void window_event_tracer::on_window_close() noexcept {
|
||||
debug_.trace("WINDOW: on_window_close()");
|
||||
}
|
||||
|
||||
void window_trace_event_listener::on_window_focus(bool focused) noexcept {
|
||||
void window_event_tracer::on_window_focus(bool focused) noexcept {
|
||||
debug_.trace("WINDOW: on_window_focus(focused: %0)", focused);
|
||||
}
|
||||
|
||||
void window_trace_event_listener::on_window_minimize(bool minimized) noexcept {
|
||||
void window_event_tracer::on_window_minimize(bool minimized) noexcept {
|
||||
debug_.trace("WINDOW: on_window_minimize(minimized: %0)", minimized);
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
window_input_source::window_input_source(input& input) noexcept
|
||||
: input_(input) {}
|
||||
|
||||
void window_input_source::on_input_char(char32_t uchar) noexcept {
|
||||
input_.post_event(input::input_char_event{uchar});
|
||||
}
|
||||
|
||||
void window_input_source::on_move_cursor(const v2f& pos) noexcept {
|
||||
input_.post_event(input::move_cursor_event{pos});
|
||||
}
|
||||
|
||||
void window_input_source::on_mouse_scroll(const v2f& delta) noexcept {
|
||||
input_.post_event(input::mouse_scroll_event{delta});
|
||||
}
|
||||
|
||||
void window_input_source::on_mouse_button(mouse_button btn, mouse_button_action act) noexcept {
|
||||
input_.post_event(input::mouse_button_event{btn, act});
|
||||
}
|
||||
|
||||
void window_input_source::on_keyboard_key(keyboard_key key, u32 scancode, keyboard_key_action act) noexcept {
|
||||
E2D_UNUSED(scancode);
|
||||
input_.post_event(input::keyboard_key_event{key, act});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <enduro2d/core/debug.hpp>
|
||||
#include <enduro2d/core/profiler.hpp>
|
||||
#include <enduro2d/core/window.hpp>
|
||||
|
||||
#define E2D_WINDOW_MODE_NONE 1
|
||||
|
||||
@@ -691,6 +691,7 @@ namespace e2d
|
||||
}
|
||||
|
||||
void window::swap_buffers() noexcept {
|
||||
E2D_PROFILER_SCOPE("window.swap_buffers");
|
||||
std::lock_guard<std::recursive_mutex> guard(state_->rmutex);
|
||||
E2D_ASSERT(
|
||||
state_->window &&
|
||||
@@ -699,6 +700,7 @@ namespace e2d
|
||||
}
|
||||
|
||||
bool window::poll_events() noexcept {
|
||||
E2D_PROFILER_SCOPE("window.poll_events");
|
||||
return glfw_state::poll_events();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,8 +26,16 @@ namespace e2d
|
||||
const library& library, str_view address)
|
||||
{
|
||||
return library.load_asset_async<binary_asset>(address)
|
||||
.then([](const binary_asset::load_result& font_data){
|
||||
return the<deferrer>().do_in_worker_thread([font_data](){
|
||||
.then([
|
||||
address = str(address)
|
||||
](const binary_asset::load_result& font_data){
|
||||
return the<deferrer>().do_in_worker_thread([
|
||||
font_data,
|
||||
address = std::move(address)
|
||||
](){
|
||||
E2D_PROFILER_SCOPE_EX("font_asset.parsing", {
|
||||
{"address", address}
|
||||
});
|
||||
font content;
|
||||
if ( !fonts::try_load_font(content, font_data->content()) ) {
|
||||
throw font_asset_loading_exception();
|
||||
@@ -35,15 +43,14 @@ namespace e2d
|
||||
return content;
|
||||
});
|
||||
})
|
||||
.then([
|
||||
.then_tuple([
|
||||
&library,
|
||||
parent_address = path::parent_path(address)
|
||||
](const font& content){
|
||||
return stdex::make_tuple_promise(std::make_tuple(
|
||||
return std::make_tuple(
|
||||
stdex::make_resolved_promise(content),
|
||||
library.load_asset_async<texture_asset>(
|
||||
path::combine(parent_address, content.info().atlas_file))
|
||||
));
|
||||
path::combine(parent_address, content.info().atlas_file)));
|
||||
})
|
||||
.then([](const std::tuple<
|
||||
font,
|
||||
|
||||
@@ -24,8 +24,16 @@ namespace e2d
|
||||
const library& library, str_view address)
|
||||
{
|
||||
return library.load_asset_async<binary_asset>(address)
|
||||
.then([](const binary_asset::load_result& image_data){
|
||||
return the<deferrer>().do_in_worker_thread([image_data](){
|
||||
.then([
|
||||
address = str(address)
|
||||
](const binary_asset::load_result& image_data){
|
||||
return the<deferrer>().do_in_worker_thread([
|
||||
image_data,
|
||||
address = std::move(address)
|
||||
](){
|
||||
E2D_PROFILER_SCOPE_EX("image_asset.load_async", {
|
||||
{"address", address}
|
||||
});
|
||||
image content;
|
||||
if ( !images::try_load_image(content, image_data->content()) ) {
|
||||
throw image_asset_loading_exception();
|
||||
|
||||
@@ -24,8 +24,16 @@ namespace e2d
|
||||
const library& library, str_view address)
|
||||
{
|
||||
return library.load_asset_async<text_asset>(address)
|
||||
.then([](const text_asset::load_result& json_data){
|
||||
return the<deferrer>().do_in_worker_thread([json_data](){
|
||||
.then([
|
||||
address = str(address)
|
||||
](const text_asset::load_result& json_data){
|
||||
return the<deferrer>().do_in_worker_thread([
|
||||
json_data,
|
||||
address = std::move(address)
|
||||
](){
|
||||
E2D_PROFILER_SCOPE_EX("json_asset.parsing", {
|
||||
{"address", address}
|
||||
});
|
||||
auto json = std::make_shared<rapidjson::Document>();
|
||||
if ( json->Parse(json_data->content().c_str()).HasParseError() ) {
|
||||
throw json_asset_loading_exception();
|
||||
|
||||
@@ -24,8 +24,16 @@ namespace e2d
|
||||
const library& library, str_view address)
|
||||
{
|
||||
return library.load_asset_async<binary_asset>(address)
|
||||
.then([](const binary_asset::load_result& mesh_data){
|
||||
return the<deferrer>().do_in_worker_thread([mesh_data](){
|
||||
.then([
|
||||
address = str(address)
|
||||
](const binary_asset::load_result& mesh_data){
|
||||
return the<deferrer>().do_in_worker_thread([
|
||||
mesh_data,
|
||||
address = std::move(address)
|
||||
](){
|
||||
E2D_PROFILER_SCOPE_EX("mesh_asset.parsing", {
|
||||
{"address", address}
|
||||
});
|
||||
mesh content;
|
||||
if ( !meshes::try_load_mesh(content, mesh_data->content()) ) {
|
||||
throw mesh_asset_loading_exception();
|
||||
|
||||
@@ -26,8 +26,16 @@ namespace e2d
|
||||
const library& library, str_view address)
|
||||
{
|
||||
return library.load_asset_async<binary_asset>(address)
|
||||
.then([](const binary_asset::load_result& script_data){
|
||||
return the<deferrer>().do_in_main_thread([script_data](){
|
||||
.then([
|
||||
address = str(address)
|
||||
](const binary_asset::load_result& script_data){
|
||||
return the<deferrer>().do_in_main_thread([
|
||||
script_data,
|
||||
address = std::move(address)
|
||||
](){
|
||||
E2D_PROFILER_SCOPE_EX("script_asset.parsing", {
|
||||
{"address", address}
|
||||
});
|
||||
std::optional<script> script_opt = the<luasol>().load_script(
|
||||
script_data->content());
|
||||
if ( !script_opt ) {
|
||||
|
||||
@@ -54,21 +54,32 @@ namespace
|
||||
const rapidjson::Value& root)
|
||||
{
|
||||
E2D_ASSERT(root.HasMember("vertex") && root["vertex"].IsString());
|
||||
auto vertex_p = library.load_asset_async<text_asset>(
|
||||
path::combine(parent_address, root["vertex"].GetString()));
|
||||
auto vertex_a = path::combine(parent_address, root["vertex"].GetString());
|
||||
auto vertex_p = library.load_asset_async<text_asset>(vertex_a);
|
||||
|
||||
E2D_ASSERT(root.HasMember("fragment") && root["fragment"].IsString());
|
||||
auto fragment_p = library.load_asset_async<text_asset>(
|
||||
path::combine(parent_address, root["fragment"].GetString()));
|
||||
auto fragment_a = path::combine(parent_address, root["fragment"].GetString());
|
||||
auto fragment_p = library.load_asset_async<text_asset>(fragment_a);
|
||||
|
||||
return stdex::make_tuple_promise(std::make_tuple(
|
||||
std::move(vertex_p),
|
||||
std::move(fragment_p)))
|
||||
.then([](const std::tuple<
|
||||
.then([
|
||||
vertex_a = std::move(vertex_a),
|
||||
fragment_a = std::move(fragment_a)
|
||||
](const std::tuple<
|
||||
text_asset::load_result,
|
||||
text_asset::load_result
|
||||
>& results){
|
||||
return the<deferrer>().do_in_main_thread([results](){
|
||||
return the<deferrer>().do_in_main_thread([
|
||||
results,
|
||||
vertex_a = std::move(vertex_a),
|
||||
fragment_a = std::move(fragment_a)
|
||||
](){
|
||||
E2D_PROFILER_SCOPE_EX("shader_asset.create_shader", {
|
||||
{"vertex_address", vertex_a},
|
||||
{"fragment_address", fragment_a}
|
||||
});
|
||||
const shader_ptr content = the<render>().create_shader(
|
||||
std::get<0>(results)->content(),
|
||||
std::get<1>(results)->content());
|
||||
|
||||
@@ -24,8 +24,16 @@ namespace e2d
|
||||
const library& library, str_view address)
|
||||
{
|
||||
return library.load_asset_async<binary_asset>(address)
|
||||
.then([](const binary_asset::load_result& shape_data){
|
||||
return the<deferrer>().do_in_worker_thread([shape_data](){
|
||||
.then([
|
||||
address = str(address)
|
||||
](const binary_asset::load_result& shape_data){
|
||||
return the<deferrer>().do_in_worker_thread([
|
||||
shape_data,
|
||||
address = std::move(address)
|
||||
](){
|
||||
E2D_PROFILER_SCOPE_EX("shape_asset.parsing", {
|
||||
{"address", address}
|
||||
});
|
||||
shape content;
|
||||
if ( !shapes::try_load_shape(content, shape_data->content()) ) {
|
||||
throw shape_asset_loading_exception();
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace
|
||||
return library.load_asset_async<binary_asset>(sound_address)
|
||||
.then([](const binary_asset::load_result& sound_data){
|
||||
return the<deferrer>().do_in_worker_thread([sound_data](){
|
||||
sound_stream_ptr content = the<audio>().preload_stream(
|
||||
sound_stream_ptr content = the<audio>().create_stream(
|
||||
sound_data->content());
|
||||
if ( !content ) {
|
||||
throw sound_asset_loading_exception();
|
||||
|
||||
@@ -116,8 +116,20 @@ namespace
|
||||
return library.load_asset_async<binary_asset>(atlas_path)
|
||||
.then([
|
||||
&library,
|
||||
atlas_path,
|
||||
atlas_folder
|
||||
](const binary_asset::load_result& atlas_data){
|
||||
return the<deferrer>().do_in_worker_thread([](){})
|
||||
.then([
|
||||
&library,
|
||||
atlas_data,
|
||||
atlas_path,
|
||||
atlas_folder
|
||||
](){
|
||||
E2D_PROFILER_SCOPE_EX("spine_asset.atlas_parsing", {
|
||||
{"address", atlas_path}
|
||||
});
|
||||
|
||||
auto atlas_internal = std::make_unique<atlas_internal_state>();
|
||||
|
||||
spine::atlas_ptr atlas(
|
||||
@@ -133,23 +145,24 @@ namespace
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
|
||||
return stdex::make_tuple_promise(std::make_tuple(
|
||||
atlas_internal->loading.load_async(library),
|
||||
stdex::make_resolved_promise(atlas_data)));
|
||||
return atlas_internal->loading.load_async(library);
|
||||
})
|
||||
.then([
|
||||
atlas_data,
|
||||
atlas_path,
|
||||
atlas_folder
|
||||
](const std::tuple<
|
||||
asset_group,
|
||||
binary_asset::load_result
|
||||
>& results){
|
||||
](auto&& dependencies){
|
||||
E2D_PROFILER_SCOPE_EX("spine_asset.atlas_parsing", {
|
||||
{"address", atlas_path}
|
||||
});
|
||||
|
||||
auto atlas_internal = std::make_unique<atlas_internal_state>();
|
||||
atlas_internal->loaded = std::get<0>(results);
|
||||
atlas_internal->loaded = std::forward<decltype(dependencies)>(dependencies);
|
||||
|
||||
spine::atlas_ptr atlas(
|
||||
spAtlas_create(
|
||||
reinterpret_cast<const char*>(std::get<1>(results)->content().data()),
|
||||
math::numeric_cast<int>(std::get<1>(results)->content().size()),
|
||||
reinterpret_cast<const char*>(atlas_data->content().data()),
|
||||
math::numeric_cast<int>(atlas_data->content().size()),
|
||||
atlas_folder.c_str(),
|
||||
atlas_internal.get()),
|
||||
spAtlas_dispose);
|
||||
@@ -169,6 +182,7 @@ namespace
|
||||
atlas->rendererObject = nullptr;
|
||||
return atlas;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
stdex::promise<spine::skeleton_data_ptr> load_skeleton_data(
|
||||
@@ -178,14 +192,23 @@ namespace
|
||||
f32 skeleton_scale,
|
||||
const spine::atlas_ptr& atlas)
|
||||
{
|
||||
return library.load_asset_async<binary_asset>(
|
||||
path::combine(parent_address, skeleton_address))
|
||||
str address = path::combine(parent_address, skeleton_address);
|
||||
return library.load_asset_async<binary_asset>(address)
|
||||
.then([
|
||||
atlas,
|
||||
skeleton_scale,
|
||||
skeleton_address
|
||||
address = std::move(address)
|
||||
](const binary_asset::load_result& skeleton_data){
|
||||
if ( strings::ends_with(skeleton_address, ".skel") ) {
|
||||
return the<deferrer>().do_in_worker_thread([
|
||||
atlas,
|
||||
skeleton_scale,
|
||||
address = std::move(address),
|
||||
skeleton_data
|
||||
](){
|
||||
E2D_PROFILER_SCOPE_EX("spine_asset.skeleton_parsing", {
|
||||
{"address", address}
|
||||
});
|
||||
if ( strings::ends_with(address, ".skel") ) {
|
||||
using skeleton_bin_ptr = std::unique_ptr<
|
||||
spSkeletonBinary,
|
||||
decltype(&::spSkeletonBinary_dispose)>;
|
||||
@@ -248,6 +271,7 @@ namespace
|
||||
return data_skeleton;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
stdex::promise<spine> parse_spine(
|
||||
|
||||
@@ -24,8 +24,16 @@ namespace e2d
|
||||
const library& library, str_view address)
|
||||
{
|
||||
return library.load_asset_async<image_asset>(address)
|
||||
.then([](const image_asset::load_result& texture_data){
|
||||
return the<deferrer>().do_in_main_thread([texture_data](){
|
||||
.then([
|
||||
address = str(address)
|
||||
](const image_asset::load_result& texture_data){
|
||||
return the<deferrer>().do_in_main_thread([
|
||||
texture_data,
|
||||
address = std::move(address)
|
||||
](){
|
||||
E2D_PROFILER_SCOPE_EX("texture_asset.create_texture", {
|
||||
{"address", address}
|
||||
});
|
||||
const texture_ptr content = the<render>().create_texture(
|
||||
texture_data->content());
|
||||
if ( !content ) {
|
||||
|
||||
@@ -24,8 +24,16 @@ namespace e2d
|
||||
const library& library, str_view address)
|
||||
{
|
||||
return library.load_asset_async<text_asset>(address)
|
||||
.then([](const text_asset::load_result& xml_data){
|
||||
return the<deferrer>().do_in_worker_thread([xml_data](){
|
||||
.then([
|
||||
address = str(address)
|
||||
](const text_asset::load_result& xml_data){
|
||||
return the<deferrer>().do_in_worker_thread([
|
||||
xml_data,
|
||||
address = std::move(address)
|
||||
](){
|
||||
E2D_PROFILER_SCOPE_EX("xml_asset.parsing", {
|
||||
{"address", address}
|
||||
});
|
||||
auto xml = std::make_shared<pugi::xml_document>();
|
||||
if ( !xml->load_string(xml_data->content().c_str()) ) {
|
||||
throw xml_asset_loading_exception();
|
||||
|
||||
@@ -38,12 +38,13 @@ namespace e2d
|
||||
state_.collect_garbage();
|
||||
}
|
||||
|
||||
std::optional<script> luasol::load_script(buffer_view src) {
|
||||
std::optional<script> luasol::load_script(str_view src) {
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
|
||||
E2D_PROFILER_SCOPE("luasol.load_script");
|
||||
|
||||
sol::load_result result = state_.load_buffer(
|
||||
reinterpret_cast<const char*>(src.data()),
|
||||
src.size());
|
||||
src.data(), src.size());
|
||||
|
||||
if ( !result.valid() ) {
|
||||
sol::error err = result;
|
||||
@@ -56,15 +57,11 @@ namespace e2d
|
||||
return script(sol::protected_function(result));
|
||||
}
|
||||
|
||||
std::optional<script> luasol::load_script(const input_stream_uptr& src) {
|
||||
std::optional<script> luasol::load_script(buffer_view src) {
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
|
||||
buffer file_data;
|
||||
if ( !streams::try_read_tail(file_data, src) ) {
|
||||
the<debug>().error("LUASOL: Failed to read script stream");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return load_script(file_data);
|
||||
return load_script(str_view(
|
||||
reinterpret_cast<const char*>(src.data()),
|
||||
src.size()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,32 +72,69 @@ namespace
|
||||
}
|
||||
|
||||
bool frame_tick() final {
|
||||
E2D_PROFILER_SCOPE("application.frame_tick");
|
||||
|
||||
world& w = the<world>();
|
||||
engine& e = the<engine>();
|
||||
|
||||
const f32 dt = e.delta_time();
|
||||
const f32 time = e.time();
|
||||
|
||||
ecs::registry& registry = the<world>().registry();
|
||||
registry.process_event(systems::pre_update_event{dt,time});
|
||||
registry.process_event(systems::update_event{dt,time});
|
||||
registry.process_event(systems::post_update_event{dt,time});
|
||||
{
|
||||
E2D_PROFILER_SCOPE("ecs.pre_update");
|
||||
w.registry().process_event(systems::pre_update_event{dt,time});
|
||||
}
|
||||
|
||||
{
|
||||
E2D_PROFILER_SCOPE("ecs.update");
|
||||
w.registry().process_event(systems::update_event{dt,time});
|
||||
}
|
||||
|
||||
{
|
||||
E2D_PROFILER_SCOPE("ecs.post_update");
|
||||
w.registry().process_event(systems::post_update_event{dt,time});
|
||||
}
|
||||
|
||||
return !the<window>().should_close()
|
||||
|| (application_ && !application_->on_should_close());
|
||||
}
|
||||
|
||||
void frame_render() final {
|
||||
ecs::registry& registry = the<world>().registry();
|
||||
registry.process_event(systems::pre_render_event{});
|
||||
registry.process_event(systems::render_event{});
|
||||
registry.process_event(systems::post_render_event{});
|
||||
E2D_PROFILER_SCOPE("application.frame_render");
|
||||
|
||||
world& w = the<world>();
|
||||
|
||||
{
|
||||
E2D_PROFILER_SCOPE("ecs.pre_render");
|
||||
w.registry().process_event(systems::pre_render_event{});
|
||||
}
|
||||
|
||||
{
|
||||
E2D_PROFILER_SCOPE("ecs.render");
|
||||
w.registry().process_event(systems::render_event{});
|
||||
}
|
||||
|
||||
{
|
||||
E2D_PROFILER_SCOPE("ecs.post_render");
|
||||
w.registry().process_event(systems::post_render_event{});
|
||||
}
|
||||
}
|
||||
|
||||
void frame_finalize() final {
|
||||
E2D_PROFILER_SCOPE("application.frame_finalize");
|
||||
|
||||
world& w = the<world>();
|
||||
ecs::registry& registry = w.registry();
|
||||
registry.process_event(systems::frame_finalize_event{});
|
||||
|
||||
{
|
||||
E2D_PROFILER_SCOPE("ecs.frame_finalize");
|
||||
w.registry().process_event(systems::frame_finalize_event{});
|
||||
}
|
||||
|
||||
{
|
||||
E2D_PROFILER_SCOPE("world.finalize_instances");
|
||||
w.finalize_instances();
|
||||
}
|
||||
}
|
||||
private:
|
||||
starter::application_uptr application_;
|
||||
};
|
||||
|
||||
@@ -100,6 +100,7 @@ namespace e2d
|
||||
ecs::registry& owner,
|
||||
const ecs::after<systems::update_event>& trigger)
|
||||
{
|
||||
E2D_PROFILER_SCOPE("flipbook_system.process");
|
||||
state_->process(trigger.event.dt, owner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,6 +396,7 @@ namespace e2d
|
||||
const ecs::after<systems::update_event>& trigger)
|
||||
{
|
||||
E2D_UNUSED(trigger);
|
||||
E2D_PROFILER_SCOPE("label_system.process");
|
||||
state_->process(owner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,12 @@ namespace
|
||||
using namespace e2d::render_system_impl;
|
||||
|
||||
void for_all_scenes(drawer::context& ctx, const ecs::registry& owner) {
|
||||
E2D_PROFILER_SCOPE("render_system.for_all_scenes");
|
||||
|
||||
const auto comp = [](const auto& l, const auto& r) noexcept {
|
||||
return std::get<scene>(l).depth() < std::get<scene>(r).depth();
|
||||
};
|
||||
|
||||
const auto func = [&ctx](
|
||||
const ecs::const_entity&,
|
||||
const scene&,
|
||||
@@ -33,6 +36,7 @@ namespace
|
||||
ctx.draw(node);
|
||||
});
|
||||
};
|
||||
|
||||
systems::for_extracted_sorted_components<scene, actor>(
|
||||
owner,
|
||||
comp,
|
||||
@@ -41,9 +45,12 @@ namespace
|
||||
}
|
||||
|
||||
void for_all_cameras(drawer& drawer, const ecs::registry& owner) {
|
||||
E2D_PROFILER_SCOPE("render_system.for_all_cameras");
|
||||
|
||||
const auto comp = [](const auto& l, const auto& r) noexcept {
|
||||
return std::get<camera>(l).depth() < std::get<camera>(r).depth();
|
||||
};
|
||||
|
||||
const auto func = [&drawer, &owner](
|
||||
const ecs::const_entity&,
|
||||
const camera& cam,
|
||||
@@ -53,6 +60,7 @@ namespace
|
||||
for_all_scenes(ctx, owner);
|
||||
});
|
||||
};
|
||||
|
||||
systems::for_extracted_sorted_components<camera, actor>(
|
||||
owner,
|
||||
comp,
|
||||
@@ -93,6 +101,7 @@ namespace e2d
|
||||
const ecs::after<systems::render_event>& trigger)
|
||||
{
|
||||
E2D_UNUSED(trigger);
|
||||
E2D_PROFILER_SCOPE("render_system.process");
|
||||
state_->process(owner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,8 +192,8 @@ namespace e2d::render_system_impl
|
||||
|
||||
float* uvs = nullptr;
|
||||
unsigned short* indices = nullptr;
|
||||
std::size_t index_count = 0;
|
||||
std::size_t vertex_count = 0;
|
||||
int index_count = 0;
|
||||
int vertex_count = 0;
|
||||
const spAtlasPage* atlas_page = nullptr;
|
||||
const spColor* attachment_color = nullptr;
|
||||
|
||||
@@ -208,8 +208,10 @@ namespace e2d::render_system_impl
|
||||
|
||||
try {
|
||||
vertex_count = 8;
|
||||
if ( temp_vertices.size() < vertex_count ) {
|
||||
temp_vertices.resize(math::max(temp_vertices.size() * 2u, vertex_count));
|
||||
if ( temp_vertices.size() < math::numeric_cast<std::size_t>(vertex_count) ) {
|
||||
temp_vertices.resize(math::max(
|
||||
temp_vertices.size() * 2u,
|
||||
math::numeric_cast<std::size_t>(vertex_count)));
|
||||
}
|
||||
} catch (...) {
|
||||
property_cache_.clear();
|
||||
@@ -239,8 +241,10 @@ namespace e2d::render_system_impl
|
||||
|
||||
try {
|
||||
vertex_count = mesh->super.worldVerticesLength;
|
||||
if ( temp_vertices.size() < vertex_count ) {
|
||||
temp_vertices.resize(math::max(temp_vertices.size() * 2u, vertex_count));
|
||||
if ( temp_vertices.size() < math::numeric_cast<std::size_t>(vertex_count) ) {
|
||||
temp_vertices.resize(math::max(
|
||||
temp_vertices.size() * 2u,
|
||||
math::numeric_cast<std::size_t>(vertex_count)));
|
||||
}
|
||||
} catch (...) {
|
||||
property_cache_.clear();
|
||||
@@ -417,7 +421,7 @@ namespace e2d::render_system_impl
|
||||
batcher_.batch(
|
||||
mat_a,
|
||||
property_cache_,
|
||||
indices, index_count,
|
||||
indices, math::numeric_cast<std::size_t>(index_count),
|
||||
batch_vertices.data(), batch_vertex_count);
|
||||
} catch (...) {
|
||||
property_cache_.clear();
|
||||
|
||||
@@ -125,6 +125,7 @@ namespace e2d
|
||||
const systems::update_event& event)
|
||||
{
|
||||
E2D_UNUSED(event);
|
||||
E2D_PROFILER_SCOPE("script_system.process");
|
||||
state_->update_process(owner);
|
||||
}
|
||||
|
||||
@@ -133,6 +134,7 @@ namespace e2d
|
||||
const ecs::before<systems::update_event>& trigger)
|
||||
{
|
||||
E2D_UNUSED(trigger);
|
||||
E2D_PROFILER_SCOPE("script_system.process");
|
||||
state_->process_events(owner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,6 +258,7 @@ namespace e2d
|
||||
ecs::registry& owner,
|
||||
const ecs::after<systems::update_event>& trigger)
|
||||
{
|
||||
E2D_PROFILER_SCOPE("spine_system.process");
|
||||
state_->process(trigger.event.dt, owner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +195,8 @@ namespace e2d
|
||||
}
|
||||
|
||||
gobject world::instantiate(const prefab& prefab, const node_iptr& parent) {
|
||||
E2D_PROFILER_SCOPE("world.instantiate");
|
||||
|
||||
gobject inst = new_instance(*this, prefab);
|
||||
|
||||
if ( parent ) {
|
||||
@@ -216,6 +218,8 @@ namespace e2d
|
||||
}
|
||||
|
||||
gobject world::instantiate(const prefab& prefab, const node_iptr& parent, const t2f& transform) {
|
||||
E2D_PROFILER_SCOPE("world.instantiate");
|
||||
|
||||
gobject inst = new_instance(*this, prefab);
|
||||
inst.component<actor>()->node()->transform(transform);
|
||||
|
||||
@@ -244,6 +248,7 @@ namespace e2d
|
||||
}
|
||||
|
||||
void world::finalize_instances() noexcept {
|
||||
E2D_PROFILER_SCOPE("world.finalize_instances");
|
||||
while ( !destroying_states_.empty() ) {
|
||||
gobject inst{&destroying_states_.front()};
|
||||
destroying_states_.pop_front();
|
||||
|
||||
@@ -105,6 +105,11 @@ namespace e2d::filesystem
|
||||
dst, make_read_file(path));
|
||||
}
|
||||
|
||||
bool try_write_all(str_view src, str_view path, bool append) noexcept {
|
||||
return streams::try_write_tail(
|
||||
src, make_write_file(path, append));
|
||||
}
|
||||
|
||||
bool try_write_all(buffer_view src, str_view path, bool append) noexcept {
|
||||
return streams::try_write_tail(
|
||||
src, make_write_file(path, append));
|
||||
|
||||
@@ -170,6 +170,12 @@ namespace e2d
|
||||
return *this;
|
||||
}
|
||||
|
||||
output_sequence& output_sequence::write_all(str_view src) noexcept {
|
||||
return success_
|
||||
? write(src.data(), src.size())
|
||||
: *this;
|
||||
}
|
||||
|
||||
output_sequence& output_sequence::write_all(buffer_view src) noexcept {
|
||||
return success_
|
||||
? write(src.data(), src.size())
|
||||
@@ -222,6 +228,14 @@ namespace e2d::streams
|
||||
: false;
|
||||
}
|
||||
|
||||
bool try_write_tail(str_view src, const output_stream_uptr& stream) noexcept {
|
||||
return stream
|
||||
? output_sequence(*stream)
|
||||
.write_all(src)
|
||||
.success()
|
||||
: false;
|
||||
}
|
||||
|
||||
bool try_write_tail(buffer_view src, const output_stream_uptr& stream) noexcept {
|
||||
return stream
|
||||
? output_sequence(*stream)
|
||||
|
||||
@@ -135,6 +135,15 @@ namespace e2d
|
||||
return path_;
|
||||
}
|
||||
|
||||
str url::schemepath() const {
|
||||
str result;
|
||||
result.reserve(scheme_.size() + scheme_separator.size() + path_.size());
|
||||
result.append(scheme_);
|
||||
result.append(scheme_separator);
|
||||
result.append(path_);
|
||||
return result;
|
||||
}
|
||||
|
||||
url& url::operator+=(str_view path) {
|
||||
return concat(path);
|
||||
}
|
||||
|
||||
@@ -33,15 +33,15 @@ TEST_CASE("vfs"){
|
||||
REQUIRE(v.read({"file", nofile_path}) == input_stream_uptr());
|
||||
}
|
||||
{
|
||||
buffer b0;
|
||||
REQUIRE(v.load({"file", file_path}, b0));
|
||||
auto b0 = v.load({"file", file_path});
|
||||
REQUIRE(b0);
|
||||
REQUIRE(b0 == buffer{"hello", 5});
|
||||
|
||||
auto b1 = v.load_async({"file", file_path}).get();
|
||||
REQUIRE(b1 == buffer{"hello", 5});
|
||||
|
||||
str b2;
|
||||
REQUIRE(v.load_as_string({"file", file_path}, b2));
|
||||
auto b2 = v.load_as_string({"file", file_path});
|
||||
REQUIRE(b2);
|
||||
REQUIRE(b2 == "hello");
|
||||
|
||||
auto b3 = v.load_as_string_async({"file", file_path}).get();
|
||||
@@ -135,15 +135,15 @@ TEST_CASE("vfs"){
|
||||
REQUIRE(b == buffer("hello", 5));
|
||||
}
|
||||
{
|
||||
buffer b0;
|
||||
REQUIRE(v.load(url("archive://test.txt"), b0));
|
||||
auto b0 = v.load(url("archive://test.txt"));
|
||||
REQUIRE(b0);
|
||||
REQUIRE(b0 == buffer("hello", 5));
|
||||
|
||||
auto b1 = v.load_async(url("archive://test.txt")).get();
|
||||
REQUIRE(b1 == buffer("hello", 5));
|
||||
|
||||
str b2;
|
||||
REQUIRE(v.load_as_string(url("archive://test.txt"), b2));
|
||||
auto b2 = v.load_as_string(url("archive://test.txt"));
|
||||
REQUIRE(b2);
|
||||
REQUIRE(b2 == "hello");
|
||||
|
||||
auto b3 = v.load_as_string_async(url("archive://test.txt")).get();
|
||||
@@ -157,15 +157,15 @@ TEST_CASE("vfs"){
|
||||
REQUIRE(b == buffer("world", 5));
|
||||
}
|
||||
{
|
||||
buffer b0;
|
||||
REQUIRE(v.load(url("archive://folder/file.txt"), b0));
|
||||
auto b0 = v.load(url("archive://folder/file.txt"));
|
||||
REQUIRE(b0);
|
||||
REQUIRE(b0 == buffer("world", 5));
|
||||
|
||||
auto b1 = v.load_async(url("archive://folder/file.txt")).get();
|
||||
REQUIRE(b1 == buffer("world", 5));
|
||||
|
||||
str b2;
|
||||
REQUIRE(v.load_as_string(url("archive://folder/file.txt"), b2));
|
||||
auto b2 = v.load_as_string(url("archive://folder/file.txt"));
|
||||
REQUIRE(b2);
|
||||
REQUIRE(b2 == "world");
|
||||
|
||||
auto b3 = v.load_as_string_async(url("archive://folder/file.txt")).get();
|
||||
@@ -174,17 +174,15 @@ TEST_CASE("vfs"){
|
||||
{
|
||||
REQUIRE(v.read(url("archive://TEst.txt")) == input_stream_uptr());
|
||||
|
||||
buffer b0;
|
||||
REQUIRE_FALSE(v.load(url("archive://TEst.txt"), b0));
|
||||
REQUIRE(b0.empty());
|
||||
auto b0 = v.load(url("archive://TEst.txt"));
|
||||
REQUIRE_FALSE(b0);
|
||||
|
||||
REQUIRE_THROWS_AS(
|
||||
v.load_async(url("archive://TEst.txt")).get(),
|
||||
vfs_load_async_exception);
|
||||
|
||||
str b2;
|
||||
REQUIRE_FALSE(v.load_as_string(url("archive://TEst.txt"), b2));
|
||||
REQUIRE(b2.empty());
|
||||
auto b2 = v.load_as_string(url("archive://TEst.txt"));
|
||||
REQUIRE_FALSE(b2);
|
||||
|
||||
REQUIRE_THROWS_AS(
|
||||
v.load_as_string_async(url("archive://TEst.txt")).get(),
|
||||
|
||||
@@ -221,10 +221,10 @@ TEST_CASE("buffer_view") {
|
||||
REQUIRE(v5.data() == b2.data());
|
||||
REQUIRE(v5.size() == 20);
|
||||
|
||||
str32 b3 = make_utf32("hello");
|
||||
u32 b3[3] = {10, 20, 30};
|
||||
buffer_view v6(b3);
|
||||
REQUIRE(v6.data() == b3.data());
|
||||
REQUIRE(v6.size() == 20);
|
||||
REQUIRE(v6.data() == &b3[0]);
|
||||
REQUIRE(v6.size() == 12);
|
||||
}
|
||||
{
|
||||
const char* s0 = "hell";
|
||||
|
||||
@@ -19,24 +19,28 @@ TEST_CASE("url") {
|
||||
REQUIRE(u.empty());
|
||||
REQUIRE(u.scheme().empty());
|
||||
REQUIRE(u.path().empty());
|
||||
REQUIRE(u.schemepath() == "://");
|
||||
}
|
||||
{
|
||||
url u("://file");
|
||||
REQUIRE(!u.empty());
|
||||
REQUIRE(u.scheme().empty());
|
||||
REQUIRE(u.path() == "file");
|
||||
REQUIRE(u.schemepath() == "://file");
|
||||
}
|
||||
{
|
||||
url u("file://");
|
||||
REQUIRE(u.empty());
|
||||
REQUIRE(u.scheme() == "file");
|
||||
REQUIRE(u.path().empty());
|
||||
REQUIRE(u.schemepath() == "file://");
|
||||
}
|
||||
{
|
||||
url u("file://test_file");
|
||||
REQUIRE(!u.empty());
|
||||
REQUIRE(u.scheme() == "file");
|
||||
REQUIRE(u.path() == "test_file");
|
||||
REQUIRE(u.schemepath() == "file://test_file");
|
||||
}
|
||||
{
|
||||
url u("dir/file");
|
||||
|
||||
Reference in New Issue
Block a user