mirror of
https://github.com/AxioDL/boo.git
synced 2025-06-07 07:03:48 +00:00
Add support for debug groups in OpenGL and Vulkan
This commit is contained in:
parent
deefc8e995
commit
ae5d7e5131
@ -15,6 +15,11 @@ endif()
|
|||||||
|
|
||||||
add_subdirectory(xxhash)
|
add_subdirectory(xxhash)
|
||||||
|
|
||||||
|
option(BOO_GRAPHICS_DEBUG_GROUPS "Enable Debug Groups for labeling graphics passes within backend API." OFF)
|
||||||
|
if (BOO_GRAPHICS_DEBUG_GROUPS)
|
||||||
|
list(APPEND _BOO_SYS_DEFINES -DBOO_GRAPHICS_DEBUG_GROUPS=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
find_package(IPP)
|
find_package(IPP)
|
||||||
if (IPP_FOUND)
|
if (IPP_FOUND)
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "IGraphicsDataFactory.hpp"
|
#include "IGraphicsDataFactory.hpp"
|
||||||
#include "boo/IWindow.hpp"
|
#include "boo/IWindow.hpp"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace boo {
|
namespace boo {
|
||||||
|
|
||||||
@ -37,6 +38,11 @@ struct IGraphicsCommandQueue {
|
|||||||
virtual void resolveDisplay(const ObjToken<ITextureR>& source) = 0;
|
virtual void resolveDisplay(const ObjToken<ITextureR>& source) = 0;
|
||||||
virtual void execute() = 0;
|
virtual void execute() = 0;
|
||||||
|
|
||||||
|
#ifdef BOO_GRAPHICS_DEBUG_GROUPS
|
||||||
|
virtual void pushDebugGroup(const char* name, const std::array<float, 4>& color = {1.f, 1.f, 1.f, 1.f}) = 0;
|
||||||
|
virtual void popDebugGroup() = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
virtual void startRenderer() = 0;
|
virtual void startRenderer() = 0;
|
||||||
virtual void stopRenderer() = 0;
|
virtual void stopRenderer() = 0;
|
||||||
};
|
};
|
||||||
|
@ -209,6 +209,13 @@ extern PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
|
|||||||
extern PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
|
extern PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
|
||||||
extern PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
|
extern PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
|
||||||
|
|
||||||
|
// VK_EXT_debug_marker
|
||||||
|
extern PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT;
|
||||||
|
extern PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT;
|
||||||
|
extern PFN_vkCmdDebugMarkerBeginEXT CmdDebugMarkerBeginEXT;
|
||||||
|
extern PFN_vkCmdDebugMarkerEndEXT CmdDebugMarkerEndEXT;
|
||||||
|
extern PFN_vkCmdDebugMarkerInsertEXT CmdDebugMarkerInsertEXT;
|
||||||
|
|
||||||
void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr);
|
void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr);
|
||||||
void init_dispatch_table_middle(VkInstance instance, bool include_bottom);
|
void init_dispatch_table_middle(VkInstance instance, bool include_bottom);
|
||||||
void init_dispatch_table_bottom(VkInstance instance, VkDevice dev);
|
void init_dispatch_table_bottom(VkInstance instance, VkDevice dev);
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
|
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
|
||||||
|
#include "boo/graphicsdev/IGraphicsCommandQueue.hpp"
|
||||||
#include "../Common.hpp"
|
#include "../Common.hpp"
|
||||||
|
|
||||||
namespace boo {
|
namespace boo {
|
||||||
@ -268,4 +269,27 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef BOO_GRAPHICS_DEBUG_GROUPS
|
||||||
|
template <typename CommandQueue>
|
||||||
|
class GraphicsDebugGroup {
|
||||||
|
/* Stack only */
|
||||||
|
void* operator new(size_t);
|
||||||
|
void operator delete(void*);
|
||||||
|
void* operator new[](size_t);
|
||||||
|
void operator delete[](void*);
|
||||||
|
CommandQueue* m_q;
|
||||||
|
public:
|
||||||
|
explicit GraphicsDebugGroup(CommandQueue* q, const char* name,
|
||||||
|
const std::array<float, 4>& color = {1.f, 1.f, 1.f, 1.f}) : m_q(q) {
|
||||||
|
m_q->pushDebugGroup(name, color);
|
||||||
|
}
|
||||||
|
~GraphicsDebugGroup() {
|
||||||
|
m_q->popDebugGroup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#define SCOPED_GRAPHICS_DEBUG_GROUP(...) GraphicsDebugGroup _GfxDbg_(__VA_ARGS__);
|
||||||
|
#else
|
||||||
|
#define SCOPED_GRAPHICS_DEBUG_GROUP(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace boo
|
} // namespace boo
|
||||||
|
@ -59,7 +59,7 @@ static logvisor::Module Log("boo::GL");
|
|||||||
class GLDataFactoryImpl;
|
class GLDataFactoryImpl;
|
||||||
struct GLCommandQueue;
|
struct GLCommandQueue;
|
||||||
|
|
||||||
class GLDataFactoryImpl : public GLDataFactory, public GraphicsDataFactoryHead {
|
class GLDataFactoryImpl final : public GLDataFactory, public GraphicsDataFactoryHead {
|
||||||
friend struct GLCommandQueue;
|
friend struct GLCommandQueue;
|
||||||
friend class GLDataFactory::Context;
|
friend class GLDataFactory::Context;
|
||||||
IGraphicsContext* m_parent;
|
IGraphicsContext* m_parent;
|
||||||
@ -1113,7 +1113,7 @@ static const size_t SEMANTIC_SIZE_TABLE[] = {0, 12, 16, 12, 16, 16, 4, 8, 16, 16
|
|||||||
static const GLenum SEMANTIC_TYPE_TABLE[] = {GL_INVALID_ENUM, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT,
|
static const GLenum SEMANTIC_TYPE_TABLE[] = {GL_INVALID_ENUM, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT,
|
||||||
GL_UNSIGNED_BYTE, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT};
|
GL_UNSIGNED_BYTE, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT};
|
||||||
|
|
||||||
struct GLCommandQueue : IGraphicsCommandQueue {
|
struct GLCommandQueue final : IGraphicsCommandQueue {
|
||||||
Platform platform() const { return IGraphicsDataFactory::Platform::OpenGL; }
|
Platform platform() const { return IGraphicsDataFactory::Platform::OpenGL; }
|
||||||
const SystemChar* platformName() const { return _SYS_STR("OpenGL"); }
|
const SystemChar* platformName() const { return _SYS_STR("OpenGL"); }
|
||||||
IGraphicsContext* m_parent = nullptr;
|
IGraphicsContext* m_parent = nullptr;
|
||||||
@ -1141,7 +1141,11 @@ struct GLCommandQueue : IGraphicsCommandQueue {
|
|||||||
DrawInstancesIndexed,
|
DrawInstancesIndexed,
|
||||||
ResolveBindTexture,
|
ResolveBindTexture,
|
||||||
GenerateMips,
|
GenerateMips,
|
||||||
Present
|
Present,
|
||||||
|
#ifdef BOO_GRAPHICS_DEBUG_GROUPS
|
||||||
|
PushDebugGroup,
|
||||||
|
PopDebugGroup,
|
||||||
|
#endif
|
||||||
} m_op;
|
} m_op;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
@ -1157,6 +1161,9 @@ struct GLCommandQueue : IGraphicsCommandQueue {
|
|||||||
size_t startInst;
|
size_t startInst;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
#ifdef BOO_GRAPHICS_DEBUG_GROUPS
|
||||||
|
std::string name;
|
||||||
|
#endif
|
||||||
ObjToken<IShaderDataBinding> binding;
|
ObjToken<IShaderDataBinding> binding;
|
||||||
ObjToken<ITexture> target;
|
ObjToken<ITexture> target;
|
||||||
ObjToken<ITextureR> source;
|
ObjToken<ITextureR> source;
|
||||||
@ -1356,20 +1363,22 @@ struct GLCommandQueue : IGraphicsCommandQueue {
|
|||||||
self->m_pendingCubeResizes.clear();
|
self->m_pendingCubeResizes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<ObjToken<IShaderDataBinding>> pendingFmtAdds;
|
||||||
|
std::vector<std::array<GLuint, 3>> pendingFmtDels;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> fmtLk(self->m_fmtMt);
|
std::lock_guard<std::recursive_mutex> fmtLk(self->m_fmtMt);
|
||||||
|
pendingFmtAdds.swap(self->m_pendingFmtAdds);
|
||||||
if (self->m_pendingFmtAdds.size()) {
|
pendingFmtDels.swap(self->m_pendingFmtDels);
|
||||||
for (ObjToken<IShaderDataBinding>& fmt : self->m_pendingFmtAdds)
|
}
|
||||||
|
if (pendingFmtAdds.size()) {
|
||||||
|
for (ObjToken<IShaderDataBinding>& fmt : pendingFmtAdds)
|
||||||
ConfigureVertexFormat(fmt.cast<GLShaderDataBinding>());
|
ConfigureVertexFormat(fmt.cast<GLShaderDataBinding>());
|
||||||
self->m_pendingFmtAdds.clear();
|
pendingFmtAdds.clear();
|
||||||
}
|
}
|
||||||
|
if (pendingFmtDels.size()) {
|
||||||
if (self->m_pendingFmtDels.size()) {
|
for (const auto& v : pendingFmtDels)
|
||||||
for (const auto& v : self->m_pendingFmtDels)
|
|
||||||
glDeleteVertexArrays(3, v.data());
|
glDeleteVertexArrays(3, v.data());
|
||||||
self->m_pendingFmtDels.clear();
|
pendingFmtDels.clear();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->m_pendingPosts2.size())
|
if (self->m_pendingPosts2.size())
|
||||||
@ -1515,7 +1524,7 @@ struct GLCommandQueue : IGraphicsCommandQueue {
|
|||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
glBlitFramebuffer(0, 0, tex->m_width, tex->m_height, 0, 0, tex->m_width, tex->m_height,
|
glBlitFramebuffer(0, 0, tex->m_width, tex->m_height, 0, 0, tex->m_width, tex->m_height,
|
||||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||||
#if 1
|
#if 0
|
||||||
/* First cubemap dump */
|
/* First cubemap dump */
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int voffset = 0;
|
int voffset = 0;
|
||||||
@ -1541,6 +1550,16 @@ struct GLCommandQueue : IGraphicsCommandQueue {
|
|||||||
self->m_parent->present();
|
self->m_parent->present();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef BOO_GRAPHICS_DEBUG_GROUPS
|
||||||
|
case Command::Op::PushDebugGroup: {
|
||||||
|
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 42, -1, cmd.name.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Command::Op::PopDebugGroup: {
|
||||||
|
glPopDebugGroup();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1732,6 +1751,7 @@ struct GLCommandQueue : IGraphicsCommandQueue {
|
|||||||
|
|
||||||
void execute() {
|
void execute() {
|
||||||
BOO_MSAN_NO_INTERCEPT
|
BOO_MSAN_NO_INTERCEPT
|
||||||
|
SCOPED_GRAPHICS_DEBUG_GROUP(this, "GLCommandQueue::execute", {1.f, 0.f, 0.f, 1.f});
|
||||||
std::unique_lock<std::mutex> lk(m_mt);
|
std::unique_lock<std::mutex> lk(m_mt);
|
||||||
m_completeBuf = m_fillBuf;
|
m_completeBuf = m_fillBuf;
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
@ -1772,6 +1792,23 @@ struct GLCommandQueue : IGraphicsCommandQueue {
|
|||||||
m_cv.notify_one();
|
m_cv.notify_one();
|
||||||
m_cmdBufs[m_fillBuf].clear();
|
m_cmdBufs[m_fillBuf].clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef BOO_GRAPHICS_DEBUG_GROUPS
|
||||||
|
void pushDebugGroup(const char* name, const std::array<float, 4>& color) {
|
||||||
|
if (GLEW_KHR_debug) {
|
||||||
|
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
|
||||||
|
cmds.emplace_back(Command::Op::PushDebugGroup);
|
||||||
|
cmds.back().name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void popDebugGroup() {
|
||||||
|
if (GLEW_KHR_debug) {
|
||||||
|
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
|
||||||
|
cmds.emplace_back(Command::Op::PopDebugGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
ObjToken<IGraphicsBufferD> GLDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count) {
|
ObjToken<IGraphicsBufferD> GLDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count) {
|
||||||
|
@ -65,7 +65,7 @@ class VulkanDataFactoryImpl;
|
|||||||
struct VulkanCommandQueue;
|
struct VulkanCommandQueue;
|
||||||
struct VulkanDescriptorPool;
|
struct VulkanDescriptorPool;
|
||||||
|
|
||||||
class VulkanDataFactoryImpl : public VulkanDataFactory, public GraphicsDataFactoryHead {
|
class VulkanDataFactoryImpl final : public VulkanDataFactory, public GraphicsDataFactoryHead {
|
||||||
friend struct VulkanCommandQueue;
|
friend struct VulkanCommandQueue;
|
||||||
friend class VulkanDataFactory::Context;
|
friend class VulkanDataFactory::Context;
|
||||||
friend struct VulkanData;
|
friend struct VulkanData;
|
||||||
@ -375,9 +375,6 @@ bool VulkanContext::initVulkan(std::string_view appName, PFN_vkGetInstanceProcAd
|
|||||||
m_instanceExtensionNames.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
m_instanceExtensionNames.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* need swapchain device extension */
|
|
||||||
m_deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
m_layerNames.push_back("VK_LAYER_LUNARG_standard_validation");
|
m_layerNames.push_back("VK_LAYER_LUNARG_standard_validation");
|
||||||
// m_layerNames.push_back("VK_LAYER_RENDERDOC_Capture");
|
// m_layerNames.push_back("VK_LAYER_RENDERDOC_Capture");
|
||||||
@ -508,14 +505,33 @@ void VulkanContext::initDevice() {
|
|||||||
vk::EnumerateDeviceExtensionProperties(m_gpus[0], nullptr, &extCount, nullptr);
|
vk::EnumerateDeviceExtensionProperties(m_gpus[0], nullptr, &extCount, nullptr);
|
||||||
std::vector<VkExtensionProperties> extensions(extCount);
|
std::vector<VkExtensionProperties> extensions(extCount);
|
||||||
vk::EnumerateDeviceExtensionProperties(m_gpus[0], nullptr, &extCount, extensions.data());
|
vk::EnumerateDeviceExtensionProperties(m_gpus[0], nullptr, &extCount, extensions.data());
|
||||||
|
bool hasSwapchain = false;
|
||||||
|
bool hasDebugMarker = false;
|
||||||
bool hasGetMemReq2 = false;
|
bool hasGetMemReq2 = false;
|
||||||
bool hasDedicatedAllocation = false;
|
bool hasDedicatedAllocation = false;
|
||||||
for (const VkExtensionProperties& ext : extensions) {
|
for (const VkExtensionProperties& ext : extensions) {
|
||||||
if (!hasGetMemReq2 && !strcmp(ext.extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME))
|
if (!hasSwapchain && !strcmp(ext.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME))
|
||||||
|
hasSwapchain = true;
|
||||||
|
else if (!hasDebugMarker && !strcmp(ext.extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME))
|
||||||
|
hasDebugMarker = true;
|
||||||
|
else if (!hasGetMemReq2 && !strcmp(ext.extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME))
|
||||||
hasGetMemReq2 = true;
|
hasGetMemReq2 = true;
|
||||||
else if (!hasDedicatedAllocation && !strcmp(ext.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME))
|
else if (!hasDedicatedAllocation && !strcmp(ext.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME))
|
||||||
hasDedicatedAllocation = true;
|
hasDedicatedAllocation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hasSwapchain)
|
||||||
|
Log.report(logvisor::Fatal, fmt("Vulkan device does not support swapchains"));
|
||||||
|
|
||||||
|
/* need swapchain device extension */
|
||||||
|
m_deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
|
#ifdef BOO_GRAPHICS_DEBUG_GROUPS
|
||||||
|
if (hasDebugMarker) {
|
||||||
|
/* Enable debug marker extension if enabled in the build system */
|
||||||
|
m_deviceExtensionNames.push_back(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
VmaAllocatorCreateFlags allocFlags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
|
VmaAllocatorCreateFlags allocFlags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
|
||||||
if (hasGetMemReq2 && hasDedicatedAllocation) {
|
if (hasGetMemReq2 && hasDedicatedAllocation) {
|
||||||
m_deviceExtensionNames.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
m_deviceExtensionNames.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
@ -2023,12 +2039,13 @@ class VulkanTextureCubeR : public GraphicsDataNode<ITextureCubeR> {
|
|||||||
texCreateInfo.extent.width = m_width;
|
texCreateInfo.extent.width = m_width;
|
||||||
texCreateInfo.extent.height = m_width;
|
texCreateInfo.extent.height = m_width;
|
||||||
texCreateInfo.extent.depth = 1;
|
texCreateInfo.extent.depth = 1;
|
||||||
texCreateInfo.mipLevels = 1;
|
texCreateInfo.mipLevels = m_mipCount;
|
||||||
texCreateInfo.arrayLayers = 6;
|
texCreateInfo.arrayLayers = 6;
|
||||||
texCreateInfo.samples = VkSampleCountFlagBits(1);
|
texCreateInfo.samples = VkSampleCountFlagBits(1);
|
||||||
texCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
texCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
texCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
texCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
texCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
texCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||||
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||||
texCreateInfo.queueFamilyIndexCount = 0;
|
texCreateInfo.queueFamilyIndexCount = 0;
|
||||||
texCreateInfo.pQueueFamilyIndices = nullptr;
|
texCreateInfo.pQueueFamilyIndices = nullptr;
|
||||||
texCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
texCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
@ -2042,12 +2059,6 @@ class VulkanTextureCubeR : public GraphicsDataNode<ITextureCubeR> {
|
|||||||
texCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
texCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
m_depthTex.createFB(ctx, &texCreateInfo);
|
m_depthTex.createFB(ctx, &texCreateInfo);
|
||||||
|
|
||||||
/* color bind target */
|
|
||||||
texCreateInfo.format = ctx->m_internalFormat;
|
|
||||||
texCreateInfo.mipLevels = m_mipCount;
|
|
||||||
texCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
m_colorBindTex.createFB(ctx, &texCreateInfo);
|
|
||||||
|
|
||||||
m_colorBindDescInfo.sampler = m_sampler;
|
m_colorBindDescInfo.sampler = m_sampler;
|
||||||
m_colorBindDescInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
m_colorBindDescInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
|
||||||
@ -2055,7 +2066,7 @@ class VulkanTextureCubeR : public GraphicsDataNode<ITextureCubeR> {
|
|||||||
VkImageViewCreateInfo viewCreateInfo = {};
|
VkImageViewCreateInfo viewCreateInfo = {};
|
||||||
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
viewCreateInfo.pNext = nullptr;
|
viewCreateInfo.pNext = nullptr;
|
||||||
viewCreateInfo.image = m_colorBindTex.m_image;
|
viewCreateInfo.image = m_colorTex.m_image;
|
||||||
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
|
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
|
||||||
viewCreateInfo.format = ctx->m_internalFormat;
|
viewCreateInfo.format = ctx->m_internalFormat;
|
||||||
viewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R;
|
viewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||||
@ -2121,11 +2132,11 @@ class VulkanTextureCubeR : public GraphicsDataNode<ITextureCubeR> {
|
|||||||
public:
|
public:
|
||||||
AllocatedImage m_colorTex;
|
AllocatedImage m_colorTex;
|
||||||
VkImageView m_colorView[6] = {};
|
VkImageView m_colorView[6] = {};
|
||||||
|
VkImageLayout m_mipsLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
|
||||||
AllocatedImage m_depthTex;
|
AllocatedImage m_depthTex;
|
||||||
VkImageView m_depthView[6] = {};
|
VkImageView m_depthView[6] = {};
|
||||||
|
|
||||||
AllocatedImage m_colorBindTex;
|
|
||||||
VkImageView m_colorBindView = VK_NULL_HANDLE;
|
VkImageView m_colorBindView = VK_NULL_HANDLE;
|
||||||
VkDescriptorImageInfo m_colorBindDescInfo = {};
|
VkDescriptorImageInfo m_colorBindDescInfo = {};
|
||||||
|
|
||||||
@ -2163,20 +2174,18 @@ public:
|
|||||||
toDepthAttachmentLayout(cmdBuf);
|
toDepthAttachmentLayout(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void toColorBindShaderReadLayout(VkCommandBuffer cmdBuf) {
|
void toColorShaderReadLayout(VkCommandBuffer cmdBuf) {
|
||||||
m_colorBindTex.toLayout(cmdBuf, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, m_mipCount, 6);
|
m_colorTex.toLayout(cmdBuf, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, m_mipCount, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
void commitLayouts() {
|
void commitLayouts() {
|
||||||
m_colorTex.commitLayout();
|
m_colorTex.commitLayout();
|
||||||
m_depthTex.commitLayout();
|
m_depthTex.commitLayout();
|
||||||
m_colorBindTex.commitLayout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rollbackLayouts() {
|
void rollbackLayouts() {
|
||||||
m_colorTex.rollbackLayout();
|
m_colorTex.rollbackLayout();
|
||||||
m_depthTex.rollbackLayout();
|
m_depthTex.rollbackLayout();
|
||||||
m_colorBindTex.rollbackLayout();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2827,7 +2836,7 @@ struct VulkanShaderDataBinding : GraphicsDataNode<IShaderDataBinding> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VulkanCommandQueue : IGraphicsCommandQueue {
|
struct VulkanCommandQueue final : IGraphicsCommandQueue {
|
||||||
Platform platform() const { return IGraphicsDataFactory::Platform::Vulkan; }
|
Platform platform() const { return IGraphicsDataFactory::Platform::Vulkan; }
|
||||||
const SystemChar* platformName() const { return _SYS_STR("Vulkan"); }
|
const SystemChar* platformName() const { return _SYS_STR("Vulkan"); }
|
||||||
VulkanContext* m_ctx;
|
VulkanContext* m_ctx;
|
||||||
@ -2964,10 +2973,12 @@ struct VulkanCommandQueue : IGraphicsCommandQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr int CubeFaceRemap[] = {0, 1, 3, 2, 4, 5};
|
||||||
int m_boundFace = 0;
|
int m_boundFace = 0;
|
||||||
void setRenderTarget(const ObjToken<ITextureCubeR>& target, int face) {
|
void setRenderTarget(const ObjToken<ITextureCubeR>& target, int face) {
|
||||||
VulkanTextureCubeR* ctarget = target.cast<VulkanTextureCubeR>();
|
VulkanTextureCubeR* ctarget = target.cast<VulkanTextureCubeR>();
|
||||||
VkCommandBuffer cmdBuf = m_cmdBufs[m_fillBuf];
|
VkCommandBuffer cmdBuf = m_cmdBufs[m_fillBuf];
|
||||||
|
face = CubeFaceRemap[face];
|
||||||
|
|
||||||
if (m_boundTarget.get() != ctarget || m_boundFace != face) {
|
if (m_boundTarget.get() != ctarget || m_boundFace != face) {
|
||||||
if (m_boundTarget)
|
if (m_boundTarget)
|
||||||
@ -3030,6 +3041,7 @@ struct VulkanCommandQueue : IGraphicsCommandQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void generateMipmaps(const ObjToken<ITextureCubeR>& tex) {
|
void generateMipmaps(const ObjToken<ITextureCubeR>& tex) {
|
||||||
|
SCOPED_GRAPHICS_DEBUG_GROUP(this, "VulkanCommandQueue::generateMipmaps", {1.f, 0.f, 0.f, 1.f});
|
||||||
VulkanTextureCubeR* ctex = tex.cast<VulkanTextureCubeR>();
|
VulkanTextureCubeR* ctex = tex.cast<VulkanTextureCubeR>();
|
||||||
VkCommandBuffer cmdBuf = m_cmdBufs[m_fillBuf];
|
VkCommandBuffer cmdBuf = m_cmdBufs[m_fillBuf];
|
||||||
if (m_boundTarget) {
|
if (m_boundTarget) {
|
||||||
@ -3039,35 +3051,6 @@ struct VulkanCommandQueue : IGraphicsCommandQueue {
|
|||||||
|
|
||||||
ctex->toColorTransferSrcLayout(cmdBuf);
|
ctex->toColorTransferSrcLayout(cmdBuf);
|
||||||
|
|
||||||
{
|
|
||||||
/* First blit performs y-inversion (can't easily invert the cube sampler or geometry) */
|
|
||||||
VkImageBlit blit = {};
|
|
||||||
|
|
||||||
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
blit.srcSubresource.layerCount = 6;
|
|
||||||
blit.srcSubresource.mipLevel = 0;
|
|
||||||
blit.srcOffsets[1].x = int32_t(ctex->m_width);
|
|
||||||
blit.srcOffsets[1].y = int32_t(ctex->m_width);
|
|
||||||
blit.srcOffsets[1].z = 1;
|
|
||||||
|
|
||||||
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
blit.dstSubresource.layerCount = 6;
|
|
||||||
blit.dstSubresource.mipLevel = 0;
|
|
||||||
|
|
||||||
blit.dstOffsets[0].y = int32_t(ctex->m_width);
|
|
||||||
blit.dstOffsets[1].x = int32_t(ctex->m_width);
|
|
||||||
blit.dstOffsets[1].z = 1;
|
|
||||||
|
|
||||||
SetImageLayout(cmdBuf, ctex->m_colorBindTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT,
|
|
||||||
ctex->m_colorBindTex.m_layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 6, 0);
|
|
||||||
|
|
||||||
vk::CmdBlitImage(cmdBuf, ctex->m_colorTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
||||||
ctex->m_colorBindTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
|
|
||||||
|
|
||||||
SetImageLayout(cmdBuf, ctex->m_colorBindTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 6, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t tmpWidth = ctex->m_width;
|
size_t tmpWidth = ctex->m_width;
|
||||||
for (size_t i = 1; i < ctex->m_mipCount; i++) {
|
for (size_t i = 1; i < ctex->m_mipCount; i++) {
|
||||||
VkImageBlit blit = {};
|
VkImageBlit blit = {};
|
||||||
@ -3088,18 +3071,18 @@ struct VulkanCommandQueue : IGraphicsCommandQueue {
|
|||||||
blit.dstOffsets[1].y = int32_t(tmpWidth);
|
blit.dstOffsets[1].y = int32_t(tmpWidth);
|
||||||
blit.dstOffsets[1].z = 1;
|
blit.dstOffsets[1].z = 1;
|
||||||
|
|
||||||
SetImageLayout(cmdBuf, ctex->m_colorBindTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT,
|
SetImageLayout(cmdBuf, ctex->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
ctex->m_colorBindTex.m_layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 6, i);
|
ctex->m_mipsLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 6, i);
|
||||||
|
|
||||||
vk::CmdBlitImage(cmdBuf, ctex->m_colorBindTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
vk::CmdBlitImage(cmdBuf, ctex->m_colorTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
ctex->m_colorBindTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
|
ctex->m_colorTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
|
||||||
|
|
||||||
SetImageLayout(cmdBuf, ctex->m_colorBindTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT,
|
SetImageLayout(cmdBuf, ctex->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 6, i);
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 6, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctex->m_colorBindTex.m_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
ctex->toColorShaderReadLayout(cmdBuf);
|
||||||
ctex->toColorBindShaderReadLayout(cmdBuf);
|
ctex->m_mipsLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void schedulePostFrameHandler(std::function<void(void)>&& func) { func(); }
|
void schedulePostFrameHandler(std::function<void(void)>&& func) { func(); }
|
||||||
@ -3426,6 +3409,26 @@ struct VulkanCommandQueue : IGraphicsCommandQueue {
|
|||||||
void _rollbackImageLayouts();
|
void _rollbackImageLayouts();
|
||||||
|
|
||||||
void execute();
|
void execute();
|
||||||
|
|
||||||
|
#ifdef BOO_GRAPHICS_DEBUG_GROUPS
|
||||||
|
void pushDebugGroup(const char* name, const std::array<float, 4>& color) {
|
||||||
|
if (vk::CmdDebugMarkerBeginEXT) {
|
||||||
|
VkCommandBuffer cmdBuf = m_cmdBufs[m_fillBuf];
|
||||||
|
VkDebugMarkerMarkerInfoEXT markerInfo = {};
|
||||||
|
markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT;
|
||||||
|
markerInfo.pMarkerName = name;
|
||||||
|
std::copy(color.begin(), color.end(), markerInfo.color);
|
||||||
|
vk::CmdDebugMarkerBeginEXT(cmdBuf, &markerInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void popDebugGroup() {
|
||||||
|
if (vk::CmdDebugMarkerEndEXT) {
|
||||||
|
VkCommandBuffer cmdBuf = m_cmdBufs[m_fillBuf];
|
||||||
|
vk::CmdDebugMarkerEndEXT(cmdBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void VulkanTextureR::doDestroy() {
|
void VulkanTextureR::doDestroy() {
|
||||||
@ -3518,7 +3521,6 @@ void VulkanTextureCubeR::doDestroy() {
|
|||||||
vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorBindView, nullptr);
|
vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorBindView, nullptr);
|
||||||
m_colorBindView = VK_NULL_HANDLE;
|
m_colorBindView = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
m_colorBindTex.destroy(m_q->m_ctx);
|
|
||||||
if (m_colorView[0]) {
|
if (m_colorView[0]) {
|
||||||
for (int i = 0; i < 6; ++i)
|
for (int i = 0; i < 6; ++i)
|
||||||
vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorView[i], nullptr);
|
vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorView[i], nullptr);
|
||||||
@ -3551,7 +3553,6 @@ VulkanTextureCubeR::~VulkanTextureCubeR() {
|
|||||||
for (int i = 0; i < 6; ++i)
|
for (int i = 0; i < 6; ++i)
|
||||||
vk::DestroyFramebuffer(m_q->m_ctx->m_dev, m_framebuffer[i], nullptr);
|
vk::DestroyFramebuffer(m_q->m_ctx->m_dev, m_framebuffer[i], nullptr);
|
||||||
vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorBindView, nullptr);
|
vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorBindView, nullptr);
|
||||||
m_colorBindTex.destroy(m_q->m_ctx);
|
|
||||||
for (int i = 0; i < 6; ++i)
|
for (int i = 0; i < 6; ++i)
|
||||||
vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorView[i], nullptr);
|
vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorView[i], nullptr);
|
||||||
m_colorTex.destroy(m_q->m_ctx);
|
m_colorTex.destroy(m_q->m_ctx);
|
||||||
@ -3945,6 +3946,8 @@ void VulkanCommandQueue::execute() {
|
|||||||
if (!m_running)
|
if (!m_running)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
SCOPED_GRAPHICS_DEBUG_GROUP(this, "VulkanCommandQueue::execute", {1.f, 0.f, 0.f, 1.f});
|
||||||
|
|
||||||
/* Stage dynamic uploads */
|
/* Stage dynamic uploads */
|
||||||
VulkanDataFactoryImpl* gfxF = static_cast<VulkanDataFactoryImpl*>(m_parent->getDataFactory());
|
VulkanDataFactoryImpl* gfxF = static_cast<VulkanDataFactoryImpl*>(m_parent->getDataFactory());
|
||||||
std::unique_lock<std::recursive_mutex> datalk(gfxF->m_dataMutex);
|
std::unique_lock<std::recursive_mutex> datalk(gfxF->m_dataMutex);
|
||||||
|
@ -183,6 +183,11 @@ PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR GetPhysicalDeviceWin32Present
|
|||||||
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
|
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
|
||||||
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
|
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
|
||||||
PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
|
PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
|
||||||
|
PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT;
|
||||||
|
PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT;
|
||||||
|
PFN_vkCmdDebugMarkerBeginEXT CmdDebugMarkerBeginEXT;
|
||||||
|
PFN_vkCmdDebugMarkerEndEXT CmdDebugMarkerEndEXT;
|
||||||
|
PFN_vkCmdDebugMarkerInsertEXT CmdDebugMarkerInsertEXT;
|
||||||
|
|
||||||
void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr) {
|
void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr) {
|
||||||
GetInstanceProcAddr = get_instance_proc_addr;
|
GetInstanceProcAddr = get_instance_proc_addr;
|
||||||
@ -636,6 +641,17 @@ void init_dispatch_table_bottom(VkInstance instance, VkDevice dev) {
|
|||||||
QueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(GetDeviceProcAddr(dev, "vkQueuePresentKHR"));
|
QueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(GetDeviceProcAddr(dev, "vkQueuePresentKHR"));
|
||||||
CreateSharedSwapchainsKHR =
|
CreateSharedSwapchainsKHR =
|
||||||
reinterpret_cast<PFN_vkCreateSharedSwapchainsKHR>(GetDeviceProcAddr(dev, "vkCreateSharedSwapchainsKHR"));
|
reinterpret_cast<PFN_vkCreateSharedSwapchainsKHR>(GetDeviceProcAddr(dev, "vkCreateSharedSwapchainsKHR"));
|
||||||
|
|
||||||
|
DebugMarkerSetObjectTagEXT = reinterpret_cast<PFN_vkDebugMarkerSetObjectTagEXT>(
|
||||||
|
GetDeviceProcAddr(dev, "vkDebugMarkerSetObjectTagEXT"));
|
||||||
|
DebugMarkerSetObjectNameEXT = reinterpret_cast<PFN_vkDebugMarkerSetObjectNameEXT>(
|
||||||
|
GetDeviceProcAddr(dev, "vkDebugMarkerSetObjectNameEXT"));
|
||||||
|
CmdDebugMarkerBeginEXT = reinterpret_cast<PFN_vkCmdDebugMarkerBeginEXT>(
|
||||||
|
GetDeviceProcAddr(dev, "vkCmdDebugMarkerBeginEXT"));
|
||||||
|
CmdDebugMarkerEndEXT = reinterpret_cast<PFN_vkCmdDebugMarkerEndEXT>(
|
||||||
|
GetDeviceProcAddr(dev, "vkCmdDebugMarkerEndEXT"));
|
||||||
|
CmdDebugMarkerInsertEXT = reinterpret_cast<PFN_vkCmdDebugMarkerInsertEXT>(
|
||||||
|
GetDeviceProcAddr(dev, "vkCmdDebugMarkerInsertEXT"));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vk
|
} // namespace vk
|
||||||
|
@ -107,14 +107,14 @@ struct Boo3DAppContext {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline std::string WCSTMBS(const wchar_t* wstr) {
|
inline std::string WCSTMBS(const wchar_t* wstr) {
|
||||||
int sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr) - 1;
|
int sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr) - 1;
|
||||||
std::string strTo(sizeNeeded, 0);
|
std::string strTo(sizeNeeded, 0);
|
||||||
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &strTo[0], sizeNeeded, nullptr, nullptr);
|
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &strTo[0], sizeNeeded, nullptr, nullptr);
|
||||||
return strTo;
|
return strTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline std::wstring MBSTWCS(const char* str) {
|
inline std::wstring MBSTWCS(const char* str) {
|
||||||
int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0) - 1;
|
int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0) - 1;
|
||||||
std::wstring strTo(sizeNeeded, 0);
|
std::wstring strTo(sizeNeeded, 0);
|
||||||
MultiByteToWideChar(CP_UTF8, 0, str, -1, &strTo[0], sizeNeeded);
|
MultiByteToWideChar(CP_UTF8, 0, str, -1, &strTo[0], sizeNeeded);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user