mirror of https://github.com/auygun/kaliber.git
Compare commits
8 Commits
be36d121b0
...
f6f67d7e53
Author | SHA1 | Date |
---|---|---|
Attila Uygun | f6f67d7e53 | |
Attila Uygun | 43afdf855f | |
Attila Uygun | 66557f07e3 | |
Attila Uygun | d5ee1c7313 | |
Attila Uygun | 8d28d85a09 | |
Attila Uygun | b160ae0bd3 | |
Attila Uygun | b7f1f7faa2 | |
Attila Uygun | 94242fca0b |
|
@ -62,8 +62,8 @@ add_library(kaliber SHARED
|
||||||
../../../src/demo/sky_quad.cc
|
../../../src/demo/sky_quad.cc
|
||||||
../../../src/engine/animatable.cc
|
../../../src/engine/animatable.cc
|
||||||
../../../src/engine/animator.cc
|
../../../src/engine/animator.cc
|
||||||
../../../src/engine/audio/audio_driver_oboe.cc
|
|
||||||
../../../src/engine/audio/audio_mixer.cc
|
../../../src/engine/audio/audio_mixer.cc
|
||||||
|
../../../src/engine/audio/audio_sink_oboe.cc
|
||||||
../../../src/engine/drawable.cc
|
../../../src/engine/drawable.cc
|
||||||
../../../src/engine/engine.cc
|
../../../src/engine/engine.cc
|
||||||
../../../src/engine/font.cc
|
../../../src/engine/font.cc
|
||||||
|
@ -74,7 +74,6 @@ add_library(kaliber SHARED
|
||||||
../../../src/engine/platform/asset_file_android.cc
|
../../../src/engine/platform/asset_file_android.cc
|
||||||
../../../src/engine/platform/asset_file.cc
|
../../../src/engine/platform/asset_file.cc
|
||||||
../../../src/engine/platform/platform_android.cc
|
../../../src/engine/platform/platform_android.cc
|
||||||
../../../src/engine/platform/platform.cc
|
|
||||||
../../../src/engine/renderer/geometry.cc
|
../../../src/engine/renderer/geometry.cc
|
||||||
../../../src/engine/renderer/opengl/render_command.cc
|
../../../src/engine/renderer/opengl/render_command.cc
|
||||||
../../../src/engine/renderer/opengl/renderer_opengl_android.cc
|
../../../src/engine/renderer/opengl/renderer_opengl_android.cc
|
||||||
|
|
|
@ -95,8 +95,8 @@ $(BASE_LIB): $(BASE_OBJS)
|
||||||
ENGINE_SRC := \
|
ENGINE_SRC := \
|
||||||
$(SRC_ROOT)/engine/animatable.cc \
|
$(SRC_ROOT)/engine/animatable.cc \
|
||||||
$(SRC_ROOT)/engine/animator.cc \
|
$(SRC_ROOT)/engine/animator.cc \
|
||||||
$(SRC_ROOT)/engine/audio/audio_driver_alsa.cc \
|
|
||||||
$(SRC_ROOT)/engine/audio/audio_mixer.cc \
|
$(SRC_ROOT)/engine/audio/audio_mixer.cc \
|
||||||
|
$(SRC_ROOT)/engine/audio/audio_sink_alsa.cc \
|
||||||
$(SRC_ROOT)/engine/drawable.cc \
|
$(SRC_ROOT)/engine/drawable.cc \
|
||||||
$(SRC_ROOT)/engine/engine.cc \
|
$(SRC_ROOT)/engine/engine.cc \
|
||||||
$(SRC_ROOT)/engine/font.cc \
|
$(SRC_ROOT)/engine/font.cc \
|
||||||
|
@ -106,7 +106,6 @@ ENGINE_SRC := \
|
||||||
$(SRC_ROOT)/engine/persistent_data.cc \
|
$(SRC_ROOT)/engine/persistent_data.cc \
|
||||||
$(SRC_ROOT)/engine/platform/asset_file_linux.cc \
|
$(SRC_ROOT)/engine/platform/asset_file_linux.cc \
|
||||||
$(SRC_ROOT)/engine/platform/asset_file.cc \
|
$(SRC_ROOT)/engine/platform/asset_file.cc \
|
||||||
$(SRC_ROOT)/engine/platform/platform.cc \
|
|
||||||
$(SRC_ROOT)/engine/platform/platform_linux.cc \
|
$(SRC_ROOT)/engine/platform/platform_linux.cc \
|
||||||
$(SRC_ROOT)/engine/renderer/geometry.cc \
|
$(SRC_ROOT)/engine/renderer/geometry.cc \
|
||||||
$(SRC_ROOT)/engine/renderer/opengl/render_command.cc \
|
$(SRC_ROOT)/engine/renderer/opengl/render_command.cc \
|
||||||
|
|
|
@ -95,7 +95,7 @@ void Credits::Show() {
|
||||||
void Credits::Hide() {
|
void Credits::Hide() {
|
||||||
text_animator_.SetEndCallback(Animator::kBlending, [&]() -> void {
|
text_animator_.SetEndCallback(Animator::kBlending, [&]() -> void {
|
||||||
for (int i = 0; i < kNumLines; ++i)
|
for (int i = 0; i < kNumLines; ++i)
|
||||||
text_[i].Destory();
|
text_[i].Destroy();
|
||||||
text_animator_.SetEndCallback(Animator::kBlending, nullptr);
|
text_animator_.SetEndCallback(Animator::kBlending, nullptr);
|
||||||
text_animator_.SetVisible(false);
|
text_animator_.SetVisible(false);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_DRIVER_H
|
|
||||||
#define ENGINE_AUDIO_AUDIO_DRIVER_H
|
|
||||||
|
|
||||||
#include "engine/audio/audio_driver.h"
|
|
||||||
|
|
||||||
namespace eng {
|
|
||||||
|
|
||||||
class AudioDriverDelegate;
|
|
||||||
|
|
||||||
// Models an audio sink sending mixed audio to the audio driver. Audio data from
|
|
||||||
// the mixer source is delivered on a pull model using AudioDriverDelegate.
|
|
||||||
class AudioDriver {
|
|
||||||
public:
|
|
||||||
AudioDriver() = default;
|
|
||||||
virtual ~AudioDriver() = default;
|
|
||||||
|
|
||||||
virtual void SetDelegate(AudioDriverDelegate* delegate) = 0;
|
|
||||||
|
|
||||||
virtual bool Initialize() = 0;
|
|
||||||
|
|
||||||
virtual void Shutdown() = 0;
|
|
||||||
|
|
||||||
virtual void Suspend() = 0;
|
|
||||||
virtual void Resume() = 0;
|
|
||||||
|
|
||||||
virtual int GetHardwareSampleRate() = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
AudioDriver(const AudioDriver&) = delete;
|
|
||||||
AudioDriver& operator=(const AudioDriver&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace eng
|
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_DRIVER_H
|
|
|
@ -1,18 +0,0 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_DRIVER_DELEGATE_H
|
|
||||||
#define ENGINE_AUDIO_AUDIO_DRIVER_DELEGATE_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
namespace eng {
|
|
||||||
|
|
||||||
class AudioDriverDelegate {
|
|
||||||
public:
|
|
||||||
AudioDriverDelegate() = default;
|
|
||||||
virtual ~AudioDriverDelegate() = default;
|
|
||||||
|
|
||||||
virtual void RenderAudio(float* output_buffer, size_t num_frames) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace eng
|
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_DRIVER_DELEGATE_H
|
|
|
@ -7,12 +7,26 @@
|
||||||
#include "base/thread_pool.h"
|
#include "base/thread_pool.h"
|
||||||
#include "engine/sound.h"
|
#include "engine/sound.h"
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#include "engine/audio/audio_sink_oboe.h"
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include "engine/audio/audio_sink_alsa.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
AudioMixer::AudioMixer()
|
AudioMixer::AudioMixer()
|
||||||
: main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()) {}
|
: main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()),
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
audio_sink_{std::make_unique<AudioSinkOboe>(this)} {
|
||||||
|
#elif defined(__linux__)
|
||||||
|
audio_sink_{std::make_unique<AudioSinkAlsa>(this)} {
|
||||||
|
#endif
|
||||||
|
bool res = audio_sink_->Initialize();
|
||||||
|
CHECK(res) << "Failed to initialize audio sink.";
|
||||||
|
}
|
||||||
|
|
||||||
AudioMixer::~AudioMixer() = default;
|
AudioMixer::~AudioMixer() = default;
|
||||||
|
|
||||||
|
@ -139,6 +153,18 @@ void AudioMixer::SetEndCallback(uint64_t resource_id, base::Closure cb) {
|
||||||
it->second->end_cb = std::move(cb);
|
it->second->end_cb = std::move(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioMixer::Suspend() {
|
||||||
|
audio_sink_->Suspend();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioMixer::Resume() {
|
||||||
|
audio_sink_->Resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
int AudioMixer::GetHardwareSampleRate() {
|
||||||
|
return audio_sink_->GetHardwareSampleRate();
|
||||||
|
}
|
||||||
|
|
||||||
void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
|
void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> scoped_lock(lock_, std::try_to_lock);
|
std::unique_lock<std::mutex> scoped_lock(lock_, std::try_to_lock);
|
||||||
|
@ -238,7 +264,7 @@ void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
|
||||||
ThreadPool::Get().PostTask(
|
ThreadPool::Get().PostTask(
|
||||||
HERE,
|
HERE,
|
||||||
std::bind(&AudioMixer::DoStream, this, *it, flags & kLoop));
|
std::bind(&AudioMixer::DoStream, this, *it, flags & kLoop));
|
||||||
} else if (num_samples) {
|
} else {
|
||||||
DLOG << "Mixer buffer underrun!";
|
DLOG << "Mixer buffer underrun!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "base/closure.h"
|
#include "base/closure.h"
|
||||||
#include "engine/audio/audio_driver_delegate.h"
|
#include "engine/audio/audio_sink_delegate.h"
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
class TaskRunner;
|
class TaskRunner;
|
||||||
|
@ -16,12 +16,13 @@ class TaskRunner;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
|
class AudioSink;
|
||||||
class Sound;
|
class Sound;
|
||||||
|
|
||||||
// Mix and render audio with low overhead. A platform specific AudioDriver
|
// Mix and render audio with low overhead. A platform specific AudioSink
|
||||||
// implementation is expected to periodically call Render() in a background
|
// implementation is expected to periodically call RenderAudio() in a background
|
||||||
// thread.
|
// thread.
|
||||||
class AudioMixer : public AudioDriverDelegate {
|
class AudioMixer : public AudioSinkDelegate {
|
||||||
public:
|
public:
|
||||||
AudioMixer();
|
AudioMixer();
|
||||||
~AudioMixer();
|
~AudioMixer();
|
||||||
|
@ -44,10 +45,16 @@ class AudioMixer : public AudioDriverDelegate {
|
||||||
|
|
||||||
void SetEnableAudio(bool enable) { audio_enabled_ = enable; }
|
void SetEnableAudio(bool enable) { audio_enabled_ = enable; }
|
||||||
|
|
||||||
|
void Suspend();
|
||||||
|
void Resume();
|
||||||
|
|
||||||
|
int GetHardwareSampleRate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum SampleFlags { kLoop = 1, kStopped = 2, kSimulateStereo = 4 };
|
enum SampleFlags { kLoop = 1, kStopped = 2, kSimulateStereo = 4 };
|
||||||
static constexpr int kChannelCount = 2;
|
static constexpr int kChannelCount = 2;
|
||||||
|
|
||||||
|
// An audio resource that gets mixed and rendered to the audio sink.
|
||||||
struct Resource {
|
struct Resource {
|
||||||
// Accessed by main thread only.
|
// Accessed by main thread only.
|
||||||
bool active = false;
|
bool active = false;
|
||||||
|
@ -80,9 +87,12 @@ class AudioMixer : public AudioDriverDelegate {
|
||||||
|
|
||||||
base::TaskRunner* main_thread_task_runner_;
|
base::TaskRunner* main_thread_task_runner_;
|
||||||
|
|
||||||
|
std::unique_ptr<AudioSink> audio_sink_;
|
||||||
|
|
||||||
bool audio_enabled_ = true;
|
bool audio_enabled_ = true;
|
||||||
|
|
||||||
// AudioDriverDelegate implementation
|
// AudioSinkDelegate implementation
|
||||||
|
int GetChannelCount() final { return kChannelCount; }
|
||||||
void RenderAudio(float* output_buffer, size_t num_frames) final;
|
void RenderAudio(float* output_buffer, size_t num_frames) final;
|
||||||
|
|
||||||
void DoStream(std::shared_ptr<Resource> sample, bool loop);
|
void DoStream(std::shared_ptr<Resource> sample, bool loop);
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef ENGINE_AUDIO_AUDIO_SINK_H
|
||||||
|
#define ENGINE_AUDIO_AUDIO_SINK_H
|
||||||
|
|
||||||
|
namespace eng {
|
||||||
|
|
||||||
|
// Models an audio sink sending mixed audio to the audio driver. Audio data from
|
||||||
|
// the mixer source is delivered on a pull model using AudioSinkDelegate.
|
||||||
|
class AudioSink {
|
||||||
|
public:
|
||||||
|
AudioSink() = default;
|
||||||
|
virtual ~AudioSink() = default;
|
||||||
|
|
||||||
|
virtual bool Initialize() = 0;
|
||||||
|
|
||||||
|
virtual void Suspend() = 0;
|
||||||
|
virtual void Resume() = 0;
|
||||||
|
|
||||||
|
virtual int GetHardwareSampleRate() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AudioSink(const AudioSink&) = delete;
|
||||||
|
AudioSink& operator=(const AudioSink&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace eng
|
||||||
|
|
||||||
|
#endif // ENGINE_AUDIO_AUDIO_SINK_H
|
|
@ -1,27 +1,29 @@
|
||||||
#include "engine/audio/audio_driver_alsa.h"
|
#include "engine/audio/audio_sink_alsa.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "engine/audio/audio_driver_delegate.h"
|
#include "engine/audio/audio_sink_delegate.h"
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
AudioDriverAlsa::AudioDriverAlsa() = default;
|
AudioSinkAlsa::AudioSinkAlsa(AudioSinkDelegate* delegate)
|
||||||
|
: delegate_(delegate) {}
|
||||||
|
|
||||||
AudioDriverAlsa::~AudioDriverAlsa() = default;
|
AudioSinkAlsa::~AudioSinkAlsa() {
|
||||||
|
LOG << "Shutting down audio.";
|
||||||
|
|
||||||
void AudioDriverAlsa::SetDelegate(AudioDriverDelegate* delegate) {
|
TerminateAudioThread();
|
||||||
delegate_ = delegate;
|
snd_pcm_drop(device_);
|
||||||
Resume();
|
snd_pcm_close(device_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioDriverAlsa::Initialize() {
|
bool AudioSinkAlsa::Initialize() {
|
||||||
LOG << "Initializing audio system.";
|
LOG << "Initializing audio.";
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -142,35 +144,29 @@ bool AudioDriverAlsa::Initialize() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverAlsa::Shutdown() {
|
void AudioSinkAlsa::Suspend() {
|
||||||
LOG << "Shutting down audio system.";
|
|
||||||
TerminateAudioThread();
|
|
||||||
snd_pcm_drop(device_);
|
|
||||||
snd_pcm_close(device_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioDriverAlsa::Suspend() {
|
|
||||||
suspend_audio_thread_.store(true, std::memory_order_relaxed);
|
suspend_audio_thread_.store(true, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverAlsa::Resume() {
|
void AudioSinkAlsa::Resume() {
|
||||||
suspend_audio_thread_.store(false, std::memory_order_relaxed);
|
suspend_audio_thread_.store(false, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AudioDriverAlsa::GetHardwareSampleRate() {
|
int AudioSinkAlsa::GetHardwareSampleRate() {
|
||||||
return sample_rate_;
|
return sample_rate_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverAlsa::StartAudioThread() {
|
void AudioSinkAlsa::StartAudioThread() {
|
||||||
|
DCHECK(!audio_thread_.joinable());
|
||||||
|
|
||||||
LOG << "Starting audio thread.";
|
LOG << "Starting audio thread.";
|
||||||
terminate_audio_thread_.store(false, std::memory_order_relaxed);
|
terminate_audio_thread_.store(false, std::memory_order_relaxed);
|
||||||
suspend_audio_thread_.store(delegate_ ? false : true,
|
suspend_audio_thread_.store(false, std::memory_order_relaxed);
|
||||||
std::memory_order_relaxed);
|
audio_thread_ = std::thread(&AudioSinkAlsa::AudioThreadMain, this);
|
||||||
audio_thread_ = std::thread(&AudioDriverAlsa::AudioThreadMain, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverAlsa::TerminateAudioThread() {
|
void AudioSinkAlsa::TerminateAudioThread() {
|
||||||
if (terminate_audio_thread_.load(std::memory_order_relaxed))
|
if (!audio_thread_.joinable())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG << "Terminating audio thread";
|
LOG << "Terminating audio thread";
|
||||||
|
@ -179,7 +175,9 @@ void AudioDriverAlsa::TerminateAudioThread() {
|
||||||
audio_thread_.join();
|
audio_thread_.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverAlsa::AudioThreadMain() {
|
void AudioSinkAlsa::AudioThreadMain() {
|
||||||
|
DCHECK(delegate_);
|
||||||
|
|
||||||
size_t num_frames = period_size_ / (num_channels_ * sizeof(float));
|
size_t num_frames = period_size_ / (num_channels_ * sizeof(float));
|
||||||
auto buffer = std::make_unique<float[]>(num_frames * 2);
|
auto buffer = std::make_unique<float[]>(num_frames * 2);
|
||||||
|
|
|
@ -1,26 +1,24 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_DRIVER_ALSA_H
|
#ifndef ENGINE_AUDIO_AUDIO_SINK_ALSA_H
|
||||||
#define ENGINE_AUDIO_AUDIO_DRIVER_ALSA_H
|
#define ENGINE_AUDIO_AUDIO_SINK_ALSA_H
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "engine/audio/audio_driver.h"
|
#include "engine/audio/audio_sink.h"
|
||||||
|
|
||||||
typedef struct _snd_pcm snd_pcm_t;
|
typedef struct _snd_pcm snd_pcm_t;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class AudioDriverAlsa final : public AudioDriver {
|
class AudioSinkDelegate;
|
||||||
public:
|
|
||||||
AudioDriverAlsa();
|
|
||||||
~AudioDriverAlsa() final;
|
|
||||||
|
|
||||||
void SetDelegate(AudioDriverDelegate* delegate) final;
|
class AudioSinkAlsa final : public AudioSink {
|
||||||
|
public:
|
||||||
|
AudioSinkAlsa(AudioSinkDelegate* delegate);
|
||||||
|
~AudioSinkAlsa() final;
|
||||||
|
|
||||||
bool Initialize() final;
|
bool Initialize() final;
|
||||||
|
|
||||||
void Shutdown() final;
|
|
||||||
|
|
||||||
void Suspend() final;
|
void Suspend() final;
|
||||||
void Resume() final;
|
void Resume() final;
|
||||||
|
|
||||||
|
@ -38,7 +36,7 @@ class AudioDriverAlsa final : public AudioDriver {
|
||||||
int sample_rate_ = 0;
|
int sample_rate_ = 0;
|
||||||
size_t period_size_ = 0;
|
size_t period_size_ = 0;
|
||||||
|
|
||||||
AudioDriverDelegate* delegate_ = nullptr;
|
AudioSinkDelegate* delegate_ = nullptr;
|
||||||
|
|
||||||
void StartAudioThread();
|
void StartAudioThread();
|
||||||
void TerminateAudioThread();
|
void TerminateAudioThread();
|
||||||
|
@ -48,4 +46,4 @@ class AudioDriverAlsa final : public AudioDriver {
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_DRIVER_ALSA_H
|
#endif // ENGINE_AUDIO_AUDIO_SINK_ALSA_H
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef ENGINE_AUDIO_AUDIO_SINK_DELEGATE_H
|
||||||
|
#define ENGINE_AUDIO_AUDIO_SINK_DELEGATE_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
namespace eng {
|
||||||
|
|
||||||
|
class AudioSinkDelegate {
|
||||||
|
public:
|
||||||
|
AudioSinkDelegate() = default;
|
||||||
|
virtual ~AudioSinkDelegate() = default;
|
||||||
|
|
||||||
|
virtual int GetChannelCount() = 0;
|
||||||
|
|
||||||
|
virtual void RenderAudio(float* output_buffer, size_t num_frames) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace eng
|
||||||
|
|
||||||
|
#endif // ENGINE_AUDIO_AUDIO_SINK_DELEGATE_H
|
|
@ -1,76 +1,67 @@
|
||||||
#include "engine/audio/audio_driver_oboe.h"
|
#include "engine/audio/audio_sink_oboe.h"
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "engine/audio/audio_driver_delegate.h"
|
#include "engine/audio/audio_sink_delegate.h"
|
||||||
#include "third_party/oboe/include/oboe/Oboe.h"
|
#include "third_party/oboe/include/oboe/Oboe.h"
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
AudioDriverOboe::AudioDriverOboe()
|
AudioSinkOboe::AudioSinkOboe(AudioSinkDelegate* delegate)
|
||||||
: callback_(std::make_unique<StreamCallback>(this)) {}
|
: callback_(std::make_unique<StreamCallback>(this)), delegate_(delegate) {}
|
||||||
|
|
||||||
AudioDriverOboe::~AudioDriverOboe() = default;
|
|
||||||
|
|
||||||
void AudioDriverOboe::SetDelegate(AudioDriverDelegate* delegate) {
|
|
||||||
delegate_ = delegate;
|
|
||||||
stream_->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AudioDriverOboe::Initialize() {
|
|
||||||
LOG << "Initializing audio system.";
|
|
||||||
|
|
||||||
return RestartStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioDriverOboe::Shutdown() {
|
|
||||||
LOG << "Shutting down audio system.";
|
|
||||||
|
|
||||||
|
AudioSinkOboe::~AudioSinkOboe() {
|
||||||
|
LOG << "Shutting down audio.";
|
||||||
stream_->stop();
|
stream_->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverOboe::Suspend() {
|
bool AudioSinkOboe::Initialize() {
|
||||||
|
LOG << "Initializing audio.";
|
||||||
|
return RestartStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioSinkOboe::Suspend() {
|
||||||
stream_->pause();
|
stream_->pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverOboe::Resume() {
|
void AudioSinkOboe::Resume() {
|
||||||
stream_->start();
|
stream_->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AudioDriverOboe::GetHardwareSampleRate() {
|
int AudioSinkOboe::GetHardwareSampleRate() {
|
||||||
return stream_->getSampleRate();
|
return stream_->getSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDriverOboe::StreamCallback::StreamCallback(AudioDriverOboe* driver)
|
AudioSinkOboe::StreamCallback::StreamCallback(AudioSinkOboe* audio_sink)
|
||||||
: driver_(driver) {}
|
: audio_sink_(audio_sink) {}
|
||||||
|
|
||||||
AudioDriverOboe::StreamCallback::~StreamCallback() = default;
|
AudioSinkOboe::StreamCallback::~StreamCallback() = default;
|
||||||
|
|
||||||
oboe::DataCallbackResult AudioDriverOboe::StreamCallback::onAudioReady(
|
oboe::DataCallbackResult AudioSinkOboe::StreamCallback::onAudioReady(
|
||||||
oboe::AudioStream* oboe_stream,
|
oboe::AudioStream* oboe_stream,
|
||||||
void* audio_data,
|
void* audio_data,
|
||||||
int32_t num_frames) {
|
int32_t num_frames) {
|
||||||
float* output_buffer = static_cast<float*>(audio_data);
|
float* output_buffer = static_cast<float*>(audio_data);
|
||||||
driver_->delegate_->RenderAudio(output_buffer, num_frames);
|
audio_sink_->delegate_->RenderAudio(output_buffer, num_frames);
|
||||||
return oboe::DataCallbackResult::Continue;
|
return oboe::DataCallbackResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverOboe::StreamCallback::onErrorAfterClose(
|
void AudioSinkOboe::StreamCallback::onErrorAfterClose(
|
||||||
oboe::AudioStream* oboe_stream,
|
oboe::AudioStream* oboe_stream,
|
||||||
oboe::Result error) {
|
oboe::Result error) {
|
||||||
LOG << "Error after close. Error: " << oboe::convertToText(error);
|
LOG << "Error after close. Error: " << oboe::convertToText(error);
|
||||||
|
|
||||||
driver_->RestartStream();
|
audio_sink_->RestartStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioDriverOboe::RestartStream() {
|
bool AudioSinkOboe::RestartStream() {
|
||||||
oboe::AudioStreamBuilder builder;
|
oboe::AudioStreamBuilder builder;
|
||||||
oboe::Result result =
|
oboe::Result result =
|
||||||
builder.setSharingMode(oboe::SharingMode::Exclusive)
|
builder.setSharingMode(oboe::SharingMode::Exclusive)
|
||||||
->setPerformanceMode(oboe::PerformanceMode::LowLatency)
|
->setPerformanceMode(oboe::PerformanceMode::LowLatency)
|
||||||
->setFormat(oboe::AudioFormat::Float)
|
->setFormat(oboe::AudioFormat::Float)
|
||||||
->setChannelCount(kChannelCount)
|
->setChannelCount(delegate_->GetChannelCount())
|
||||||
->setDirection(oboe::Direction::Output)
|
->setDirection(oboe::Direction::Output)
|
||||||
->setUsage(oboe::Usage::Game)
|
->setUsage(oboe::Usage::Game)
|
||||||
->setCallback(callback_.get())
|
->setCallback(callback_.get())
|
||||||
|
@ -88,8 +79,7 @@ bool AudioDriverOboe::RestartStream() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delegate_)
|
stream_->start();
|
||||||
stream_->start();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,33 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_DRIVER_OBOE_H
|
#ifndef ENGINE_AUDIO_AUDIO_SINK_OBOE_H
|
||||||
#define ENGINE_AUDIO_AUDIO_DRIVER_OBOE_H
|
#define ENGINE_AUDIO_AUDIO_SINK_OBOE_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "third_party/oboe/include/oboe/AudioStream.h"
|
#include "third_party/oboe/include/oboe/AudioStream.h"
|
||||||
#include "third_party/oboe/include/oboe/AudioStreamCallback.h"
|
#include "third_party/oboe/include/oboe/AudioStreamCallback.h"
|
||||||
|
|
||||||
#include "engine/audio/audio_driver.h"
|
#include "engine/audio/audio_sink.h"
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class AudioDriverOboe final : public AudioDriver {
|
class AudioSinkDelegate;
|
||||||
public:
|
|
||||||
AudioDriverOboe();
|
|
||||||
~AudioDriverOboe() final;
|
|
||||||
|
|
||||||
void SetDelegate(AudioDriverDelegate* delegate) final;
|
class AudioSinkOboe final : public AudioSink {
|
||||||
|
public:
|
||||||
|
AudioSinkOboe(AudioSinkDelegate* delegate);
|
||||||
|
~AudioSinkOboe() final;
|
||||||
|
|
||||||
bool Initialize() final;
|
bool Initialize() final;
|
||||||
|
|
||||||
void Shutdown() final;
|
|
||||||
|
|
||||||
void Suspend() final;
|
void Suspend() final;
|
||||||
void Resume() final;
|
void Resume() final;
|
||||||
|
|
||||||
int GetHardwareSampleRate() final;
|
int GetHardwareSampleRate() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr int kChannelCount = 2;
|
|
||||||
|
|
||||||
class StreamCallback final : public oboe::AudioStreamCallback {
|
class StreamCallback final : public oboe::AudioStreamCallback {
|
||||||
public:
|
public:
|
||||||
StreamCallback(AudioDriverOboe* audio);
|
StreamCallback(AudioSinkOboe* audio);
|
||||||
~StreamCallback() final;
|
~StreamCallback() final;
|
||||||
|
|
||||||
oboe::DataCallbackResult onAudioReady(oboe::AudioStream* oboe_stream,
|
oboe::DataCallbackResult onAudioReady(oboe::AudioStream* oboe_stream,
|
||||||
|
@ -42,17 +38,17 @@ class AudioDriverOboe final : public AudioDriver {
|
||||||
oboe::Result error) final;
|
oboe::Result error) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioDriverOboe* driver_;
|
AudioSinkOboe* audio_sink_;
|
||||||
};
|
};
|
||||||
|
|
||||||
oboe::ManagedStream stream_;
|
oboe::ManagedStream stream_;
|
||||||
std::unique_ptr<StreamCallback> callback_;
|
std::unique_ptr<StreamCallback> callback_;
|
||||||
|
|
||||||
AudioDriverDelegate* delegate_ = nullptr;
|
AudioSinkDelegate* delegate_ = nullptr;
|
||||||
|
|
||||||
bool RestartStream();
|
bool RestartStream();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_DRIVER_OBOE_H
|
#endif // ENGINE_AUDIO_AUDIO_SINK_OBOE_H
|
|
@ -1,8 +1,8 @@
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
|
#include "base/task_runner.h"
|
||||||
#include "engine/animator.h"
|
#include "engine/animator.h"
|
||||||
#include "engine/audio/audio_driver.h"
|
|
||||||
#include "engine/audio/audio_mixer.h"
|
#include "engine/audio/audio_mixer.h"
|
||||||
#include "engine/drawable.h"
|
#include "engine/drawable.h"
|
||||||
#include "engine/font.h"
|
#include "engine/font.h"
|
||||||
|
@ -14,40 +14,52 @@
|
||||||
#include "engine/mesh.h"
|
#include "engine/mesh.h"
|
||||||
#include "engine/platform/platform.h"
|
#include "engine/platform/platform.h"
|
||||||
#include "engine/renderer/geometry.h"
|
#include "engine/renderer/geometry.h"
|
||||||
|
#include "engine/renderer/opengl/renderer_opengl.h"
|
||||||
#include "engine/renderer/renderer.h"
|
#include "engine/renderer/renderer.h"
|
||||||
#include "engine/renderer/shader.h"
|
#include "engine/renderer/shader.h"
|
||||||
#include "engine/renderer/texture.h"
|
#include "engine/renderer/texture.h"
|
||||||
|
#include "engine/renderer/vulkan/renderer_vulkan.h"
|
||||||
#include "engine/shader_source.h"
|
#include "engine/shader_source.h"
|
||||||
#include "third_party/texture_compressor/texture_compressor.h"
|
#include "third_party/texture_compressor/texture_compressor.h"
|
||||||
|
|
||||||
|
#define USE_VULKAN_RENDERER 1
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
|
extern void KaliberMain(Platform* platform) {
|
||||||
|
TaskRunner::CreateThreadLocalTaskRunner();
|
||||||
|
Engine(platform).Run();
|
||||||
|
}
|
||||||
|
|
||||||
Engine* Engine::singleton = nullptr;
|
Engine* Engine::singleton = nullptr;
|
||||||
|
|
||||||
Engine::Engine(Platform* platform,
|
Engine::Engine(Platform* platform)
|
||||||
Renderer* renderer,
|
|
||||||
AudioDriver* audio_driver)
|
|
||||||
: platform_(platform),
|
: platform_(platform),
|
||||||
renderer_(renderer),
|
audio_mixer_{std::make_unique<AudioMixer>()},
|
||||||
audio_driver_(audio_driver),
|
quad_{std::make_unique<Geometry>(nullptr)},
|
||||||
audio_mixer_{std::make_unique<AudioMixer>()} {
|
pass_through_shader_{std::make_unique<Shader>(nullptr)},
|
||||||
|
solid_shader_{std::make_unique<Shader>(nullptr)} {
|
||||||
DCHECK(!singleton);
|
DCHECK(!singleton);
|
||||||
singleton = this;
|
singleton = this;
|
||||||
|
|
||||||
audio_driver_->SetDelegate(audio_mixer_.get());
|
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>();
|
stats_ = std::make_unique<ImageQuad>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Engine::~Engine() {
|
Engine::~Engine() {
|
||||||
|
LOG << "Shutting down engine.";
|
||||||
|
|
||||||
|
game_.reset();
|
||||||
stats_.reset();
|
stats_.reset();
|
||||||
|
textures_.clear();
|
||||||
|
shaders_.clear();
|
||||||
|
quad_.reset();
|
||||||
|
pass_through_shader_.reset();
|
||||||
|
solid_shader_.reset();
|
||||||
|
renderer_.reset();
|
||||||
singleton = nullptr;
|
singleton = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +67,43 @@ Engine& Engine::Get() {
|
||||||
return *singleton;
|
return *singleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Engine::Initialize() {
|
void Engine::Run() {
|
||||||
|
Initialize();
|
||||||
|
|
||||||
|
timer_.Reset();
|
||||||
|
float accumulator = 0.0;
|
||||||
|
float frame_frac = 0.0f;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
Draw(frame_frac);
|
||||||
|
|
||||||
|
// Accumulate time.
|
||||||
|
timer_.Update();
|
||||||
|
accumulator += timer_.GetSecondsPassed();
|
||||||
|
|
||||||
|
// Subdivide the frame time using fixed time steps.
|
||||||
|
while (accumulator >= time_step_) {
|
||||||
|
TaskRunner::GetThreadLocalTaskRunner()->SingleConsumerRun();
|
||||||
|
platform_->Update();
|
||||||
|
Update(time_step_);
|
||||||
|
accumulator -= time_step_;
|
||||||
|
|
||||||
|
if (platform_->should_exit())
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate frame fraction from remainder of the frame time.
|
||||||
|
frame_frac = accumulator / time_step_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::Initialize() {
|
||||||
|
LOG << "Initializing engine.";
|
||||||
|
|
||||||
|
thread_pool_.Initialize();
|
||||||
|
|
||||||
|
CreateRenderer(true);
|
||||||
|
|
||||||
// Normalize viewport.
|
// Normalize viewport.
|
||||||
if (GetScreenWidth() > GetScreenHeight()) {
|
if (GetScreenWidth() > GetScreenHeight()) {
|
||||||
float aspect_ratio = (float)GetScreenWidth() / (float)GetScreenHeight();
|
float aspect_ratio = (float)GetScreenWidth() / (float)GetScreenHeight();
|
||||||
|
@ -71,52 +119,16 @@ bool Engine::Initialize() {
|
||||||
|
|
||||||
LOG << "image scale factor: " << GetImageScaleFactor();
|
LOG << "image scale factor: " << GetImageScaleFactor();
|
||||||
|
|
||||||
if (renderer_->SupportsDXT5()) {
|
|
||||||
tex_comp_alpha_ = TextureCompressor::Create(TextureCompressor::kFormatDXT5);
|
|
||||||
} else if (renderer_->SupportsATC()) {
|
|
||||||
tex_comp_alpha_ =
|
|
||||||
TextureCompressor::Create(TextureCompressor::kFormatATCIA);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renderer_->SupportsDXT1()) {
|
|
||||||
tex_comp_opaque_ =
|
|
||||||
TextureCompressor::Create(TextureCompressor::kFormatDXT1);
|
|
||||||
} else if (renderer_->SupportsATC()) {
|
|
||||||
tex_comp_opaque_ = TextureCompressor::Create(TextureCompressor::kFormatATC);
|
|
||||||
} else if (renderer_->SupportsETC1()) {
|
|
||||||
tex_comp_opaque_ =
|
|
||||||
TextureCompressor::Create(TextureCompressor::kFormatETC1);
|
|
||||||
}
|
|
||||||
|
|
||||||
system_font_ = std::make_unique<Font>();
|
system_font_ = std::make_unique<Font>();
|
||||||
system_font_->Load("engine/RobotoMono-Regular.ttf");
|
system_font_->Load("engine/RobotoMono-Regular.ttf");
|
||||||
|
|
||||||
if (!CreateRenderResources())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SetImageSource("stats_tex", std::bind(&Engine::PrintStats, this));
|
SetImageSource("stats_tex", std::bind(&Engine::PrintStats, this));
|
||||||
stats_->SetZOrder(std::numeric_limits<int>::max());
|
stats_->SetZOrder(std::numeric_limits<int>::max());
|
||||||
|
|
||||||
game_ = GameFactoryBase::CreateGame("");
|
game_ = GameFactoryBase::CreateGame("");
|
||||||
if (!game_) {
|
CHECK(game_) << "No game found to run.";
|
||||||
LOG << "No game found to run.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!game_->Initialize()) {
|
CHECK(game_->Initialize()) << "Failed to initialize the game.";
|
||||||
LOG << "Failed to initialize the game.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::Shutdown() {
|
|
||||||
LOG << "Shutting down engine.";
|
|
||||||
game_.reset();
|
|
||||||
stats_->Destory();
|
|
||||||
textures_.clear();
|
|
||||||
shaders_.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::Update(float delta_time) {
|
void Engine::Update(float delta_time) {
|
||||||
|
@ -157,20 +169,6 @@ void Engine::Draw(float frame_frac) {
|
||||||
renderer_->Present();
|
renderer_->Present();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::LostFocus() {
|
|
||||||
audio_driver_->Suspend();
|
|
||||||
|
|
||||||
if (game_)
|
|
||||||
game_->LostFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::GainedFocus(bool from_interstitial_ad) {
|
|
||||||
audio_driver_->Resume();
|
|
||||||
|
|
||||||
if (game_)
|
|
||||||
game_->GainedFocus(from_interstitial_ad);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::AddDrawable(Drawable* drawable) {
|
void Engine::AddDrawable(Drawable* drawable) {
|
||||||
DCHECK(std::find(drawables_.begin(), drawables_.end(), drawable) ==
|
DCHECK(std::find(drawables_.begin(), drawables_.end(), drawable) ==
|
||||||
drawables_.end());
|
drawables_.end());
|
||||||
|
@ -199,6 +197,32 @@ void Engine::RemoveAnimator(Animator* animator) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Engine::CreateRenderer(bool vulkan) {
|
||||||
|
if ((dynamic_cast<RendererVulkan*>(renderer_.get()) && vulkan) ||
|
||||||
|
(dynamic_cast<RendererOpenGL*>(renderer_.get()) && !vulkan))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (vulkan)
|
||||||
|
renderer_ =
|
||||||
|
std::make_unique<RendererVulkan>(std::bind(&Engine::ContextLost, this));
|
||||||
|
else
|
||||||
|
renderer_ =
|
||||||
|
std::make_unique<RendererOpenGL>(std::bind(&Engine::ContextLost, this));
|
||||||
|
|
||||||
|
bool result = renderer_->Initialize(platform_);
|
||||||
|
if (!result && vulkan) {
|
||||||
|
LOG << "Failed to initialize " << renderer_->GetDebugName() << " renderer.";
|
||||||
|
LOG << "Fallback to OpenGL renderer.";
|
||||||
|
CreateRenderer(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CHECK(result) << "Failed to initialize " << renderer_->GetDebugName()
|
||||||
|
<< " renderer.";
|
||||||
|
|
||||||
|
CreateTextureCompressors();
|
||||||
|
ContextLost();
|
||||||
|
}
|
||||||
|
|
||||||
void Engine::Exit() {
|
void Engine::Exit() {
|
||||||
platform_->Exit();
|
platform_->Exit();
|
||||||
}
|
}
|
||||||
|
@ -321,40 +345,6 @@ void Engine::RemoveCustomShader(const std::string& asset_name) {
|
||||||
shaders_.erase(it);
|
shaders_.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::AddInputEvent(std::unique_ptr<InputEvent> event) {
|
|
||||||
if (replaying_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (event->GetType()) {
|
|
||||||
case InputEvent::kDragEnd:
|
|
||||||
if (((GetScreenSize() / 2) * 0.9f - event->GetVector()).Length() <=
|
|
||||||
0.25f) {
|
|
||||||
SetSatsVisible(!stats_->IsVisible());
|
|
||||||
// TODO: Enqueue DragCancel so we can consume this event.
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InputEvent::kKeyPress:
|
|
||||||
if (event->GetKeyPress() == 's') {
|
|
||||||
SetSatsVisible(!stats_->IsVisible());
|
|
||||||
// Consume event.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InputEvent::kDrag:
|
|
||||||
if (stats_->IsVisible()) {
|
|
||||||
if ((stats_->GetPosition() - event->GetVector()).Length() <=
|
|
||||||
stats_->GetSize().y)
|
|
||||||
stats_->SetPosition(event->GetVector());
|
|
||||||
// TODO: Enqueue DragCancel so we can consume this event.
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
input_queue_.push_back(std::move(event));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<InputEvent> Engine::GetNextInputEvent() {
|
std::unique_ptr<InputEvent> Engine::GetNextInputEvent() {
|
||||||
std::unique_ptr<InputEvent> event;
|
std::unique_ptr<InputEvent> event;
|
||||||
|
|
||||||
|
@ -481,32 +471,107 @@ const std::string& Engine::GetSharedDataPath() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Engine::GetAudioHardwareSampleRate() {
|
int Engine::GetAudioHardwareSampleRate() {
|
||||||
return audio_driver_->GetHardwareSampleRate();
|
return audio_mixer_->GetHardwareSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Engine::IsMobile() const {
|
bool Engine::IsMobile() const {
|
||||||
return platform_->mobile_device();
|
return platform_->mobile_device();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::ContextLost() {
|
void Engine::OnWindowCreated() {
|
||||||
CreateRenderResources();
|
renderer_->Initialize(platform_);
|
||||||
|
|
||||||
for (auto& t : textures_) {
|
|
||||||
t.second.texture->Destroy();
|
|
||||||
RefreshImage(t.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& s : shaders_) {
|
|
||||||
auto source = std::make_unique<ShaderSource>();
|
|
||||||
if (source->Load(s.second.file_name))
|
|
||||||
s.second.shader->Create(std::move(source), quad_->vertex_description(),
|
|
||||||
quad_->primitive(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
game_->ContextLost();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Engine::CreateRenderResources() {
|
void Engine::OnWindowDestroyed() {
|
||||||
|
renderer_->Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::OnWindowResized(int width, int height) {
|
||||||
|
if (width != renderer_->screen_width() ||
|
||||||
|
height != renderer_->screen_height()) {
|
||||||
|
renderer_->Shutdown();
|
||||||
|
renderer_->Initialize(platform_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::LostFocus() {
|
||||||
|
audio_mixer_->Suspend();
|
||||||
|
|
||||||
|
if (game_)
|
||||||
|
game_->LostFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::GainedFocus(bool from_interstitial_ad) {
|
||||||
|
timer_.Reset();
|
||||||
|
audio_mixer_->Resume();
|
||||||
|
|
||||||
|
if (game_)
|
||||||
|
game_->GainedFocus(from_interstitial_ad);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::AddInputEvent(std::unique_ptr<InputEvent> event) {
|
||||||
|
if (replaying_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
event->SetVector(ToPosition(event->GetVector()) * Vector2f(1, -1));
|
||||||
|
|
||||||
|
switch (event->GetType()) {
|
||||||
|
case InputEvent::kDragEnd:
|
||||||
|
if (((GetScreenSize() / 2) * 0.9f - event->GetVector()).Length() <=
|
||||||
|
0.25f) {
|
||||||
|
SetSatsVisible(!stats_->IsVisible());
|
||||||
|
// TODO: Enqueue DragCancel so we can consume this event.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case InputEvent::kKeyPress:
|
||||||
|
if (event->GetKeyPress() == 's') {
|
||||||
|
SetSatsVisible(!stats_->IsVisible());
|
||||||
|
// Consume event.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case InputEvent::kDrag:
|
||||||
|
if (stats_->IsVisible()) {
|
||||||
|
if ((stats_->GetPosition() - event->GetVector()).Length() <=
|
||||||
|
stats_->GetSize().y)
|
||||||
|
stats_->SetPosition(event->GetVector());
|
||||||
|
// TODO: Enqueue DragCancel so we can consume this event.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_queue_.push_back(std::move(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::CreateTextureCompressors() {
|
||||||
|
tex_comp_alpha_.reset();
|
||||||
|
tex_comp_opaque_.reset();
|
||||||
|
|
||||||
|
if (renderer_->SupportsDXT5()) {
|
||||||
|
tex_comp_alpha_ = TextureCompressor::Create(TextureCompressor::kFormatDXT5);
|
||||||
|
} else if (renderer_->SupportsATC()) {
|
||||||
|
tex_comp_alpha_ =
|
||||||
|
TextureCompressor::Create(TextureCompressor::kFormatATCIA);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renderer_->SupportsDXT1()) {
|
||||||
|
tex_comp_opaque_ =
|
||||||
|
TextureCompressor::Create(TextureCompressor::kFormatDXT1);
|
||||||
|
} else if (renderer_->SupportsATC()) {
|
||||||
|
tex_comp_opaque_ = TextureCompressor::Create(TextureCompressor::kFormatATC);
|
||||||
|
} else if (renderer_->SupportsETC1()) {
|
||||||
|
tex_comp_opaque_ =
|
||||||
|
TextureCompressor::Create(TextureCompressor::kFormatETC1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::ContextLost() {
|
||||||
|
quad_->SetRenderer(renderer_.get());
|
||||||
|
pass_through_shader_->SetRenderer(renderer_.get());
|
||||||
|
solid_shader_->SetRenderer(renderer_.get());
|
||||||
|
|
||||||
// This creates a normalized unit sized quad.
|
// This creates a normalized unit sized quad.
|
||||||
static const char vertex_description[] = "p2f;t2f";
|
static const char vertex_description[] = "p2f;t2f";
|
||||||
static const float vertices[] = {
|
static const float vertices[] = {
|
||||||
|
@ -521,23 +586,37 @@ bool Engine::CreateRenderResources() {
|
||||||
|
|
||||||
// Create the shader we can reuse for texture rendering.
|
// Create the shader we can reuse for texture rendering.
|
||||||
auto source = std::make_unique<ShaderSource>();
|
auto source = std::make_unique<ShaderSource>();
|
||||||
if (!source->Load("engine/pass_through.glsl")) {
|
if (source->Load("engine/pass_through.glsl")) {
|
||||||
|
pass_through_shader_->Create(std::move(source), quad_->vertex_description(),
|
||||||
|
quad_->primitive(), false);
|
||||||
|
} else {
|
||||||
LOG << "Could not create pass through shader.";
|
LOG << "Could not create pass through shader.";
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
pass_through_shader_->Create(std::move(source), quad_->vertex_description(),
|
|
||||||
quad_->primitive(), false);
|
|
||||||
|
|
||||||
// Create the shader we can reuse for solid rendering.
|
// Create the shader we can reuse for solid rendering.
|
||||||
source = std::make_unique<ShaderSource>();
|
source = std::make_unique<ShaderSource>();
|
||||||
if (!source->Load("engine/solid.glsl")) {
|
if (source->Load("engine/solid.glsl")) {
|
||||||
|
solid_shader_->Create(std::move(source), quad_->vertex_description(),
|
||||||
|
quad_->primitive(), false);
|
||||||
|
} else {
|
||||||
LOG << "Could not create solid shader.";
|
LOG << "Could not create solid shader.";
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
solid_shader_->Create(std::move(source), quad_->vertex_description(),
|
|
||||||
quad_->primitive(), false);
|
|
||||||
|
|
||||||
return true;
|
for (auto& t : textures_) {
|
||||||
|
t.second.texture->SetRenderer(renderer_.get());
|
||||||
|
RefreshImage(t.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& s : shaders_) {
|
||||||
|
s.second.shader->SetRenderer(renderer_.get());
|
||||||
|
auto source = std::make_unique<ShaderSource>();
|
||||||
|
if (source->Load(s.second.file_name))
|
||||||
|
s.second.shader->Create(std::move(source), quad_->vertex_description(),
|
||||||
|
quad_->primitive(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game_)
|
||||||
|
game_->ContextLost();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::SetSatsVisible(bool visible) {
|
void Engine::SetSatsVisible(bool visible) {
|
||||||
|
@ -545,7 +624,7 @@ void Engine::SetSatsVisible(bool visible) {
|
||||||
if (visible)
|
if (visible)
|
||||||
stats_->Create("stats_tex");
|
stats_->Create("stats_tex");
|
||||||
else
|
else
|
||||||
stats_->Destory();
|
stats_->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Image> Engine::PrintStats() {
|
std::unique_ptr<Image> Engine::PrintStats() {
|
||||||
|
|
|
@ -8,15 +8,17 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
|
#include "base/thread_pool.h"
|
||||||
|
#include "base/timer.h"
|
||||||
#include "base/vecmath.h"
|
#include "base/vecmath.h"
|
||||||
#include "engine/persistent_data.h"
|
#include "engine/persistent_data.h"
|
||||||
|
#include "engine/platform/platform_observer.h"
|
||||||
|
|
||||||
class TextureCompressor;
|
class TextureCompressor;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class Animator;
|
class Animator;
|
||||||
class AudioDriver;
|
|
||||||
class AudioMixer;
|
class AudioMixer;
|
||||||
class Font;
|
class Font;
|
||||||
class Game;
|
class Game;
|
||||||
|
@ -30,24 +32,16 @@ class Shader;
|
||||||
class Texture;
|
class Texture;
|
||||||
class Platform;
|
class Platform;
|
||||||
|
|
||||||
class Engine {
|
class Engine : public PlatformObserver {
|
||||||
public:
|
public:
|
||||||
using CreateImageCB = std::function<std::unique_ptr<Image>()>;
|
using CreateImageCB = std::function<std::unique_ptr<Image>()>;
|
||||||
|
|
||||||
Engine(Platform* platform, Renderer* renderer, AudioDriver* audio_driver);
|
Engine(Platform* platform);
|
||||||
~Engine();
|
~Engine();
|
||||||
|
|
||||||
static Engine& Get();
|
static Engine& Get();
|
||||||
|
|
||||||
bool Initialize();
|
void Run();
|
||||||
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
void Update(float delta_time);
|
|
||||||
void Draw(float frame_frac);
|
|
||||||
|
|
||||||
void LostFocus();
|
|
||||||
void GainedFocus(bool from_interstitial_ad);
|
|
||||||
|
|
||||||
void AddDrawable(Drawable* drawable);
|
void AddDrawable(Drawable* drawable);
|
||||||
void RemoveDrawable(Drawable* drawable);
|
void RemoveDrawable(Drawable* drawable);
|
||||||
|
@ -55,6 +49,8 @@ class Engine {
|
||||||
void AddAnimator(Animator* animator);
|
void AddAnimator(Animator* animator);
|
||||||
void RemoveAnimator(Animator* animator);
|
void RemoveAnimator(Animator* animator);
|
||||||
|
|
||||||
|
void CreateRenderer(bool vulkan);
|
||||||
|
|
||||||
void Exit();
|
void Exit();
|
||||||
|
|
||||||
// Convert size from pixels to viewport scale.
|
// Convert size from pixels to viewport scale.
|
||||||
|
@ -65,7 +61,7 @@ class Engine {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::unique_ptr<T> CreateRenderResource() {
|
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,
|
void SetImageSource(const std::string& asset_name,
|
||||||
|
@ -85,7 +81,6 @@ class Engine {
|
||||||
Shader* GetCustomShader(const std::string& asset_name);
|
Shader* GetCustomShader(const std::string& asset_name);
|
||||||
void RemoveCustomShader(const std::string& asset_name);
|
void RemoveCustomShader(const std::string& asset_name);
|
||||||
|
|
||||||
void AddInputEvent(std::unique_ptr<InputEvent> event);
|
|
||||||
std::unique_ptr<InputEvent> GetNextInputEvent();
|
std::unique_ptr<InputEvent> GetNextInputEvent();
|
||||||
|
|
||||||
void StartRecording(const Json::Value& payload);
|
void StartRecording(const Json::Value& payload);
|
||||||
|
@ -173,9 +168,8 @@ class Engine {
|
||||||
static Engine* singleton;
|
static Engine* singleton;
|
||||||
|
|
||||||
Platform* platform_ = nullptr;
|
Platform* platform_ = nullptr;
|
||||||
Renderer* renderer_ = nullptr;
|
|
||||||
AudioDriver* audio_driver_ = nullptr;
|
|
||||||
|
|
||||||
|
std::unique_ptr<Renderer> renderer_;
|
||||||
std::unique_ptr<AudioMixer> audio_mixer_;
|
std::unique_ptr<AudioMixer> audio_mixer_;
|
||||||
std::unique_ptr<Game> game_;
|
std::unique_ptr<Game> game_;
|
||||||
|
|
||||||
|
@ -220,11 +214,26 @@ class Engine {
|
||||||
bool replaying_ = false;
|
bool replaying_ = false;
|
||||||
unsigned int replay_index_ = 0;
|
unsigned int replay_index_ = 0;
|
||||||
|
|
||||||
|
base::ThreadPool thread_pool_;
|
||||||
|
base::Timer timer_;
|
||||||
base::Randomf random_;
|
base::Randomf random_;
|
||||||
|
|
||||||
void ContextLost();
|
void Initialize();
|
||||||
|
|
||||||
bool CreateRenderResources();
|
void Update(float delta_time);
|
||||||
|
void Draw(float frame_frac);
|
||||||
|
|
||||||
|
// PlatformObserver implementation
|
||||||
|
void OnWindowCreated() final;
|
||||||
|
void OnWindowDestroyed() final;
|
||||||
|
void OnWindowResized(int width, int height) final;
|
||||||
|
void LostFocus() final;
|
||||||
|
void GainedFocus(bool from_interstitial_ad) final;
|
||||||
|
void AddInputEvent(std::unique_ptr<InputEvent> event) final;
|
||||||
|
|
||||||
|
void CreateTextureCompressors();
|
||||||
|
|
||||||
|
void ContextLost();
|
||||||
|
|
||||||
void SetSatsVisible(bool visible);
|
void SetSatsVisible(bool visible);
|
||||||
std::unique_ptr<Image> PrintStats();
|
std::unique_ptr<Image> PrintStats();
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace eng {
|
||||||
ImageQuad::ImageQuad() = default;
|
ImageQuad::ImageQuad() = default;
|
||||||
|
|
||||||
ImageQuad::~ImageQuad() {
|
ImageQuad::~ImageQuad() {
|
||||||
Destory();
|
Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageQuad::Create(const std::string& asset_name,
|
void ImageQuad::Create(const std::string& asset_name,
|
||||||
|
@ -32,7 +32,8 @@ void ImageQuad::Create(const std::string& asset_name,
|
||||||
asset_name_ = asset_name;
|
asset_name_ = asset_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageQuad::Destory() {
|
// TODO: typo
|
||||||
|
void ImageQuad::Destroy() {
|
||||||
if (texture_) {
|
if (texture_) {
|
||||||
Engine::Get().ReleaseTexture(asset_name_);
|
Engine::Get().ReleaseTexture(asset_name_);
|
||||||
texture_ = nullptr;
|
texture_ = nullptr;
|
||||||
|
|
|
@ -24,7 +24,7 @@ class ImageQuad final : public Animatable {
|
||||||
int frame_width = 0,
|
int frame_width = 0,
|
||||||
int frame_height = 0);
|
int frame_height = 0);
|
||||||
|
|
||||||
void Destory();
|
void Destroy();
|
||||||
|
|
||||||
void AutoScale();
|
void AutoScale();
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ class InputEvent {
|
||||||
InputEvent(Type type, char key) : type_(type), key_(key) {}
|
InputEvent(Type type, char key) : type_(type), key_(key) {}
|
||||||
~InputEvent() = default;
|
~InputEvent() = default;
|
||||||
|
|
||||||
|
void SetVector(base::Vector2f vec) { vec_ = vec; }
|
||||||
|
|
||||||
Type GetType() const { return type_; }
|
Type GetType() const { return type_; }
|
||||||
|
|
||||||
size_t GetPointerId() const { return pointer_id_; }
|
size_t GetPointerId() const { return pointer_id_; }
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
#include "engine/platform/platform.h"
|
|
||||||
|
|
||||||
#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"
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
#include "engine/audio/audio_driver_oboe.h"
|
|
||||||
#elif defined(__linux__)
|
|
||||||
#include "engine/audio/audio_driver_alsa.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace base;
|
|
||||||
|
|
||||||
namespace eng {
|
|
||||||
|
|
||||||
Platform::Platform() = default;
|
|
||||||
|
|
||||||
Platform::~Platform() = default;
|
|
||||||
|
|
||||||
void Platform::InitializeCommon() {
|
|
||||||
LOG << "Initializing platform.";
|
|
||||||
|
|
||||||
thread_pool_.Initialize();
|
|
||||||
TaskRunner::CreateThreadLocalTaskRunner();
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
audio_driver_ = std::make_unique<AudioDriverOboe>();
|
|
||||||
#elif defined(__linux__)
|
|
||||||
audio_driver_ = std::make_unique<AudioDriverAlsa>();
|
|
||||||
#endif
|
|
||||||
bool res = audio_driver_->Initialize();
|
|
||||||
CHECK(res) << "Failed to initialize audio driver.";
|
|
||||||
|
|
||||||
auto context = std::make_unique<VulkanContext>();
|
|
||||||
if (context->Initialize()) {
|
|
||||||
renderer_ = std::make_unique<RendererVulkan>(std::move(context));
|
|
||||||
} else {
|
|
||||||
LOG << "Failed to initialize Vulkan context. Fallback to OpenGL.";
|
|
||||||
renderer_ = std::make_unique<RendererOpenGL>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::ShutdownCommon() {
|
|
||||||
LOG << "Shutting down platform.";
|
|
||||||
|
|
||||||
audio_driver_->Shutdown();
|
|
||||||
renderer_->Shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::RunMainLoop() {
|
|
||||||
engine_ =
|
|
||||||
std::make_unique<Engine>(this, renderer_.get(), audio_driver_.get());
|
|
||||||
bool res = engine_->Initialize();
|
|
||||||
CHECK(res) << "Failed to initialize the engine.";
|
|
||||||
|
|
||||||
// Use fixed time steps.
|
|
||||||
float time_step = engine_->time_step();
|
|
||||||
|
|
||||||
timer_.Reset();
|
|
||||||
float accumulator = 0.0;
|
|
||||||
float frame_frac = 0.0f;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
engine_->Draw(frame_frac);
|
|
||||||
|
|
||||||
// Accumulate time.
|
|
||||||
timer_.Update();
|
|
||||||
accumulator += timer_.GetSecondsPassed();
|
|
||||||
|
|
||||||
// Subdivide the frame time.
|
|
||||||
while (accumulator >= time_step) {
|
|
||||||
TaskRunner::GetThreadLocalTaskRunner()->SingleConsumerRun();
|
|
||||||
|
|
||||||
Update();
|
|
||||||
engine_->Update(time_step);
|
|
||||||
|
|
||||||
if (should_exit_) {
|
|
||||||
thread_pool_.Shutdown();
|
|
||||||
engine_->Shutdown();
|
|
||||||
engine_.reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
accumulator -= time_step;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Calculate frame fraction from remainder of the frame time.
|
|
||||||
frame_frac = accumulator / time_step;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace eng
|
|
|
@ -1,12 +1,8 @@
|
||||||
#ifndef ENGINE_PLATFORM_PLATFORM_H
|
#ifndef ENGINE_PLATFORM_PLATFORM_H
|
||||||
#define ENGINE_PLATFORM_PLATFORM_H
|
#define ENGINE_PLATFORM_PLATFORM_H
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "base/thread_pool.h"
|
|
||||||
#include "base/timer.h"
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
|
|
||||||
#include "../../base/vecmath.h"
|
#include "../../base/vecmath.h"
|
||||||
|
@ -24,27 +20,23 @@ struct ANativeWindow;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class AudioDriver;
|
class PlatformObserver;
|
||||||
class Renderer;
|
|
||||||
class Engine;
|
|
||||||
|
|
||||||
class Platform {
|
class Platform {
|
||||||
public:
|
public:
|
||||||
Platform();
|
|
||||||
~Platform();
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
void Initialize(android_app* app);
|
Platform(android_app* app);
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
void Initialize();
|
Platform();
|
||||||
#endif
|
#endif
|
||||||
|
~Platform();
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
void Exit();
|
void Exit();
|
||||||
|
|
||||||
|
void SetObserver(PlatformObserver* observer) { observer_ = observer; }
|
||||||
|
|
||||||
void Vibrate(int duration);
|
void Vibrate(int duration);
|
||||||
|
|
||||||
void ShowInterstitialAd();
|
void ShowInterstitialAd();
|
||||||
|
@ -53,8 +45,6 @@ class Platform {
|
||||||
|
|
||||||
void SetKeepScreenOn(bool keep_screen_on);
|
void SetKeepScreenOn(bool keep_screen_on);
|
||||||
|
|
||||||
void RunMainLoop();
|
|
||||||
|
|
||||||
int GetDeviceDpi() const { return device_dpi_; }
|
int GetDeviceDpi() const { return device_dpi_; }
|
||||||
|
|
||||||
const std::string& GetRootPath() const { return root_path_; }
|
const std::string& GetRootPath() const { return root_path_; }
|
||||||
|
@ -65,9 +55,16 @@ class Platform {
|
||||||
|
|
||||||
bool mobile_device() const { return mobile_device_; }
|
bool mobile_device() const { return mobile_device_; }
|
||||||
|
|
||||||
protected:
|
bool should_exit() const { return should_exit_; }
|
||||||
base::Timer timer_;
|
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
ANativeWindow* GetWindow();
|
||||||
|
#elif defined(__linux__)
|
||||||
|
Display* GetDisplay();
|
||||||
|
Window GetWindow();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
bool mobile_device_ = false;
|
bool mobile_device_ = false;
|
||||||
int device_dpi_ = 100;
|
int device_dpi_ = 100;
|
||||||
std::string root_path_;
|
std::string root_path_;
|
||||||
|
@ -77,11 +74,7 @@ class Platform {
|
||||||
bool has_focus_ = false;
|
bool has_focus_ = false;
|
||||||
bool should_exit_ = false;
|
bool should_exit_ = false;
|
||||||
|
|
||||||
std::unique_ptr<AudioDriver> audio_driver_;
|
PlatformObserver* observer_ = nullptr;
|
||||||
std::unique_ptr<Renderer> renderer_;
|
|
||||||
std::unique_ptr<Engine> engine_;
|
|
||||||
|
|
||||||
base::ThreadPool thread_pool_;
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
|
|
||||||
|
@ -116,10 +109,9 @@ class Platform {
|
||||||
bool CreateWindow(int width, int height);
|
bool CreateWindow(int width, int height);
|
||||||
void DestroyWindow();
|
void DestroyWindow();
|
||||||
|
|
||||||
#endif
|
XVisualInfo* GetXVisualInfo(Display* display);
|
||||||
|
|
||||||
void InitializeCommon();
|
#endif
|
||||||
void ShutdownCommon();
|
|
||||||
|
|
||||||
Platform(const Platform&) = delete;
|
Platform(const Platform&) = delete;
|
||||||
Platform& operator=(const Platform&) = delete;
|
Platform& operator=(const Platform&) = delete;
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
#include "engine/platform/platform.h"
|
#include "engine/platform/platform.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <android_native_app_glue.h>
|
#include <android_native_app_glue.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "base/task_runner.h"
|
|
||||||
#include "engine/engine.h"
|
|
||||||
#include "engine/input_event.h"
|
#include "engine/input_event.h"
|
||||||
#include "engine/renderer/renderer.h"
|
#include "engine/platform/platform_observer.h"
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
|
||||||
|
@ -201,10 +201,12 @@ int32_t GetDensityDpi(android_app* app) {
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
|
void KaliberMain(Platform* platform);
|
||||||
|
|
||||||
int32_t Platform::HandleInput(android_app* app, AInputEvent* event) {
|
int32_t Platform::HandleInput(android_app* app, AInputEvent* event) {
|
||||||
Platform* platform = reinterpret_cast<Platform*>(app->userData);
|
Platform* platform = reinterpret_cast<Platform*>(app->userData);
|
||||||
|
|
||||||
if (!platform->engine_)
|
if (!platform->observer_)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY &&
|
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY &&
|
||||||
|
@ -212,7 +214,7 @@ int32_t Platform::HandleInput(android_app* app, AInputEvent* event) {
|
||||||
if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_UP) {
|
if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_UP) {
|
||||||
auto input_event =
|
auto input_event =
|
||||||
std::make_unique<InputEvent>(InputEvent::kNavigateBack);
|
std::make_unique<InputEvent>(InputEvent::kNavigateBack);
|
||||||
platform->engine_->AddInputEvent(std::move(input_event));
|
platform->observer_->AddInputEvent(std::move(input_event));
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
} else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
|
} else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
|
||||||
|
@ -227,7 +229,6 @@ int32_t Platform::HandleInput(android_app* app, AInputEvent* event) {
|
||||||
int32_t id = AMotionEvent_getPointerId(event, i);
|
int32_t id = AMotionEvent_getPointerId(event, i);
|
||||||
if (id < 2) {
|
if (id < 2) {
|
||||||
pos[id] = {AMotionEvent_getX(event, i), AMotionEvent_getY(event, i)};
|
pos[id] = {AMotionEvent_getX(event, i), AMotionEvent_getY(event, i)};
|
||||||
pos[id] = platform->engine_->ToPosition(pos[id]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,34 +240,30 @@ int32_t Platform::HandleInput(android_app* app, AInputEvent* event) {
|
||||||
switch (flags) {
|
switch (flags) {
|
||||||
case AMOTION_EVENT_ACTION_DOWN:
|
case AMOTION_EVENT_ACTION_DOWN:
|
||||||
case AMOTION_EVENT_ACTION_POINTER_DOWN:
|
case AMOTION_EVENT_ACTION_POINTER_DOWN:
|
||||||
// DLOG << "AMOTION_EVENT_ACTION_DOWN - pointer_id: " << pointer_id;
|
|
||||||
platform->pointer_pos_[pointer_id] = pos[pointer_id];
|
platform->pointer_pos_[pointer_id] = pos[pointer_id];
|
||||||
platform->pointer_down_[pointer_id] = true;
|
platform->pointer_down_[pointer_id] = true;
|
||||||
input_event =
|
input_event = std::make_unique<InputEvent>(InputEvent::kDragStart,
|
||||||
std::make_unique<InputEvent>(InputEvent::kDragStart, pointer_id,
|
pointer_id, pos[pointer_id]);
|
||||||
pos[pointer_id] * Vector2f(1, -1));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AMOTION_EVENT_ACTION_UP:
|
case AMOTION_EVENT_ACTION_UP:
|
||||||
case AMOTION_EVENT_ACTION_POINTER_UP:
|
case AMOTION_EVENT_ACTION_POINTER_UP:
|
||||||
// DLOG << "AMOTION_EVENT_ACTION_UP - pointer_id: " << pointer_id;
|
|
||||||
platform->pointer_pos_[pointer_id] = pos[pointer_id];
|
platform->pointer_pos_[pointer_id] = pos[pointer_id];
|
||||||
platform->pointer_down_[pointer_id] = false;
|
platform->pointer_down_[pointer_id] = false;
|
||||||
input_event =
|
input_event = std::make_unique<InputEvent>(InputEvent::kDragEnd,
|
||||||
std::make_unique<InputEvent>(InputEvent::kDragEnd, pointer_id,
|
pointer_id, pos[pointer_id]);
|
||||||
pos[pointer_id] * Vector2f(1, -1));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AMOTION_EVENT_ACTION_MOVE:
|
case AMOTION_EVENT_ACTION_MOVE:
|
||||||
if (platform->pointer_down_[0] && pos[0] != platform->pointer_pos_[0]) {
|
if (platform->pointer_down_[0] && pos[0] != platform->pointer_pos_[0]) {
|
||||||
platform->pointer_pos_[0] = pos[0];
|
platform->pointer_pos_[0] = pos[0];
|
||||||
input_event = std::make_unique<InputEvent>(InputEvent::kDrag, 0,
|
input_event =
|
||||||
pos[0] * Vector2f(1, -1));
|
std::make_unique<InputEvent>(InputEvent::kDrag, 0, pos[0]);
|
||||||
}
|
}
|
||||||
if (platform->pointer_down_[1] && pos[1] != platform->pointer_pos_[1]) {
|
if (platform->pointer_down_[1] && pos[1] != platform->pointer_pos_[1]) {
|
||||||
platform->pointer_pos_[1] = pos[1];
|
platform->pointer_pos_[1] = pos[1];
|
||||||
input_event = std::make_unique<InputEvent>(InputEvent::kDrag, 1,
|
input_event =
|
||||||
pos[1] * Vector2f(1, -1));
|
std::make_unique<InputEvent>(InputEvent::kDrag, 1, pos[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -276,7 +273,7 @@ int32_t Platform::HandleInput(android_app* app, AInputEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input_event) {
|
if (input_event) {
|
||||||
platform->engine_->AddInputEvent(std::move(input_event));
|
platform->observer_->AddInputEvent(std::move(input_event));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -295,30 +292,23 @@ void Platform::HandleCmd(android_app* app, int32_t cmd) {
|
||||||
DLOG << "APP_CMD_INIT_WINDOW";
|
DLOG << "APP_CMD_INIT_WINDOW";
|
||||||
if (app->window != NULL) {
|
if (app->window != NULL) {
|
||||||
platform->SetFrameRate(60);
|
platform->SetFrameRate(60);
|
||||||
bool res = platform->renderer_->Initialize(app->window);
|
if (platform->observer_)
|
||||||
CHECK(res) << "Failed to initialize "
|
platform->observer_->OnWindowCreated();
|
||||||
<< platform->renderer_->GetDebugName() << " renderer.";
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APP_CMD_TERM_WINDOW:
|
case APP_CMD_TERM_WINDOW:
|
||||||
DLOG << "APP_CMD_TERM_WINDOW";
|
DLOG << "APP_CMD_TERM_WINDOW";
|
||||||
platform->renderer_->Shutdown();
|
if (platform->observer_)
|
||||||
|
platform->observer_->OnWindowDestroyed();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APP_CMD_CONFIG_CHANGED:
|
case APP_CMD_CONFIG_CHANGED:
|
||||||
DLOG << "APP_CMD_CONFIG_CHANGED";
|
DLOG << "APP_CMD_CONFIG_CHANGED";
|
||||||
if (platform->app_->window != NULL) {
|
if (platform->app_->window != NULL && platform->observer_)
|
||||||
int width = platform->renderer_->screen_width();
|
platform->observer_->OnWindowResized(
|
||||||
int height = platform->renderer_->screen_height();
|
ANativeWindow_getWidth(app->window),
|
||||||
if (width != ANativeWindow_getWidth(app->window) ||
|
ANativeWindow_getHeight(app->window));
|
||||||
height != ANativeWindow_getHeight(app->window)) {
|
|
||||||
platform->renderer_->Shutdown();
|
|
||||||
bool res = platform->renderer_->Initialize(platform->app_->window);
|
|
||||||
CHECK(res) << "Failed to initialize "
|
|
||||||
<< platform->renderer_->GetDebugName() << " renderer.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APP_CMD_STOP:
|
case APP_CMD_STOP:
|
||||||
|
@ -327,18 +317,18 @@ void Platform::HandleCmd(android_app* app, int32_t cmd) {
|
||||||
|
|
||||||
case APP_CMD_GAINED_FOCUS:
|
case APP_CMD_GAINED_FOCUS:
|
||||||
DLOG << "APP_CMD_GAINED_FOCUS";
|
DLOG << "APP_CMD_GAINED_FOCUS";
|
||||||
platform->timer_.Reset();
|
// platform->timer_.Reset();
|
||||||
platform->has_focus_ = true;
|
platform->has_focus_ = true;
|
||||||
if (platform->engine_)
|
if (platform->observer_)
|
||||||
platform->engine_->GainedFocus(g_showing_interstitial_ad);
|
platform->observer_->GainedFocus(g_showing_interstitial_ad);
|
||||||
g_showing_interstitial_ad = false;
|
g_showing_interstitial_ad = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APP_CMD_LOST_FOCUS:
|
case APP_CMD_LOST_FOCUS:
|
||||||
DLOG << "APP_CMD_LOST_FOCUS";
|
DLOG << "APP_CMD_LOST_FOCUS";
|
||||||
platform->has_focus_ = false;
|
platform->has_focus_ = false;
|
||||||
if (platform->engine_)
|
if (platform->observer_)
|
||||||
platform->engine_->LostFocus();
|
platform->observer_->LostFocus();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APP_CMD_LOW_MEMORY:
|
case APP_CMD_LOW_MEMORY:
|
||||||
|
@ -347,11 +337,10 @@ void Platform::HandleCmd(android_app* app, int32_t cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Platform::Initialize(android_app* app) {
|
Platform::Platform(android_app* app) {
|
||||||
Platform::InitializeCommon();
|
LOG << "Initializing platform.";
|
||||||
|
|
||||||
app_ = app;
|
app_ = app;
|
||||||
|
|
||||||
mobile_device_ = true;
|
mobile_device_ = true;
|
||||||
|
|
||||||
root_path_ = ::GetApkPath(app->activity);
|
root_path_ = ::GetApkPath(app->activity);
|
||||||
|
@ -385,8 +374,8 @@ void Platform::Initialize(android_app* app) {
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Platform::Shutdown() {
|
Platform::~Platform() {
|
||||||
Platform::ShutdownCommon();
|
LOG << "Shutting down platform.";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Platform::Update() {
|
void Platform::Update() {
|
||||||
|
@ -439,12 +428,14 @@ void Platform::SetFrameRate(float frame_rate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ANativeWindow* Platform::GetWindow() {
|
||||||
|
return app_->window;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
||||||
void android_main(android_app* app) {
|
void android_main(android_app* app) {
|
||||||
eng::Platform platform;
|
eng::Platform platform(app);
|
||||||
platform.Initialize(app);
|
eng::KaliberMain(&platform);
|
||||||
platform.RunMainLoop();
|
|
||||||
platform.Shutdown();
|
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
#include "engine/platform/platform.h"
|
#include "engine/platform/platform.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "base/task_runner.h"
|
|
||||||
#include "base/vecmath.h"
|
#include "base/vecmath.h"
|
||||||
#include "engine/engine.h"
|
|
||||||
#include "engine/input_event.h"
|
#include "engine/input_event.h"
|
||||||
#include "engine/renderer/renderer.h"
|
#include "engine/platform/platform_observer.h"
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
void Platform::Initialize() {
|
void KaliberMain(Platform* platform);
|
||||||
Platform::InitializeCommon();
|
|
||||||
|
Platform::Platform() {
|
||||||
|
LOG << "Initializing platform.";
|
||||||
|
|
||||||
root_path_ = "../../";
|
root_path_ = "../../";
|
||||||
LOG << "Root path: " << root_path_.c_str();
|
LOG << "Root path: " << root_path_.c_str();
|
||||||
|
@ -26,10 +28,6 @@ void Platform::Initialize() {
|
||||||
bool res = CreateWindow(800, 1205);
|
bool res = CreateWindow(800, 1205);
|
||||||
CHECK(res) << "Failed to create window.";
|
CHECK(res) << "Failed to create window.";
|
||||||
|
|
||||||
res = renderer_->Initialize(display_, window_);
|
|
||||||
CHECK(res) << "Failed to initialize " << renderer_->GetDebugName()
|
|
||||||
<< " renderer.";
|
|
||||||
|
|
||||||
XSelectInput(display_, window_,
|
XSelectInput(display_, window_,
|
||||||
KeyPressMask | Button1MotionMask | ButtonPressMask |
|
KeyPressMask | Button1MotionMask | ButtonPressMask |
|
||||||
ButtonReleaseMask | FocusChangeMask);
|
ButtonReleaseMask | FocusChangeMask);
|
||||||
|
@ -37,9 +35,8 @@ void Platform::Initialize() {
|
||||||
XSetWMProtocols(display_, window_, &WM_DELETE_WINDOW, 1);
|
XSetWMProtocols(display_, window_, &WM_DELETE_WINDOW, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Platform::Shutdown() {
|
Platform::~Platform() {
|
||||||
Platform::ShutdownCommon();
|
LOG << "Shutting down platform.";
|
||||||
|
|
||||||
DestroyWindow();
|
DestroyWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,47 +49,41 @@ void Platform::Update() {
|
||||||
KeySym key = XLookupKeysym(&e.xkey, 0);
|
KeySym key = XLookupKeysym(&e.xkey, 0);
|
||||||
auto input_event =
|
auto input_event =
|
||||||
std::make_unique<InputEvent>(InputEvent::kKeyPress, (char)key);
|
std::make_unique<InputEvent>(InputEvent::kKeyPress, (char)key);
|
||||||
engine_->AddInputEvent(std::move(input_event));
|
observer_->AddInputEvent(std::move(input_event));
|
||||||
// TODO: e.xkey.state & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask))
|
// TODO: e.xkey.state & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MotionNotify: {
|
case MotionNotify: {
|
||||||
Vector2f v(e.xmotion.x, e.xmotion.y);
|
Vector2f v(e.xmotion.x, e.xmotion.y);
|
||||||
v = engine_->ToPosition(v);
|
auto input_event =
|
||||||
// DLOG << "drag: " << v;
|
std::make_unique<InputEvent>(InputEvent::kDrag, 0, v);
|
||||||
auto input_event = std::make_unique<InputEvent>(InputEvent::kDrag, 0,
|
observer_->AddInputEvent(std::move(input_event));
|
||||||
v * Vector2f(1, -1));
|
|
||||||
engine_->AddInputEvent(std::move(input_event));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ButtonPress: {
|
case ButtonPress: {
|
||||||
if (e.xbutton.button == 1) {
|
if (e.xbutton.button == 1) {
|
||||||
Vector2f v(e.xbutton.x, e.xbutton.y);
|
Vector2f v(e.xbutton.x, e.xbutton.y);
|
||||||
v = engine_->ToPosition(v);
|
auto input_event =
|
||||||
// DLOG << "drag-start: " << v;
|
std::make_unique<InputEvent>(InputEvent::kDragStart, 0, v);
|
||||||
auto input_event = std::make_unique<InputEvent>(
|
observer_->AddInputEvent(std::move(input_event));
|
||||||
InputEvent::kDragStart, 0, v * Vector2f(1, -1));
|
|
||||||
engine_->AddInputEvent(std::move(input_event));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ButtonRelease: {
|
case ButtonRelease: {
|
||||||
if (e.xbutton.button == 1) {
|
if (e.xbutton.button == 1) {
|
||||||
Vector2f v(e.xbutton.x, e.xbutton.y);
|
Vector2f v(e.xbutton.x, e.xbutton.y);
|
||||||
v = engine_->ToPosition(v);
|
auto input_event =
|
||||||
// DLOG << "drag-end!";
|
std::make_unique<InputEvent>(InputEvent::kDragEnd, 0, v);
|
||||||
auto input_event = std::make_unique<InputEvent>(
|
observer_->AddInputEvent(std::move(input_event));
|
||||||
InputEvent::kDragEnd, 0, v * Vector2f(1, -1));
|
|
||||||
engine_->AddInputEvent(std::move(input_event));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FocusOut: {
|
case FocusOut: {
|
||||||
engine_->LostFocus();
|
observer_->LostFocus();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FocusIn: {
|
case FocusIn: {
|
||||||
engine_->GainedFocus(false);
|
observer_->GainedFocus(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ClientMessage: {
|
case ClientMessage: {
|
||||||
|
@ -127,7 +118,7 @@ bool Platform::CreateWindow(int width, int height) {
|
||||||
|
|
||||||
Window root_window = DefaultRootWindow(display_);
|
Window root_window = DefaultRootWindow(display_);
|
||||||
|
|
||||||
XVisualInfo* visual_info = renderer_->GetXVisualInfo(display_);
|
XVisualInfo* visual_info = GetXVisualInfo(display_);
|
||||||
if (!visual_info) {
|
if (!visual_info) {
|
||||||
LOG << "No appropriate visual found.";
|
LOG << "No appropriate visual found.";
|
||||||
return false;
|
return false;
|
||||||
|
@ -151,18 +142,35 @@ bool Platform::CreateWindow(int width, int height) {
|
||||||
void Platform::DestroyWindow() {
|
void Platform::DestroyWindow() {
|
||||||
if (display_) {
|
if (display_) {
|
||||||
XDestroyWindow(display_, window_);
|
XDestroyWindow(display_, window_);
|
||||||
|
#if 0 // TODO: Figure out why XCloseDisplay is crashing
|
||||||
XCloseDisplay(display_);
|
XCloseDisplay(display_);
|
||||||
|
#endif
|
||||||
display_ = nullptr;
|
display_ = nullptr;
|
||||||
window_ = 0;
|
window_ = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
} // namespace eng
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
eng::Platform platform;
|
eng::Platform platform;
|
||||||
platform.Initialize();
|
eng::KaliberMain(&platform);
|
||||||
platform.RunMainLoop();
|
|
||||||
platform.Shutdown();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef ENGINE_PLATFORM_PLATFORM_OBSERVER_H
|
||||||
|
#define ENGINE_PLATFORM_PLATFORM_OBSERVER_H
|
||||||
|
|
||||||
|
namespace eng {
|
||||||
|
|
||||||
|
class InputEvent;
|
||||||
|
|
||||||
|
class PlatformObserver {
|
||||||
|
public:
|
||||||
|
PlatformObserver() = default;
|
||||||
|
virtual ~PlatformObserver() = default;
|
||||||
|
|
||||||
|
virtual void OnWindowCreated() = 0;
|
||||||
|
virtual void OnWindowDestroyed() = 0;
|
||||||
|
virtual void OnWindowResized(int width, int height) = 0;
|
||||||
|
virtual void LostFocus() = 0;
|
||||||
|
virtual void GainedFocus(bool from_interstitial_ad) = 0;
|
||||||
|
virtual void AddInputEvent(std::unique_ptr<InputEvent> event) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace eng
|
||||||
|
|
||||||
|
#endif // ENGINE_PLATFORM_PLATFORM_OBSERVER_H
|
|
@ -40,13 +40,35 @@ const std::string kAttributeNames[eng::kAttribType_Max] = {
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
#ifdef THREADED_RENDERING
|
#ifdef THREADED_RENDERING
|
||||||
RendererOpenGL::RendererOpenGL()
|
RendererOpenGL::RendererOpenGL(base::Closure context_lost_cb)
|
||||||
: main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()) {}
|
: Renderer(context_lost_cb),
|
||||||
|
main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()) {}
|
||||||
#else
|
#else
|
||||||
RendererOpenGL::RendererOpenGL() = default;
|
RendererOpenGL::RendererOpenGL() = default;
|
||||||
#endif // THREADED_RENDERING
|
#endif // THREADED_RENDERING
|
||||||
|
|
||||||
RendererOpenGL::~RendererOpenGL() = default;
|
RendererOpenGL::~RendererOpenGL() {
|
||||||
|
Shutdown();
|
||||||
|
OnDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererOpenGL::Shutdown() {
|
||||||
|
#ifdef THREADED_RENDERING
|
||||||
|
if (terminate_render_thread_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOG << "Shutting down renderer.";
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> scoped_lock(mutex_);
|
||||||
|
terminate_render_thread_ = true;
|
||||||
|
}
|
||||||
|
cv_.notify_one();
|
||||||
|
LOG << "Terminating render thread";
|
||||||
|
render_thread_.join();
|
||||||
|
#else
|
||||||
|
ShutdownInternal();
|
||||||
|
#endif // THREADED_RENDERING
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t RendererOpenGL::CreateGeometry(std::unique_ptr<Mesh> mesh) {
|
uint64_t RendererOpenGL::CreateGeometry(std::unique_ptr<Mesh> mesh) {
|
||||||
auto cmd = std::make_unique<CmdCreateGeometry>();
|
auto cmd = std::make_unique<CmdCreateGeometry>();
|
||||||
|
@ -348,24 +370,6 @@ bool RendererOpenGL::StartRenderThread() {
|
||||||
#endif // THREADED_RENDERING
|
#endif // THREADED_RENDERING
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererOpenGL::TerminateRenderThread() {
|
|
||||||
#ifdef THREADED_RENDERING
|
|
||||||
if (terminate_render_thread_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Notify worker thread and wait for it to terminate.
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> scoped_lock(mutex_);
|
|
||||||
terminate_render_thread_ = true;
|
|
||||||
}
|
|
||||||
cv_.notify_one();
|
|
||||||
LOG << "Terminating render thread";
|
|
||||||
render_thread_.join();
|
|
||||||
#else
|
|
||||||
ShutdownInternal();
|
|
||||||
#endif // THREADED_RENDERING
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef THREADED_RENDERING
|
#ifdef THREADED_RENDERING
|
||||||
|
|
||||||
void RendererOpenGL::RenderThreadMain(std::promise<bool> promise) {
|
void RendererOpenGL::RenderThreadMain(std::promise<bool> promise) {
|
||||||
|
|
|
@ -37,15 +37,10 @@ struct RenderCommand;
|
||||||
|
|
||||||
class RendererOpenGL final : public Renderer {
|
class RendererOpenGL final : public Renderer {
|
||||||
public:
|
public:
|
||||||
RendererOpenGL();
|
RendererOpenGL(base::Closure context_lost_cb);
|
||||||
~RendererOpenGL() final;
|
~RendererOpenGL() final;
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
virtual bool Initialize(Platform* platform) final;
|
||||||
bool Initialize(ANativeWindow* window) final;
|
|
||||||
#elif defined(__linux__)
|
|
||||||
bool Initialize(Display* display, Window window) final;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void Shutdown() final;
|
void Shutdown() final;
|
||||||
|
|
||||||
uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) final;
|
uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) final;
|
||||||
|
@ -89,10 +84,6 @@ class RendererOpenGL final : public Renderer {
|
||||||
|
|
||||||
const char* GetDebugName() final { return "OpenGL"; }
|
const char* GetDebugName() final { return "OpenGL"; }
|
||||||
|
|
||||||
#if defined(__linux__) && !defined(__ANDROID__)
|
|
||||||
XVisualInfo* GetXVisualInfo(Display* display) final;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct GeometryOpenGL {
|
struct GeometryOpenGL {
|
||||||
struct Element {
|
struct Element {
|
||||||
|
@ -165,12 +156,13 @@ class RendererOpenGL final : public Renderer {
|
||||||
bool InitCommon();
|
bool InitCommon();
|
||||||
void ShutdownInternal();
|
void ShutdownInternal();
|
||||||
|
|
||||||
|
void OnDestroy();
|
||||||
|
|
||||||
void ContextLost();
|
void ContextLost();
|
||||||
|
|
||||||
void DestroyAllResources();
|
void DestroyAllResources();
|
||||||
|
|
||||||
bool StartRenderThread();
|
bool StartRenderThread();
|
||||||
void TerminateRenderThread();
|
|
||||||
|
|
||||||
#ifdef THREADED_RENDERING
|
#ifdef THREADED_RENDERING
|
||||||
void RenderThreadMain(std::promise<bool> promise);
|
void RenderThreadMain(std::promise<bool> promise);
|
||||||
|
|
|
@ -3,20 +3,20 @@
|
||||||
#include <android/native_window.h>
|
#include <android/native_window.h>
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
|
#include "engine/platform/platform.h"
|
||||||
#include "third_party/android/GLContext.h"
|
#include "third_party/android/GLContext.h"
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
bool RendererOpenGL::Initialize(ANativeWindow* window) {
|
bool RendererOpenGL::Initialize(Platform* platform) {
|
||||||
LOG << "Initializing renderer.";
|
LOG << "Initializing renderer.";
|
||||||
|
|
||||||
window_ = window;
|
window_ = platform->GetWindow();
|
||||||
return StartRenderThread();
|
return StartRenderThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererOpenGL::Shutdown() {
|
void RendererOpenGL::OnDestroy() {
|
||||||
LOG << "Shutting down renderer.";
|
ndk_helper::GLContext::GetInstance()->Invalidate();
|
||||||
TerminateRenderThread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RendererOpenGL::InitInternal() {
|
bool RendererOpenGL::InitInternal() {
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
#include "engine/renderer/opengl/renderer_opengl.h"
|
#include "engine/renderer/opengl/renderer_opengl.h"
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
|
#include "engine/platform/platform.h"
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
bool RendererOpenGL::Initialize(Display* display, Window window) {
|
bool RendererOpenGL::Initialize(Platform* platform) {
|
||||||
LOG << "Initializing renderer.";
|
LOG << "Initializing renderer.";
|
||||||
|
|
||||||
display_ = display;
|
display_ = platform->GetDisplay();
|
||||||
window_ = window;
|
window_ = platform->GetWindow();
|
||||||
|
|
||||||
XWindowAttributes xwa;
|
XWindowAttributes xwa;
|
||||||
XGetWindowAttributes(display_, window_, &xwa);
|
XGetWindowAttributes(display_, window_, &xwa);
|
||||||
|
@ -18,16 +19,13 @@ bool RendererOpenGL::Initialize(Display* display, Window window) {
|
||||||
return StartRenderThread();
|
return StartRenderThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererOpenGL::Shutdown() {
|
void RendererOpenGL::OnDestroy() {}
|
||||||
LOG << "Shutting down renderer.";
|
|
||||||
|
|
||||||
TerminateRenderThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RendererOpenGL::InitInternal() {
|
bool RendererOpenGL::InitInternal() {
|
||||||
// Create the OpenGL context.
|
GLint glx_attributes[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER,
|
||||||
glx_context_ =
|
None};
|
||||||
glXCreateContext(display_, GetXVisualInfo(display_), NULL, GL_TRUE);
|
XVisualInfo* visual_info = glXChooseVisual(display_, 0, glx_attributes);
|
||||||
|
glx_context_ = glXCreateContext(display_, visual_info, NULL, GL_TRUE);
|
||||||
if (!glx_context_) {
|
if (!glx_context_) {
|
||||||
LOG << "Couldn't create the glx context.";
|
LOG << "Couldn't create the glx context.";
|
||||||
return false;
|
return false;
|
||||||
|
@ -63,11 +61,4 @@ 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
|
@ -15,6 +15,11 @@ class RenderResource {
|
||||||
|
|
||||||
uint64_t resource_id() { return resource_id_; }
|
uint64_t resource_id() { return resource_id_; }
|
||||||
|
|
||||||
|
void SetRenderer(Renderer* renderer) {
|
||||||
|
renderer_ = renderer;
|
||||||
|
resource_id_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint64_t resource_id_ = 0;
|
uint64_t resource_id_ = 0;
|
||||||
Renderer* renderer_ = nullptr;
|
Renderer* renderer_ = nullptr;
|
||||||
|
|
|
@ -4,40 +4,26 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#if defined(__linux__) && !defined(__ANDROID__)
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "base/closure.h"
|
#include "base/closure.h"
|
||||||
#include "base/vecmath.h"
|
#include "base/vecmath.h"
|
||||||
#include "engine/renderer/renderer_types.h"
|
#include "engine/renderer/renderer_types.h"
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
struct ANativeWindow;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class Image;
|
class Image;
|
||||||
class ShaderSource;
|
class ShaderSource;
|
||||||
class Mesh;
|
class Mesh;
|
||||||
|
class Platform;
|
||||||
|
|
||||||
class Renderer {
|
class Renderer {
|
||||||
public:
|
public:
|
||||||
const unsigned kInvalidId = 0;
|
const unsigned kInvalidId = 0;
|
||||||
|
|
||||||
Renderer() = default;
|
Renderer(base::Closure context_lost_cb)
|
||||||
|
: context_lost_cb_{std::move(context_lost_cb)} {}
|
||||||
virtual ~Renderer() = default;
|
virtual ~Renderer() = default;
|
||||||
|
|
||||||
void SetContextLostCB(base::Closure cb) { context_lost_cb_ = std::move(cb); }
|
virtual bool Initialize(Platform* platform) = 0;
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
virtual bool Initialize(ANativeWindow* window) = 0;
|
|
||||||
#elif defined(__linux__)
|
|
||||||
virtual bool Initialize(Display* display, Window window) = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
virtual void Shutdown() = 0;
|
virtual void Shutdown() = 0;
|
||||||
|
|
||||||
virtual uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) = 0;
|
virtual uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) = 0;
|
||||||
|
@ -94,10 +80,6 @@ class Renderer {
|
||||||
|
|
||||||
virtual const char* GetDebugName() = 0;
|
virtual const char* GetDebugName() = 0;
|
||||||
|
|
||||||
#if defined(__linux__) && !defined(__ANDROID__)
|
|
||||||
virtual XVisualInfo* GetXVisualInfo(Display* display) = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct TextureCompression {
|
struct TextureCompression {
|
||||||
unsigned etc1 : 1;
|
unsigned etc1 : 1;
|
||||||
|
|
|
@ -370,10 +370,12 @@ std::pair<int, int> GetNumBlocksForImageFormat(VkFormat format,
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
RendererVulkan::RendererVulkan(std::unique_ptr<VulkanContext> context)
|
RendererVulkan::RendererVulkan(base::Closure context_lost_cb)
|
||||||
: context_{std::move(context)} {}
|
: Renderer(context_lost_cb) {}
|
||||||
|
|
||||||
RendererVulkan::~RendererVulkan() = default;
|
RendererVulkan::~RendererVulkan() {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t RendererVulkan::CreateGeometry(std::unique_ptr<Mesh> mesh) {
|
uint64_t RendererVulkan::CreateGeometry(std::unique_ptr<Mesh> mesh) {
|
||||||
auto& geometry = geometries_[++last_resource_id_] = {};
|
auto& geometry = geometries_[++last_resource_id_] = {};
|
||||||
|
@ -707,7 +709,7 @@ uint64_t RendererVulkan::CreateShader(
|
||||||
pipeline_info.pDepthStencilState = &depth_stencil;
|
pipeline_info.pDepthStencilState = &depth_stencil;
|
||||||
pipeline_info.pDynamicState = &dynamic_state_create_info;
|
pipeline_info.pDynamicState = &dynamic_state_create_info;
|
||||||
pipeline_info.layout = shader.pipeline_layout;
|
pipeline_info.layout = shader.pipeline_layout;
|
||||||
pipeline_info.renderPass = context_->GetRenderPass();
|
pipeline_info.renderPass = context_.GetRenderPass();
|
||||||
pipeline_info.subpass = 0;
|
pipeline_info.subpass = 0;
|
||||||
pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
|
pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
@ -828,7 +830,7 @@ void RendererVulkan::UploadUniforms(uint64_t resource_id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererVulkan::PrepareForDrawing() {
|
void RendererVulkan::PrepareForDrawing() {
|
||||||
context_->PrepareBuffers();
|
context_.PrepareBuffers();
|
||||||
DrawListBegin();
|
DrawListBegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -840,20 +842,20 @@ void RendererVulkan::Present() {
|
||||||
bool RendererVulkan::InitializeInternal() {
|
bool RendererVulkan::InitializeInternal() {
|
||||||
glslang::InitializeProcess();
|
glslang::InitializeProcess();
|
||||||
|
|
||||||
device_ = context_->GetDevice();
|
device_ = context_.GetDevice();
|
||||||
|
|
||||||
// Allocate one extra frame to ensure it's unused at any time without having
|
// Allocate one extra frame to ensure it's unused at any time without having
|
||||||
// to use a fence.
|
// to use a fence.
|
||||||
int frame_count = context_->GetSwapchainImageCount() + 1;
|
int frame_count = context_.GetSwapchainImageCount() + 1;
|
||||||
frames_.resize(frame_count);
|
frames_.resize(frame_count);
|
||||||
frames_drawn_ = frame_count;
|
frames_drawn_ = frame_count;
|
||||||
|
|
||||||
// Initialize allocator
|
// Initialize allocator
|
||||||
VmaAllocatorCreateInfo allocator_info;
|
VmaAllocatorCreateInfo allocator_info;
|
||||||
memset(&allocator_info, 0, sizeof(VmaAllocatorCreateInfo));
|
memset(&allocator_info, 0, sizeof(VmaAllocatorCreateInfo));
|
||||||
allocator_info.physicalDevice = context_->GetPhysicalDevice();
|
allocator_info.physicalDevice = context_.GetPhysicalDevice();
|
||||||
allocator_info.device = device_;
|
allocator_info.device = device_;
|
||||||
allocator_info.instance = context_->GetInstance();
|
allocator_info.instance = context_.GetInstance();
|
||||||
vmaCreateAllocator(&allocator_info, &allocator_);
|
vmaCreateAllocator(&allocator_info, &allocator_);
|
||||||
|
|
||||||
for (size_t i = 0; i < frames_.size(); i++) {
|
for (size_t i = 0; i < frames_.size(); i++) {
|
||||||
|
@ -861,7 +863,7 @@ bool RendererVulkan::InitializeInternal() {
|
||||||
VkCommandPoolCreateInfo cmd_pool_info;
|
VkCommandPoolCreateInfo cmd_pool_info;
|
||||||
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
cmd_pool_info.pNext = nullptr;
|
cmd_pool_info.pNext = nullptr;
|
||||||
cmd_pool_info.queueFamilyIndex = context_->GetGraphicsQueue();
|
cmd_pool_info.queueFamilyIndex = context_.GetGraphicsQueue();
|
||||||
cmd_pool_info.flags = 0;
|
cmd_pool_info.flags = 0;
|
||||||
|
|
||||||
VkResult err = vkCreateCommandPool(device_, &cmd_pool_info, nullptr,
|
VkResult err = vkCreateCommandPool(device_, &cmd_pool_info, nullptr,
|
||||||
|
@ -1014,8 +1016,8 @@ void RendererVulkan::Shutdown() {
|
||||||
current_staging_buffer_ = 0;
|
current_staging_buffer_ = 0;
|
||||||
staging_buffer_used_ = false;
|
staging_buffer_used_ = false;
|
||||||
|
|
||||||
context_->DestroyWindow();
|
context_.DestroyWindow();
|
||||||
context_->Shutdown();
|
context_.Shutdown();
|
||||||
|
|
||||||
glslang::FinalizeProcess();
|
glslang::FinalizeProcess();
|
||||||
}
|
}
|
||||||
|
@ -1023,8 +1025,8 @@ void RendererVulkan::Shutdown() {
|
||||||
void RendererVulkan::BeginFrame() {
|
void RendererVulkan::BeginFrame() {
|
||||||
FreePendingResources(current_frame_);
|
FreePendingResources(current_frame_);
|
||||||
|
|
||||||
context_->AppendCommandBuffer(frames_[current_frame_].setup_command_buffer);
|
context_.AppendCommandBuffer(frames_[current_frame_].setup_command_buffer);
|
||||||
context_->AppendCommandBuffer(frames_[current_frame_].draw_command_buffer);
|
context_.AppendCommandBuffer(frames_[current_frame_].draw_command_buffer);
|
||||||
|
|
||||||
vkResetCommandPool(device_, frames_[current_frame_].setup_command_pool, 0);
|
vkResetCommandPool(device_, frames_[current_frame_].setup_command_pool, 0);
|
||||||
vkResetCommandPool(device_, frames_[current_frame_].draw_command_pool, 0);
|
vkResetCommandPool(device_, frames_[current_frame_].draw_command_pool, 0);
|
||||||
|
@ -1063,7 +1065,7 @@ void RendererVulkan::BeginFrame() {
|
||||||
void RendererVulkan::FlushSetupBuffer() {
|
void RendererVulkan::FlushSetupBuffer() {
|
||||||
vkEndCommandBuffer(frames_[current_frame_].setup_command_buffer);
|
vkEndCommandBuffer(frames_[current_frame_].setup_command_buffer);
|
||||||
|
|
||||||
context_->Flush(false);
|
context_.Flush(false);
|
||||||
|
|
||||||
vkResetCommandPool(device_, frames_[current_frame_].setup_command_pool, 0);
|
vkResetCommandPool(device_, frames_[current_frame_].setup_command_pool, 0);
|
||||||
|
|
||||||
|
@ -1079,8 +1081,8 @@ void RendererVulkan::FlushSetupBuffer() {
|
||||||
DLOG << "vkBeginCommandBuffer failed with error " << string_VkResult(err);
|
DLOG << "vkBeginCommandBuffer failed with error " << string_VkResult(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context_->AppendCommandBuffer(frames_[current_frame_].setup_command_buffer,
|
context_.AppendCommandBuffer(frames_[current_frame_].setup_command_buffer,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererVulkan::FreePendingResources(int frame) {
|
void RendererVulkan::FreePendingResources(int frame) {
|
||||||
|
@ -1907,8 +1909,8 @@ void RendererVulkan::DrawListBegin() {
|
||||||
VkRenderPassBeginInfo render_pass_begin;
|
VkRenderPassBeginInfo render_pass_begin;
|
||||||
render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
render_pass_begin.pNext = nullptr;
|
render_pass_begin.pNext = nullptr;
|
||||||
render_pass_begin.renderPass = context_->GetRenderPass();
|
render_pass_begin.renderPass = context_.GetRenderPass();
|
||||||
render_pass_begin.framebuffer = context_->GetFramebuffer();
|
render_pass_begin.framebuffer = context_.GetFramebuffer();
|
||||||
|
|
||||||
render_pass_begin.renderArea.extent.width = screen_width_;
|
render_pass_begin.renderArea.extent.width = screen_width_;
|
||||||
render_pass_begin.renderArea.extent.height = screen_height_;
|
render_pass_begin.renderArea.extent.height = screen_height_;
|
||||||
|
@ -1974,7 +1976,7 @@ void RendererVulkan::SwapBuffers() {
|
||||||
vkEndCommandBuffer(frames_[current_frame_].setup_command_buffer);
|
vkEndCommandBuffer(frames_[current_frame_].setup_command_buffer);
|
||||||
vkEndCommandBuffer(frames_[current_frame_].draw_command_buffer);
|
vkEndCommandBuffer(frames_[current_frame_].draw_command_buffer);
|
||||||
|
|
||||||
context_->SwapBuffers();
|
context_.SwapBuffers();
|
||||||
current_frame_ = (current_frame_ + 1) % frames_.size();
|
current_frame_ = (current_frame_ + 1) % frames_.size();
|
||||||
|
|
||||||
active_pipeline_ = VK_NULL_HANDLE;
|
active_pipeline_ = VK_NULL_HANDLE;
|
||||||
|
@ -2033,13 +2035,13 @@ bool RendererVulkan::SetUniformInternal(ShaderVulkan& shader,
|
||||||
|
|
||||||
bool RendererVulkan::IsFormatSupported(VkFormat format) {
|
bool RendererVulkan::IsFormatSupported(VkFormat format) {
|
||||||
VkFormatProperties properties;
|
VkFormatProperties properties;
|
||||||
vkGetPhysicalDeviceFormatProperties(context_->GetPhysicalDevice(), format,
|
vkGetPhysicalDeviceFormatProperties(context_.GetPhysicalDevice(), format,
|
||||||
&properties);
|
&properties);
|
||||||
return properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
return properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RendererVulkan::GetAndResetFPS() {
|
size_t RendererVulkan::GetAndResetFPS() {
|
||||||
return context_->GetAndResetFPS();
|
return context_.GetAndResetFPS();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererVulkan::DestroyAllResources() {
|
void RendererVulkan::DestroyAllResources() {
|
||||||
|
|
|
@ -18,19 +18,12 @@
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class Image;
|
|
||||||
|
|
||||||
class RendererVulkan final : public Renderer {
|
class RendererVulkan final : public Renderer {
|
||||||
public:
|
public:
|
||||||
RendererVulkan(std::unique_ptr<VulkanContext> context);
|
RendererVulkan(base::Closure context_lost_cb);
|
||||||
~RendererVulkan() final;
|
~RendererVulkan() final;
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
virtual bool Initialize(Platform* platform) final;
|
||||||
bool Initialize(ANativeWindow* window) final;
|
|
||||||
#elif defined(__linux__)
|
|
||||||
bool Initialize(Display* display, Window window) final;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void Shutdown() final;
|
void Shutdown() final;
|
||||||
|
|
||||||
uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) final;
|
uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) final;
|
||||||
|
@ -74,10 +67,6 @@ class RendererVulkan final : public Renderer {
|
||||||
|
|
||||||
const char* GetDebugName() final { return "Vulkan"; }
|
const char* GetDebugName() final { return "Vulkan"; }
|
||||||
|
|
||||||
#if defined(__linux__) && !defined(__ANDROID__)
|
|
||||||
XVisualInfo* GetXVisualInfo(Display* display) final;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// VkBuffer or VkImage with allocator.
|
// VkBuffer or VkImage with allocator.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -156,7 +145,7 @@ class RendererVulkan final : public Renderer {
|
||||||
|
|
||||||
bool context_lost_ = false;
|
bool context_lost_ = false;
|
||||||
|
|
||||||
std::unique_ptr<VulkanContext> context_;
|
VulkanContext context_;
|
||||||
|
|
||||||
VmaAllocator allocator_ = nullptr;
|
VmaAllocator allocator_ = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,22 @@
|
||||||
#include <android/native_window.h>
|
#include <android/native_window.h>
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
|
#include "engine/platform/platform.h"
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
bool RendererVulkan::Initialize(ANativeWindow* window) {
|
bool RendererVulkan::Initialize(Platform* platform) {
|
||||||
LOG << "Initializing renderer.";
|
LOG << "Initializing renderer.";
|
||||||
|
|
||||||
screen_width_ = ANativeWindow_getWidth(window);
|
screen_width_ = ANativeWindow_getWidth(platform->GetWindow());
|
||||||
screen_height_ = ANativeWindow_getHeight(window);
|
screen_height_ = ANativeWindow_getHeight(platform->GetWindow());
|
||||||
|
|
||||||
if (!context_->CreateWindow(window, screen_width_, screen_height_)) {
|
if (!context_.Initialize()) {
|
||||||
|
LOG << "Failed to initialize Vulkan context.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!context_.CreateWindow(platform->GetWindow(), screen_width_,
|
||||||
|
screen_height_)) {
|
||||||
LOG << "Vulkan context failed to create window.";
|
LOG << "Vulkan context failed to create window.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,24 @@
|
||||||
#include "engine/renderer/vulkan/renderer_vulkan.h"
|
#include "engine/renderer/vulkan/renderer_vulkan.h"
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
|
#include "engine/platform/platform.h"
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
bool RendererVulkan::Initialize(Display* display, Window window) {
|
bool RendererVulkan::Initialize(Platform* platform) {
|
||||||
LOG << "Initializing renderer.";
|
LOG << "Initializing renderer.";
|
||||||
|
|
||||||
XWindowAttributes xwa;
|
XWindowAttributes xwa;
|
||||||
XGetWindowAttributes(display, window, &xwa);
|
XGetWindowAttributes(platform->GetDisplay(), platform->GetWindow(), &xwa);
|
||||||
screen_width_ = xwa.width;
|
screen_width_ = xwa.width;
|
||||||
screen_height_ = xwa.height;
|
screen_height_ = xwa.height;
|
||||||
|
|
||||||
if (!context_->CreateWindow(display, window, screen_width_, screen_height_)) {
|
if (!context_.Initialize()) {
|
||||||
|
LOG << "Failed to initialize Vulkan context.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!context_.CreateWindow(platform->GetDisplay(), platform->GetWindow(),
|
||||||
|
screen_width_, screen_height_)) {
|
||||||
LOG << "Vulkan context failed to create window.";
|
LOG << "Vulkan context failed to create window.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -20,13 +26,4 @@ bool RendererVulkan::Initialize(Display* display, Window window) {
|
||||||
return InitializeInternal();
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
|
@ -35,9 +35,11 @@ VulkanContext::~VulkanContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanContext::Initialize() {
|
bool VulkanContext::Initialize() {
|
||||||
if (volkInitialize() != VK_SUCCESS) {
|
if (instance_ != VK_NULL_HANDLE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (volkInitialize() != VK_SUCCESS)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!CreatePhysicalDevice())
|
if (!CreatePhysicalDevice())
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in New Issue