Add drawing code for devices with low sampler images
This commit is contained in:
parent
bb6551fdf6
commit
ea1733ed08
@ -2,11 +2,20 @@ layout(location = 0) in vec4 f_color;
|
||||
layout(location = 1) in vec2 f_uv;
|
||||
layout(location = 2) flat in int f_sampler_index;
|
||||
|
||||
#ifdef BIND_TEXTURES_AT_ONCE
|
||||
layout(binding = 0) uniform sampler2D f_tex[SAMPLER_SIZE];
|
||||
#else
|
||||
layout(binding = 0) uniform sampler2D f_tex;
|
||||
#endif
|
||||
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
o_color = texture(f_tex[GE_SAMPLE_TEX_INDEX(f_sampler_index)], f_uv) * f_color;
|
||||
#ifdef BIND_TEXTURES_AT_ONCE
|
||||
vec4 tex_color = texture(f_tex[GE_SAMPLE_TEX_INDEX(f_sampler_index)], f_uv);
|
||||
#else
|
||||
vec4 tex_color = texture(f_tex, f_uv);
|
||||
#endif
|
||||
o_color = tex_color * f_color;
|
||||
}
|
||||
|
@ -283,6 +283,8 @@ namespace GE
|
||||
VkDeviceMemory& buffer_memory);
|
||||
VkPhysicalDevice getPhysicalDevice() const { return m_physical_device; }
|
||||
void waitIdle() { vkQueueWaitIdle(m_graphics_queue); }
|
||||
const VkPhysicalDeviceFeatures& getPhysicalDeviceFeatures() const
|
||||
{ return m_features; }
|
||||
const VkPhysicalDeviceProperties& getPhysicalDeviceProperties() const
|
||||
{ return m_properties; }
|
||||
VkCommandBuffer beginSingleTimeCommands();
|
||||
|
@ -83,7 +83,9 @@ void GEVulkan2dRenderer::createDescriptorSetLayout()
|
||||
{
|
||||
VkDescriptorSetLayoutBinding sampler_layout_binding = {};
|
||||
sampler_layout_binding.binding = 0;
|
||||
sampler_layout_binding.descriptorCount = GEVulkanShaderManager::getSamplerSize();
|
||||
sampler_layout_binding.descriptorCount =
|
||||
GEVulkanFeatures::supportsBindTexturesAtOnce() ?
|
||||
GEVulkanShaderManager::getSamplerSize() : 1;
|
||||
sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
sampler_layout_binding.pImmutableSamplers = NULL;
|
||||
sampler_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
@ -276,6 +278,9 @@ void GEVulkan2dRenderer::createTrisBuffers()
|
||||
void GEVulkan2dRenderer::createDescriptorPool()
|
||||
{
|
||||
uint32_t descriptor_count = g_vk->getMaxFrameInFlight();
|
||||
if (!GEVulkanFeatures::supportsBindTexturesAtOnce())
|
||||
descriptor_count *= GEVulkanShaderManager::getSamplerSize();
|
||||
|
||||
std::array<VkDescriptorPoolSize, 1> pool_sizes = {};
|
||||
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
pool_sizes[0].descriptorCount = GEVulkanShaderManager::getSamplerSize() *
|
||||
@ -295,7 +300,10 @@ void GEVulkan2dRenderer::createDescriptorPool()
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkan2dRenderer::createDescriptorSets()
|
||||
{
|
||||
g_descriptor_sets.resize(g_vk->getMaxFrameInFlight());
|
||||
unsigned set_size = g_vk->getMaxFrameInFlight();
|
||||
if (!GEVulkanFeatures::supportsBindTexturesAtOnce())
|
||||
set_size *= GEVulkanShaderManager::getSamplerSize();
|
||||
g_descriptor_sets.resize(set_size);
|
||||
std::vector<VkDescriptorSetLayout> layouts(g_descriptor_sets.size(),
|
||||
g_descriptor_set_layout);
|
||||
|
||||
@ -371,20 +379,43 @@ void GEVulkan2dRenderer::render()
|
||||
if (image_infos.size() >= GEVulkanShaderManager::getSamplerSize())
|
||||
break;
|
||||
}
|
||||
image_infos.resize(GEVulkanShaderManager::getSamplerSize(), image_infos[0]);
|
||||
|
||||
VkWriteDescriptorSet write_descriptor_set = {};
|
||||
write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set.dstBinding = 0;
|
||||
write_descriptor_set.dstArrayElement = 0;
|
||||
write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
write_descriptor_set.descriptorCount = GEVulkanShaderManager::getSamplerSize();
|
||||
write_descriptor_set.pBufferInfo = 0;
|
||||
write_descriptor_set.dstSet = g_descriptor_sets[g_vk->getCurrentFrame()];
|
||||
write_descriptor_set.pImageInfo = image_infos.data();
|
||||
if (GEVulkanFeatures::supportsBindTexturesAtOnce())
|
||||
{
|
||||
image_infos.resize(GEVulkanShaderManager::getSamplerSize(), image_infos[0]);
|
||||
|
||||
vkUpdateDescriptorSets(g_vk->getDevice(), 1, &write_descriptor_set, 0,
|
||||
NULL);
|
||||
VkWriteDescriptorSet write_descriptor_set = {};
|
||||
write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set.dstBinding = 0;
|
||||
write_descriptor_set.dstArrayElement = 0;
|
||||
write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
write_descriptor_set.descriptorCount = GEVulkanShaderManager::getSamplerSize();
|
||||
write_descriptor_set.pBufferInfo = 0;
|
||||
write_descriptor_set.dstSet = g_descriptor_sets[g_vk->getCurrentFrame()];
|
||||
write_descriptor_set.pImageInfo = image_infos.data();
|
||||
|
||||
vkUpdateDescriptorSets(g_vk->getDevice(), 1, &write_descriptor_set, 0,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned i = 0; i < image_infos.size(); i++)
|
||||
{
|
||||
VkWriteDescriptorSet write_descriptor_set = {};
|
||||
write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set.dstBinding = 0;
|
||||
write_descriptor_set.dstArrayElement = 0;
|
||||
write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
write_descriptor_set.descriptorCount = 1;
|
||||
write_descriptor_set.pBufferInfo = 0;
|
||||
const unsigned set_idx = g_vk->getCurrentFrame() * GEVulkanShaderManager::getSamplerSize() + i;
|
||||
write_descriptor_set.dstSet = g_descriptor_sets[set_idx];
|
||||
write_descriptor_set.pImageInfo = &image_infos[i];
|
||||
|
||||
vkUpdateDescriptorSets(g_vk->getDevice(), 1, &write_descriptor_set,
|
||||
0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
VkDeviceSize offsets[] = {0};
|
||||
VkBuffer vertex_buffer = VK_NULL_HANDLE;
|
||||
@ -418,9 +449,12 @@ void GEVulkan2dRenderer::render()
|
||||
vkCmdBindIndexBuffer(g_vk->getCurrentCommandBuffer(), indices_buffer, 0,
|
||||
VK_INDEX_TYPE_UINT16);
|
||||
|
||||
vkCmdBindDescriptorSets(g_vk->getCurrentCommandBuffer(),
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipeline_layout, 0, 1,
|
||||
&g_descriptor_sets[g_vk->getCurrentFrame()], 0, NULL);
|
||||
if (GEVulkanFeatures::supportsBindTexturesAtOnce())
|
||||
{
|
||||
vkCmdBindDescriptorSets(g_vk->getCurrentCommandBuffer(),
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipeline_layout, 0, 1,
|
||||
&g_descriptor_sets[g_vk->getCurrentFrame()], 0, NULL);
|
||||
}
|
||||
|
||||
if (GEVulkanFeatures::supportsDifferentTexturePerDraw())
|
||||
{
|
||||
@ -437,6 +471,13 @@ void GEVulkan2dRenderer::render()
|
||||
Tri& cur_tri = g_tris_queue[g_tris_index_queue[idx]];
|
||||
if (cur_tri.sampler_idx != sampler_idx)
|
||||
{
|
||||
if (!GEVulkanFeatures::supportsBindTexturesAtOnce())
|
||||
{
|
||||
const unsigned set_idx = g_vk->getCurrentFrame() * GEVulkanShaderManager::getSamplerSize() + sampler_idx;
|
||||
vkCmdBindDescriptorSets(g_vk->getCurrentCommandBuffer(),
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipeline_layout, 0, 1,
|
||||
&g_descriptor_sets[set_idx], 0, NULL);
|
||||
}
|
||||
vkCmdDrawIndexed(g_vk->getCurrentCommandBuffer(), idx_count, 1,
|
||||
idx - idx_count, 0, 0);
|
||||
sampler_idx = cur_tri.sampler_idx;
|
||||
@ -447,6 +488,13 @@ void GEVulkan2dRenderer::render()
|
||||
idx_count += 3;
|
||||
}
|
||||
}
|
||||
if (!GEVulkanFeatures::supportsBindTexturesAtOnce())
|
||||
{
|
||||
const unsigned set_idx = g_vk->getCurrentFrame() * GEVulkanShaderManager::getSamplerSize() + sampler_idx;
|
||||
vkCmdBindDescriptorSets(g_vk->getCurrentCommandBuffer(),
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipeline_layout, 0, 1,
|
||||
&g_descriptor_sets[set_idx], 0, NULL);
|
||||
}
|
||||
vkCmdDrawIndexed(g_vk->getCurrentCommandBuffer(), idx_count, 1,
|
||||
idx - idx_count, 0, 0);
|
||||
}
|
||||
@ -474,7 +522,7 @@ void GEVulkan2dRenderer::addVerticesIndices(irr::video::S3DVertex* vertices,
|
||||
g_tex_map[t] = pre_size;
|
||||
}
|
||||
int sampler_idx = g_tex_map.at(t);
|
||||
// In STK we rarely use more than 96 textures per (2d) draw call
|
||||
// In STK we rarely use more than 256 textures per (2d) draw call
|
||||
if (sampler_idx >= (int)GEVulkanShaderManager::getSamplerSize())
|
||||
sampler_idx = GEVulkanShaderManager::getSamplerSize() - 1;
|
||||
uint16_t last_index = (uint16_t)g_tris_queue.size();
|
||||
|
@ -482,6 +482,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
|
||||
|
||||
m_device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
findPhysicalDevice();
|
||||
vkGetPhysicalDeviceProperties(m_physical_device, &m_properties);
|
||||
GEVulkanFeatures::init(this);
|
||||
createDevice();
|
||||
|
||||
@ -495,7 +496,6 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
|
||||
}
|
||||
#endif
|
||||
|
||||
vkGetPhysicalDeviceProperties(m_physical_device, &m_properties);
|
||||
createSwapChain();
|
||||
createSyncObjects();
|
||||
createCommandPool();
|
||||
@ -756,9 +756,8 @@ void GEVulkanDriver::createDevice()
|
||||
}
|
||||
|
||||
VkPhysicalDeviceFeatures device_features = {};
|
||||
if (m_features.shaderSampledImageArrayDynamicIndexing == VK_FALSE)
|
||||
throw std::runtime_error("doesn't support shaderSampledImageArrayDynamicIndexing");
|
||||
device_features.shaderSampledImageArrayDynamicIndexing = VK_TRUE;
|
||||
device_features.shaderSampledImageArrayDynamicIndexing =
|
||||
GEVulkanFeatures::supportsBindTexturesAtOnce();
|
||||
|
||||
VkPhysicalDeviceVulkan12Features vulkan12_features = {};
|
||||
vulkan12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "ge_vulkan_features.hpp"
|
||||
|
||||
#include "ge_vulkan_driver.hpp"
|
||||
#include "ge_vulkan_shader_manager.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
@ -13,6 +14,7 @@ namespace GE
|
||||
namespace GEVulkanFeatures
|
||||
{
|
||||
// ============================================================================
|
||||
bool g_supports_bind_textures_at_once = false;
|
||||
// https://chunkstories.xyz/blog/a-note-on-descriptor-indexing
|
||||
bool g_supports_descriptor_indexing = false;
|
||||
bool g_supports_non_uniform_indexing = false;
|
||||
@ -22,6 +24,24 @@ bool g_supports_partially_bound = false;
|
||||
// ============================================================================
|
||||
void GEVulkanFeatures::init(GEVulkanDriver* vk)
|
||||
{
|
||||
g_supports_bind_textures_at_once = true;
|
||||
VkPhysicalDeviceLimits limit = vk->getPhysicalDeviceProperties().limits;
|
||||
// https://vulkan.gpuinfo.org/displaydevicelimit.php?name=maxDescriptorSetSamplers&platform=all
|
||||
// https://vulkan.gpuinfo.org/displaydevicelimit.php?name=maxDescriptorSetSampledImages&platform=all
|
||||
// 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
|
||||
if (limit.maxDescriptorSetSamplers < GEVulkanShaderManager::getSamplerSize())
|
||||
g_supports_bind_textures_at_once = false;
|
||||
if (limit.maxDescriptorSetSampledImages < GEVulkanShaderManager::getSamplerSize())
|
||||
g_supports_bind_textures_at_once = false;
|
||||
if (limit.maxPerStageDescriptorSamplers < GEVulkanShaderManager::getSamplerSize())
|
||||
g_supports_bind_textures_at_once = false;
|
||||
if (limit.maxPerStageDescriptorSampledImages < GEVulkanShaderManager::getSamplerSize())
|
||||
g_supports_bind_textures_at_once = false;
|
||||
if (vk->getPhysicalDeviceFeatures().shaderSampledImageArrayDynamicIndexing == VK_FALSE)
|
||||
g_supports_bind_textures_at_once = false;
|
||||
|
||||
uint32_t extension_count;
|
||||
vkEnumerateDeviceExtensionProperties(vk->getPhysicalDevice(), NULL,
|
||||
&extension_count, NULL);
|
||||
@ -58,6 +78,9 @@ void GEVulkanFeatures::init(GEVulkanDriver* vk)
|
||||
// ----------------------------------------------------------------------------
|
||||
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 supports VK_EXT_descriptor_indexing",
|
||||
g_supports_descriptor_indexing ? "true" : "false");
|
||||
@ -69,6 +92,12 @@ void GEVulkanFeatures::printStats()
|
||||
g_supports_partially_bound ? "true" : "false");
|
||||
} // printStats
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GEVulkanFeatures::supportsBindTexturesAtOnce()
|
||||
{
|
||||
return g_supports_bind_textures_at_once;
|
||||
} // supportsBindTexturesAtOnce
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GEVulkanFeatures::supportsDescriptorIndexing()
|
||||
{
|
||||
@ -84,7 +113,8 @@ bool GEVulkanFeatures::supportsNonUniformIndexing()
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GEVulkanFeatures::supportsDifferentTexturePerDraw()
|
||||
{
|
||||
return g_supports_descriptor_indexing && g_supports_non_uniform_indexing;
|
||||
return g_supports_bind_textures_at_once &&
|
||||
g_supports_descriptor_indexing && g_supports_non_uniform_indexing;
|
||||
} // supportsDifferentTexturePerDraw
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -13,6 +13,8 @@ void init(GEVulkanDriver*);
|
||||
// ----------------------------------------------------------------------------
|
||||
void printStats();
|
||||
// ----------------------------------------------------------------------------
|
||||
bool supportsBindTexturesAtOnce();
|
||||
// ----------------------------------------------------------------------------
|
||||
bool supportsDescriptorIndexing();
|
||||
// ----------------------------------------------------------------------------
|
||||
bool supportsNonUniformIndexing();
|
||||
|
@ -20,7 +20,7 @@ GEVulkanDriver* g_vk = NULL;
|
||||
irr::io::IFileSystem* g_file_system = NULL;
|
||||
|
||||
std::string g_predefines = "";
|
||||
uint32_t g_sampler_size = 0;
|
||||
uint32_t g_sampler_size = 256;
|
||||
|
||||
VkShaderModule g_2d_render_vert = VK_NULL_HANDLE;
|
||||
VkShaderModule g_2d_render_frag = VK_NULL_HANDLE;
|
||||
@ -32,16 +32,12 @@ void GEVulkanShaderManager::init(GEVulkanDriver* vk)
|
||||
g_vk = vk;
|
||||
g_file_system = vk->getFileSystem();
|
||||
|
||||
VkPhysicalDeviceLimits limit = g_vk->getPhysicalDeviceProperties().limits;
|
||||
// According to https://vulkan.gpuinfo.org/displaydevicelimit.php?name=maxDescriptorSetSampledImages&platform=all
|
||||
// almost all users have at least 96
|
||||
if (limit.maxDescriptorSetSampledImages < 96)
|
||||
throw std::runtime_error("maxDescriptorSetSampledImages is too low");
|
||||
g_sampler_size = 96;
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "#version 450\n";
|
||||
oss << "#define SAMPLER_SIZE " << g_sampler_size << "\n";
|
||||
if (GEVulkanFeatures::supportsBindTexturesAtOnce())
|
||||
oss << "#define BIND_TEXTURES_AT_ONCE\n";
|
||||
|
||||
if (GEVulkanFeatures::supportsDifferentTexturePerDraw())
|
||||
{
|
||||
oss << "#extension GL_EXT_nonuniform_qualifier : enable\n";
|
||||
|
Loading…
Reference in New Issue
Block a user