Renderer code refactoring.

This commit is contained in:
Attila Uygun 2021-10-25 22:54:57 +02:00
parent 79d9d294e6
commit 042bffaff3
20 changed files with 569 additions and 594 deletions

View File

@ -81,7 +81,6 @@ add_library(kaliber SHARED
../../../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
../../../src/engine/renderer/opengl/renderer_opengl.cc ../../../src/engine/renderer/opengl/renderer_opengl.cc
../../../src/engine/renderer/render_resource.cc
../../../src/engine/renderer/renderer_types.cc ../../../src/engine/renderer/renderer_types.cc
../../../src/engine/renderer/shader.cc ../../../src/engine/renderer/shader.cc
../../../src/engine/renderer/texture.cc ../../../src/engine/renderer/texture.cc

View File

@ -106,7 +106,6 @@ GLTEST_SRC := \
$(SRC_ROOT)/engine/renderer/opengl/render_command.cc \ $(SRC_ROOT)/engine/renderer/opengl/render_command.cc \
$(SRC_ROOT)/engine/renderer/opengl/renderer_opengl_linux.cc \ $(SRC_ROOT)/engine/renderer/opengl/renderer_opengl_linux.cc \
$(SRC_ROOT)/engine/renderer/opengl/renderer_opengl.cc \ $(SRC_ROOT)/engine/renderer/opengl/renderer_opengl.cc \
$(SRC_ROOT)/engine/renderer/render_resource.cc \
$(SRC_ROOT)/engine/renderer/renderer_types.cc \ $(SRC_ROOT)/engine/renderer/renderer_types.cc \
$(SRC_ROOT)/engine/renderer/shader.cc \ $(SRC_ROOT)/engine/renderer/shader.cc \
$(SRC_ROOT)/engine/renderer/texture.cc \ $(SRC_ROOT)/engine/renderer/texture.cc \

View File

@ -8,7 +8,6 @@ source_set("engine") {
"audio/audio_base.cc", "audio/audio_base.cc",
"audio/audio_base.h", "audio/audio_base.h",
"audio/audio_forward.h", "audio/audio_forward.h",
"audio/audio_sample.h",
"audio/audio.h", "audio/audio.h",
"drawable.cc", "drawable.cc",
"drawable.h", "drawable.h",
@ -29,9 +28,7 @@ source_set("engine") {
"persistent_data.h", "persistent_data.h",
"platform/asset_file.cc", "platform/asset_file.cc",
"platform/asset_file.h", "platform/asset_file.h",
"platform/platform_base.cc", "platform/platform.cc",
"platform/platform_base.h",
"platform/platform_forward.h",
"platform/platform.h", "platform/platform.h",
"renderer/geometry.cc", "renderer/geometry.cc",
"renderer/geometry.h", "renderer/geometry.h",
@ -40,7 +37,6 @@ source_set("engine") {
"renderer/opengl/render_command.h", "renderer/opengl/render_command.h",
"renderer/opengl/renderer_opengl.cc", "renderer/opengl/renderer_opengl.cc",
"renderer/opengl/renderer_opengl.h", "renderer/opengl/renderer_opengl.h",
"renderer/render_resource.cc",
"renderer/render_resource.h", "renderer/render_resource.h",
"renderer/renderer_types.cc", "renderer/renderer_types.cc",
"renderer/renderer_types.h", "renderer/renderer_types.h",

View File

@ -440,16 +440,13 @@ bool Engine::IsMobile() const {
return platform_->mobile_device(); return platform_->mobile_device();
} }
std::unique_ptr<RenderResource> Engine::CreateRenderResourceInternal(
RenderResourceFactoryBase& factory) {
return renderer_->CreateResource(factory);
}
void Engine::ContextLost() { void Engine::ContextLost() {
CreateRenderResources(); CreateRenderResources();
for (auto& t : textures_) for (auto& t : textures_) {
t.second.texture->Destroy();
RefreshImage(t.first); RefreshImage(t.first);
}
game_->ContextLost(); game_->ContextLost();
} }

View File

@ -11,7 +11,6 @@
#include "../base/vecmath.h" #include "../base/vecmath.h"
#include "audio/audio_forward.h" #include "audio/audio_forward.h"
#include "persistent_data.h" #include "persistent_data.h"
#include "renderer/render_resource.h"
class TextureCompressor; class TextureCompressor;
@ -65,10 +64,7 @@ class Engine {
template <typename T> template <typename T>
std::unique_ptr<T> CreateRenderResource() { std::unique_ptr<T> CreateRenderResource() {
RenderResourceFactory<T> factory; return std::unique_ptr<T>(static_cast<T*>(new T(renderer_)));
std::unique_ptr<RenderResource> resource =
CreateRenderResourceInternal(factory);
return std::unique_ptr<T>(static_cast<T*>(resource.release()));
} }
void SetImageSource(const std::string& asset_name, void SetImageSource(const std::string& asset_name,
@ -212,9 +208,6 @@ class Engine {
base::Random random_; base::Random random_;
std::unique_ptr<RenderResource> CreateRenderResourceInternal(
RenderResourceFactoryBase& factory);
void ContextLost(); void ContextLost();
bool CreateRenderResources(); bool CreateRenderResources();

View File

@ -5,10 +5,7 @@
namespace eng { namespace eng {
Geometry::Geometry(unsigned resource_id, Geometry::Geometry(Renderer* renderer) : RenderResource(renderer) {}
std::shared_ptr<void> impl_data,
Renderer* renderer)
: RenderResource(resource_id, impl_data, renderer) {}
Geometry::~Geometry() { Geometry::~Geometry() {
Destroy(); Destroy();
@ -16,22 +13,21 @@ Geometry::~Geometry() {
void Geometry::Create(std::unique_ptr<Mesh> mesh) { void Geometry::Create(std::unique_ptr<Mesh> mesh) {
Destroy(); Destroy();
valid_ = true;
vertex_description_ = mesh->vertex_description(); vertex_description_ = mesh->vertex_description();
primitive_ = mesh->primitive(); primitive_ = mesh->primitive();
renderer_->CreateGeometry(impl_data_, std::move(mesh)); resource_id_ = renderer_->CreateGeometry(std::move(mesh));
} }
void Geometry::Destroy() { void Geometry::Destroy() {
if (valid_) { if (IsValid()) {
renderer_->DestroyGeometry(impl_data_); renderer_->DestroyGeometry(resource_id_);
valid_ = false; resource_id_ = 0;
} }
} }
void Geometry::Draw() { void Geometry::Draw() {
if (valid_) if (IsValid())
renderer_->Draw(impl_data_); renderer_->Draw(resource_id_);
} }
} // namespace eng } // namespace eng

View File

@ -14,14 +14,12 @@ class Mesh;
class Geometry : public RenderResource { class Geometry : public RenderResource {
public: public:
Geometry(unsigned resource_id, Geometry(Renderer* renderer);
std::shared_ptr<void> impl_data, ~Geometry();
Renderer* renderer);
~Geometry() override;
void Create(std::unique_ptr<Mesh> mesh); void Create(std::unique_ptr<Mesh> mesh);
void Destroy() override; void Destroy();
void Draw(); void Draw();

View File

@ -15,6 +15,8 @@
namespace eng { namespace eng {
RENDER_COMMAND_IMPL(CmdPresent, false); RENDER_COMMAND_IMPL(CmdPresent, false);
RENDER_COMMAND_IMPL(CmdInvalidateAllResources, true);
RENDER_COMMAND_IMPL(CmdCreateTexture, true);
RENDER_COMMAND_IMPL(CmdUpdateTexture, true); RENDER_COMMAND_IMPL(CmdUpdateTexture, true);
RENDER_COMMAND_IMPL(CmdDestoryTexture, true); RENDER_COMMAND_IMPL(CmdDestoryTexture, true);
RENDER_COMMAND_IMPL(CmdActivateTexture, false); RENDER_COMMAND_IMPL(CmdActivateTexture, false);

View File

@ -50,81 +50,88 @@ struct RenderCommand {
RENDER_COMMAND_BEGIN(CmdPresent) RENDER_COMMAND_BEGIN(CmdPresent)
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdInvalidateAllResources)
RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdCreateTexture)
uint64_t resource_id;
RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdUpdateTexture) RENDER_COMMAND_BEGIN(CmdUpdateTexture)
std::unique_ptr<Image> image; std::unique_ptr<Image> image;
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdDestoryTexture) RENDER_COMMAND_BEGIN(CmdDestoryTexture)
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdActivateTexture) RENDER_COMMAND_BEGIN(CmdActivateTexture)
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdCreateGeometry) RENDER_COMMAND_BEGIN(CmdCreateGeometry)
std::unique_ptr<Mesh> mesh; std::unique_ptr<Mesh> mesh;
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdDestroyGeometry) RENDER_COMMAND_BEGIN(CmdDestroyGeometry)
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdDrawGeometry) RENDER_COMMAND_BEGIN(CmdDrawGeometry)
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdCreateShader) RENDER_COMMAND_BEGIN(CmdCreateShader)
std::unique_ptr<ShaderSource> source; std::unique_ptr<ShaderSource> source;
VertexDescripton vertex_description; VertexDescripton vertex_description;
std::shared_ptr<void> impl_data; uint64_t resource_id;
bool enable_depth_test; bool enable_depth_test;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdDestroyShader) RENDER_COMMAND_BEGIN(CmdDestroyShader)
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdActivateShader) RENDER_COMMAND_BEGIN(CmdActivateShader)
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdSetUniformVec2) RENDER_COMMAND_BEGIN(CmdSetUniformVec2)
std::string name; std::string name;
base::Vector2f v; base::Vector2f v;
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdSetUniformVec3) RENDER_COMMAND_BEGIN(CmdSetUniformVec3)
std::string name; std::string name;
base::Vector3f v; base::Vector3f v;
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdSetUniformVec4) RENDER_COMMAND_BEGIN(CmdSetUniformVec4)
std::string name; std::string name;
base::Vector4f v; base::Vector4f v;
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdSetUniformMat4) RENDER_COMMAND_BEGIN(CmdSetUniformMat4)
std::string name; std::string name;
base::Matrix4f m; base::Matrix4f m;
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdSetUniformInt) RENDER_COMMAND_BEGIN(CmdSetUniformInt)
std::string name; std::string name;
int i; int i;
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
RENDER_COMMAND_BEGIN(CmdSetUniformFloat) RENDER_COMMAND_BEGIN(CmdSetUniformFloat)
std::string name; std::string name;
float f; float f;
std::shared_ptr<void> impl_data; uint64_t resource_id;
RENDER_COMMAND_END RENDER_COMMAND_END
} // namespace eng } // namespace eng

View File

@ -45,47 +45,54 @@ RendererOpenGL::RendererOpenGL() = default;
RendererOpenGL::~RendererOpenGL() = default; RendererOpenGL::~RendererOpenGL() = default;
void RendererOpenGL::CreateGeometry(std::shared_ptr<void> impl_data, uint64_t RendererOpenGL::CreateGeometry(std::unique_ptr<Mesh> mesh) {
std::unique_ptr<Mesh> mesh) {
auto cmd = std::make_unique<CmdCreateGeometry>(); auto cmd = std::make_unique<CmdCreateGeometry>();
cmd->mesh = std::move(mesh); cmd->mesh = std::move(mesh);
cmd->impl_data = impl_data; cmd->resource_id = ++last_resource_id_;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
return last_resource_id_;
} }
void RendererOpenGL::DestroyGeometry(std::shared_ptr<void> impl_data) { void RendererOpenGL::DestroyGeometry(uint64_t resource_id) {
auto cmd = std::make_unique<CmdDestroyGeometry>(); auto cmd = std::make_unique<CmdDestroyGeometry>();
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::Draw(std::shared_ptr<void> impl_data) { void RendererOpenGL::Draw(uint64_t resource_id) {
auto cmd = std::make_unique<CmdDrawGeometry>(); auto cmd = std::make_unique<CmdDrawGeometry>();
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::UpdateTexture(std::shared_ptr<void> impl_data, uint64_t RendererOpenGL::CreateTexture() {
auto cmd = std::make_unique<CmdCreateTexture>();
cmd->resource_id = ++last_resource_id_;
EnqueueCommand(std::move(cmd));
return last_resource_id_;
}
void RendererOpenGL::UpdateTexture(uint64_t resource_id,
std::unique_ptr<Image> image) { std::unique_ptr<Image> image) {
auto cmd = std::make_unique<CmdUpdateTexture>(); auto cmd = std::make_unique<CmdUpdateTexture>();
cmd->image = std::move(image); cmd->image = std::move(image);
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::DestroyTexture(std::shared_ptr<void> impl_data) { void RendererOpenGL::DestroyTexture(uint64_t resource_id) {
auto cmd = std::make_unique<CmdDestoryTexture>(); auto cmd = std::make_unique<CmdDestoryTexture>();
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::ActivateTexture(std::shared_ptr<void> impl_data) { void RendererOpenGL::ActivateTexture(uint64_t resource_id) {
auto cmd = std::make_unique<CmdActivateTexture>(); auto cmd = std::make_unique<CmdActivateTexture>();
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::CreateShader(std::shared_ptr<void> impl_data, uint64_t RendererOpenGL::CreateShader(
std::unique_ptr<ShaderSource> source, std::unique_ptr<ShaderSource> source,
const VertexDescripton& vertex_description, const VertexDescripton& vertex_description,
Primitive primitive, Primitive primitive,
@ -93,80 +100,81 @@ void RendererOpenGL::CreateShader(std::shared_ptr<void> impl_data,
auto cmd = std::make_unique<CmdCreateShader>(); auto cmd = std::make_unique<CmdCreateShader>();
cmd->source = std::move(source); cmd->source = std::move(source);
cmd->vertex_description = vertex_description; cmd->vertex_description = vertex_description;
cmd->impl_data = impl_data; cmd->resource_id = ++last_resource_id_;
cmd->enable_depth_test = enable_depth_test; cmd->enable_depth_test = enable_depth_test;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
return last_resource_id_;
} }
void RendererOpenGL::DestroyShader(std::shared_ptr<void> impl_data) { void RendererOpenGL::DestroyShader(uint64_t resource_id) {
auto cmd = std::make_unique<CmdDestroyShader>(); auto cmd = std::make_unique<CmdDestroyShader>();
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::ActivateShader(std::shared_ptr<void> impl_data) { void RendererOpenGL::ActivateShader(uint64_t resource_id) {
auto cmd = std::make_unique<CmdActivateShader>(); auto cmd = std::make_unique<CmdActivateShader>();
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::SetUniform(std::shared_ptr<void> impl_data, void RendererOpenGL::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector2f& val) { const base::Vector2f& val) {
auto cmd = std::make_unique<CmdSetUniformVec2>(); auto cmd = std::make_unique<CmdSetUniformVec2>();
cmd->name = name; cmd->name = name;
cmd->v = val; cmd->v = val;
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::SetUniform(std::shared_ptr<void> impl_data, void RendererOpenGL::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector3f& val) { const base::Vector3f& val) {
auto cmd = std::make_unique<CmdSetUniformVec3>(); auto cmd = std::make_unique<CmdSetUniformVec3>();
cmd->name = name; cmd->name = name;
cmd->v = val; cmd->v = val;
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::SetUniform(std::shared_ptr<void> impl_data, void RendererOpenGL::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector4f& val) { const base::Vector4f& val) {
auto cmd = std::make_unique<CmdSetUniformVec4>(); auto cmd = std::make_unique<CmdSetUniformVec4>();
cmd->name = name; cmd->name = name;
cmd->v = val; cmd->v = val;
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::SetUniform(std::shared_ptr<void> impl_data, void RendererOpenGL::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Matrix4f& val) { const base::Matrix4f& val) {
auto cmd = std::make_unique<CmdSetUniformMat4>(); auto cmd = std::make_unique<CmdSetUniformMat4>();
cmd->name = name; cmd->name = name;
cmd->m = val; cmd->m = val;
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::SetUniform(std::shared_ptr<void> impl_data, void RendererOpenGL::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
float val) { float val) {
auto cmd = std::make_unique<CmdSetUniformFloat>(); auto cmd = std::make_unique<CmdSetUniformFloat>();
cmd->name = name; cmd->name = name;
cmd->f = val; cmd->f = val;
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
void RendererOpenGL::SetUniform(std::shared_ptr<void> impl_data, void RendererOpenGL::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
int val) { int val) {
auto cmd = std::make_unique<CmdSetUniformInt>(); auto cmd = std::make_unique<CmdSetUniformInt>();
cmd->name = name; cmd->name = name;
cmd->i = val; cmd->i = val;
cmd->impl_data = impl_data; cmd->resource_id = resource_id;
EnqueueCommand(std::move(cmd)); EnqueueCommand(std::move(cmd));
} }
@ -182,47 +190,21 @@ void RendererOpenGL::ContextLost() {
LOG << "Context lost."; LOG << "Context lost.";
#ifdef THREADED_RENDERING #ifdef THREADED_RENDERING
{
std::unique_lock<std::mutex> scoped_lock(mutex_);
global_commands_.clear(); global_commands_.clear();
draw_commands_[0].clear(); draw_commands_[0].clear();
draw_commands_[1].clear(); draw_commands_[1].clear();
}
main_thread_task_runner_->PostTask( DestroyAllResources();
HERE, std::bind(&RendererOpenGL::InvalidateAllResources, this));
main_thread_task_runner_->PostTask(HERE, context_lost_cb_); main_thread_task_runner_->PostTask(HERE, context_lost_cb_);
#else #else
InvalidateAllResources(); DestroyAllResources();
context_lost_cb_(); context_lost_cb_();
#endif // THREADED_RENDERING #endif // THREADED_RENDERING
} }
std::unique_ptr<RenderResource> RendererOpenGL::CreateResource(
RenderResourceFactoryBase& factory) {
static unsigned last_id = 0;
// Set implementation specific data. This data will be sent with render
// commands to the render thread and sould not be used in any other thread.
std::shared_ptr<void> impl_data;
if (factory.IsTypeOf<Geometry>())
impl_data = std::make_shared<GeometryOpenGL>();
else if (factory.IsTypeOf<Shader>())
impl_data = std::make_shared<ShaderOpenGL>();
else if (factory.IsTypeOf<Texture>())
impl_data = std::make_shared<TextureOpenGL>();
else
NOTREACHED << "- Unknown resource type.";
unsigned resource_id = ++last_id;
auto resource = factory.Create(resource_id, impl_data, this);
resources_[resource_id] = resource.get();
return resource;
}
void RendererOpenGL::ReleaseResource(unsigned resource_id) {
auto it = resources_.find(resource_id);
if (it != resources_.end())
resources_.erase(it);
}
size_t RendererOpenGL::GetAndResetFPS() { size_t RendererOpenGL::GetAndResetFPS() {
int ret = fps_; int ret = fps_;
fps_ = 0; fps_ = 0;
@ -309,9 +291,37 @@ bool RendererOpenGL::InitCommon() {
return true; return true;
} }
void RendererOpenGL::InvalidateAllResources() { void RendererOpenGL::DestroyAllResources() {
for (auto& r : resources_) std::vector<uint64_t> resource_ids;
r.second->Destroy(); for (auto& r : geometries_)
resource_ids.push_back(r.first);
for (auto& r : resource_ids) {
auto cmd = std::make_unique<CmdDestroyGeometry>();
cmd->resource_id = r;
ProcessCommand(cmd.get());
}
resource_ids.clear();
for (auto& r : shaders_)
resource_ids.push_back(r.first);
for (auto& r : resource_ids) {
auto cmd = std::make_unique<CmdDestroyShader>();
cmd->resource_id = r;
ProcessCommand(cmd.get());
}
resource_ids.clear();
for (auto& r : textures_)
resource_ids.push_back(r.first);
for (auto& r : resource_ids) {
auto cmd = std::make_unique<CmdDestoryTexture>();
cmd->resource_id = r;
ProcessCommand(cmd.get());
}
DCHECK(geometries_.size() == 0);
DCHECK(shaders_.size() == 0);
DCHECK(textures_.size() == 0);
} }
bool RendererOpenGL::StartRenderThread() { bool RendererOpenGL::StartRenderThread() {
@ -425,6 +435,9 @@ void RendererOpenGL::ProcessCommand(RenderCommand* cmd) {
case CmdPresent::CMD_ID: case CmdPresent::CMD_ID:
HandleCmdPresent(cmd); HandleCmdPresent(cmd);
break; break;
case CmdCreateTexture::CMD_ID:
HandleCmdCreateTexture(cmd);
break;
case CmdUpdateTexture::CMD_ID: case CmdUpdateTexture::CMD_ID:
HandleCmdUpdateTexture(cmd); HandleCmdUpdateTexture(cmd);
break; break;
@ -475,18 +488,29 @@ void RendererOpenGL::ProcessCommand(RenderCommand* cmd) {
} }
} }
void RendererOpenGL::HandleCmdUpdateTexture(RenderCommand* cmd) { void RendererOpenGL::HandleCmdCreateTexture(RenderCommand* cmd) {
auto* c = static_cast<CmdUpdateTexture*>(cmd); auto* c = static_cast<CmdCreateTexture*>(cmd);
auto impl_data = reinterpret_cast<TextureOpenGL*>(c->impl_data.get());
bool new_texture = impl_data->id == 0;
GLuint gl_id = 0; GLuint gl_id = 0;
if (new_texture)
glGenTextures(1, &gl_id); glGenTextures(1, &gl_id);
else
gl_id = impl_data->id;
glBindTexture(GL_TEXTURE_2D, gl_id); BindTexture(gl_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
textures_.insert({c->resource_id, {gl_id}});
}
void RendererOpenGL::HandleCmdUpdateTexture(RenderCommand* cmd) {
auto* c = static_cast<CmdUpdateTexture*>(cmd);
auto it = textures_.find(c->resource_id);
if (it == textures_.end())
return;
BindTexture(it->second.id);
if (c->image->IsCompressed()) { if (c->image->IsCompressed()) {
GLenum format = 0; GLenum format = 0;
switch (c->image->GetFormat()) { switch (c->image->GetFormat()) {
@ -515,8 +539,8 @@ void RendererOpenGL::HandleCmdUpdateTexture(RenderCommand* cmd) {
c->image->GetHeight(), 0, c->image->GetSize(), c->image->GetHeight(), 0, c->image->GetSize(),
c->image->GetBuffer()); c->image->GetBuffer());
// Sometimes the first glCompressedTexImage2D call after context-lost // On some devices the first glCompressedTexImage2D call after context-lost
// generates GL_INVALID_VALUE. // returns GL_INVALID_VALUE for some reason.
GLenum err = glGetError(); GLenum err = glGetError();
if (err == GL_INVALID_VALUE) { if (err == GL_INVALID_VALUE) {
glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, c->image->GetWidth(), glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, c->image->GetWidth(),
@ -532,40 +556,30 @@ void RendererOpenGL::HandleCmdUpdateTexture(RenderCommand* cmd) {
c->image->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, c->image->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
c->image->GetBuffer()); c->image->GetBuffer());
} }
if (new_texture) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
*impl_data = {gl_id};
}
} }
void RendererOpenGL::HandleCmdDestoryTexture(RenderCommand* cmd) { void RendererOpenGL::HandleCmdDestoryTexture(RenderCommand* cmd) {
auto* c = static_cast<CmdDestoryTexture*>(cmd); auto* c = static_cast<CmdDestoryTexture*>(cmd);
auto impl_data = reinterpret_cast<TextureOpenGL*>(c->impl_data.get()); auto it = textures_.find(c->resource_id);
if (impl_data->id > 0) { if (it == textures_.end())
glDeleteTextures(1, &(impl_data->id)); return;
*impl_data = {};
} glDeleteTextures(1, &(it->second.id));
textures_.erase(it);
} }
void RendererOpenGL::HandleCmdActivateTexture(RenderCommand* cmd) { void RendererOpenGL::HandleCmdActivateTexture(RenderCommand* cmd) {
auto* c = static_cast<CmdActivateTexture*>(cmd); auto* c = static_cast<CmdActivateTexture*>(cmd);
auto impl_data = reinterpret_cast<TextureOpenGL*>(c->impl_data.get()); auto it = textures_.find(c->resource_id);
if (impl_data->id > 0 && impl_data->id != active_texture_id_) { if (it == textures_.end()) {
glBindTexture(GL_TEXTURE_2D, impl_data->id); return;
active_texture_id_ = impl_data->id;
} }
BindTexture(it->second.id);
} }
void RendererOpenGL::HandleCmdCreateGeometry(RenderCommand* cmd) { void RendererOpenGL::HandleCmdCreateGeometry(RenderCommand* cmd) {
auto* c = static_cast<CmdCreateGeometry*>(cmd); auto* c = static_cast<CmdCreateGeometry*>(cmd);
auto impl_data = reinterpret_cast<GeometryOpenGL*>(c->impl_data.get());
if (impl_data->vertex_buffer_id > 0)
return;
// Verify that we have a valid layout and get the total byte size per vertex. // Verify that we have a valid layout and get the total byte size per vertex.
GLuint vertex_size = c->mesh->GetVertexSize(); GLuint vertex_size = c->mesh->GetVertexSize();
@ -613,7 +627,7 @@ void RendererOpenGL::HandleCmdCreateGeometry(RenderCommand* cmd) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
} }
*impl_data = {(GLsizei)c->mesh->num_vertices(), geometries_[c->resource_id] = {(GLsizei)c->mesh->num_vertices(),
(GLsizei)c->mesh->num_indices(), (GLsizei)c->mesh->num_indices(),
kGlPrimitive[c->mesh->primitive()], kGlPrimitive[c->mesh->primitive()],
kGlDataType[c->mesh->index_description()], kGlDataType[c->mesh->index_description()],
@ -626,58 +640,58 @@ void RendererOpenGL::HandleCmdCreateGeometry(RenderCommand* cmd) {
void RendererOpenGL::HandleCmdDestroyGeometry(RenderCommand* cmd) { void RendererOpenGL::HandleCmdDestroyGeometry(RenderCommand* cmd) {
auto* c = static_cast<CmdDestroyGeometry*>(cmd); auto* c = static_cast<CmdDestroyGeometry*>(cmd);
auto impl_data = reinterpret_cast<GeometryOpenGL*>(c->impl_data.get()); auto it = geometries_.find(c->resource_id);
if (impl_data->vertex_buffer_id == 0) if (it == geometries_.end())
return; return;
if (impl_data->index_buffer_id) if (it->second.index_buffer_id)
glDeleteBuffers(1, &(impl_data->index_buffer_id)); glDeleteBuffers(1, &(it->second.index_buffer_id));
if (impl_data->vertex_buffer_id) if (it->second.vertex_buffer_id)
glDeleteBuffers(1, &(impl_data->vertex_buffer_id)); glDeleteBuffers(1, &(it->second.vertex_buffer_id));
if (impl_data->vertex_array_id) if (it->second.vertex_array_id)
glDeleteVertexArrays(1, &(impl_data->vertex_array_id)); glDeleteVertexArrays(1, &(it->second.vertex_array_id));
*impl_data = {}; geometries_.erase(it);
} }
void RendererOpenGL::HandleCmdDrawGeometry(RenderCommand* cmd) { void RendererOpenGL::HandleCmdDrawGeometry(RenderCommand* cmd) {
auto* c = static_cast<CmdDrawGeometry*>(cmd); auto* c = static_cast<CmdDrawGeometry*>(cmd);
auto impl_data = reinterpret_cast<GeometryOpenGL*>(c->impl_data.get()); auto it = geometries_.find(c->resource_id);
if (impl_data->vertex_buffer_id == 0) if (it == geometries_.end())
return; return;
// Set up the vertex data. // Set up the vertex data.
if (impl_data->vertex_array_id) if (it->second.vertex_array_id)
glBindVertexArray(impl_data->vertex_array_id); glBindVertexArray(it->second.vertex_array_id);
else { else {
glBindBuffer(GL_ARRAY_BUFFER, impl_data->vertex_buffer_id); glBindBuffer(GL_ARRAY_BUFFER, it->second.vertex_buffer_id);
for (GLuint attribute_index = 0; for (GLuint attribute_index = 0;
attribute_index < (GLuint)impl_data->vertex_layout.size(); attribute_index < (GLuint)it->second.vertex_layout.size();
++attribute_index) { ++attribute_index) {
GeometryOpenGL::Element& e = impl_data->vertex_layout[attribute_index]; GeometryOpenGL::Element& e = it->second.vertex_layout[attribute_index];
glEnableVertexAttribArray(attribute_index); glEnableVertexAttribArray(attribute_index);
glVertexAttribPointer(attribute_index, e.num_elements, e.type, GL_FALSE, glVertexAttribPointer(attribute_index, e.num_elements, e.type, GL_FALSE,
impl_data->vertex_size, it->second.vertex_size,
(const GLvoid*)e.vertex_offset); (const GLvoid*)e.vertex_offset);
} }
if (impl_data->num_indices > 0) if (it->second.num_indices > 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, impl_data->index_buffer_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, it->second.index_buffer_id);
} }
// Draw the primitive. // Draw the primitive.
if (impl_data->num_indices > 0) if (it->second.num_indices > 0)
glDrawElements(impl_data->primitive, impl_data->num_indices, glDrawElements(it->second.primitive, it->second.num_indices,
impl_data->index_type, NULL); it->second.index_type, NULL);
else else
glDrawArrays(impl_data->primitive, 0, impl_data->num_vertices); glDrawArrays(it->second.primitive, 0, it->second.num_vertices);
// Clean up states. // Clean up states.
if (impl_data->vertex_array_id) if (it->second.vertex_array_id)
glBindVertexArray(0); glBindVertexArray(0);
else { else {
for (GLuint attribute_index = 0; for (GLuint attribute_index = 0;
attribute_index < (GLuint)impl_data->vertex_layout.size(); attribute_index < (GLuint)it->second.vertex_layout.size();
++attribute_index) ++attribute_index)
glDisableVertexAttribArray(attribute_index); glDisableVertexAttribArray(attribute_index);
@ -688,9 +702,6 @@ void RendererOpenGL::HandleCmdDrawGeometry(RenderCommand* cmd) {
void RendererOpenGL::HandleCmdCreateShader(RenderCommand* cmd) { void RendererOpenGL::HandleCmdCreateShader(RenderCommand* cmd) {
auto* c = static_cast<CmdCreateShader*>(cmd); auto* c = static_cast<CmdCreateShader*>(cmd);
auto impl_data = reinterpret_cast<ShaderOpenGL*>(c->impl_data.get());
if (impl_data->id > 0)
return;
GLuint vertex_shader = GLuint vertex_shader =
CreateShader(c->source->GetVertexSource(), GL_VERTEX_SHADER); CreateShader(c->source->GetVertexSource(), GL_VERTEX_SHADER);
@ -728,25 +739,29 @@ void RendererOpenGL::HandleCmdCreateShader(RenderCommand* cmd) {
} }
} }
*impl_data = {id, {}, c->enable_depth_test}; shaders_[c->resource_id] = {id, {}, c->enable_depth_test};
} }
void RendererOpenGL::HandleCmdDestroyShader(RenderCommand* cmd) { void RendererOpenGL::HandleCmdDestroyShader(RenderCommand* cmd) {
auto* c = static_cast<CmdDestroyShader*>(cmd); auto* c = static_cast<CmdDestroyShader*>(cmd);
auto impl_data = reinterpret_cast<ShaderOpenGL*>(c->impl_data.get()); auto it = shaders_.find(c->resource_id);
if (impl_data->id > 0) { if (it == shaders_.end())
glDeleteProgram(impl_data->id); return;
*impl_data = {};
} glDeleteProgram(it->second.id);
shaders_.erase(it);
} }
void RendererOpenGL::HandleCmdActivateShader(RenderCommand* cmd) { void RendererOpenGL::HandleCmdActivateShader(RenderCommand* cmd) {
auto* c = static_cast<CmdActivateShader*>(cmd); auto* c = static_cast<CmdActivateShader*>(cmd);
auto impl_data = reinterpret_cast<ShaderOpenGL*>(c->impl_data.get()); auto it = shaders_.find(c->resource_id);
if (impl_data->id > 0 && impl_data->id != active_shader_id_) { if (it == shaders_.end())
glUseProgram(impl_data->id); return;
active_shader_id_ = impl_data->id;
if (impl_data->enable_depth_test) if (it->second.id != active_shader_id_) {
glUseProgram(it->second.id);
active_shader_id_ = it->second.id;
if (it->second.enable_depth_test)
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
else else
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
@ -755,67 +770,74 @@ void RendererOpenGL::HandleCmdActivateShader(RenderCommand* cmd) {
void RendererOpenGL::HandleCmdSetUniformVec2(RenderCommand* cmd) { void RendererOpenGL::HandleCmdSetUniformVec2(RenderCommand* cmd) {
auto* c = static_cast<CmdSetUniformVec2*>(cmd); auto* c = static_cast<CmdSetUniformVec2*>(cmd);
auto impl_data = reinterpret_cast<ShaderOpenGL*>(c->impl_data.get()); auto it = shaders_.find(c->resource_id);
if (impl_data->id > 0) { if (it == shaders_.end())
GLint index = return;
GetUniformLocation(impl_data->id, c->name, impl_data->uniforms);
GLint index = GetUniformLocation(it->second.id, c->name, it->second.uniforms);
if (index >= 0) if (index >= 0)
glUniform2fv(index, 1, c->v.GetData()); glUniform2fv(index, 1, c->v.GetData());
}
} }
void RendererOpenGL::HandleCmdSetUniformVec3(RenderCommand* cmd) { void RendererOpenGL::HandleCmdSetUniformVec3(RenderCommand* cmd) {
auto* c = static_cast<CmdSetUniformVec3*>(cmd); auto* c = static_cast<CmdSetUniformVec3*>(cmd);
auto impl_data = reinterpret_cast<ShaderOpenGL*>(c->impl_data.get()); auto it = shaders_.find(c->resource_id);
if (impl_data->id > 0) { if (it == shaders_.end())
GLint index = return;
GetUniformLocation(impl_data->id, c->name, impl_data->uniforms);
GLint index = GetUniformLocation(it->second.id, c->name, it->second.uniforms);
if (index >= 0) if (index >= 0)
glUniform3fv(index, 1, c->v.GetData()); glUniform3fv(index, 1, c->v.GetData());
}
} }
void RendererOpenGL::HandleCmdSetUniformVec4(RenderCommand* cmd) { void RendererOpenGL::HandleCmdSetUniformVec4(RenderCommand* cmd) {
auto* c = static_cast<CmdSetUniformVec4*>(cmd); auto* c = static_cast<CmdSetUniformVec4*>(cmd);
auto impl_data = reinterpret_cast<ShaderOpenGL*>(c->impl_data.get()); auto it = shaders_.find(c->resource_id);
if (impl_data->id > 0) { if (it == shaders_.end())
GLint index = return;
GetUniformLocation(impl_data->id, c->name, impl_data->uniforms);
GLint index = GetUniformLocation(it->second.id, c->name, it->second.uniforms);
if (index >= 0) if (index >= 0)
glUniform4fv(index, 1, c->v.GetData()); glUniform4fv(index, 1, c->v.GetData());
}
} }
void RendererOpenGL::HandleCmdSetUniformMat4(RenderCommand* cmd) { void RendererOpenGL::HandleCmdSetUniformMat4(RenderCommand* cmd) {
auto* c = static_cast<CmdSetUniformMat4*>(cmd); auto* c = static_cast<CmdSetUniformMat4*>(cmd);
auto impl_data = reinterpret_cast<ShaderOpenGL*>(c->impl_data.get()); auto it = shaders_.find(c->resource_id);
if (impl_data->id > 0) { if (it == shaders_.end())
GLint index = return;
GetUniformLocation(impl_data->id, c->name, impl_data->uniforms);
GLint index = GetUniformLocation(it->second.id, c->name, it->second.uniforms);
if (index >= 0) if (index >= 0)
glUniformMatrix4fv(index, 1, GL_FALSE, c->m.GetData()); glUniformMatrix4fv(index, 1, GL_FALSE, c->m.GetData());
}
} }
void RendererOpenGL::HandleCmdSetUniformFloat(RenderCommand* cmd) { void RendererOpenGL::HandleCmdSetUniformFloat(RenderCommand* cmd) {
auto* c = static_cast<CmdSetUniformFloat*>(cmd); auto* c = static_cast<CmdSetUniformFloat*>(cmd);
auto impl_data = reinterpret_cast<ShaderOpenGL*>(c->impl_data.get()); auto it = shaders_.find(c->resource_id);
if (impl_data->id > 0) { if (it == shaders_.end())
GLint index = return;
GetUniformLocation(impl_data->id, c->name, impl_data->uniforms);
GLint index = GetUniformLocation(it->second.id, c->name, it->second.uniforms);
if (index >= 0) if (index >= 0)
glUniform1f(index, c->f); glUniform1f(index, c->f);
}
} }
void RendererOpenGL::HandleCmdSetUniformInt(RenderCommand* cmd) { void RendererOpenGL::HandleCmdSetUniformInt(RenderCommand* cmd) {
auto* c = static_cast<CmdSetUniformInt*>(cmd); auto* c = static_cast<CmdSetUniformInt*>(cmd);
auto impl_data = reinterpret_cast<ShaderOpenGL*>(c->impl_data.get()); auto it = shaders_.find(c->resource_id);
if (impl_data->id > 0) { if (it == shaders_.end())
GLint index = return;
GetUniformLocation(impl_data->id, c->name, impl_data->uniforms);
GLint index = GetUniformLocation(it->second.id, c->name, it->second.uniforms);
if (index >= 0) if (index >= 0)
glUniform1i(index, c->i); glUniform1i(index, c->i);
}
void RendererOpenGL::BindTexture(GLuint id) {
if (id != active_texture_id_) {
glBindTexture(GL_TEXTURE_2D, id);
active_texture_id_ = id;
} }
} }

View File

@ -20,7 +20,6 @@
#include "opengl.h" #include "opengl.h"
#include "../render_resource.h"
#include "../renderer.h" #include "../renderer.h"
#if defined(__ANDROID__) #if defined(__ANDROID__)
@ -50,51 +49,46 @@ class RendererOpenGL : public Renderer {
void Shutdown() override; void Shutdown() override;
void CreateGeometry(std::shared_ptr<void> impl_data, uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) override;
std::unique_ptr<Mesh> mesh) override; void DestroyGeometry(uint64_t resource_id) override;
void DestroyGeometry(std::shared_ptr<void> impl_data) override; void Draw(uint64_t resource_id) override;
void Draw(std::shared_ptr<void> impl_data) override;
void UpdateTexture(std::shared_ptr<void> impl_data, uint64_t CreateTexture() override;
void UpdateTexture(uint64_t resource_id,
std::unique_ptr<Image> image) override; std::unique_ptr<Image> image) override;
void DestroyTexture(std::shared_ptr<void> impl_data) override; void DestroyTexture(uint64_t resource_id) override;
void ActivateTexture(std::shared_ptr<void> impl_data) override; void ActivateTexture(uint64_t resource_id) override;
void CreateShader(std::shared_ptr<void> impl_data, uint64_t CreateShader(std::unique_ptr<ShaderSource> source,
std::unique_ptr<ShaderSource> source,
const VertexDescripton& vertex_description, const VertexDescripton& vertex_description,
Primitive primitive, Primitive primitive,
bool enable_depth_test) override; bool enable_depth_test) override;
void DestroyShader(std::shared_ptr<void> impl_data) override; void DestroyShader(uint64_t resource_id) override;
void ActivateShader(std::shared_ptr<void> impl_data) override; void ActivateShader(uint64_t resource_id) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector2f& val) override; const base::Vector2f& val) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector3f& val) override; const base::Vector3f& val) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector4f& val) override; const base::Vector4f& val) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Matrix4f& val) override; const base::Matrix4f& val) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
float val) override; float val) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
int val) override; int val) override;
void UploadUniforms(std::shared_ptr<void> impl_data) override {} void UploadUniforms(uint64_t resource_id) override {}
void PrepareForDrawing() override {} void PrepareForDrawing() override {}
void Present() override; void Present() override;
std::unique_ptr<RenderResource> CreateResource(
RenderResourceFactoryBase& factory) override;
void ReleaseResource(unsigned resource_id) override;
size_t GetAndResetFPS() override; size_t GetAndResetFPS() override;
#if defined(__linux__) && !defined(__ANDROID__) #if defined(__linux__) && !defined(__ANDROID__)
@ -130,14 +124,17 @@ class RendererOpenGL : public Renderer {
GLuint id = 0; GLuint id = 0;
}; };
std::unordered_map<uint64_t, GeometryOpenGL> geometries_;
std::unordered_map<uint64_t, ShaderOpenGL> shaders_;
std::unordered_map<uint64_t, TextureOpenGL> textures_;
uint64_t last_resource_id_ = 0;
GLuint active_shader_id_ = 0; GLuint active_shader_id_ = 0;
GLuint active_texture_id_ = 0; GLuint active_texture_id_ = 0;
bool vertex_array_objects_ = false; bool vertex_array_objects_ = false;
bool npot_ = false; bool npot_ = false;
std::unordered_map<unsigned, RenderResource*> resources_;
#ifdef THREADED_RENDERING #ifdef THREADED_RENDERING
// Global commands are independent from frames and guaranteed to be processed. // Global commands are independent from frames and guaranteed to be processed.
std::deque<std::unique_ptr<RenderCommand>> global_commands_; std::deque<std::unique_ptr<RenderCommand>> global_commands_;
@ -172,7 +169,7 @@ class RendererOpenGL : public Renderer {
void ContextLost(); void ContextLost();
void InvalidateAllResources(); void DestroyAllResources();
bool StartRenderThread(); bool StartRenderThread();
void TerminateRenderThread(); void TerminateRenderThread();
@ -185,6 +182,7 @@ class RendererOpenGL : public Renderer {
void ProcessCommand(RenderCommand* cmd); void ProcessCommand(RenderCommand* cmd);
void HandleCmdPresent(RenderCommand* cmd); void HandleCmdPresent(RenderCommand* cmd);
void HandleCmdCreateTexture(RenderCommand* cmd);
void HandleCmdUpdateTexture(RenderCommand* cmd); void HandleCmdUpdateTexture(RenderCommand* cmd);
void HandleCmdDestoryTexture(RenderCommand* cmd); void HandleCmdDestoryTexture(RenderCommand* cmd);
void HandleCmdActivateTexture(RenderCommand* cmd); void HandleCmdActivateTexture(RenderCommand* cmd);
@ -201,6 +199,7 @@ class RendererOpenGL : public Renderer {
void HandleCmdSetUniformFloat(RenderCommand* cmd); void HandleCmdSetUniformFloat(RenderCommand* cmd);
void HandleCmdSetUniformInt(RenderCommand* cmd); void HandleCmdSetUniformInt(RenderCommand* cmd);
void BindTexture(GLuint id);
bool SetupVertexLayout(const VertexDescripton& vd, bool SetupVertexLayout(const VertexDescripton& vd,
GLuint vertex_size, GLuint vertex_size,
bool use_vao, bool use_vao,

View File

@ -1,16 +0,0 @@
#include "render_resource.h"
#include "renderer.h"
namespace eng {
RenderResource::RenderResource(unsigned resource_id,
std::shared_ptr<void> impl_data,
Renderer* renderer)
: resource_id_(resource_id), impl_data_(impl_data), renderer_(renderer) {}
RenderResource::~RenderResource() {
renderer_->ReleaseResource(resource_id_);
}
} // namespace eng

View File

@ -1,10 +1,7 @@
#ifndef RENDER_RESOURCE_H #ifndef RENDER_RESOURCE_H
#define RENDER_RESOURCE_H #define RENDER_RESOURCE_H
#include <array> #include <cstdint>
#include <memory>
#include <typeindex>
#include <typeinfo>
namespace eng { namespace eng {
@ -12,60 +9,22 @@ class Renderer;
class RenderResource { class RenderResource {
public: public:
RenderResource(unsigned resource_id, RenderResource(Renderer* renderer) : renderer_(renderer){};
std::shared_ptr<void> impl_data,
Renderer* renderer);
virtual ~RenderResource();
virtual void Destroy() = 0; bool IsValid() const { return resource_id_ != 0; }
bool IsValid() const { return valid_; } uint64_t resource_id() { return resource_id_; }
std::shared_ptr<void> impl_data() { return impl_data_; }
protected: protected:
unsigned resource_id_ = 0; uint64_t resource_id_ = 0;
std::shared_ptr<void> impl_data_; // For use in render thread only.
bool valid_ = false;
Renderer* renderer_ = nullptr; Renderer* renderer_ = nullptr;
~RenderResource() = default;
RenderResource(const RenderResource&) = delete; RenderResource(const RenderResource&) = delete;
RenderResource& operator=(const RenderResource&) = delete; RenderResource& operator=(const RenderResource&) = delete;
}; };
class RenderResourceFactoryBase {
public:
RenderResourceFactoryBase(std::type_index resource_type)
: resource_type_(resource_type) {}
virtual ~RenderResourceFactoryBase() = default;
virtual std::unique_ptr<eng::RenderResource>
Create(unsigned id, std::shared_ptr<void> impl_data, Renderer* renderer) = 0;
template <typename T>
bool IsTypeOf() const {
return resource_type_ == std::type_index(typeid(T));
}
private:
std::type_index resource_type_;
};
template <typename T>
class RenderResourceFactory : public RenderResourceFactoryBase {
public:
RenderResourceFactory()
: RenderResourceFactoryBase(std::type_index(typeid(T))) {}
~RenderResourceFactory() override = default;
std::unique_ptr<eng::RenderResource> Create(unsigned id,
std::shared_ptr<void> impl_data,
Renderer* renderer) override {
return std::make_unique<T>(id, impl_data, renderer);
}
};
} // namespace eng } // namespace eng
#endif // RENDER_RESOURCE_H #endif // RENDER_RESOURCE_H

View File

@ -40,51 +40,46 @@ class Renderer {
virtual void Shutdown() = 0; virtual void Shutdown() = 0;
virtual void CreateGeometry(std::shared_ptr<void> impl_data, virtual uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) = 0;
std::unique_ptr<Mesh> mesh) = 0; virtual void DestroyGeometry(uint64_t resource_id) = 0;
virtual void DestroyGeometry(std::shared_ptr<void> impl_data) = 0; virtual void Draw(uint64_t resource_id) = 0;
virtual void Draw(std::shared_ptr<void> impl_data) = 0;
virtual void UpdateTexture(std::shared_ptr<void> impl_data, virtual uint64_t CreateTexture() = 0;
virtual void UpdateTexture(uint64_t resource_id,
std::unique_ptr<Image> image) = 0; std::unique_ptr<Image> image) = 0;
virtual void DestroyTexture(std::shared_ptr<void> impl_data) = 0; virtual void DestroyTexture(uint64_t resource_id) = 0;
virtual void ActivateTexture(std::shared_ptr<void> impl_data) = 0; virtual void ActivateTexture(uint64_t resource_id) = 0;
virtual void CreateShader(std::shared_ptr<void> impl_data, virtual uint64_t CreateShader(std::unique_ptr<ShaderSource> source,
std::unique_ptr<ShaderSource> source,
const VertexDescripton& vertex_description, const VertexDescripton& vertex_description,
Primitive primitive, Primitive primitive,
bool enable_depth_test) = 0; bool enable_depth_test) = 0;
virtual void DestroyShader(std::shared_ptr<void> impl_data) = 0; virtual void DestroyShader(uint64_t resource_id) = 0;
virtual void ActivateShader(std::shared_ptr<void> impl_data) = 0; virtual void ActivateShader(uint64_t resource_id) = 0;
virtual void SetUniform(std::shared_ptr<void> impl_data, virtual void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector2f& val) = 0; const base::Vector2f& val) = 0;
virtual void SetUniform(std::shared_ptr<void> impl_data, virtual void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector3f& val) = 0; const base::Vector3f& val) = 0;
virtual void SetUniform(std::shared_ptr<void> impl_data, virtual void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector4f& val) = 0; const base::Vector4f& val) = 0;
virtual void SetUniform(std::shared_ptr<void> impl_data, virtual void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Matrix4f& val) = 0; const base::Matrix4f& val) = 0;
virtual void SetUniform(std::shared_ptr<void> impl_data, virtual void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
float val) = 0; float val) = 0;
virtual void SetUniform(std::shared_ptr<void> impl_data, virtual void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
int val) = 0; int val) = 0;
virtual void UploadUniforms(std::shared_ptr<void> impl_data) = 0; virtual void UploadUniforms(uint64_t resource_id) = 0;
virtual void PrepareForDrawing() = 0; virtual void PrepareForDrawing() = 0;
virtual void Present() = 0; virtual void Present() = 0;
virtual std::unique_ptr<RenderResource> CreateResource(
RenderResourceFactoryBase& factory) = 0;
virtual void ReleaseResource(unsigned resource_id) = 0;
bool SupportsETC1() const { return texture_compression_.etc1; } bool SupportsETC1() const { return texture_compression_.etc1; }
bool SupportsDXT1() const { bool SupportsDXT1() const {
return texture_compression_.dxt1 || texture_compression_.s3tc; return texture_compression_.dxt1 || texture_compression_.s3tc;

View File

@ -7,10 +7,7 @@ using namespace base;
namespace eng { namespace eng {
Shader::Shader(unsigned resource_id, Shader::Shader(Renderer* renderer) : RenderResource(renderer) {}
std::shared_ptr<void> impl_data,
Renderer* renderer)
: RenderResource(resource_id, impl_data, renderer) {}
Shader::~Shader() { Shader::~Shader() {
Destroy(); Destroy();
@ -21,56 +18,55 @@ void Shader::Create(std::unique_ptr<ShaderSource> source,
Primitive primitive, Primitive primitive,
bool enable_depth_test) { bool enable_depth_test) {
Destroy(); Destroy();
valid_ = true; resource_id_ = renderer_->CreateShader(std::move(source), vd, primitive,
renderer_->CreateShader(impl_data_, std::move(source), vd, primitive,
enable_depth_test); enable_depth_test);
} }
void Shader::Destroy() { void Shader::Destroy() {
if (valid_) { if (IsValid()) {
renderer_->DestroyShader(impl_data_); renderer_->DestroyShader(resource_id_);
valid_ = false; resource_id_ = 0;
} }
} }
void Shader::Activate() { void Shader::Activate() {
if (valid_) if (IsValid())
renderer_->ActivateShader(impl_data_); renderer_->ActivateShader(resource_id_);
} }
void Shader::SetUniform(const std::string& name, const Vector2f& v) { void Shader::SetUniform(const std::string& name, const Vector2f& v) {
if (valid_) if (IsValid())
renderer_->SetUniform(impl_data_, name, v); renderer_->SetUniform(resource_id_, name, v);
} }
void Shader::SetUniform(const std::string& name, const Vector3f& v) { void Shader::SetUniform(const std::string& name, const Vector3f& v) {
if (valid_) if (IsValid())
renderer_->SetUniform(impl_data_, name, v); renderer_->SetUniform(resource_id_, name, v);
} }
void Shader::SetUniform(const std::string& name, const Vector4f& v) { void Shader::SetUniform(const std::string& name, const Vector4f& v) {
if (valid_) if (IsValid())
renderer_->SetUniform(impl_data_, name, v); renderer_->SetUniform(resource_id_, name, v);
} }
void Shader::SetUniform(const std::string& name, const Matrix4f& m) { void Shader::SetUniform(const std::string& name, const Matrix4f& m) {
if (valid_) if (IsValid())
renderer_->SetUniform(impl_data_, name, m); renderer_->SetUniform(resource_id_, name, m);
} }
void Shader::SetUniform(const std::string& name, float f) { void Shader::SetUniform(const std::string& name, float f) {
if (valid_) if (IsValid())
renderer_->SetUniform(impl_data_, name, f); renderer_->SetUniform(resource_id_, name, f);
} }
void Shader::SetUniform(const std::string& name, int i) { void Shader::SetUniform(const std::string& name, int i) {
if (valid_) if (IsValid())
renderer_->SetUniform(impl_data_, name, i); renderer_->SetUniform(resource_id_, name, i);
} }
void Shader::UploadUniforms() { void Shader::UploadUniforms() {
if (valid_) if (IsValid())
renderer_->UploadUniforms(impl_data_); renderer_->UploadUniforms(resource_id_);
} }
} // namespace eng } // namespace eng

View File

@ -15,17 +15,15 @@ class ShaderSource;
class Shader : public RenderResource { class Shader : public RenderResource {
public: public:
Shader(unsigned resource_id, Shader(Renderer* renderer);
std::shared_ptr<void> impl_data, ~Shader();
Renderer* renderer);
~Shader() override;
void Create(std::unique_ptr<ShaderSource> source, void Create(std::unique_ptr<ShaderSource> source,
const VertexDescripton& vd, const VertexDescripton& vd,
Primitive primitive, Primitive primitive,
bool enable_depth_test); bool enable_depth_test);
void Destroy() override; void Destroy();
void Activate(); void Activate();

View File

@ -6,33 +6,31 @@
namespace eng { namespace eng {
Texture::Texture(unsigned resource_id, Texture::Texture(Renderer* renderer) : RenderResource(renderer) {}
std::shared_ptr<void> impl_data,
Renderer* renderer)
: RenderResource(resource_id, impl_data, renderer) {}
Texture::~Texture() { Texture::~Texture() {
Destroy(); Destroy();
} }
void Texture::Update(std::unique_ptr<Image> image) { void Texture::Update(std::unique_ptr<Image> image) {
valid_ = true; if (!IsValid())
resource_id_ = renderer_->CreateTexture();
width_ = image->GetWidth(); width_ = image->GetWidth();
height_ = image->GetHeight(); height_ = image->GetHeight();
renderer_->UpdateTexture(impl_data_, std::move(image)); renderer_->UpdateTexture(resource_id_, std::move(image));
} }
void Texture::Destroy() { void Texture::Destroy() {
if (valid_) { if (IsValid()) {
renderer_->DestroyTexture(impl_data_); renderer_->DestroyTexture(resource_id_);
valid_ = false; resource_id_ = 0;
DLOG << "Texture destroyed. resource_id: " << resource_id_; DLOG << "Texture destroyed. resource_id: " << resource_id_;
} }
} }
void Texture::Activate() { void Texture::Activate() {
if (valid_) if (IsValid())
renderer_->ActivateTexture(impl_data_); renderer_->ActivateTexture(resource_id_);
} }
} // namespace eng } // namespace eng

View File

@ -13,15 +13,12 @@ class Renderer;
class Texture : public RenderResource { class Texture : public RenderResource {
public: public:
Texture(unsigned resource_id, Texture(Renderer* renderer);
std::shared_ptr<void> impl_data, ~Texture();
Renderer* renderer);
~Texture() override;
// Uploads image.
void Update(std::unique_ptr<Image> image); void Update(std::unique_ptr<Image> image);
void Destroy() override; void Destroy();
void Activate(); void Activate();

View File

@ -259,39 +259,39 @@ RendererVulkan::RendererVulkan() = default;
RendererVulkan::~RendererVulkan() = default; RendererVulkan::~RendererVulkan() = default;
void RendererVulkan::CreateGeometry(std::shared_ptr<void> impl_data, uint64_t RendererVulkan::CreateGeometry(std::unique_ptr<Mesh> mesh) {
std::unique_ptr<Mesh> mesh) { auto& geometry = geometries_[++last_resource_id_] = {};
auto geometry = reinterpret_cast<GeometryVulkan*>(impl_data.get());
geometry->num_vertices = mesh->num_vertices(); geometry.num_vertices = mesh->num_vertices();
size_t vertex_data_size = mesh->GetVertexSize() * geometry->num_vertices; size_t vertex_data_size = mesh->GetVertexSize() * geometry.num_vertices;
size_t index_data_size = 0; size_t index_data_size = 0;
if (mesh->GetIndices()) { if (mesh->GetIndices()) {
geometry->num_indices = mesh->num_indices(); geometry.num_indices = mesh->num_indices();
geometry->index_type = GetIndexType(mesh->index_description()); geometry.index_type = GetIndexType(mesh->index_description());
index_data_size = mesh->GetIndexSize() * geometry->num_indices; index_data_size = mesh->GetIndexSize() * geometry.num_indices;
} }
size_t data_size = vertex_data_size + index_data_size; size_t data_size = vertex_data_size + index_data_size;
AllocateBuffer(geometry->buffer, data_size, AllocateBuffer(geometry.buffer, data_size,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VMA_MEMORY_USAGE_GPU_ONLY); VMA_MEMORY_USAGE_GPU_ONLY);
task_runner_.PostTask(HERE, std::bind(&RendererVulkan::UpdateBuffer, this, task_runner_.PostTask(HERE, std::bind(&RendererVulkan::UpdateBuffer, this,
std::get<0>(geometry->buffer), 0, std::get<0>(geometry.buffer), 0,
mesh->GetVertices(), vertex_data_size)); mesh->GetVertices(), vertex_data_size));
if (geometry->num_indices > 0) { if (geometry.num_indices > 0) {
geometry->indices_offset = vertex_data_size; geometry.indices_offset = vertex_data_size;
task_runner_.PostTask( task_runner_.PostTask(
HERE, std::bind(&RendererVulkan::UpdateBuffer, this, HERE, std::bind(&RendererVulkan::UpdateBuffer, this,
std::get<0>(geometry->buffer), geometry->indices_offset, std::get<0>(geometry.buffer), geometry.indices_offset,
mesh->GetIndices(), index_data_size)); mesh->GetIndices(), index_data_size));
} }
task_runner_.PostTask(HERE, task_runner_.PostTask(HERE,
std::bind(&RendererVulkan::BufferMemoryBarrier, this, std::bind(&RendererVulkan::BufferMemoryBarrier, this,
std::get<0>(geometry->buffer), 0, data_size, std::get<0>(geometry.buffer), 0, data_size,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
@ -301,70 +301,87 @@ void RendererVulkan::CreateGeometry(std::shared_ptr<void> impl_data,
std::unique_ptr<Mesh> own(mesh); std::unique_ptr<Mesh> own(mesh);
}); });
semaphore_.Release(); semaphore_.Release();
return last_resource_id_;
} }
void RendererVulkan::DestroyGeometry(std::shared_ptr<void> impl_data) { void RendererVulkan::DestroyGeometry(uint64_t resource_id) {
auto geometry = reinterpret_cast<GeometryVulkan*>(impl_data.get()); auto it = geometries_.find(resource_id);
FreeBuffer(std::move(geometry->buffer)); if (it == geometries_.end())
geometry = {}; return;
FreeBuffer(std::move(it->second.buffer));
geometries_.erase(it);
} }
void RendererVulkan::Draw(std::shared_ptr<void> impl_data) { void RendererVulkan::Draw(uint64_t resource_id) {
auto geometry = reinterpret_cast<GeometryVulkan*>(impl_data.get()); auto it = geometries_.find(resource_id);
if (it == geometries_.end())
return;
VkDeviceSize offset = 0; VkDeviceSize offset = 0;
vkCmdBindVertexBuffers(frames_[current_frame_].draw_command_buffer, 0, 1, vkCmdBindVertexBuffers(frames_[current_frame_].draw_command_buffer, 0, 1,
&std::get<0>(geometry->buffer), &offset); &std::get<0>(it->second.buffer), &offset);
if (geometry->num_indices > 0) { if (it->second.num_indices > 0) {
vkCmdBindIndexBuffer(frames_[current_frame_].draw_command_buffer, vkCmdBindIndexBuffer(frames_[current_frame_].draw_command_buffer,
std::get<0>(geometry->buffer), std::get<0>(it->second.buffer),
geometry->indices_offset, geometry->index_type); it->second.indices_offset, it->second.index_type);
vkCmdDrawIndexed(frames_[current_frame_].draw_command_buffer, vkCmdDrawIndexed(frames_[current_frame_].draw_command_buffer,
geometry->num_indices, 1, 0, 0, 0); it->second.num_indices, 1, 0, 0, 0);
} else { } else {
vkCmdDraw(frames_[current_frame_].draw_command_buffer, vkCmdDraw(frames_[current_frame_].draw_command_buffer,
geometry->num_vertices, 1, 0, 0); it->second.num_vertices, 1, 0, 0);
} }
} }
void RendererVulkan::UpdateTexture(std::shared_ptr<void> impl_data, uint64_t RendererVulkan::CreateTexture() {
textures_.insert({++last_resource_id_, {}});
return last_resource_id_;
}
void RendererVulkan::UpdateTexture(uint64_t resource_id,
std::unique_ptr<Image> image) { std::unique_ptr<Image> image) {
auto texture = reinterpret_cast<TextureVulkan*>(impl_data.get()); auto it = textures_.find(resource_id);
if (it == textures_.end())
return;
VkImageLayout old_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkImageLayout old_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkFormat format = GetImageFormat(image->GetFormat()); VkFormat format = GetImageFormat(image->GetFormat());
if (texture->view != VK_NULL_HANDLE && if (it->second.view != VK_NULL_HANDLE &&
(texture->width != image->GetWidth() || (it->second.width != image->GetWidth() ||
texture->height != image->GetHeight())) { it->second.height != image->GetHeight())) {
// Size mismatch. Recreate the texture. // Size mismatch. Recreate the texture.
FreeTexture(std::move(texture->image), texture->view, FreeTexture(std::move(it->second.image), it->second.view,
std::move(texture->desc_set)); std::move(it->second.desc_set));
*texture = {}; it->second = {};
} }
if (texture->view == VK_NULL_HANDLE) { if (it->second.view == VK_NULL_HANDLE) {
CreateTexture(texture->image, texture->view, texture->desc_set, format, CreateTexture(it->second.image, it->second.view, it->second.desc_set,
image->GetWidth(), image->GetHeight(), format, image->GetWidth(), image->GetHeight(),
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VMA_MEMORY_USAGE_GPU_ONLY); VMA_MEMORY_USAGE_GPU_ONLY);
old_layout = VK_IMAGE_LAYOUT_UNDEFINED; old_layout = VK_IMAGE_LAYOUT_UNDEFINED;
texture->width = image->GetWidth(); it->second.width = image->GetWidth();
texture->height = image->GetHeight(); it->second.height = image->GetHeight();
} }
task_runner_.PostTask( task_runner_.PostTask(
HERE, HERE,
std::bind(&RendererVulkan::ImageMemoryBarrier, this, std::bind(&RendererVulkan::ImageMemoryBarrier, this,
std::get<0>(texture->image), std::get<0>(it->second.image),
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT,
old_layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)); old_layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL));
task_runner_.PostTask( task_runner_.PostTask(
HERE, std::bind(&RendererVulkan::UpdateImage, this, HERE, std::bind(&RendererVulkan::UpdateImage, this,
std::get<0>(texture->image), format, image->GetBuffer(), std::get<0>(it->second.image), format, image->GetBuffer(),
image->GetWidth(), image->GetHeight())); image->GetWidth(), image->GetHeight()));
task_runner_.PostTask( task_runner_.PostTask(
HERE, std::bind(&RendererVulkan::ImageMemoryBarrier, this, HERE,
std::get<0>(texture->image), VK_ACCESS_TRANSFER_WRITE_BIT, std::bind(&RendererVulkan::ImageMemoryBarrier, this,
std::get<0>(it->second.image), VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
@ -378,26 +395,30 @@ void RendererVulkan::UpdateTexture(std::shared_ptr<void> impl_data,
semaphore_.Release(); semaphore_.Release();
} }
void RendererVulkan::DestroyTexture(std::shared_ptr<void> impl_data) { void RendererVulkan::DestroyTexture(uint64_t resource_id) {
auto texture = reinterpret_cast<TextureVulkan*>(impl_data.get()); auto it = textures_.find(resource_id);
FreeTexture(std::move(texture->image), texture->view, if (it == textures_.end())
std::move(texture->desc_set)); return;
*texture = {};
FreeTexture(std::move(it->second.image), it->second.view,
std::move(it->second.desc_set));
textures_.erase(it);
} }
void RendererVulkan::ActivateTexture(std::shared_ptr<void> impl_data) { void RendererVulkan::ActivateTexture(uint64_t resource_id) {
auto texture = reinterpret_cast<TextureVulkan*>(impl_data.get()); auto it = textures_.find(resource_id);
if (it == textures_.end())
return;
// Keep as pengind and bind later in ActivateShader. // Keep as pengind and bind later in ActivateShader.
penging_descriptor_sets_[/*TODO*/ 0] = std::get<0>(texture->desc_set); penging_descriptor_sets_[/*TODO*/ 0] = std::get<0>(it->second.desc_set);
} }
void RendererVulkan::CreateShader(std::shared_ptr<void> impl_data, uint64_t RendererVulkan::CreateShader(
std::unique_ptr<ShaderSource> source, std::unique_ptr<ShaderSource> source,
const VertexDescripton& vertex_description, const VertexDescripton& vertex_description,
Primitive primitive, Primitive primitive,
bool enable_depth_test) { bool enable_depth_test) {
auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get());
auto it = spirv_cache_.find(source->name()); auto it = spirv_cache_.find(source->name());
if (it == spirv_cache_.end()) { if (it == spirv_cache_.end()) {
std::array<std::vector<uint8_t>, 2> spirv; std::array<std::vector<uint8_t>, 2> spirv;
@ -426,7 +447,7 @@ void RendererVulkan::CreateShader(std::shared_ptr<void> impl_data,
if (vkCreateShaderModule(device_, &shader_module_info, nullptr, if (vkCreateShaderModule(device_, &shader_module_info, nullptr,
&vert_shader_module) != VK_SUCCESS) { &vert_shader_module) != VK_SUCCESS) {
DLOG << "vkCreateShaderModule failed!"; DLOG << "vkCreateShaderModule failed!";
return; return 0;
} }
} }
@ -441,12 +462,14 @@ void RendererVulkan::CreateShader(std::shared_ptr<void> impl_data,
if (vkCreateShaderModule(device_, &shader_module_info, nullptr, if (vkCreateShaderModule(device_, &shader_module_info, nullptr,
&frag_shader_module) != VK_SUCCESS) { &frag_shader_module) != VK_SUCCESS) {
DLOG << "vkCreateShaderModule failed!"; DLOG << "vkCreateShaderModule failed!";
return; return 0;
} }
} }
auto& shader = shaders_[++last_resource_id_] = {};
if (!CreatePipelineLayout(shader, spirv_vertex, spirv_fragment)) if (!CreatePipelineLayout(shader, spirv_vertex, spirv_fragment))
return; DLOG << "Failed to create pipeline layout!";
VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; VkPipelineShaderStageCreateInfo vert_shader_stage_info{};
vert_shader_stage_info.sType = vert_shader_stage_info.sType =
@ -567,97 +590,125 @@ void RendererVulkan::CreateShader(std::shared_ptr<void> impl_data,
pipeline_info.pColorBlendState = &color_blending; pipeline_info.pColorBlendState = &color_blending;
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;
if (vkCreateGraphicsPipelines(device_, VK_NULL_HANDLE, 1, &pipeline_info, if (vkCreateGraphicsPipelines(device_, VK_NULL_HANDLE, 1, &pipeline_info,
nullptr, &shader->pipeline) != VK_SUCCESS) nullptr, &shader.pipeline) != VK_SUCCESS)
DLOG << "failed to create graphics pipeline."; DLOG << "failed to create graphics pipeline.";
vkDestroyShaderModule(device_, frag_shader_module, nullptr); vkDestroyShaderModule(device_, frag_shader_module, nullptr);
vkDestroyShaderModule(device_, vert_shader_module, nullptr); vkDestroyShaderModule(device_, vert_shader_module, nullptr);
return last_resource_id_;
} }
void RendererVulkan::DestroyShader(std::shared_ptr<void> impl_data) { void RendererVulkan::DestroyShader(uint64_t resource_id) {
auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get()); auto it = shaders_.find(resource_id);
if (it == shaders_.end())
return;
frames_[current_frame_].pipelines_to_destroy.push_back( frames_[current_frame_].pipelines_to_destroy.push_back(
std::make_tuple(shader->pipeline, shader->pipeline_layout)); std::make_tuple(it->second.pipeline, it->second.pipeline_layout));
*shader = {}; shaders_.erase(it);
} }
void RendererVulkan::ActivateShader(std::shared_ptr<void> impl_data) { void RendererVulkan::ActivateShader(uint64_t resource_id) {
auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get()); auto it = shaders_.find(resource_id);
if (active_pipeline_ != shader->pipeline) { if (it == shaders_.end())
active_pipeline_ = shader->pipeline; return;
if (active_pipeline_ != it->second.pipeline) {
active_pipeline_ = it->second.pipeline;
vkCmdBindPipeline(frames_[current_frame_].draw_command_buffer, vkCmdBindPipeline(frames_[current_frame_].draw_command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS, shader->pipeline); VK_PIPELINE_BIND_POINT_GRAPHICS, it->second.pipeline);
} }
for (int i = 0; i < shader->desc_set_count; ++i) { for (int i = 0; i < it->second.desc_set_count; ++i) {
if (active_descriptor_sets_[i] != penging_descriptor_sets_[i]) { if (active_descriptor_sets_[i] != penging_descriptor_sets_[i]) {
active_descriptor_sets_[i] = penging_descriptor_sets_[i]; active_descriptor_sets_[i] = penging_descriptor_sets_[i];
vkCmdBindDescriptorSets(frames_[current_frame_].draw_command_buffer, vkCmdBindDescriptorSets(frames_[current_frame_].draw_command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_GRAPHICS,
shader->pipeline_layout, 0, 1, it->second.pipeline_layout, 0, 1,
&active_descriptor_sets_[i], 0, nullptr); &active_descriptor_sets_[i], 0, nullptr);
break; break;
} }
} }
} }
void RendererVulkan::SetUniform(std::shared_ptr<void> impl_data, void RendererVulkan::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector2f& val) { const base::Vector2f& val) {
auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get()); auto it = shaders_.find(resource_id);
SetUniformInternal(shader, name, val); if (it == shaders_.end())
return;
SetUniformInternal(it->second, name, val);
} }
void RendererVulkan::SetUniform(std::shared_ptr<void> impl_data, void RendererVulkan::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector3f& val) { const base::Vector3f& val) {
auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get()); auto it = shaders_.find(resource_id);
SetUniformInternal(shader, name, val); if (it == shaders_.end())
return;
SetUniformInternal(it->second, name, val);
} }
void RendererVulkan::SetUniform(std::shared_ptr<void> impl_data, void RendererVulkan::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector4f& val) { const base::Vector4f& val) {
auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get()); auto it = shaders_.find(resource_id);
SetUniformInternal(shader, name, val); if (it == shaders_.end())
return;
SetUniformInternal(it->second, name, val);
} }
void RendererVulkan::SetUniform(std::shared_ptr<void> impl_data, void RendererVulkan::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Matrix4f& val) { const base::Matrix4f& val) {
auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get()); auto it = shaders_.find(resource_id);
SetUniformInternal(shader, name, val); if (it == shaders_.end())
return;
SetUniformInternal(it->second, name, val);
} }
void RendererVulkan::SetUniform(std::shared_ptr<void> impl_data, void RendererVulkan::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
float val) { float val) {
auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get()); auto it = shaders_.find(resource_id);
SetUniformInternal(shader, name, val); if (it == shaders_.end())
return;
SetUniformInternal(it->second, name, val);
} }
void RendererVulkan::SetUniform(std::shared_ptr<void> impl_data, void RendererVulkan::SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
int val) { int val) {
auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get()); auto it = shaders_.find(resource_id);
for (auto& sampler_name : shader->sampler_uniform_names) { if (it == shaders_.end())
return;
for (auto& sampler_name : it->second.sampler_uniform_names) {
if (name == sampler_name) if (name == sampler_name)
return; return;
} }
SetUniformInternal(shader, name, val); SetUniformInternal(it->second, name, val);
} }
void RendererVulkan::UploadUniforms(std::shared_ptr<void> impl_data) { void RendererVulkan::UploadUniforms(uint64_t resource_id) {
auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get()); auto it = shaders_.find(resource_id);
if (it == shaders_.end())
return;
vkCmdPushConstants( vkCmdPushConstants(
frames_[current_frame_].draw_command_buffer, shader->pipeline_layout, frames_[current_frame_].draw_command_buffer, it->second.pipeline_layout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
shader->push_constants_size, shader->push_constants.get()); it->second.push_constants_size, it->second.push_constants.get());
} }
void RendererVulkan::PrepareForDrawing() { void RendererVulkan::PrepareForDrawing() {
@ -818,7 +869,7 @@ void RendererVulkan::Shutdown() {
return; return;
LOG << "Shutting down renderer."; LOG << "Shutting down renderer.";
InvalidateAllResources(); DestroyAllResources();
quit_.store(true, std::memory_order_relaxed); quit_.store(true, std::memory_order_relaxed);
semaphore_.Release(); semaphore_.Release();
@ -1520,7 +1571,7 @@ void RendererVulkan::ImageMemoryBarrier(VkImage image,
} }
bool RendererVulkan::CreatePipelineLayout( bool RendererVulkan::CreatePipelineLayout(
ShaderVulkan* shader, ShaderVulkan& shader,
const std::vector<uint8_t>& spirv_vertex, const std::vector<uint8_t>& spirv_vertex,
const std::vector<uint8_t>& spirv_fragment) { const std::vector<uint8_t>& spirv_fragment) {
SpvReflectShaderModule module_vertex; SpvReflectShaderModule module_vertex;
@ -1608,14 +1659,14 @@ bool RendererVulkan::CreatePipelineLayout(
break; break;
} }
shader->sampler_uniform_names.push_back(binding.name); shader.sampler_uniform_names.push_back(binding.name);
shader->desc_set_count++; shader.desc_set_count++;
} }
} }
if (active_descriptor_sets_.size() < shader->desc_set_count) { if (active_descriptor_sets_.size() < shader.desc_set_count) {
active_descriptor_sets_.resize(shader->desc_set_count); active_descriptor_sets_.resize(shader.desc_set_count);
penging_descriptor_sets_.resize(shader->desc_set_count); penging_descriptor_sets_.resize(shader.desc_set_count);
} }
// Parse push constants. // Parse push constants.
@ -1679,10 +1730,10 @@ bool RendererVulkan::CreatePipelineLayout(
break; break;
} }
shader->push_constants_size = pconstants_vertex[0]->size; shader.push_constants_size = pconstants_vertex[0]->size;
shader->push_constants = shader.push_constants =
std::make_unique<char[]>(shader->push_constants_size); std::make_unique<char[]>(shader.push_constants_size);
memset(shader->push_constants.get(), 0, shader->push_constants_size); memset(shader.push_constants.get(), 0, shader.push_constants_size);
size_t offset = 0; size_t offset = 0;
for (uint32_t j = 0; j < pconstants_vertex[0]->member_count; j++) { for (uint32_t j = 0; j < pconstants_vertex[0]->member_count; j++) {
@ -1691,7 +1742,7 @@ bool RendererVulkan::CreatePipelineLayout(
<< " padded_size: " << " padded_size: "
<< pconstants_vertex[0]->members[j].padded_size; << pconstants_vertex[0]->members[j].padded_size;
shader->variables[pconstants_vertex[0]->members[j].name] = { shader.variables[pconstants_vertex[0]->members[j].name] = {
pconstants_vertex[0]->members[j].size, offset}; pconstants_vertex[0]->members[j].size, offset};
offset += pconstants_vertex[0]->members[j].padded_size; offset += pconstants_vertex[0]->members[j].padded_size;
} }
@ -1716,11 +1767,11 @@ bool RendererVulkan::CreatePipelineLayout(
} }
VkPushConstantRange push_constant_range; VkPushConstantRange push_constant_range;
if (shader->push_constants_size) { if (shader.push_constants_size) {
push_constant_range.stageFlags = push_constant_range.stageFlags =
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
push_constant_range.offset = 0; push_constant_range.offset = 0;
push_constant_range.size = shader->push_constants_size; push_constant_range.size = shader.push_constants_size;
pipeline_layout_create_info.pushConstantRangeCount = 1; pipeline_layout_create_info.pushConstantRangeCount = 1;
pipeline_layout_create_info.pPushConstantRanges = &push_constant_range; pipeline_layout_create_info.pPushConstantRanges = &push_constant_range;
@ -1730,7 +1781,7 @@ bool RendererVulkan::CreatePipelineLayout(
} }
if (vkCreatePipelineLayout(device_, &pipeline_layout_create_info, nullptr, if (vkCreatePipelineLayout(device_, &pipeline_layout_create_info, nullptr,
&shader->pipeline_layout) != VK_SUCCESS) { &shader.pipeline_layout) != VK_SUCCESS) {
DLOG << "Failed to create pipeline layout!"; DLOG << "Failed to create pipeline layout!";
break; break;
} }
@ -1855,11 +1906,11 @@ void RendererVulkan::SetupThreadMain(int preallocate) {
} }
template <typename T> template <typename T>
bool RendererVulkan::SetUniformInternal(ShaderVulkan* shader, bool RendererVulkan::SetUniformInternal(ShaderVulkan& shader,
const std::string& name, const std::string& name,
T val) { T val) {
auto it = shader->variables.find(name); auto it = shader.variables.find(name);
if (it == shader->variables.end()) { if (it == shader.variables.end()) {
DLOG << "No variable found with name " << name; DLOG << "No variable found with name " << name;
return false; return false;
} }
@ -1868,8 +1919,7 @@ bool RendererVulkan::SetUniformInternal(ShaderVulkan* shader,
return false; return false;
} }
auto* dst = auto* dst = reinterpret_cast<T*>(shader.push_constants.get() + it->second[1]);
reinterpret_cast<T*>(shader->push_constants.get() + it->second[1]);
*dst = val; *dst = val;
return true; return true;
} }
@ -1881,39 +1931,32 @@ bool RendererVulkan::IsFormatSupported(VkFormat format) {
return properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; return properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
} }
std::unique_ptr<RenderResource> RendererVulkan::CreateResource(
RenderResourceFactoryBase& factory) {
static unsigned last_id = 0;
std::shared_ptr<void> impl_data;
if (factory.IsTypeOf<Geometry>())
impl_data = std::make_shared<GeometryVulkan>();
else if (factory.IsTypeOf<Shader>())
impl_data = std::make_shared<ShaderVulkan>();
else if (factory.IsTypeOf<Texture>())
impl_data = std::make_shared<TextureVulkan>();
else
NOTREACHED << "- Unknown resource type.";
unsigned resource_id = ++last_id;
auto resource = factory.Create(resource_id, impl_data, this);
resources_[resource_id] = resource.get();
return resource;
}
void RendererVulkan::ReleaseResource(unsigned resource_id) {
auto it = resources_.find(resource_id);
if (it != resources_.end())
resources_.erase(it);
}
size_t RendererVulkan::GetAndResetFPS() { size_t RendererVulkan::GetAndResetFPS() {
return context_.GetAndResetFPS(); return context_.GetAndResetFPS();
} }
void RendererVulkan::InvalidateAllResources() { void RendererVulkan::DestroyAllResources() {
for (auto& r : resources_) std::vector<uint64_t> resource_ids;
r.second->Destroy(); for (auto& r : geometries_)
resource_ids.push_back(r.first);
for (auto& r : resource_ids)
DestroyGeometry(r);
resource_ids.clear();
for (auto& r : shaders_)
resource_ids.push_back(r.first);
for (auto& r : resource_ids)
DestroyShader(r);
resource_ids.clear();
for (auto& r : textures_)
resource_ids.push_back(r.first);
for (auto& r : resource_ids)
DestroyTexture(r);
DCHECK(geometries_.size() == 0);
DCHECK(shaders_.size() == 0);
DCHECK(textures_.size() == 0);
} }
} // namespace eng } // namespace eng

View File

@ -13,7 +13,6 @@
#include "../../../base/semaphore.h" #include "../../../base/semaphore.h"
#include "../../../base/task_runner.h" #include "../../../base/task_runner.h"
#include "../../../third_party/vma/vk_mem_alloc.h" #include "../../../third_party/vma/vk_mem_alloc.h"
#include "../render_resource.h"
#include "../renderer.h" #include "../renderer.h"
namespace eng { namespace eng {
@ -33,51 +32,46 @@ class RendererVulkan : public Renderer {
void Shutdown() override; void Shutdown() override;
void CreateGeometry(std::shared_ptr<void> impl_data, uint64_t CreateGeometry(std::unique_ptr<Mesh> mesh) override;
std::unique_ptr<Mesh> mesh) override; void DestroyGeometry(uint64_t resource_id) override;
void DestroyGeometry(std::shared_ptr<void> impl_data) override; void Draw(uint64_t resource_id) override;
void Draw(std::shared_ptr<void> impl_data) override;
void UpdateTexture(std::shared_ptr<void> impl_data, uint64_t CreateTexture() override;
void UpdateTexture(uint64_t resource_id,
std::unique_ptr<Image> image) override; std::unique_ptr<Image> image) override;
void DestroyTexture(std::shared_ptr<void> impl_data) override; void DestroyTexture(uint64_t resource_id) override;
void ActivateTexture(std::shared_ptr<void> impl_data) override; void ActivateTexture(uint64_t resource_id) override;
void CreateShader(std::shared_ptr<void> impl_data, uint64_t CreateShader(std::unique_ptr<ShaderSource> source,
std::unique_ptr<ShaderSource> source,
const VertexDescripton& vertex_description, const VertexDescripton& vertex_description,
Primitive primitive, Primitive primitive,
bool enable_depth_test) override; bool enable_depth_test) override;
void DestroyShader(std::shared_ptr<void> impl_data) override; void DestroyShader(uint64_t resource_id) override;
void ActivateShader(std::shared_ptr<void> impl_data) override; void ActivateShader(uint64_t resource_id) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector2f& val) override; const base::Vector2f& val) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector3f& val) override; const base::Vector3f& val) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Vector4f& val) override; const base::Vector4f& val) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
const base::Matrix4f& val) override; const base::Matrix4f& val) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
float val) override; float val) override;
void SetUniform(std::shared_ptr<void> impl_data, void SetUniform(uint64_t resource_id,
const std::string& name, const std::string& name,
int val) override; int val) override;
void UploadUniforms(std::shared_ptr<void> impl_data) override; void UploadUniforms(uint64_t resource_id) override;
void PrepareForDrawing() override; void PrepareForDrawing() override;
void Present() override; void Present() override;
std::unique_ptr<RenderResource> CreateResource(
RenderResourceFactoryBase& factory) override;
void ReleaseResource(unsigned resource_id) override;
size_t GetAndResetFPS() override; size_t GetAndResetFPS() override;
#if defined(__linux__) && !defined(__ANDROID__) #if defined(__linux__) && !defined(__ANDROID__)
@ -155,6 +149,11 @@ class RendererVulkan : public Renderer {
VmaAllocationInfo alloc_info; VmaAllocationInfo alloc_info;
}; };
std::unordered_map<uint64_t, GeometryVulkan> geometries_;
std::unordered_map<uint64_t, ShaderVulkan> shaders_;
std::unordered_map<uint64_t, TextureVulkan> textures_;
uint64_t last_resource_id_ = 0;
VulkanContext context_; VulkanContext context_;
VmaAllocator allocator_ = nullptr; VmaAllocator allocator_ = nullptr;
@ -179,8 +178,6 @@ class RendererVulkan : public Renderer {
VkSampler sampler_ = VK_NULL_HANDLE; VkSampler sampler_ = VK_NULL_HANDLE;
std::unordered_map<unsigned, RenderResource*> resources_;
std::thread setup_thread_; std::thread setup_thread_;
base::TaskRunner task_runner_; base::TaskRunner task_runner_;
base::Semaphore semaphore_; base::Semaphore semaphore_;
@ -250,7 +247,7 @@ class RendererVulkan : public Renderer {
VkImageLayout old_layout, VkImageLayout old_layout,
VkImageLayout new_layout); VkImageLayout new_layout);
bool CreatePipelineLayout(ShaderVulkan* shader, bool CreatePipelineLayout(ShaderVulkan& shader,
const std::vector<uint8_t>& spirv_vertex, const std::vector<uint8_t>& spirv_vertex,
const std::vector<uint8_t>& spirv_fragment); const std::vector<uint8_t>& spirv_fragment);
@ -262,11 +259,11 @@ class RendererVulkan : public Renderer {
void SetupThreadMain(int preallocate); void SetupThreadMain(int preallocate);
template <typename T> template <typename T>
bool SetUniformInternal(ShaderVulkan* shader, const std::string& name, T val); bool SetUniformInternal(ShaderVulkan& shader, const std::string& name, T val);
bool IsFormatSupported(VkFormat format); bool IsFormatSupported(VkFormat format);
void InvalidateAllResources(); void DestroyAllResources();
}; };
} // namespace eng } // namespace eng