Compare commits

...

4 Commits

Author SHA1 Message Date
Attila Uygun 9680ca975c PlatformObserver wip 2023-05-25 16:02:00 +02:00
Attila Uygun b1c2e3f0d4 for android 2023-05-25 15:33:05 +02:00
Attila Uygun aca0213b0a crash fix 2023-05-25 10:48:19 +02:00
Attila Uygun a7ea09b149 move renderer ownership to engine (WIP) 2023-05-25 07:43:09 +02:00
13 changed files with 186 additions and 130 deletions

View File

@ -13,36 +13,53 @@
#include "engine/mesh.h"
#include "engine/platform/platform.h"
#include "engine/renderer/geometry.h"
#include "engine/renderer/opengl/renderer_opengl.h"
#include "engine/renderer/renderer.h"
#include "engine/renderer/shader.h"
#include "engine/renderer/texture.h"
#include "engine/renderer/vulkan/renderer_vulkan.h"
#include "engine/shader_source.h"
#include "third_party/texture_compressor/texture_compressor.h"
#define USE_VULKAN_RENDERER 1
using namespace base;
namespace eng {
Engine* Engine::singleton = nullptr;
Engine::Engine(Platform* platform, Renderer* renderer)
Engine::Engine(Platform* platform)
: platform_(platform),
renderer_(renderer),
audio_mixer_{std::make_unique<AudioMixer>()} {
#if (USE_VULKAN_RENDERER == 1)
renderer_{std::make_unique<RendererVulkan>()},
#else
renderer_{std::make_unique<RendererOpenGL>()},
#endif
audio_mixer_{std::make_unique<AudioMixer>()},
quad_{CreateRenderResource<Geometry>()},
pass_through_shader_{CreateRenderResource<Shader>()},
solid_shader_{CreateRenderResource<Shader>()} {
DCHECK(!singleton);
singleton = this;
platform_->SetObserver(this);
renderer_->SetContextLostCB(std::bind(&Engine::ContextLost, this));
quad_ = CreateRenderResource<Geometry>();
pass_through_shader_ = CreateRenderResource<Shader>();
solid_shader_ = CreateRenderResource<Shader>();
stats_ = std::make_unique<ImageQuad>();
}
Engine::~Engine() {
LOG << "Shutting down engine.";
game_.reset();
stats_.reset();
textures_.clear();
shaders_.clear();
quad_.reset();
pass_through_shader_.reset();
solid_shader_.reset();
renderer_.reset();
singleton = nullptr;
}
@ -51,6 +68,8 @@ Engine& Engine::Get() {
}
bool Engine::Initialize() {
InitializeRenderer();
// Normalize viewport.
if (GetScreenWidth() > GetScreenHeight()) {
float aspect_ratio = (float)GetScreenWidth() / (float)GetScreenHeight();
@ -91,14 +110,6 @@ bool Engine::Initialize() {
return true;
}
void Engine::Shutdown() {
LOG << "Shutting down engine.";
game_.reset();
stats_->Destory();
textures_.clear();
shaders_.clear();
}
void Engine::Update(float delta_time) {
seconds_accumulated_ += delta_time;
++tick_;
@ -180,25 +191,25 @@ void Engine::RemoveAnimator(Animator* animator) {
}
void Engine::SwitchRenderer(bool vulkan) {
Renderer* new_renderer = platform_->SwitchRenderer(vulkan);
if (new_renderer == renderer_)
return;
// Renderer* new_renderer = platform_->SwitchRenderer(vulkan);
// if (new_renderer == renderer_)
// return;
renderer_ = new_renderer;
renderer_->SetContextLostCB(std::bind(&Engine::ContextLost, this));
CreateTextureCompressors();
// renderer_ = new_renderer;
// renderer_->SetContextLostCB(std::bind(&Engine::ContextLost, this));
// CreateTextureCompressors();
for (auto& t : textures_)
t.second.texture->SetRenderer(renderer_);
// for (auto& t : textures_)
// t.second.texture->SetRenderer(renderer_);
for (auto& s : shaders_)
s.second.shader->SetRenderer(renderer_);
// for (auto& s : shaders_)
// s.second.shader->SetRenderer(renderer_);
quad_->SetRenderer(renderer_);
pass_through_shader_->SetRenderer(renderer_);
solid_shader_->SetRenderer(renderer_);
// quad_->SetRenderer(renderer_);
// pass_through_shader_->SetRenderer(renderer_);
// solid_shader_->SetRenderer(renderer_);
ContextLost();
// ContextLost();
}
void Engine::Exit() {
@ -490,6 +501,33 @@ bool Engine::IsMobile() const {
return platform_->mobile_device();
}
void Engine::OnWindowCreated() {
InitializeRenderer();
}
void Engine::OnWindowDestroyed() {
renderer_->Shutdown();
}
void Engine::OnWindowResized(int width, int height) {
if (width != renderer_->screen_width() ||
height != renderer_->screen_height()) {
renderer_->Shutdown();
InitializeRenderer();
}
}
void Engine::InitializeRenderer() {
bool res;
#if defined(__ANDROID__)
res = renderer_->Initialize(platform_->GetWindow());
#elif defined(__linux__)
res = renderer_->Initialize(platform_->GetDisplay(), platform_->GetWindow());
#endif
CHECK(res) << "Failed to initialize " << renderer_->GetDebugName()
<< " renderer.";
}
void Engine::CreateTextureCompressors() {
tex_comp_alpha_.reset();
tex_comp_opaque_.reset();

View File

@ -10,6 +10,7 @@
#include "base/random.h"
#include "base/vecmath.h"
#include "engine/persistent_data.h"
#include "engine/platform/platform_observer.h"
class TextureCompressor;
@ -29,19 +30,17 @@ class Shader;
class Texture;
class Platform;
class Engine {
class Engine : public PlatformObserver {
public:
using CreateImageCB = std::function<std::unique_ptr<Image>()>;
Engine(Platform* platform, Renderer* renderer);
Engine(Platform* platform);
~Engine();
static Engine& Get();
bool Initialize();
void Shutdown();
void Update(float delta_time);
void Draw(float frame_frac);
@ -66,7 +65,7 @@ class Engine {
template <typename T>
std::unique_ptr<T> CreateRenderResource() {
return std::unique_ptr<T>(static_cast<T*>(new T(renderer_)));
return std::unique_ptr<T>(static_cast<T*>(new T(renderer_.get())));
}
void SetImageSource(const std::string& asset_name,
@ -174,10 +173,9 @@ class Engine {
static Engine* singleton;
Platform* platform_ = nullptr;
Renderer* renderer_ = nullptr;
std::unique_ptr<Renderer> renderer_;
std::unique_ptr<AudioMixer> audio_mixer_;
std::unique_ptr<Game> game_;
std::unique_ptr<Geometry> quad_;
@ -223,6 +221,13 @@ class Engine {
base::Randomf random_;
// PlatformObserver implementation
void OnWindowCreated() final;
void OnWindowDestroyed() final;
void OnWindowResized(int width, int height) final;
void InitializeRenderer();
void CreateTextureCompressors();
void ContextLost();

View File

@ -32,6 +32,7 @@ void ImageQuad::Create(const std::string& asset_name,
asset_name_ = asset_name;
}
// TODO: typo
void ImageQuad::Destory() {
if (texture_) {
Engine::Get().ReleaseTexture(asset_name_);

View File

@ -3,10 +3,6 @@
#include "base/log.h"
#include "base/task_runner.h"
#include "engine/engine.h"
#include "engine/renderer/opengl/renderer_opengl.h"
#include "engine/renderer/vulkan/renderer_vulkan.h"
#define USE_VULKAN_RENDERER 1
using namespace base;
@ -16,47 +12,35 @@ Platform::Platform() = default;
Platform::~Platform() = default;
Renderer* Platform::SwitchRenderer(bool vulkan) {
DCHECK(renderer_);
// Renderer* Platform::SwitchRenderer(bool vulkan) {
// DCHECK(renderer_);
if ((dynamic_cast<RendererVulkan*>(renderer_.get()) && vulkan) ||
(dynamic_cast<RendererOpenGL*>(renderer_.get()) && !vulkan))
return renderer_.get();
// if ((dynamic_cast<RendererVulkan*>(renderer_.get()) && vulkan) ||
// (dynamic_cast<RendererOpenGL*>(renderer_.get()) && !vulkan))
// return renderer_.get();
if (vulkan)
renderer_ = std::make_unique<RendererVulkan>();
else
renderer_ = std::make_unique<RendererOpenGL>();
// if (vulkan)
// renderer_ = std::make_unique<RendererVulkan>();
// else
// renderer_ = std::make_unique<RendererOpenGL>();
bool result = InitializeRenderer();
CHECK(result) << "Failed to initialize " << renderer_->GetDebugName()
<< " renderer.";
LOG << "Switched to " << renderer_->GetDebugName() << " renderer.";
return renderer_.get();
}
// bool result = InitializeRenderer();
// CHECK(result) << "Failed to initialize " << renderer_->GetDebugName()
// << " renderer.";
// LOG << "Switched to " << renderer_->GetDebugName() << " renderer.";
// return renderer_.get();
// }
void Platform::InitializeCommon() {
LOG << "Initializing platform.";
thread_pool_.Initialize();
TaskRunner::CreateThreadLocalTaskRunner();
#if (USE_VULKAN_RENDERER == 1)
renderer_ = std::make_unique<RendererVulkan>();
#else
renderer_ = std::make_unique<RendererOpenGL>();
#endif
}
void Platform::ShutdownCommon() {
LOG << "Shutting down platform.";
renderer_->Shutdown();
}
void Platform::RunMainLoop() {
engine_ =
std::make_unique<Engine>(this, renderer_.get());
std::make_unique<Engine>(this);
bool res = engine_->Initialize();
CHECK(res) << "Failed to initialize the engine.";
@ -83,8 +67,7 @@ void Platform::RunMainLoop() {
if (should_exit_) {
thread_pool_.Shutdown();
engine_->Shutdown();
engine_.reset();
// engine_.reset();
return;
}
accumulator -= time_step;

View File

@ -24,8 +24,8 @@ struct ANativeWindow;
namespace eng {
class Renderer;
class Engine;
class PlatformObserver;
class Platform {
public:
@ -44,7 +44,9 @@ class Platform {
void Exit();
Renderer* SwitchRenderer(bool vulkan);
void SetObserver(PlatformObserver* observer) { observer_ = observer; }
// Renderer* SwitchRenderer(bool vulkan);
void Vibrate(int duration);
@ -66,6 +68,13 @@ class Platform {
bool mobile_device() const { return mobile_device_; }
#if defined(__ANDROID__)
ANativeWindow* GetWindow();
#elif defined(__linux__)
Display* GetDisplay();
Window GetWindow();
#endif
protected:
base::Timer timer_;
@ -78,7 +87,8 @@ class Platform {
bool has_focus_ = false;
bool should_exit_ = false;
std::unique_ptr<Renderer> renderer_;
PlatformObserver* observer_ = nullptr;
std::unique_ptr<Engine> engine_;
base::ThreadPool thread_pool_;
@ -116,12 +126,11 @@ class Platform {
bool CreateWindow(int width, int height);
void DestroyWindow();
XVisualInfo* GetXVisualInfo(Display* display);
#endif
void InitializeCommon();
void ShutdownCommon();
bool InitializeRenderer();
Platform(const Platform&) = delete;
Platform& operator=(const Platform&) = delete;

View File

@ -9,7 +9,7 @@
#include "base/task_runner.h"
#include "engine/engine.h"
#include "engine/input_event.h"
#include "engine/renderer/renderer.h"
#include "engine/platform/platform_observer.h"
using namespace base;
@ -295,30 +295,21 @@ void Platform::HandleCmd(android_app* app, int32_t cmd) {
DLOG << "APP_CMD_INIT_WINDOW";
if (app->window != NULL) {
platform->SetFrameRate(60);
bool res = platform->InitializeRenderer();
CHECK(res) << "Failed to initialize "
<< platform->renderer_->GetDebugName() << " renderer.";
platform->observer_->OnWindowCreated();
}
break;
case APP_CMD_TERM_WINDOW:
DLOG << "APP_CMD_TERM_WINDOW";
platform->renderer_->Shutdown();
platform->observer_->OnWindowDestroyed();
break;
case APP_CMD_CONFIG_CHANGED:
DLOG << "APP_CMD_CONFIG_CHANGED";
if (platform->app_->window != NULL) {
int width = platform->renderer_->screen_width();
int height = platform->renderer_->screen_height();
if (width != ANativeWindow_getWidth(app->window) ||
height != ANativeWindow_getHeight(app->window)) {
platform->renderer_->Shutdown();
bool res = platform->InitializeRenderer();
CHECK(res) << "Failed to initialize "
<< platform->renderer_->GetDebugName() << " renderer.";
}
}
if (platform->app_->window != NULL)
platform->observer_->OnWindowResized(
ANativeWindow_getWidth(app->window),
ANativeWindow_getHeight(app->window));
break;
case APP_CMD_STOP:
@ -386,7 +377,7 @@ void Platform::Initialize(android_app* app) {
}
void Platform::Shutdown() {
Platform::ShutdownCommon();
LOG << "Shutting down platform.";
}
void Platform::Update() {
@ -439,8 +430,8 @@ void Platform::SetFrameRate(float frame_rate) {
}
}
bool Platform::InitializeRenderer() {
return renderer_->Initialize(app_->window);
ANativeWindow* Platform::GetWindow() {
return app_->window;
}
} // namespace eng

View File

@ -5,7 +5,6 @@
#include "base/vecmath.h"
#include "engine/engine.h"
#include "engine/input_event.h"
#include "engine/renderer/renderer.h"
using namespace base;
@ -26,10 +25,6 @@ void Platform::Initialize() {
bool res = CreateWindow(800, 1205);
CHECK(res) << "Failed to create window.";
res = InitializeRenderer();
CHECK(res) << "Failed to initialize " << renderer_->GetDebugName()
<< " renderer.";
XSelectInput(display_, window_,
KeyPressMask | Button1MotionMask | ButtonPressMask |
ButtonReleaseMask | FocusChangeMask);
@ -38,8 +33,7 @@ void Platform::Initialize() {
}
void Platform::Shutdown() {
Platform::ShutdownCommon();
LOG << "Shutting down platform.";
DestroyWindow();
}
@ -127,7 +121,7 @@ bool Platform::CreateWindow(int width, int height) {
Window root_window = DefaultRootWindow(display_);
XVisualInfo* visual_info = renderer_->GetXVisualInfo(display_);
XVisualInfo* visual_info = GetXVisualInfo(display_);
if (!visual_info) {
LOG << "No appropriate visual found.";
return false;
@ -151,14 +145,29 @@ bool Platform::CreateWindow(int width, int height) {
void Platform::DestroyWindow() {
if (display_) {
XDestroyWindow(display_, window_);
#if 0 // TODO: Figure out why XCloseDisplay is crashing
XCloseDisplay(display_);
#endif
display_ = nullptr;
window_ = 0;
}
}
bool Platform::InitializeRenderer() {
return renderer_->Initialize(display_, window_);
Display* Platform::GetDisplay() {
return display_;
}
Window Platform::GetWindow() {
return window_;
}
XVisualInfo* Platform::GetXVisualInfo(Display* display) {
long visual_mask = VisualScreenMask;
int num_visuals;
XVisualInfo visual_info_template = {};
visual_info_template.screen = DefaultScreen(display);
return XGetVisualInfo(display, visual_mask, &visual_info_template,
&num_visuals);
}
} // namespace eng

View File

@ -0,0 +1,18 @@
#ifndef ENGINE_PLATFORM_PLATFORM_OBSERVER_H
#define ENGINE_PLATFORM_PLATFORM_OBSERVER_H
namespace eng {
class PlatformObserver {
public:
PlatformObserver() = default;
virtual ~PlatformObserver() = default;
virtual void OnWindowCreated() = 0;
virtual void OnWindowDestroyed() = 0;
virtual void OnWindowResized(int width, int height) = 0;
};
} // namespace eng
#endif // ENGINE_PLATFORM_PLATFORM_OBSERVER_H

View File

@ -89,9 +89,9 @@ class RendererOpenGL final : public Renderer {
const char* GetDebugName() final { return "OpenGL"; }
#if defined(__linux__) && !defined(__ANDROID__)
XVisualInfo* GetXVisualInfo(Display* display) final;
#endif
// #if defined(__linux__) && !defined(__ANDROID__)
// XVisualInfo* GetXVisualInfo(Display* display) final;
// #endif
private:
struct GeometryOpenGL {

View File

@ -21,9 +21,11 @@ bool RendererOpenGL::Initialize(Display* display, Window window) {
void RendererOpenGL::OnDestroy() {}
bool RendererOpenGL::InitInternal() {
// Create the OpenGL context.
GLint glx_attributes[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER,
None};
XVisualInfo* visual_info = glXChooseVisual(display_, 0, glx_attributes);
glx_context_ =
glXCreateContext(display_, GetXVisualInfo(display_), NULL, GL_TRUE);
glXCreateContext(display_, visual_info, NULL, GL_TRUE);
if (!glx_context_) {
LOG << "Couldn't create the glx context.";
return false;
@ -59,11 +61,11 @@ void RendererOpenGL::HandleCmdPresent(RenderCommand* cmd) {
}
}
XVisualInfo* RendererOpenGL::GetXVisualInfo(Display* display) {
// Look for the right visual to set up the OpenGL context.
GLint glx_attributes[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER,
None};
return glXChooseVisual(display, 0, glx_attributes);
}
// XVisualInfo* RendererOpenGL::GetXVisualInfo(Display* display) {
// // Look for the right visual to set up the OpenGL context.
// GLint glx_attributes[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER,
// None};
// return glXChooseVisual(display, 0, glx_attributes);
// }
} // namespace eng

View File

@ -94,9 +94,9 @@ class Renderer {
virtual const char* GetDebugName() = 0;
#if defined(__linux__) && !defined(__ANDROID__)
virtual XVisualInfo* GetXVisualInfo(Display* display) = 0;
#endif
// #if defined(__linux__) && !defined(__ANDROID__)
// virtual XVisualInfo* GetXVisualInfo(Display* display) = 0;
// #endif
protected:
struct TextureCompression {

View File

@ -74,9 +74,9 @@ class RendererVulkan final : public Renderer {
const char* GetDebugName() final { return "Vulkan"; }
#if defined(__linux__) && !defined(__ANDROID__)
XVisualInfo* GetXVisualInfo(Display* display) final;
#endif
// #if defined(__linux__) && !defined(__ANDROID__)
// XVisualInfo* GetXVisualInfo(Display* display) final;
// #endif
private:
// VkBuffer or VkImage with allocator.

View File

@ -24,13 +24,13 @@ bool RendererVulkan::Initialize(Display* display, Window window) {
return InitializeInternal();
}
XVisualInfo* RendererVulkan::GetXVisualInfo(Display* display) {
long visual_mask = VisualScreenMask;
int num_visuals;
XVisualInfo visual_info_template = {};
visual_info_template.screen = DefaultScreen(display);
return XGetVisualInfo(display, visual_mask, &visual_info_template,
&num_visuals);
}
// XVisualInfo* RendererVulkan::GetXVisualInfo(Display* display) {
// long visual_mask = VisualScreenMask;
// int num_visuals;
// XVisualInfo visual_info_template = {};
// visual_info_template.screen = DefaultScreen(display);
// return XGetVisualInfo(display, visual_mask, &visual_info_template,
// &num_visuals);
// }
} // namespace eng