Refactor various headers

This commit is contained in:
2025-06-26 22:00:28 +10:00
parent 04eec1b703
commit db7d50c371
20 changed files with 486 additions and 454 deletions

View File

@@ -27,7 +27,6 @@ set(ENGINE_SRC
platform/linux/x11/window_driver.cpp platform/linux/x11/window_driver.cpp
platform/windows/window_driver.cpp platform/windows/window_driver.cpp
platform/window_driver.cpp platform/window_driver.cpp
render/renderer.cpp
render/render_device.cpp render/render_device.cpp
render/render_driver.cpp render/render_driver.cpp
) )

View File

@@ -7,10 +7,6 @@
#pragma once #pragma once
namespace Nova { namespace Nova {
enum class WindowAPI { WAYLAND, WINDOWS, X11 };
class WindowDriver;
struct Window; struct Window;
using WindowID = Window*; using WindowID = Window*;
} // namespace Nova } // namespace Nova

View File

@@ -7,13 +7,17 @@
#pragma once #pragma once
#include <nova/api.h> #include <nova/api.h>
#include <nova/platform/window_fwd.h> #include <nova/platform/platform_structs.h>
#include <nova/render/render_fwd.h> #include <nova/render/render_structs.h>
#include <nova/types.h> #include <nova/types.h>
#include <string_view> #include <string_view>
namespace Nova { namespace Nova {
class RenderDriver;
enum class WindowAPI { WAYLAND, WINDOWS, X11 };
class NOVA_API WindowDriver { class NOVA_API WindowDriver {
public: public:
static WindowDriver* create(); static WindowDriver* create();

View File

@@ -7,15 +7,6 @@
#pragma once #pragma once
namespace Nova { namespace Nova {
enum class CullMode { NONE, FRONT, BACK };
enum class FrontFace { CLOCKWISE, COUNTER_CLOCKWISE };
enum class InputRate { VERTEX, INSTANCE };
enum class PipelineType { GRAPHICS, COMPUTE };
enum class PrimitiveTopology { POINT_LIST, LINE_LIST, LINE_STRIP, TRIANGLE_LIST, TRIANGLE_STRIP };
enum class QueueType { UNDEFINED, GRAPHICS, COMPUTE, TRANSFER };
enum class RenderAPI { DX12, VULKAN };
enum class ShaderStage { VERTEX, FRAGMENT, GEOMETRY, TESS_CONTROL, TESS_EVAL, COMPUTE, MESH, TASK };
enum class DataFormat { enum class DataFormat {
UNDEFINED, UNDEFINED,
R4G4_UNORM_PACK8, R4G4_UNORM_PACK8,
@@ -237,31 +228,4 @@ namespace Nova {
G16_B16R16_2PLANE_422_UNORM, G16_B16R16_2PLANE_422_UNORM,
G16_B16_R16_3PLANE_444_UNORM, G16_B16_R16_3PLANE_444_UNORM,
}; };
class RenderDriver;
struct RenderDevice;
struct VertexAttribute;
struct VertexBinding;
struct RenderPassParams;
struct GraphicsPipelineParams;
struct ComputePipelineParams;
struct CommandBuffer;
struct CommandPool;
struct Pipeline;
struct Queue;
struct RenderPass;
struct Shader;
struct Surface;
struct Swapchain;
using CommandBufferID = CommandBuffer*;
using CommandPoolID = CommandPool*;
using PipelineID = Pipeline*;
using QueueID = Queue*;
using RenderPassID = RenderPass*;
using ShaderID = Shader*;
using SurfaceID = Surface*;
using SwapchainID = Swapchain*;
} // namespace Nova } // namespace Nova

View File

@@ -0,0 +1,13 @@
/**
* Copyright (c) 2025, Jayden Grubb <contact@jaydengrubb.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
namespace Nova {
struct ComputePipelineParams {
// TODO
};
} // namespace Nova

View File

@@ -6,12 +6,18 @@
#pragma once #pragma once
#include <nova/render/render_fwd.h> #include <nova/render/data_format.h>
#include <nova/render/render_structs.h>
#include <nova/types.h> #include <nova/types.h>
#include <vector> #include <vector>
namespace Nova { namespace Nova {
enum class CullMode { NONE, FRONT, BACK };
enum class FrontFace { CLOCKWISE, COUNTER_CLOCKWISE };
enum class InputRate { VERTEX, INSTANCE };
enum class PrimitiveTopology { POINT_LIST, LINE_LIST, LINE_STRIP, TRIANGLE_LIST, TRIANGLE_STRIP };
struct VertexAttribute { struct VertexAttribute {
u32 binding = 0; u32 binding = 0;
u32 location = 0; u32 location = 0;
@@ -25,8 +31,6 @@ namespace Nova {
InputRate rate = InputRate::VERTEX; InputRate rate = InputRate::VERTEX;
}; };
struct RenderPassParams {};
struct GraphicsPipelineParams { struct GraphicsPipelineParams {
std::vector<ShaderID> shaders; std::vector<ShaderID> shaders;
std::vector<VertexBinding> bindings; std::vector<VertexBinding> bindings;
@@ -54,6 +58,4 @@ namespace Nova {
RenderPassID render_pass = nullptr; RenderPassID render_pass = nullptr;
u32 subpass = 0; u32 subpass = 0;
}; };
struct ComputePipelineParams {};
} // namespace Nova } // namespace Nova

View File

@@ -0,0 +1,13 @@
/**
* Copyright (c) 2025, Jayden Grubb <contact@jaydengrubb.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
namespace Nova {
struct RenderPassParams {
// TODO
};
} // namespace Nova

View File

@@ -7,7 +7,7 @@
#pragma once #pragma once
#include <nova/api.h> #include <nova/api.h>
#include <nova/render/render_fwd.h> #include <nova/render/render_structs.h>
#include <nova/types.h> #include <nova/types.h>
#include <initializer_list> #include <initializer_list>
@@ -15,13 +15,15 @@
#include <string> #include <string>
namespace Nova { namespace Nova {
struct NOVA_API RenderDevice { class RenderDriver;
enum class Vendor { UNKNOWN = 0, INTEL = 0x8086, AMD = 0x1002, NVIDIA = 0x10de };
enum class Type { OTHER = 0, INTEGRATED = 1, DISCRETE = 2, VIRTUAL = 3, CPU = 4 };
enum class DeviceVendor { UNKNOWN = 0, INTEL = 0x8086, AMD = 0x1002, NVIDIA = 0x10de };
enum class DeviceType { OTHER = 0, INTEGRATED = 1, DISCRETE = 2, VIRTUAL = 3, CPU = 4 };
struct NOVA_API RenderDevice {
std::string name; std::string name;
Vendor vendor; DeviceVendor vendor;
Type type; DeviceType type;
u32 deviceID; u32 deviceID;
void* handle; void* handle;

View File

@@ -7,14 +7,25 @@
#pragma once #pragma once
#include <nova/api.h> #include <nova/api.h>
#include <nova/platform/window_fwd.h> #include <nova/platform/platform_structs.h>
#include <nova/render/render_fwd.h> #include <nova/render/params/compute_pipeline.h>
#include <nova/render/params/graphics_pipeline.h>
#include <nova/render/params/render_pass.h>
#include <nova/render/render_device.h>
#include <nova/render/render_structs.h>
#include <nova/types.h> #include <nova/types.h>
#include <span> #include <span>
#include <string> #include <string>
namespace Nova { namespace Nova {
class WindowDriver;
enum class PipelineType { GRAPHICS, COMPUTE };
enum class QueueType { UNDEFINED, GRAPHICS, COMPUTE, TRANSFER };
enum class RenderAPI { DX12, VULKAN };
enum class ShaderStage { VERTEX, FRAGMENT, GEOMETRY, TESS_CONTROL, TESS_EVAL, COMPUTE, MESH, TASK };
class NOVA_API RenderDriver { class NOVA_API RenderDriver {
public: public:
static RenderDriver* create(RenderAPI api, WindowDriver* window_driver = nullptr); static RenderDriver* create(RenderAPI api, WindowDriver* window_driver = nullptr);

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2025, Jayden Grubb <contact@jaydengrubb.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
namespace Nova {
struct CommandBuffer;
struct CommandPool;
struct Pipeline;
struct Queue;
struct RenderPass;
struct Shader;
struct Surface;
struct Swapchain;
using CommandBufferID = CommandBuffer*;
using CommandPoolID = CommandPool*;
using PipelineID = Pipeline*;
using QueueID = Queue*;
using RenderPassID = RenderPass*;
using ShaderID = Shader*;
using SurfaceID = Surface*;
using SwapchainID = Swapchain*;
} // namespace Nova

View File

@@ -1,19 +0,0 @@
/**
* Copyright (c) 2025, Jayden Grubb <contact@jaydengrubb.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
#include <nova/api.h>
#include <nova/render/render_fwd.h>
namespace Nova {
class NOVA_API Renderer {
public:
static void init(RenderAPI api);
static void shutdown();
static RenderDriver* get_driver();
};
} // namespace Nova

View File

@@ -8,24 +8,26 @@
#include "drivers/vulkan/render_driver.h" #include "drivers/vulkan/render_driver.h"
#include "drivers/vulkan/render_structs.h"
#include <nova/core/debug.h> #include <nova/core/debug.h>
#include <nova/platform/window_driver.h> #include <nova/platform/window_driver.h>
#include <nova/render/render_device.h> #include <nova/render/render_device.h>
#include <nova/render/render_params.h>
#include <nova/version.h> #include <nova/version.h>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <algorithm> #include <algorithm>
#include <bit> #include <bit>
#include <format> #include <format>
#include <limits> #include <limits>
#include <string_view>
#define VALIDATION_LAYER "VK_LAYER_KHRONOS_validation" namespace {
#define MAX_QUEUES_PER_FAMILY 2U static constexpr u32 MAX_QUEUES_PER_FAMILY = 2;
static constexpr std::string_view VALIDATION_LAYER = "VK_LAYER_KHRONOS_validation";
using namespace Nova; static constexpr VkShaderStageFlagBits VK_SHADER_STAGE_MAP[] = {
static constexpr VkShaderStageFlagBits VK_SHADER_STAGE_MAP[] = {
VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_VERTEX_BIT,
VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
VK_SHADER_STAGE_GEOMETRY_BIT, VK_SHADER_STAGE_GEOMETRY_BIT,
@@ -34,44 +36,40 @@ static constexpr VkShaderStageFlagBits VK_SHADER_STAGE_MAP[] = {
VK_SHADER_STAGE_COMPUTE_BIT, VK_SHADER_STAGE_COMPUTE_BIT,
VK_SHADER_STAGE_MESH_BIT_EXT, VK_SHADER_STAGE_MESH_BIT_EXT,
VK_SHADER_STAGE_TASK_BIT_EXT VK_SHADER_STAGE_TASK_BIT_EXT
}; };
static constexpr VkPrimitiveTopology VK_PRIMITIVE_TOPOLOGY_MAP[] = { static constexpr VkPrimitiveTopology VK_PRIMITIVE_TOPOLOGY_MAP[] = {
VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
}; };
// clang-format off static constexpr VkCullModeFlags VK_CULL_MODE_MAP[] = {
static constexpr VkCullModeFlags VK_CULL_MODE_MAP[] = {
VK_CULL_MODE_NONE, VK_CULL_MODE_NONE,
VK_CULL_MODE_FRONT_BIT, VK_CULL_MODE_FRONT_BIT,
VK_CULL_MODE_BACK_BIT VK_CULL_MODE_BACK_BIT,
}; };
static constexpr VkFrontFace VK_FRONT_FACE_MAP[] = { static constexpr VkFrontFace VK_FRONT_FACE_MAP[] = {
VK_FRONT_FACE_COUNTER_CLOCKWISE, VK_FRONT_FACE_COUNTER_CLOCKWISE,
VK_FRONT_FACE_CLOCKWISE VK_FRONT_FACE_CLOCKWISE,
}; };
static constexpr VkVertexInputRate VK_VERTEX_INPUT_RATE_MAP[] = { static constexpr VkVertexInputRate VK_VERTEX_INPUT_RATE_MAP[] = {
VK_VERTEX_INPUT_RATE_VERTEX, VK_VERTEX_INPUT_RATE_VERTEX,
VK_VERTEX_INPUT_RATE_INSTANCE VK_VERTEX_INPUT_RATE_INSTANCE,
}; };
static constexpr VkQueueFlagBits VK_QUEUE_FLAGS_MAP[] = { static constexpr VkQueueFlagBits VK_QUEUE_FLAGS_MAP[] = {
static_cast<VkQueueFlagBits>(0), static_cast<VkQueueFlagBits>(0),
VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_GRAPHICS_BIT,
VK_QUEUE_COMPUTE_BIT, VK_QUEUE_COMPUTE_BIT,
VK_QUEUE_TRANSFER_BIT VK_QUEUE_TRANSFER_BIT,
}; };
// clang-format on static constexpr VkFormat VK_FORMAT_MAP[] = {
static constexpr VkFormat VK_FORMAT_MAP[] = {
VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED,
VK_FORMAT_R4G4_UNORM_PACK8, VK_FORMAT_R4G4_UNORM_PACK8,
VK_FORMAT_R4G4B4A4_UNORM_PACK16, VK_FORMAT_R4G4B4A4_UNORM_PACK16,
@@ -291,7 +289,10 @@ static constexpr VkFormat VK_FORMAT_MAP[] = {
VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM
}; };
} // namespace
using namespace Nova;
VulkanRenderDriver::VulkanRenderDriver(WindowDriver* p_driver) : m_window_driver(p_driver) { VulkanRenderDriver::VulkanRenderDriver(WindowDriver* p_driver) : m_window_driver(p_driver) {
NOVA_AUTO_TRACE(); NOVA_AUTO_TRACE();
@@ -1058,7 +1059,7 @@ void VulkanRenderDriver::_check_layers() {
for (const auto& layer : available) { for (const auto& layer : available) {
if (std::string_view(layer.layerName) == VALIDATION_LAYER) { if (std::string_view(layer.layerName) == VALIDATION_LAYER) {
NOVA_LOG("Using layer: {}", layer.layerName); NOVA_LOG("Using layer: {}", layer.layerName);
m_layers.push_back(VALIDATION_LAYER); m_layers.push_back(VALIDATION_LAYER.data());
return; return;
} }
} }
@@ -1104,12 +1105,13 @@ void VulkanRenderDriver::_init_hardware() {
VkPhysicalDeviceProperties properties; VkPhysicalDeviceProperties properties;
vkGetPhysicalDeviceProperties(device, &properties); vkGetPhysicalDeviceProperties(device, &properties);
m_devices.emplace_back(); m_devices.emplace_back<RenderDevice>({
m_devices.back().name = properties.deviceName; .name = properties.deviceName,
m_devices.back().vendor = static_cast<RenderDevice::Vendor>(properties.vendorID); .vendor = static_cast<DeviceVendor>(properties.vendorID),
m_devices.back().type = static_cast<RenderDevice::Type>(properties.deviceType); .type = static_cast<DeviceType>(properties.deviceType),
m_devices.back().deviceID = properties.deviceID; .deviceID = properties.deviceID,
m_devices.back().handle = device; .handle = device,
});
NOVA_LOG("Found device: {}", properties.deviceName); NOVA_LOG("Found device: {}", properties.deviceName);
} }

View File

@@ -9,62 +9,13 @@
#ifdef NOVA_VULKAN #ifdef NOVA_VULKAN
#include <nova/render/render_driver.h> #include <nova/render/render_driver.h>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
namespace Nova { namespace Nova {
struct CommandBuffer {
VkCommandBuffer handle = VK_NULL_HANDLE;
};
struct CommandPool {
VkCommandPool handle = VK_NULL_HANDLE;
std::vector<CommandBufferID> allocated_buffers;
};
struct Pipeline {
PipelineType type;
VkPipeline handle = VK_NULL_HANDLE;
VkPipelineLayout layout = VK_NULL_HANDLE;
};
struct Queue {
VkQueue handle = VK_NULL_HANDLE;
u32 family_index;
u32 queue_index;
u32 usage_count = 0;
};
struct RenderPass {
VkRenderPass handle = VK_NULL_HANDLE;
};
struct Shader {
VkShaderModule handle = VK_NULL_HANDLE;
ShaderStage stage = ShaderStage::VERTEX;
std::string name;
};
struct Surface {
VkSurfaceKHR handle = VK_NULL_HANDLE;
u32 width = 0;
u32 height = 0;
bool dirty = false; // TODO: Use state enum
};
struct Swapchain {
VkSwapchainKHR handle = VK_NULL_HANDLE;
VkFormat format = VK_FORMAT_UNDEFINED;
VkColorSpaceKHR color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
std::vector<VkImage> images;
std::vector<VkImageView> image_views;
std::vector<VkFramebuffer> framebuffers;
SurfaceID surface = nullptr;
RenderPassID render_pass = nullptr;
};
class VulkanRenderDriver final : public RenderDriver { class VulkanRenderDriver final : public RenderDriver {
public: public:
explicit VulkanRenderDriver(WindowDriver* window_driver); explicit VulkanRenderDriver(WindowDriver* window_driver);

View File

@@ -0,0 +1,70 @@
/**
* Copyright (c) 2025, Jayden Grubb <contact@jaydengrubb.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
/// NOTE: This header should only be included in implementation files
#include <nova/render/render_driver.h>
#include <nova/render/render_structs.h>
#include <nova/types.h>
#include <vulkan/vulkan.h>
#include <string>
#include <vector>
namespace Nova {
struct CommandBuffer {
VkCommandBuffer handle = VK_NULL_HANDLE;
};
struct CommandPool {
VkCommandPool handle = VK_NULL_HANDLE;
std::vector<CommandBufferID> allocated_buffers;
};
struct Pipeline {
PipelineType type;
VkPipeline handle = VK_NULL_HANDLE;
VkPipelineLayout layout = VK_NULL_HANDLE;
};
struct Queue {
VkQueue handle = VK_NULL_HANDLE;
u32 family_index;
u32 queue_index;
u32 usage_count = 0;
};
struct RenderPass {
VkRenderPass handle = VK_NULL_HANDLE;
};
struct Shader {
VkShaderModule handle = VK_NULL_HANDLE;
ShaderStage stage = ShaderStage::VERTEX;
std::string name;
};
struct Surface {
VkSurfaceKHR handle = VK_NULL_HANDLE;
u32 width = 0;
u32 height = 0;
bool dirty = false; // TODO: Use state enum
};
struct Swapchain {
VkSwapchainKHR handle = VK_NULL_HANDLE;
VkFormat format = VK_FORMAT_UNDEFINED;
VkColorSpaceKHR color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
std::vector<VkImage> images;
std::vector<VkImageView> image_views;
std::vector<VkFramebuffer> framebuffers;
SurfaceID surface = nullptr;
RenderPassID render_pass = nullptr;
};
} // namespace Nova

View File

@@ -8,8 +8,12 @@
#include "platform/linux/x11/window_driver.h" #include "platform/linux/x11/window_driver.h"
#include "platform/linux/x11/window_structs.h"
#include "platform/linux/x11/wrapper.h"
#ifdef NOVA_VULKAN #ifdef NOVA_VULKAN
#include "drivers/vulkan/render_driver.h" #include "drivers/vulkan/render_driver.h"
#include "drivers/vulkan/render_structs.h"
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <vulkan/vulkan_xlib.h> #include <vulkan/vulkan_xlib.h>

View File

@@ -8,24 +8,13 @@
#ifdef NOVA_X11 #ifdef NOVA_X11
#include <X11/Xlib.h> #include "platform/linux/x11/wrapper.h"
#include <nova/platform/window_driver.h> #include <nova/platform/window_driver.h>
#include <unordered_map> #include <unordered_map>
namespace X11 {
using Window = ::Window;
using Display = ::Display;
using Atom = ::Atom;
} // namespace X11
namespace Nova { namespace Nova {
struct Window {
X11::Window handle = 0;
int width = 0;
int height = 0;
};
class X11WindowDriver final : public WindowDriver { class X11WindowDriver final : public WindowDriver {
public: public:
X11WindowDriver(); X11WindowDriver();

View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) 2025, Jayden Grubb <contact@jaydengrubb.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
/// NOTE: This header should only be included in implementation files
#include "platform/linux/x11/wrapper.h"
#include <nova/platform/platform_structs.h>
namespace Nova {
struct Window {
X11::Window handle = 0;
int width = 0;
int height = 0;
};
} // namespace Nova

View File

@@ -0,0 +1,15 @@
/**
* Copyright (c) 2025, Jayden Grubb <contact@jaydengrubb.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
#include <X11/Xlib.h>
namespace X11 {
using Window = ::Window;
using Display = ::Display;
using Atom = ::Atom;
} // namespace X11

View File

@@ -32,16 +32,16 @@ u32 RenderDevice::choose_device(RenderDriver* p_driver, std::span<const SurfaceI
} }
switch (device.type) { switch (device.type) {
case Type::DISCRETE: case DeviceType::DISCRETE:
score += prefer_discrete ? 4 : 3; score += prefer_discrete ? 4 : 3;
break; break;
case Type::INTEGRATED: case DeviceType::INTEGRATED:
score += prefer_discrete ? 3 : 4; score += prefer_discrete ? 3 : 4;
break; break;
case Type::VIRTUAL: case DeviceType::VIRTUAL:
score += 2; score += 2;
break; break;
case Type::CPU: case DeviceType::CPU:
score += 1; score += 1;
break; break;
default: default:

View File

@@ -1,32 +0,0 @@
/**
* Copyright (c) 2025, Jayden Grubb <contact@jaydengrubb.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <nova/core/debug.h>
#include <nova/render/render_driver.h>
#include <nova/render/renderer.h>
#include <memory>
using namespace Nova;
static std::unique_ptr<RenderDriver> s_driver;
void Renderer::init(const RenderAPI p_api) {
NOVA_AUTO_TRACE();
NOVA_ASSERT(!s_driver);
s_driver = std::unique_ptr<RenderDriver>(RenderDriver::create(p_api, nullptr));
}
void Renderer::shutdown() {
NOVA_AUTO_TRACE();
s_driver.reset();
}
RenderDriver* Renderer::get_driver() {
NOVA_ASSERT(s_driver);
return s_driver.get();
}