OpenGLRenderer: Use generic DeviceObject

This commit is contained in:
Lynix 2020-04-26 16:26:08 +02:00
parent b4b15f826d
commit 1c23949608
6 changed files with 137 additions and 215 deletions

View File

@ -9,41 +9,43 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/MovablePtr.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/Context.hpp>
#include <string>
namespace Nz::GL
{
template<typename C>
template<typename C, GLenum ObjectType, typename... CreateArgs>
class DeviceObject
{
public:
DeviceObject();
DeviceObject() = default;
DeviceObject(const DeviceObject&) = delete;
DeviceObject(DeviceObject&& object) noexcept;
DeviceObject(DeviceObject&& object) noexcept = default;
~DeviceObject();
bool Create(OpenGLDevice& device);
bool Create(OpenGLDevice& device, CreateArgs... args);
void Destroy();
bool IsValid() const;
Device* GetDevice() const;
VkResult GetLastErrorCode() const;
OpenGLDevice* GetDevice() const;
GLuint GetObjectId() const;
void SetDebugName(const char* name);
void SetDebugName(const std::string& name);
void SetDebugName(const std::string_view& name);
DeviceObject& operator=(const DeviceObject&) = delete;
DeviceObject& operator=(DeviceObject&& object) noexcept;
DeviceObject& operator=(DeviceObject&& object) noexcept = default;
operator VkType() const;
static constexpr GLuint InvalidObject = 0;
protected:
const Context& EnsureDeviceContext();
MovablePtr<OpenGLDevice> m_device;
GLuint m_handle;
MovableValue<GLuint> m_objectId;
};
}
#include <Nazara/OpenGLRenderer/Wrapper/DeviceObject.inl>
#endif // NAZARA_OPENGLRENDERER_VKDEVICEOBJECT_HPP
#endif

View File

@ -7,116 +7,88 @@
#include <Nazara/OpenGLRenderer/Utils.hpp>
#include <Nazara/OpenGLRenderer/Debug.hpp>
namespace Nz
namespace Nz::GL
{
namespace Vk
template<typename C, GLenum ObjectType, typename... CreateArgs>
DeviceObject<C, ObjectType, CreateArgs...>::~DeviceObject()
{
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
DeviceObject<C, VkType, CreateInfo, ObjectType>::DeviceObject() :
m_handle(VK_NULL_HANDLE)
Destroy();
}
template<typename C, GLenum ObjectType, typename... CreateArgs>
bool DeviceObject<C, ObjectType, CreateArgs...>::Create(OpenGLDevice& device, CreateArgs... args)
{
Destroy();
m_device = &device;
const Context& context = EnsureDeviceContext();
m_objectId = C::CreateHelper(*m_device, context, args...);
if (m_objectId == InvalidObject)
{
NazaraError("Failed to create OpenGL object"); //< TODO: Handle error message
return false;
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
DeviceObject<C, VkType, CreateInfo, ObjectType>::DeviceObject(DeviceObject&& object) noexcept :
m_device(std::move(object.m_device)),
m_allocator(object.m_allocator),
m_handle(object.m_handle),
m_lastErrorCode(object.m_lastErrorCode)
return true;
}
template<typename C, GLenum ObjectType, typename... CreateArgs>
void DeviceObject<C, ObjectType, CreateArgs...>::Destroy()
{
if (IsValid())
{
object.m_handle = VK_NULL_HANDLE;
const Context& context = EnsureDeviceContext();
C::DestroyHelper(*m_device, context, m_objectId);
m_objectId = InvalidObject;
}
}
template<typename C, GLenum ObjectType, typename... CreateArgs>
bool DeviceObject<C, ObjectType, CreateArgs...>::IsValid() const
{
return m_objectId != InvalidObject;
}
template<typename C, GLenum ObjectType, typename... CreateArgs>
OpenGLDevice* DeviceObject<C, ObjectType, CreateArgs...>::GetDevice() const
{
return m_device;
}
template<typename C, GLenum ObjectType, typename... CreateArgs>
GLuint DeviceObject<C, ObjectType, CreateArgs...>::GetObjectId() const
{
return m_objectId;
}
template<typename C, GLenum ObjectType, typename... CreateArgs>
void DeviceObject<C, ObjectType, CreateArgs...>::SetDebugName(const std::string_view& name)
{
const Context& context = EnsureDeviceContext();
if (context.glObjectLabel)
context.glObjectLabel(ObjectType, m_objectId, name.size(), name.data());
}
template<typename C, GLenum ObjectType, typename... CreateArgs>
const Context& DeviceObject<C, ObjectType, CreateArgs...>::EnsureDeviceContext()
{
assert(m_device);
const Context* activeContext = Context::GetCurrentContext();
if (!activeContext || activeContext->GetDevice() != m_device)
{
const Context& referenceContext = m_device->GetReferenceContext();
if (!Context::SetCurrentContext(&referenceContext))
throw std::runtime_error("failed to activate context");
return referenceContext;
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
DeviceObject<C, VkType, CreateInfo, ObjectType>::~DeviceObject()
{
Destroy();
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
bool DeviceObject<C, VkType, CreateInfo, ObjectType>::Create(Device& device, const CreateInfo& createInfo, const VkAllocationCallbacks* allocator)
{
m_device = &device;
m_lastErrorCode = C::CreateHelper(*m_device, &createInfo, allocator, &m_handle);
if (m_lastErrorCode != VkResult::VK_SUCCESS)
{
NazaraError("Failed to create OpenGL object: " + TranslateOpenGLError(m_lastErrorCode));
return false;
}
// Store the allocator to access them when needed
if (allocator)
m_allocator = *allocator;
else
m_allocator.pfnAllocation = nullptr;
return true;
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
void DeviceObject<C, VkType, CreateInfo, ObjectType>::Destroy()
{
if (IsValid())
{
C::DestroyHelper(*m_device, m_handle, (m_allocator.pfnAllocation) ? &m_allocator : nullptr);
m_handle = VK_NULL_HANDLE;
}
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
bool DeviceObject<C, VkType, CreateInfo, ObjectType>::IsValid() const
{
return m_handle != VK_NULL_HANDLE;
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
Device* DeviceObject<C, VkType, CreateInfo, ObjectType>::GetDevice() const
{
return m_device;
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
VkResult DeviceObject<C, VkType, CreateInfo, ObjectType>::GetLastErrorCode() const
{
return m_lastErrorCode;
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
void DeviceObject<C, VkType, CreateInfo, ObjectType>::SetDebugName(const char* name)
{
if (m_device->vkSetDebugUtilsObjectNameEXT)
{
VkDebugUtilsObjectNameInfoEXT debugName = { VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT };
debugName.objectType = ObjectType;
debugName.objectHandle = static_cast<UInt64>(reinterpret_cast<std::uintptr_t>(m_handle));
debugName.pObjectName = name;
m_device->vkSetDebugUtilsObjectNameEXT(*m_device, &debugName);
}
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
void DeviceObject<C, VkType, CreateInfo, ObjectType>::SetDebugName(const std::string& name)
{
return SetDebugName(name.data());
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
auto DeviceObject<C, VkType, CreateInfo, ObjectType>::operator=(DeviceObject&& object) noexcept -> DeviceObject&
{
std::swap(m_allocator, object.m_allocator);
std::swap(m_device, object.m_device);
std::swap(m_handle, object.m_handle);
std::swap(m_lastErrorCode, object.m_lastErrorCode);
return *this;
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
DeviceObject<C, VkType, CreateInfo, ObjectType>::operator VkType() const
{
return m_handle;
}
return *activeContext;
}
}

View File

@ -10,22 +10,22 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/MovableValue.hpp>
#include <Nazara/OpenGLRenderer/OpenGLDevice.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/DeviceObject.hpp>
namespace Nz::GL
{
class Shader
class Shader : public DeviceObject<Shader, GL_SHADER, GLenum>
{
friend DeviceObject;
public:
Shader() = default;
Shader(const Shader&) = delete;
Shader(Shader&&) noexcept = default;
inline ~Shader();
~Shader() = default;
inline void Compile();
inline bool Create(OpenGLDevice& device, GLenum type);
inline void Destroy();
inline bool GetCompilationStatus(std::string* error = nullptr);
inline void SetBinarySource(GLenum binaryFormat, const void* binary, GLsizei length);
@ -38,8 +38,8 @@ namespace Nz::GL
Shader& operator=(Shader&&) noexcept = default;
private:
MovablePtr<OpenGLDevice> m_device;
MovableValue<GLuint> m_shader;
static inline GLuint CreateHelper(OpenGLDevice& device, const Context& context, GLenum shaderStage);
static inline void DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId);
};
}

View File

@ -8,58 +8,32 @@
namespace Nz::GL
{
inline Shader::~Shader()
{
Destroy();
}
inline void Shader::Compile()
{
assert(m_shader);
m_device->GetReferenceContext().glCompileShader(m_shader);
}
inline bool Shader::Create(OpenGLDevice& device, GLenum type)
{
Destroy();
m_device = &device;
m_shader = device.GetReferenceContext().glCreateShader(type);
if (!m_shader)
return false; //< TODO: Handle error messages
return true;
}
inline void Shader::Destroy()
{
if (m_shader)
{
m_device->GetReferenceContext().glDeleteShader(m_shader);
m_shader = 0;
}
assert(m_objectId);
m_device->GetReferenceContext().glCompileShader(m_objectId);
}
inline bool Shader::GetCompilationStatus(std::string* error)
{
assert(m_shader);
const GL::Context& context = m_device->GetReferenceContext();
assert(m_objectId);
const Context& context = EnsureDeviceContext();
GLint success;
context.glGetShaderiv(m_shader, GL_COMPILE_STATUS, &success);
context.glGetShaderiv(m_objectId, GL_COMPILE_STATUS, &success);
if (!success)
{
if (error)
{
GLint logLength;
context.glGetShaderiv(m_shader, GL_INFO_LOG_LENGTH, &logLength);
context.glGetShaderiv(m_objectId, GL_INFO_LOG_LENGTH, &logLength);
error->resize(logLength);
if (logLength > 0)
{
GLsizei dummy;
context.glGetShaderInfoLog(m_shader, logLength, &dummy, error->data());
context.glGetShaderInfoLog(m_objectId, logLength, &dummy, error->data());
}
}
@ -71,25 +45,35 @@ namespace Nz::GL
inline void Shader::SetBinarySource(GLenum binaryFormat, const void* binary, GLsizei length)
{
assert(m_shader);
assert(m_objectId);
m_device->GetReferenceContext().glShaderBinary(1U, &m_shader.Get(), binaryFormat, binary, length);
m_device->GetReferenceContext().glShaderBinary(1U, &m_objectId.Get(), binaryFormat, binary, length);
}
inline void Shader::SetSource(const char* source, GLint length)
{
assert(m_shader);
assert(m_objectId);
m_device->GetReferenceContext().glShaderSource(m_shader, 1U, &source, &length);
m_device->GetReferenceContext().glShaderSource(m_objectId, 1U, &source, &length);
}
inline void Shader::SpecializeShader(const GLchar* pEntryPoint, GLuint numSpecializationConstants, const GLuint* pConstantIndex, const GLuint* pConstantValue)
{
assert(m_shader);
const GL::Context& context = m_device->GetReferenceContext();
assert(m_objectId);
const Context& context = EnsureDeviceContext();
assert(context.glSpecializeShaderARB);
context.glSpecializeShaderARB(m_shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue);
context.glSpecializeShaderARB(m_objectId, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue);
}
inline GLuint Shader::CreateHelper(OpenGLDevice& device, const Context& context, GLenum shaderStage)
{
return context.glCreateShader(shaderStage);
}
inline void Shader::DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId)
{
context.glDeleteShader(objectId);
}
}

View File

@ -10,19 +10,19 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/MovableValue.hpp>
#include <Nazara/OpenGLRenderer/OpenGLDevice.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/DeviceObject.hpp>
namespace Nz::GL
{
class Texture
class Texture : public DeviceObject<Texture, GL_TEXTURE>
{
friend DeviceObject;
public:
Texture() = default;
Texture(const Texture&) = delete;
Texture(Texture&&) noexcept = default;
inline ~Texture();
inline bool Create(OpenGLDevice& device);
inline void Destroy();
~Texture() = default;
inline void TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border);
inline void TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* data);
@ -32,10 +32,8 @@ namespace Nz::GL
Texture& operator=(Texture&&) noexcept = default;
private:
const Context& EnsureDeviceContext();
MovablePtr<OpenGLDevice> m_device;
MovableValue<GLuint> m_texture;
static inline GLuint CreateHelper(OpenGLDevice& device, const Context& context);
static inline void DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId);
};
}

View File

@ -8,38 +8,6 @@
namespace Nz::GL
{
inline Texture::~Texture()
{
Destroy();
}
inline bool Texture::Create(OpenGLDevice& device)
{
Destroy();
m_device = &device;
const Context& context = EnsureDeviceContext();
context.glGenTextures(1U, &m_texture.Get());
if (!m_texture)
return false; //< TODO: Handle error messages
return true;
}
inline void Texture::Destroy()
{
if (m_texture)
{
const Context& context = EnsureDeviceContext();
context.glDeleteTextures(1U, &m_texture.Get());
m_device->NotifyTextureDestruction(m_texture);
m_texture = 0;
}
}
inline void Texture::TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border)
{
return TexImage2D(level, internalFormat, width, height, border, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
@ -48,7 +16,7 @@ namespace Nz::GL
inline void Texture::TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* data)
{
const Context& context = EnsureDeviceContext();
context.BindTexture(TextureTarget::Target2D, m_texture);
context.BindTexture(TextureTarget::Target2D, m_objectId);
context.glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, border, format, type, data);
//< TODO: Handle errors
@ -57,27 +25,25 @@ namespace Nz::GL
inline void Texture::TexSubImage2D(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data)
{
const Context& context = EnsureDeviceContext();
context.BindTexture(TextureTarget::Target2D, m_texture);
context.BindTexture(TextureTarget::Target2D, m_objectId);
context.glTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, format, type, data);
//< TODO: Handle errors
}
inline const Context& Texture::EnsureDeviceContext()
inline GLuint Texture::CreateHelper(OpenGLDevice& device, const Context& context)
{
assert(m_device);
GLuint sampler = 0;
context.glGenTextures(1U, &sampler);
const Context* activeContext = Context::GetCurrentContext();
if (!activeContext || activeContext->GetDevice() != m_device)
{
const Context& referenceContext = m_device->GetReferenceContext();
if (!Context::SetCurrentContext(&referenceContext))
throw std::runtime_error("failed to activate context");
return sampler;
}
return referenceContext;
}
inline void Texture::DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId)
{
context.glDeleteTextures(1U, &objectId);
return *activeContext;
device.NotifyTextureDestruction(objectId);
}
}