Add texture mapping

This commit is contained in:
Benau 2022-07-21 12:26:06 +08:00
parent fec21afc8e
commit 3d0d666e09
14 changed files with 264 additions and 33 deletions

View File

@ -1,8 +1,13 @@
layout(location = 0) in vec4 f_vertex_color;
layout(location = 1) in vec2 f_uv;
layout(location = 2) flat in int f_material_id;
layout(location = 0) out vec4 o_color;
#include "utils/sample_mesh_texture.h"
void main()
{
o_color = f_vertex_color;
vec3 mixed_color = sampleMeshTexture0(f_material_id, f_uv).xyz * f_vertex_color.xyz;
o_color = vec4(mixed_color, 1.0);
}

View File

@ -1,4 +1,4 @@
layout(std140, set = 0, binding = 0) uniform CameraBuffer
layout(std140, set = 1, binding = 0) uniform CameraBuffer
{
mat4 m_view_matrix;
mat4 m_projection_matrix;
@ -10,9 +10,12 @@ layout(std140, set = 0, binding = 0) uniform CameraBuffer
struct ObjectData
{
mat4 m_model;
int m_skinning_offest;
int m_material_id;
vec2 m_texture_trans;
};
layout(std140, set = 0, binding = 1) readonly buffer ObjectBuffer
layout(std140, set = 1, binding = 1) readonly buffer ObjectBuffer
{
ObjectData m_objects[];
} u_object_buffer;
@ -27,6 +30,8 @@ layout(location = 6) in ivec4 v_joint;
layout(location = 7) in vec4 v_weight;
layout(location = 0) out vec4 f_vertex_color;
layout(location = 1) out vec2 f_uv;
layout(location = 2) flat out int f_material_id;
void main()
{
@ -34,4 +39,6 @@ void main()
gl_Position = u_camera.m_projection_view_matrix * model_matrix *
vec4(v_position, 1.0);
f_vertex_color = v_color.zyxw;
f_uv = v_uv;
f_material_id = u_object_buffer.m_objects[gl_InstanceIndex].m_material_id;
}

View File

@ -0,0 +1,87 @@
#ifdef BIND_MESH_TEXTURES_AT_ONCE
layout(binding = 0) uniform sampler2D f_mesh_textures[SAMPLER_SIZE * TOTAL_MESH_TEXTURE_LAYER];
vec4 sampleMeshTexture0(int material_id, vec2 uv)
{
return texture(f_mesh_textures[(TOTAL_MESH_TEXTURE_LAYER * material_id) + 0], uv);
}
vec4 sampleMeshTexture1(int material_id, vec2 uv)
{
return texture(f_mesh_textures[(TOTAL_MESH_TEXTURE_LAYER * material_id) + 1], uv);
}
vec4 sampleMeshTexture2(int material_id, vec2 uv)
{
return texture(f_mesh_textures[(TOTAL_MESH_TEXTURE_LAYER * material_id) + 2], uv);
}
vec4 sampleMeshTexture3(int material_id, vec2 uv)
{
return texture(f_mesh_textures[(TOTAL_MESH_TEXTURE_LAYER * material_id) + 3], uv);
}
vec4 sampleMeshTexture4(int material_id, vec2 uv)
{
return texture(f_mesh_textures[(TOTAL_MESH_TEXTURE_LAYER * material_id) + 4], uv);
}
vec4 sampleMeshTexture5(int material_id, vec2 uv)
{
return texture(f_mesh_textures[(TOTAL_MESH_TEXTURE_LAYER * material_id) + 5], uv);
}
vec4 sampleMeshTexture6(int material_id, vec2 uv)
{
return texture(f_mesh_textures[(TOTAL_MESH_TEXTURE_LAYER * material_id) + 6], uv);
}
vec4 sampleMeshTexture7(int material_id, vec2 uv)
{
return texture(f_mesh_textures[(TOTAL_MESH_TEXTURE_LAYER * material_id) + 7], uv);
}
#else
layout(binding = 0) uniform sampler2D f_mesh_textures[TOTAL_MESH_TEXTURE_LAYER];
vec4 sampleMeshTexture0(int material_id, vec2 uv)
{
return texture(f_mesh_textures[0], uv);
}
vec4 sampleMeshTexture1(int material_id, vec2 uv)
{
return texture(f_mesh_textures[1], uv);
}
#ifdef PBR_ENABLED
vec4 sampleMeshTexture2(int material_id, vec2 uv)
{
return texture(f_mesh_textures[2], uv);
}
vec4 sampleMeshTexture3(int material_id, vec2 uv)
{
return texture(f_mesh_textures[3], uv);
}
vec4 sampleMeshTexture4(int material_id, vec2 uv)
{
return texture(f_mesh_textures[4], uv);
}
vec4 sampleMeshTexture5(int material_id, vec2 uv)
{
return texture(f_mesh_textures[5], uv);
}
vec4 sampleMeshTexture6(int material_id, vec2 uv)
{
return texture(f_mesh_textures[6], uv);
}
vec4 sampleMeshTexture7(int material_id, vec2 uv)
{
return texture(f_mesh_textures[7], uv);
}
#endif
#endif

View File

@ -25,6 +25,7 @@ namespace GE
{
class GEVulkanDepthTexture;
class GEVulkanMeshCache;
class GEVulkanTextureDescriptor;
enum GEVulkanSampler : unsigned
{
GVS_MIN = 0,
@ -343,6 +344,8 @@ namespace GE
VkFormatFeatureFlags features);
VmaAllocator getVmaAllocator() const { return m_vk->allocator; }
GEVulkanMeshCache* getVulkanMeshCache() const;
GEVulkanTextureDescriptor* getMeshTextureDescriptor() const
{ return m_mesh_texture_descriptor; }
private:
struct SwapChainSupportDetails
{
@ -469,6 +472,7 @@ namespace GE
IrrlichtDevice* m_irrlicht_device;
GEVulkanDepthTexture* m_depth_texture;
GEVulkanTextureDescriptor* m_mesh_texture_descriptor;
void createInstance(SDL_Window* window);
void findPhysicalDevice();

View File

@ -45,6 +45,8 @@ public:
const irr::core::vector3df& scale = irr::core::vector3df(1.0f, 1.0f, 1.0f),
bool alsoAddIfMeshPointerZero = false);
// ------------------------------------------------------------------------
virtual void clear();
// ------------------------------------------------------------------------
virtual void drawAll(irr::u32 flags = 0xFFFFFFFF);
// ------------------------------------------------------------------------
virtual irr::u32 registerNodeForRendering(irr::scene::ISceneNode* node,

View File

@ -54,6 +54,13 @@ public:
// ------------------------------------------------------------------------
~GEVulkanTextureDescriptor();
// ------------------------------------------------------------------------
void clear()
{
m_texture_list.clear();
m_needs_update_descriptor = true;
m_recreate_next_frame = false;
}
// ------------------------------------------------------------------------
void handleDeletedTextures()
{
bool has_deleted_image_view = false;
@ -69,11 +76,7 @@ public:
}
}
if (has_deleted_image_view || m_recreate_next_frame)
{
m_texture_list.clear();
m_needs_update_descriptor = true;
m_recreate_next_frame = false;
}
clear();
}
// ------------------------------------------------------------------------
int getTextureID(const irr::video::ITexture** list);

View File

@ -7,12 +7,25 @@
#include "ge_vulkan_camera_scene_node.hpp"
#include "ge_vulkan_driver.hpp"
#include "ge_vulkan_dynamic_buffer.hpp"
#include "ge_vulkan_features.hpp"
#include "ge_vulkan_mesh_cache.hpp"
#include "ge_vulkan_mesh_scene_node.hpp"
#include "ge_vulkan_shader_manager.hpp"
#include "ge_vulkan_texture_descriptor.hpp"
namespace GE
{
// ============================================================================
ObjectData::ObjectData(irr::scene::ISceneNode* node, int material_id)
{
memcpy(m_mat_1, node->getAbsoluteTransformation().pointer(),
sizeof(irr::core::matrix4));
m_skinning_offset = -1;
m_material_id = material_id;
m_texture_trans[0] = 0.0f;
m_texture_trans[1] = 0.0f;
} // ObjectData
// ----------------------------------------------------------------------------
GEVulkanDrawCall::GEVulkanDrawCall()
{
@ -29,6 +42,7 @@ GEVulkanDrawCall::GEVulkanDrawCall()
m_descriptor_pool = VK_NULL_HANDLE;
m_graphics_pipeline = VK_NULL_HANDLE;
m_pipeline_layout = VK_NULL_HANDLE;
m_texture_descriptor = getVKDriver()->getMeshTextureDescriptor();
} // GEVulkanDrawCall
// ----------------------------------------------------------------------------
@ -86,11 +100,26 @@ void GEVulkanDrawCall::generate()
unsigned accumulated_instance = 0;
for (auto& p : m_visible_nodes)
{
irr::video::SMaterial& m = p.first->getMaterial();
std::array<const irr::video::ITexture*, 8> textures =
{{
m.TextureLayer[0].Texture,
m.TextureLayer[1].Texture,
m.TextureLayer[2].Texture,
m.TextureLayer[3].Texture,
m.TextureLayer[4].Texture,
m.TextureLayer[5].Texture,
m.TextureLayer[6].Texture,
m.TextureLayer[7].Texture
}};
const irr::video::ITexture** list = &textures[0];
const int material_id = m_texture_descriptor->getTextureID(list);
m_materials.push_back(material_id);
unsigned visible_count = p.second.size();
if (visible_count != 0)
{
for (auto* node : p.second)
m_visible_trans.push_back(node->getAbsoluteTransformation());
m_visible_objects.emplace_back(node, material_id);
VkDrawIndexedIndirectCommand cmd;
cmd.indexCount = p.first->getIndexCount();
cmd.instanceCount = visible_count;
@ -110,7 +139,8 @@ void GEVulkanDrawCall::prepare(GEVulkanCameraSceneNode* cam)
{
m_visible_nodes.clear();
m_cmds.clear();
m_visible_trans.clear();
m_visible_objects.clear();
m_materials.clear();
m_culling_tool->init(cam);
} // prepare
@ -192,10 +222,16 @@ void GEVulkanDrawCall::createVulkanData()
}
// m_pipeline_layout
std::array<VkDescriptorSetLayout, 2> all_layouts =
{{
*m_texture_descriptor->getDescriptorSetLayout(),
m_data_layout
}};
VkPipelineLayoutCreateInfo pipeline_layout_info = {};
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipeline_layout_info.setLayoutCount = 1;
pipeline_layout_info.pSetLayouts = &m_data_layout;
pipeline_layout_info.setLayoutCount = all_layouts.size();
pipeline_layout_info.pSetLayouts = all_layouts.data();
result = vkCreatePipelineLayout(vk->getDevice(), &pipeline_layout_info,
NULL, &m_pipeline_layout);
@ -366,13 +402,13 @@ void GEVulkanDrawCall::createVulkanData()
if (result != VK_SUCCESS)
throw std::runtime_error("vkCreateGraphicsPipelines failed");
size_t size = m_visible_trans.size();
if (m_visible_trans.empty())
size_t size = m_visible_objects.size();
if (m_visible_objects.empty())
size = 100;
m_dynamic_data = new GEVulkanDynamicBuffer(GVDBT_GPU_RAM,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
(sizeof(irr::core::matrix4) * size) + sizeof(GEVulkanCameraUBO));
(sizeof(ObjectData) * size) + sizeof(GEVulkanCameraUBO));
} // createVulkanData
// ----------------------------------------------------------------------------
@ -385,7 +421,7 @@ void GEVulkanDrawCall::uploadDynamicData(GEVulkanDriver* vk,
const VkPhysicalDeviceLimits& limit =
vk->getPhysicalDeviceProperties().limits;
const size_t object_data_size =
sizeof(irr::core::matrix4) * m_visible_trans.size();
sizeof(ObjectData) * m_visible_objects.size();
size_t ubo_alignment = limit.minUniformBufferOffsetAlignment;
size_t ubo_padding = 0;
if (ubo_alignment > 0)
@ -393,7 +429,7 @@ void GEVulkanDrawCall::uploadDynamicData(GEVulkanDriver* vk,
m_object_data_padded_size = object_data_size + ubo_padding;
std::vector<std::pair<void*, size_t> > data;
data.emplace_back((void*)m_visible_trans.data(), object_data_size);
data.emplace_back((void*)m_visible_objects.data(), object_data_size);
if (ubo_padding > 0)
data.emplace_back((void*)m_object_data_padding, ubo_padding);
data.emplace_back(cam->getUBOData(), sizeof(GEVulkanCameraUBO));
@ -455,11 +491,20 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam)
vkUpdateDescriptorSets(vk->getDevice(), data_set.size(), data_set.data(),
0, NULL);
m_texture_descriptor->updateDescriptor();
vkCmdBindPipeline(vk->getCurrentCommandBuffer(),
VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphics_pipeline);
if (GEVulkanFeatures::supportsBindMeshTexturesAtOnce())
{
vkCmdBindDescriptorSets(vk->getCurrentCommandBuffer(),
VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1,
m_texture_descriptor->getDescriptorSet(), 0, NULL);
}
vkCmdBindDescriptorSets(vk->getCurrentCommandBuffer(),
VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1,
&m_data_descriptor_sets[cur_frame], 0, NULL);
VkDeviceSize offsets[] = {0};
@ -488,8 +533,16 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam)
scissor.extent.height = vp.height;
vkCmdSetScissor(vk->getCurrentCommandBuffer(), 0, 1, &scissor);
for (VkDrawIndexedIndirectCommand& cmd : m_cmds)
for (unsigned i = 0; i < m_cmds.size(); i++)
{
if (!GEVulkanFeatures::supportsBindMeshTexturesAtOnce())
{
vkCmdBindDescriptorSets(vk->getCurrentCommandBuffer(),
VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1,
&m_texture_descriptor->getDescriptorSet()[m_materials[i]], 0,
NULL);
}
const VkDrawIndexedIndirectCommand& cmd = m_cmds[i];
vkCmdDrawIndexed(vk->getCurrentCommandBuffer(), cmd.indexCount,
cmd.instanceCount, cmd.firstIndex, cmd.vertexOffset,
cmd.firstInstance);

View File

@ -20,6 +20,20 @@ class GESPMBuffer;
class GEVulkanCameraSceneNode;
class GEVulkanDriver;
class GEVulkanDynamicBuffer;
class GEVulkanTextureDescriptor;
struct ObjectData
{
float m_mat_1[4];
float m_mat_2[4];
float m_mat_3[4];
float m_mat_4[4];
int m_skinning_offset;
int m_material_id;
float m_texture_trans[2];
// ------------------------------------------------------------------------
ObjectData(irr::scene::ISceneNode* node, int material_id);
};
class GEVulkanDrawCall
{
@ -30,7 +44,7 @@ private:
std::vector<VkDrawIndexedIndirectCommand> m_cmds;
std::vector<irr::core::matrix4> m_visible_trans;
std::vector<ObjectData> m_visible_objects;
GEVulkanDynamicBuffer* m_dynamic_data;
@ -48,6 +62,9 @@ private:
VkPipeline m_graphics_pipeline;
std::vector<int> m_materials;
GEVulkanTextureDescriptor* m_texture_descriptor;
// ------------------------------------------------------------------------
void createVulkanData();
public:

View File

@ -11,7 +11,7 @@
#include "ge_vulkan_mesh_cache.hpp"
#include "ge_vulkan_scene_manager.hpp"
#include "ge_vulkan_shader_manager.hpp"
#include "ge_vulkan_texture.hpp"
#include "ge_vulkan_texture_descriptor.hpp"
#include "ISceneManager.h"
#include "IrrlichtDevice.h"
@ -490,7 +490,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
IrrlichtDevice* device)
: CNullDriver(io, core::dimension2d<u32>(0, 0)),
m_params(params), m_irrlicht_device(device),
m_depth_texture(NULL)
m_depth_texture(NULL), m_mesh_texture_descriptor(NULL)
{
m_vk.reset(new VK());
m_physical_device = VK_NULL_HANDLE;
@ -622,6 +622,10 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
GE::setVideoDriver(this);
createUnicolorTextures();
GEVulkan2dRenderer::init(this);
m_mesh_texture_descriptor = new GEVulkanTextureDescriptor(
GEVulkanShaderManager::getSamplerSize(),
GEVulkanShaderManager::getMeshTextureLayer(),
GEVulkanFeatures::supportsBindMeshTexturesAtOnce());
GEVulkanFeatures::printStats();
}
catch (std::exception& e)
@ -666,6 +670,7 @@ void GEVulkanDriver::destroyVulkan()
if (m_irrlicht_device->getSceneManager() &&
m_irrlicht_device->getSceneManager()->getMeshCache())
getVulkanMeshCache()->destroy();
delete m_mesh_texture_descriptor;
GEVulkan2dRenderer::destroy();
GEVulkanShaderManager::destroy();
@ -2220,6 +2225,7 @@ VkFormat GEVulkanDriver::findSupportedFormat(const std::vector<VkFormat>& candid
void GEVulkanDriver::handleDeletedTextures()
{
GEVulkan2dRenderer::handleDeletedTextures();
m_mesh_texture_descriptor->handleDeletedTextures();
} // handleDeletedTextures
}

View File

@ -3,6 +3,7 @@
#include "ge_vulkan_driver.hpp"
#include "ge_vulkan_shader_manager.hpp"
#include <algorithm>
#include <set>
#include <string>
#include <vector>
@ -21,6 +22,7 @@ bool g_supports_r8_blit = false;
bool g_supports_descriptor_indexing = false;
bool g_supports_non_uniform_indexing = false;
bool g_supports_partially_bound = false;
uint32_t g_max_sampler_supported = 0;
} // GEVulkanFeatures
// ============================================================================
@ -34,14 +36,15 @@ void GEVulkanFeatures::init(GEVulkanDriver* vk)
// https://vulkan.gpuinfo.org/displaydevicelimit.php?name=maxPerStageDescriptorSamplers&platform=all
// https://vulkan.gpuinfo.org/displaydevicelimit.php?name=maxPerStageDescriptorSampledImages&platform=all
// We decide 256 (GEVulkanShaderManager::getSamplerSize()) based on those infos
g_max_sampler_supported = std::min(
{
limit.maxDescriptorSetSamplers,
limit.maxDescriptorSetSampledImages,
limit.maxPerStageDescriptorSamplers,
limit.maxPerStageDescriptorSampledImages
});
const unsigned max_sampler_size = GEVulkanShaderManager::getSamplerSize();
if (limit.maxDescriptorSetSamplers < max_sampler_size)
g_supports_bind_textures_at_once = false;
if (limit.maxDescriptorSetSampledImages < max_sampler_size)
g_supports_bind_textures_at_once = false;
if (limit.maxPerStageDescriptorSamplers < max_sampler_size)
g_supports_bind_textures_at_once = false;
if (limit.maxPerStageDescriptorSampledImages < max_sampler_size)
if (max_sampler_size > g_max_sampler_supported)
g_supports_bind_textures_at_once = false;
if (vk->getPhysicalDeviceFeatures().shaderSampledImageArrayDynamicIndexing == VK_FALSE)
{
@ -107,11 +110,15 @@ void GEVulkanFeatures::init(GEVulkanDriver* vk)
if (props2.sType ==
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES)
{
g_max_sampler_supported = std::min(
{
props2.maxPerStageDescriptorUpdateAfterBindSamplers,
props2.maxPerStageDescriptorUpdateAfterBindSampledImages,
props2.maxDescriptorSetUpdateAfterBindSamplers,
props2.maxDescriptorSetUpdateAfterBindSampledImages
});
g_supports_bind_textures_at_once =
props2.maxPerStageDescriptorUpdateAfterBindSamplers > max_sampler_size &&
props2.maxPerStageDescriptorUpdateAfterBindSampledImages > max_sampler_size &&
props2.maxDescriptorSetUpdateAfterBindSamplers > max_sampler_size &&
props2.maxDescriptorSetUpdateAfterBindSampledImages > max_sampler_size;
g_max_sampler_supported >= max_sampler_size;
}
}
} // init
@ -122,6 +129,9 @@ void GEVulkanFeatures::printStats()
os::Printer::log(
"Vulkan can bind textures at once in shader",
g_supports_bind_textures_at_once ? "true" : "false");
os::Printer::log(
"Vulkan can bind mesh textures at once in shader",
supportsBindMeshTexturesAtOnce() ? "true" : "false");
os::Printer::log(
"Vulkan supports linear blitting for rgba8",
g_supports_rgba8_blit ? "true" : "false");
@ -182,4 +192,14 @@ bool GEVulkanFeatures::supportsPartiallyBound()
return g_supports_partially_bound;
} // supportsPartiallyBound
// ----------------------------------------------------------------------------
bool GEVulkanFeatures::supportsBindMeshTexturesAtOnce()
{
if (!g_supports_bind_textures_at_once)
return false;
const unsigned sampler_count = GEVulkanShaderManager::getSamplerSize() *
GEVulkanShaderManager::getMeshTextureLayer();
return g_max_sampler_supported >= sampler_count;
} // supportsBindMeshTexturesAtOnce
}

View File

@ -26,6 +26,8 @@ bool supportsNonUniformIndexing();
bool supportsDifferentTexturePerDraw();
// ----------------------------------------------------------------------------
bool supportsPartiallyBound();
// ----------------------------------------------------------------------------
bool supportsBindMeshTexturesAtOnce();
}; // GEVulkanFeatures
}

View File

@ -6,8 +6,10 @@
#include "ge_vulkan_animated_mesh_scene_node.hpp"
#include "ge_vulkan_camera_scene_node.hpp"
#include "ge_vulkan_draw_call.hpp"
#include "ge_vulkan_driver.hpp"
#include "ge_vulkan_mesh_cache.hpp"
#include "ge_vulkan_mesh_scene_node.hpp"
#include "ge_vulkan_texture_descriptor.hpp"
namespace GE
{
@ -28,6 +30,14 @@ GEVulkanSceneManager::~GEVulkanSceneManager()
{
} // ~GEVulkanSceneManager
// ----------------------------------------------------------------------------
void GEVulkanSceneManager::clear()
{
irr::scene::CSceneManager::clear();
static_cast<GEVulkanDriver*>(getVideoDriver())
->getMeshTextureDescriptor()->clear();
} // clear
// ----------------------------------------------------------------------------
irr::scene::ICameraSceneNode* GEVulkanSceneManager::addCameraSceneNode(
irr::scene::ISceneNode* parent,

View File

@ -21,6 +21,10 @@ GEVulkanDriver* g_vk = NULL;
irr::io::IFileSystem* g_file_system = NULL;
std::string g_predefines = "";
// More when PBR is used later
uint32_t g_mesh_texture_layer = 2;
uint32_t g_sampler_size = 256;
std::map<std::string, VkShaderModule> g_shaders;
@ -109,8 +113,11 @@ void GEVulkanShaderManager::init(GEVulkanDriver* vk)
std::ostringstream oss;
oss << "#version 450\n";
oss << "#define SAMPLER_SIZE " << g_sampler_size << "\n";
oss << "#define TOTAL_MESH_TEXTURE_LAYER " << g_mesh_texture_layer << "\n";
if (GEVulkanFeatures::supportsBindTexturesAtOnce())
oss << "#define BIND_TEXTURES_AT_ONCE\n";
if (GEVulkanFeatures::supportsBindMeshTexturesAtOnce())
oss << "#define BIND_MESH_TEXTURES_AT_ONCE\n";
if (GEVulkanFeatures::supportsDifferentTexturePerDraw())
{
@ -222,6 +229,12 @@ unsigned GEVulkanShaderManager::getSamplerSize()
return g_sampler_size;
} // getSamplerSize
// ----------------------------------------------------------------------------
unsigned GEVulkanShaderManager::getMeshTextureLayer()
{
return g_mesh_texture_layer;
} // getMeshTextureLayer
// ----------------------------------------------------------------------------
VkShaderModule GEVulkanShaderManager::getShader(const std::string& filename)
{

View File

@ -22,6 +22,8 @@ VkShaderModule getShader(const std::string& filename);
VkShaderModule loadShader(shaderc_shader_kind, const std::string&);
// ----------------------------------------------------------------------------
unsigned getSamplerSize();
// ----------------------------------------------------------------------------
unsigned getMeshTextureLayer();
}; // GEVulkanShaderManager
}