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/Prerequisites.hpp>
#include <Nazara/Core/MovablePtr.hpp> #include <Nazara/Core/MovablePtr.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/Context.hpp>
#include <string> #include <string>
namespace Nz::GL namespace Nz::GL
{ {
template<typename C> template<typename C, GLenum ObjectType, typename... CreateArgs>
class DeviceObject class DeviceObject
{ {
public: public:
DeviceObject(); DeviceObject() = default;
DeviceObject(const DeviceObject&) = delete; DeviceObject(const DeviceObject&) = delete;
DeviceObject(DeviceObject&& object) noexcept; DeviceObject(DeviceObject&& object) noexcept = default;
~DeviceObject(); ~DeviceObject();
bool Create(OpenGLDevice& device); bool Create(OpenGLDevice& device, CreateArgs... args);
void Destroy(); void Destroy();
bool IsValid() const; bool IsValid() const;
Device* GetDevice() const; OpenGLDevice* GetDevice() const;
VkResult GetLastErrorCode() const; GLuint GetObjectId() const;
void SetDebugName(const char* name); void SetDebugName(const std::string_view& name);
void SetDebugName(const std::string& name);
DeviceObject& operator=(const DeviceObject&) = delete; 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: protected:
const Context& EnsureDeviceContext();
MovablePtr<OpenGLDevice> m_device; MovablePtr<OpenGLDevice> m_device;
GLuint m_handle; MovableValue<GLuint> m_objectId;
}; };
} }
#include <Nazara/OpenGLRenderer/Wrapper/DeviceObject.inl> #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/Utils.hpp>
#include <Nazara/OpenGLRenderer/Debug.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)
{
}
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)
{
object.m_handle = VK_NULL_HANDLE;
}
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType>
DeviceObject<C, VkType, CreateInfo, ObjectType>::~DeviceObject()
{ {
Destroy(); Destroy();
} }
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType> template<typename C, GLenum ObjectType, typename... CreateArgs>
bool DeviceObject<C, VkType, CreateInfo, ObjectType>::Create(Device& device, const CreateInfo& createInfo, const VkAllocationCallbacks* allocator) bool DeviceObject<C, ObjectType, CreateArgs...>::Create(OpenGLDevice& device, CreateArgs... args)
{ {
Destroy();
m_device = &device; m_device = &device;
m_lastErrorCode = C::CreateHelper(*m_device, &createInfo, allocator, &m_handle);
if (m_lastErrorCode != VkResult::VK_SUCCESS) const Context& context = EnsureDeviceContext();
m_objectId = C::CreateHelper(*m_device, context, args...);
if (m_objectId == InvalidObject)
{ {
NazaraError("Failed to create OpenGL object: " + TranslateOpenGLError(m_lastErrorCode)); NazaraError("Failed to create OpenGL object"); //< TODO: Handle error message
return false; return false;
} }
// Store the allocator to access them when needed
if (allocator)
m_allocator = *allocator;
else
m_allocator.pfnAllocation = nullptr;
return true; return true;
} }
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType> template<typename C, GLenum ObjectType, typename... CreateArgs>
void DeviceObject<C, VkType, CreateInfo, ObjectType>::Destroy() void DeviceObject<C, ObjectType, CreateArgs...>::Destroy()
{ {
if (IsValid()) if (IsValid())
{ {
C::DestroyHelper(*m_device, m_handle, (m_allocator.pfnAllocation) ? &m_allocator : nullptr); const Context& context = EnsureDeviceContext();
m_handle = VK_NULL_HANDLE;
C::DestroyHelper(*m_device, context, m_objectId);
m_objectId = InvalidObject;
} }
} }
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType> template<typename C, GLenum ObjectType, typename... CreateArgs>
bool DeviceObject<C, VkType, CreateInfo, ObjectType>::IsValid() const bool DeviceObject<C, ObjectType, CreateArgs...>::IsValid() const
{ {
return m_handle != VK_NULL_HANDLE; return m_objectId != InvalidObject;
} }
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType> template<typename C, GLenum ObjectType, typename... CreateArgs>
Device* DeviceObject<C, VkType, CreateInfo, ObjectType>::GetDevice() const OpenGLDevice* DeviceObject<C, ObjectType, CreateArgs...>::GetDevice() const
{ {
return m_device; return m_device;
} }
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType> template<typename C, GLenum ObjectType, typename... CreateArgs>
VkResult DeviceObject<C, VkType, CreateInfo, ObjectType>::GetLastErrorCode() const GLuint DeviceObject<C, ObjectType, CreateArgs...>::GetObjectId() const
{ {
return m_lastErrorCode; return m_objectId;
} }
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType> template<typename C, GLenum ObjectType, typename... CreateArgs>
void DeviceObject<C, VkType, CreateInfo, ObjectType>::SetDebugName(const char* name) void DeviceObject<C, ObjectType, CreateArgs...>::SetDebugName(const std::string_view& name)
{ {
if (m_device->vkSetDebugUtilsObjectNameEXT) const Context& context = EnsureDeviceContext();
{
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); if (context.glObjectLabel)
} context.glObjectLabel(ObjectType, m_objectId, name.size(), name.data());
} }
template<typename C, typename VkType, typename CreateInfo, VkObjectType ObjectType> template<typename C, GLenum ObjectType, typename... CreateArgs>
void DeviceObject<C, VkType, CreateInfo, ObjectType>::SetDebugName(const std::string& name) const Context& DeviceObject<C, ObjectType, CreateArgs...>::EnsureDeviceContext()
{ {
return SetDebugName(name.data()); 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> return *activeContext;
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;
}
} }
} }

View File

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

View File

@ -8,58 +8,32 @@
namespace Nz::GL namespace Nz::GL
{ {
inline Shader::~Shader()
{
Destroy();
}
inline void Shader::Compile() inline void Shader::Compile()
{ {
assert(m_shader); assert(m_objectId);
m_device->GetReferenceContext().glCompileShader(m_shader); m_device->GetReferenceContext().glCompileShader(m_objectId);
}
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;
}
} }
inline bool Shader::GetCompilationStatus(std::string* error) inline bool Shader::GetCompilationStatus(std::string* error)
{ {
assert(m_shader); assert(m_objectId);
const GL::Context& context = m_device->GetReferenceContext(); const Context& context = EnsureDeviceContext();
GLint success; GLint success;
context.glGetShaderiv(m_shader, GL_COMPILE_STATUS, &success); context.glGetShaderiv(m_objectId, GL_COMPILE_STATUS, &success);
if (!success) if (!success)
{ {
if (error) if (error)
{ {
GLint logLength; GLint logLength;
context.glGetShaderiv(m_shader, GL_INFO_LOG_LENGTH, &logLength); context.glGetShaderiv(m_objectId, GL_INFO_LOG_LENGTH, &logLength);
error->resize(logLength); error->resize(logLength);
if (logLength > 0) if (logLength > 0)
{ {
GLsizei dummy; 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) 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) 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) inline void Shader::SpecializeShader(const GLchar* pEntryPoint, GLuint numSpecializationConstants, const GLuint* pConstantIndex, const GLuint* pConstantValue)
{ {
assert(m_shader); assert(m_objectId);
const GL::Context& context = m_device->GetReferenceContext(); const Context& context = EnsureDeviceContext();
assert(context.glSpecializeShaderARB); 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/Prerequisites.hpp>
#include <Nazara/Core/MovableValue.hpp> #include <Nazara/Core/MovableValue.hpp>
#include <Nazara/OpenGLRenderer/OpenGLDevice.hpp> #include <Nazara/OpenGLRenderer/OpenGLDevice.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/DeviceObject.hpp>
namespace Nz::GL namespace Nz::GL
{ {
class Texture class Texture : public DeviceObject<Texture, GL_TEXTURE>
{ {
friend DeviceObject;
public: public:
Texture() = default; Texture() = default;
Texture(const Texture&) = delete; Texture(const Texture&) = delete;
Texture(Texture&&) noexcept = default; Texture(Texture&&) noexcept = default;
inline ~Texture(); ~Texture() = default;
inline bool Create(OpenGLDevice& device);
inline void Destroy();
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);
inline void TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* data); 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; Texture& operator=(Texture&&) noexcept = default;
private: private:
const Context& EnsureDeviceContext(); static inline GLuint CreateHelper(OpenGLDevice& device, const Context& context);
static inline void DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId);
MovablePtr<OpenGLDevice> m_device;
MovableValue<GLuint> m_texture;
}; };
} }

View File

@ -8,38 +8,6 @@
namespace Nz::GL 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) 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); 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) 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(); 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); context.glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, border, format, type, data);
//< TODO: Handle errors //< 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) 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(); 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); context.glTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, format, type, data);
//< TODO: Handle errors //< 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(); return sampler;
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;
} }
return *activeContext; inline void Texture::DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId)
{
context.glDeleteTextures(1U, &objectId);
device.NotifyTextureDestruction(objectId);
} }
} }