Add initial 2D vulkan rendering
This commit is contained in:
parent
cb607a16ff
commit
1cf2c0c5bf
@ -8,5 +8,5 @@ layout(location = 0) out vec4 o_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
o_color = texture(f_tex[f_sampler_index], f_uv) * f_color;
|
||||
o_color = texture(f_tex[GE_SAMPLE_TEX_INDEX(f_sampler_index)], f_uv) * f_color;
|
||||
}
|
||||
|
@ -25,7 +25,10 @@ set(GE_SOURCES
|
||||
src/ge_main.cpp
|
||||
src/ge_texture.cpp
|
||||
src/ge_dx9_texture.cpp
|
||||
src/ge_vulkan_2d_renderer.cpp
|
||||
src/ge_vulkan_driver.cpp
|
||||
src/ge_vulkan_dynamic_buffer.cpp
|
||||
src/ge_vulkan_features.cpp
|
||||
src/ge_vulkan_shader_manager.cpp
|
||||
src/ge_vulkan_texture.cpp
|
||||
src/ge_gl_texture.cpp
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "../source/Irrlicht/CNullDriver.h"
|
||||
#include "SIrrCreationParameters.h"
|
||||
#include "SColor.h"
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -23,8 +23,9 @@ namespace GE
|
||||
{
|
||||
enum GEVulkanSampler : unsigned
|
||||
{
|
||||
GVS_MIN,
|
||||
GVS_NEAREST = GVS_MIN
|
||||
GVS_MIN = 0,
|
||||
GVS_NEAREST = GVS_MIN,
|
||||
GVS_COUNT,
|
||||
};
|
||||
class GEVulkanDriver : public video::CNullDriver
|
||||
{
|
||||
@ -40,10 +41,10 @@ namespace GE
|
||||
virtual bool beginScene(bool backBuffer=true, bool zBuffer=true,
|
||||
SColor color=SColor(255,0,0,0),
|
||||
const SExposedVideoData& videoData=SExposedVideoData(),
|
||||
core::rect<s32>* sourceRect=0) { return true; }
|
||||
core::rect<s32>* sourceRect=0);
|
||||
|
||||
//! applications must call this method after performing any rendering. returns false if failed.
|
||||
virtual bool endScene() { return true; }
|
||||
virtual bool endScene();
|
||||
|
||||
//! queries the features of the driver, returns true if feature is available
|
||||
virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const { return true; }
|
||||
@ -52,7 +53,7 @@ namespace GE
|
||||
virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) {}
|
||||
|
||||
//! sets a material
|
||||
virtual void setMaterial(const SMaterial& material) {}
|
||||
virtual void setMaterial(const SMaterial& material) { Material = material; }
|
||||
|
||||
//! sets a render target
|
||||
virtual bool setRenderTarget(video::ITexture* texture,
|
||||
@ -120,17 +121,17 @@ namespace GE
|
||||
virtual void draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount,
|
||||
const void* indexList, u32 primitiveCount,
|
||||
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType,
|
||||
E_INDEX_TYPE iType) {}
|
||||
E_INDEX_TYPE iType);
|
||||
|
||||
//! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted.
|
||||
virtual void draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
|
||||
const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect = 0,
|
||||
SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false) {}
|
||||
SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false);
|
||||
|
||||
//! Draws a part of the texture into the rectangle.
|
||||
virtual void draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
|
||||
const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect = 0,
|
||||
const video::SColor* const colors=0, bool useAlphaChannelOfTexture=false) {}
|
||||
const video::SColor* const colors=0, bool useAlphaChannelOfTexture=false);
|
||||
|
||||
//! Draws a set of 2d images, using a color and the alpha channel of the texture.
|
||||
virtual void draw2DImageBatch(const video::ITexture* texture,
|
||||
@ -138,7 +139,7 @@ namespace GE
|
||||
const core::array<core::rect<s32> >& sourceRects,
|
||||
const core::rect<s32>* clipRect=0,
|
||||
SColor color=SColor(255,255,255,255),
|
||||
bool useAlphaChannelOfTexture=false) {}
|
||||
bool useAlphaChannelOfTexture=false);
|
||||
|
||||
//!Draws an 2d rectangle with a gradient.
|
||||
virtual void draw2DRectangle(const core::rect<s32>& pos,
|
||||
@ -268,11 +269,12 @@ namespace GE
|
||||
|
||||
virtual void enableScissorTest(const core::rect<s32>& r) {}
|
||||
virtual void disableScissorTest() {}
|
||||
virtual const core::dimension2d<u32>& getCurrentRenderTargetSize() const { return ScreenSize; }
|
||||
VkSampler getSampler(GEVulkanSampler s) const
|
||||
{
|
||||
if (m_vk->samplers.find(s) == m_vk->samplers.end())
|
||||
if (s >= GVS_COUNT)
|
||||
return VK_NULL_HANDLE;
|
||||
return m_vk->samplers.at(s);
|
||||
return m_vk->samplers[s];
|
||||
}
|
||||
VkDevice getDevice() const { return m_vk->device; }
|
||||
void destroyVulkan();
|
||||
@ -286,7 +288,22 @@ namespace GE
|
||||
VkCommandBuffer beginSingleTimeCommands();
|
||||
void endSingleTimeCommands(VkCommandBuffer command_buffer);
|
||||
io::IFileSystem* getFileSystem() const { return FileSystem; }
|
||||
VkExtent2D getSwapChainExtent() const { return m_swap_chain_extent; }
|
||||
size_t getSwapChainImagesCount() const
|
||||
{ return m_vk->swap_chain_images.size(); }
|
||||
VkRenderPass getRenderPass() const { return m_vk->render_pass; }
|
||||
void copyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer, VkDeviceSize size);
|
||||
VkCommandBuffer getCurrentCommandBuffer()
|
||||
{ return m_vk->command_buffers[m_current_frame]; }
|
||||
std::vector<VkImage>& getSwapChainImages()
|
||||
{ return m_vk->swap_chain_images; }
|
||||
std::vector<VkFramebuffer>& getSwapChainFramebuffers()
|
||||
{ return m_vk->swap_chain_framebuffers; }
|
||||
|
||||
unsigned int getCurrentFrame() const { return m_current_frame; }
|
||||
unsigned int getCurrentImageIndex() const { return m_image_index; }
|
||||
constexpr static unsigned getMaxFrameInFlight() { return 2; }
|
||||
video::SColor getClearColor() const { return m_clear_color; }
|
||||
private:
|
||||
struct SwapChainSupportDetails
|
||||
{
|
||||
@ -320,6 +337,7 @@ namespace GE
|
||||
E_GPU_SHADING_LANGUAGE shadingLang = EGSL_DEFAULT) { return 0; }
|
||||
|
||||
SIrrlichtCreationParameters m_params;
|
||||
SMaterial Material;
|
||||
// RAII to auto cleanup
|
||||
struct VK
|
||||
{
|
||||
@ -334,7 +352,9 @@ namespace GE
|
||||
std::vector<VkFence> in_flight_fences;
|
||||
VkCommandPool command_pool;
|
||||
std::vector<VkCommandBuffer> command_buffers;
|
||||
std::map<GEVulkanSampler, VkSampler> samplers;
|
||||
std::array<VkSampler, GVS_COUNT> samplers;
|
||||
VkRenderPass render_pass;
|
||||
std::vector<VkFramebuffer> swap_chain_framebuffers;
|
||||
VK()
|
||||
{
|
||||
instance = VK_NULL_HANDLE;
|
||||
@ -342,11 +362,16 @@ namespace GE
|
||||
device = VK_NULL_HANDLE;
|
||||
swap_chain = VK_NULL_HANDLE;
|
||||
command_pool = VK_NULL_HANDLE;
|
||||
samplers = {{}};
|
||||
render_pass = VK_NULL_HANDLE;
|
||||
}
|
||||
~VK()
|
||||
{
|
||||
for (auto& sampler : samplers)
|
||||
vkDestroySampler(device, sampler.second, NULL);
|
||||
for (VkFramebuffer& framebuffer : swap_chain_framebuffers)
|
||||
vkDestroyFramebuffer(device, framebuffer, NULL);
|
||||
vkDestroyRenderPass(device, render_pass, NULL);
|
||||
for (unsigned i = 0; i < GVS_COUNT; i++)
|
||||
vkDestroySampler(device, samplers[i], NULL);
|
||||
if (!command_buffers.empty())
|
||||
{
|
||||
vkFreeCommandBuffers(device, command_pool,
|
||||
@ -389,6 +414,10 @@ namespace GE
|
||||
VkPhysicalDeviceProperties m_properties;
|
||||
VkPhysicalDeviceFeatures m_features;
|
||||
|
||||
unsigned int m_current_frame;
|
||||
uint32_t m_image_index;
|
||||
video::SColor m_clear_color;
|
||||
|
||||
void createInstance(SDL_Window* window);
|
||||
void findPhysicalDevice();
|
||||
bool checkDeviceExtensions(VkPhysicalDevice device);
|
||||
@ -403,6 +432,8 @@ namespace GE
|
||||
void createCommandPool();
|
||||
void createCommandBuffers();
|
||||
void createSamplers();
|
||||
void createRenderPass();
|
||||
void createFramebuffers();
|
||||
std::string getVulkanVersionString() const;
|
||||
std::string getDriverVersionString() const;
|
||||
};
|
||||
|
478
lib/graphics_engine/src/ge_vulkan_2d_renderer.cpp
Normal file
478
lib/graphics_engine/src/ge_vulkan_2d_renderer.cpp
Normal file
@ -0,0 +1,478 @@
|
||||
#include "ge_vulkan_2d_renderer.hpp"
|
||||
|
||||
#include "ge_main.hpp"
|
||||
#include "ge_vulkan_driver.hpp"
|
||||
#include "ge_vulkan_dynamic_buffer.hpp"
|
||||
#include "ge_vulkan_shader_manager.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include "vector2d.h"
|
||||
#include "SColor.h"
|
||||
|
||||
namespace GE
|
||||
{
|
||||
// ============================================================================
|
||||
namespace GEVulkan2dRenderer
|
||||
{
|
||||
using namespace irr;
|
||||
// ============================================================================
|
||||
GEVulkanDriver* g_vk;
|
||||
|
||||
VkPipelineLayout g_pipeline_layout = VK_NULL_HANDLE;
|
||||
VkPipeline g_graphics_pipeline = VK_NULL_HANDLE;
|
||||
|
||||
VkDescriptorPool g_descriptor_pool = VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout g_descriptor_set_layout = VK_NULL_HANDLE;
|
||||
|
||||
GEVulkanDynamicBuffer* g_tris_buffer = NULL;
|
||||
|
||||
GEVulkanDynamicBuffer* g_tris_index_buffer = NULL;
|
||||
|
||||
std::vector<VkDescriptorSet> g_descriptor_sets;
|
||||
|
||||
struct Tri
|
||||
{
|
||||
core::vector2df pos;
|
||||
video::SColor color;
|
||||
core::vector2df uv;
|
||||
int sampler_idx;
|
||||
};
|
||||
|
||||
std::map<const irr::video::ITexture*, unsigned> g_tex_map;
|
||||
std::vector<Tri> g_tris_queue;
|
||||
std::vector<uint16_t> g_tris_index_queue;
|
||||
} // GEVulkan2dRenderer
|
||||
|
||||
// ============================================================================
|
||||
void GEVulkan2dRenderer::init(GEVulkanDriver* vk)
|
||||
{
|
||||
g_vk = vk;
|
||||
createDescriptorSetLayout();
|
||||
createPipelineLayout();
|
||||
createGraphicsPipeline();
|
||||
createTrisBuffers();
|
||||
createDescriptorPool();
|
||||
createDescriptorSets();
|
||||
} // init
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkan2dRenderer::destroy()
|
||||
{
|
||||
delete g_tris_buffer;
|
||||
g_tris_buffer = NULL;
|
||||
delete g_tris_index_buffer;
|
||||
g_tris_index_buffer = NULL;
|
||||
|
||||
vkDestroyDescriptorSetLayout(g_vk->getDevice(), g_descriptor_set_layout,
|
||||
NULL);
|
||||
vkDestroyDescriptorPool(g_vk->getDevice(), g_descriptor_pool, NULL);
|
||||
vkDestroyPipeline(g_vk->getDevice(), g_graphics_pipeline, NULL);
|
||||
vkDestroyPipelineLayout(g_vk->getDevice(), g_pipeline_layout, NULL);
|
||||
g_descriptor_sets.clear();
|
||||
} // destroy
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkan2dRenderer::createDescriptorSetLayout()
|
||||
{
|
||||
VkDescriptorSetLayoutBinding sampler_layout_binding = {};
|
||||
sampler_layout_binding.binding = 0;
|
||||
sampler_layout_binding.descriptorCount = GEVulkanShaderManager::getSamplerSize();
|
||||
sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
sampler_layout_binding.pImmutableSamplers = NULL;
|
||||
sampler_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
std::array<VkDescriptorSetLayoutBinding, 1> bindings =
|
||||
{
|
||||
sampler_layout_binding
|
||||
};
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo layout_info = {};
|
||||
layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
layout_info.bindingCount = (uint32_t)(bindings.size());
|
||||
layout_info.pBindings = &bindings[0];
|
||||
|
||||
VkResult result = vkCreateDescriptorSetLayout(g_vk->getDevice(), &layout_info,
|
||||
NULL, &g_descriptor_set_layout);
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("vkCreateDescriptorSetLayout failed");
|
||||
} // createDescriptorSetLayout
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkan2dRenderer::createPipelineLayout()
|
||||
{
|
||||
VkPipelineLayoutCreateInfo pipeline_layout_info = {};
|
||||
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipeline_layout_info.setLayoutCount = 1;
|
||||
pipeline_layout_info.pSetLayouts = &g_descriptor_set_layout;
|
||||
|
||||
VkResult result = vkCreatePipelineLayout(g_vk->getDevice(), &pipeline_layout_info,
|
||||
nullptr, &g_pipeline_layout);
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("vkCreatePipelineLayout failed");
|
||||
} // createPipelineLayout
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkan2dRenderer::createGraphicsPipeline()
|
||||
{
|
||||
VkPipelineShaderStageCreateInfo vert_shader_stage_info = {};
|
||||
vert_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vert_shader_stage_info.module = GEVulkanShaderManager::get2dRenderVert();
|
||||
vert_shader_stage_info.pName = "main";
|
||||
|
||||
VkPipelineShaderStageCreateInfo frag_shader_stage_info = {};
|
||||
frag_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
frag_shader_stage_info.module = GEVulkanShaderManager::get2dRenderFrag();
|
||||
frag_shader_stage_info.pName = "main";
|
||||
|
||||
VkPipelineShaderStageCreateInfo shader_stages[] =
|
||||
{
|
||||
vert_shader_stage_info,
|
||||
frag_shader_stage_info
|
||||
};
|
||||
|
||||
VkVertexInputBindingDescription binding_description = {};
|
||||
binding_description.binding = 0;
|
||||
binding_description.stride = sizeof(Tri);
|
||||
binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
std::array<VkVertexInputAttributeDescription, 4> attribute_descriptions = {};
|
||||
attribute_descriptions[0].binding = 0;
|
||||
attribute_descriptions[0].location = 0;
|
||||
attribute_descriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
|
||||
attribute_descriptions[0].offset = offsetof(Tri, pos);
|
||||
attribute_descriptions[1].binding = 0;
|
||||
attribute_descriptions[1].location = 1;
|
||||
attribute_descriptions[1].format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
attribute_descriptions[1].offset = offsetof(Tri, color);
|
||||
attribute_descriptions[2].binding = 0;
|
||||
attribute_descriptions[2].location = 2;
|
||||
attribute_descriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
|
||||
attribute_descriptions[2].offset = offsetof(Tri, uv);
|
||||
attribute_descriptions[3].binding = 0;
|
||||
attribute_descriptions[3].location = 3;
|
||||
attribute_descriptions[3].format = VK_FORMAT_R32_SINT;
|
||||
attribute_descriptions[3].offset = offsetof(Tri, sampler_idx);
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
|
||||
vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertex_input_info.vertexBindingDescriptionCount = 1;
|
||||
vertex_input_info.vertexAttributeDescriptionCount = (uint32_t)(attribute_descriptions.size());
|
||||
vertex_input_info.pVertexBindingDescriptions = &binding_description;
|
||||
vertex_input_info.pVertexAttributeDescriptions = &attribute_descriptions[0];
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo input_assembly = {};
|
||||
input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
input_assembly.primitiveRestartEnable = VK_FALSE;
|
||||
|
||||
VkViewport viewport = {};
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = (float)g_vk->getSwapChainExtent().width;
|
||||
viewport.height = (float)g_vk->getSwapChainExtent().height;
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
VkRect2D scissor = {};
|
||||
scissor.offset = {0, 0};
|
||||
scissor.extent = g_vk->getSwapChainExtent();
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewport_state = {};
|
||||
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
viewport_state.viewportCount = 1;
|
||||
viewport_state.pViewports = &viewport;
|
||||
viewport_state.scissorCount = 1;
|
||||
viewport_state.pScissors = &scissor;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer = {};
|
||||
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rasterizer.depthClampEnable = VK_FALSE;
|
||||
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
||||
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rasterizer.lineWidth = 1.0f;
|
||||
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
rasterizer.depthBiasEnable = VK_FALSE;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisampling = {};
|
||||
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisampling.sampleShadingEnable = VK_FALSE;
|
||||
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo depth_stencil = {};
|
||||
depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
depth_stencil.depthTestEnable = VK_FALSE;
|
||||
depth_stencil.depthWriteEnable = VK_FALSE;
|
||||
depth_stencil.depthBoundsTestEnable = VK_FALSE;
|
||||
depth_stencil.stencilTestEnable = VK_FALSE;
|
||||
|
||||
VkPipelineColorBlendAttachmentState color_blend_attachment = {};
|
||||
color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
|
||||
VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
|
||||
VK_COLOR_COMPONENT_A_BIT;
|
||||
color_blend_attachment.blendEnable = VK_TRUE;
|
||||
color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo color_blending = {};
|
||||
color_blending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
color_blending.logicOpEnable = VK_FALSE;
|
||||
color_blending.logicOp = VK_LOGIC_OP_COPY;
|
||||
color_blending.attachmentCount = 1;
|
||||
color_blending.pAttachments = &color_blend_attachment;
|
||||
color_blending.blendConstants[0] = 0.0f;
|
||||
color_blending.blendConstants[1] = 0.0f;
|
||||
color_blending.blendConstants[2] = 0.0f;
|
||||
color_blending.blendConstants[3] = 0.0f;
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipeline_info = {};
|
||||
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipeline_info.stageCount = 2;
|
||||
pipeline_info.pStages = shader_stages;
|
||||
pipeline_info.pVertexInputState = &vertex_input_info;
|
||||
pipeline_info.pInputAssemblyState = &input_assembly;
|
||||
pipeline_info.pViewportState = &viewport_state;
|
||||
pipeline_info.pRasterizationState = &rasterizer;
|
||||
pipeline_info.pMultisampleState = &multisampling;
|
||||
pipeline_info.pDepthStencilState = &depth_stencil;
|
||||
pipeline_info.pColorBlendState = &color_blending;
|
||||
pipeline_info.layout = g_pipeline_layout;
|
||||
pipeline_info.renderPass = g_vk->getRenderPass();
|
||||
pipeline_info.subpass = 0;
|
||||
pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
|
||||
|
||||
VkResult result = vkCreateGraphicsPipelines(g_vk->getDevice(),
|
||||
VK_NULL_HANDLE, 1, &pipeline_info, NULL, &g_graphics_pipeline);
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("vkCreateGraphicsPipelines failed");
|
||||
} // createGraphicsPipeline
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkan2dRenderer::createTrisBuffers()
|
||||
{
|
||||
g_tris_buffer = new GEVulkanDynamicBuffer(GVDBT_SYSTEM_RAM,
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 10000);
|
||||
g_tris_index_buffer = new GEVulkanDynamicBuffer(GVDBT_SYSTEM_RAM,
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT, 2000);
|
||||
} // createTrisBuffers
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkan2dRenderer::createDescriptorPool()
|
||||
{
|
||||
uint32_t descriptor_count = g_vk->getMaxFrameInFlight();
|
||||
std::array<VkDescriptorPoolSize, 1> pool_sizes = {};
|
||||
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
pool_sizes[0].descriptorCount = GEVulkanShaderManager::getSamplerSize() *
|
||||
g_vk->getMaxFrameInFlight();
|
||||
|
||||
VkDescriptorPoolCreateInfo pool_info = {};
|
||||
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
pool_info.poolSizeCount = (uint32_t)(pool_sizes.size());
|
||||
pool_info.pPoolSizes = &pool_sizes[0];
|
||||
pool_info.maxSets = descriptor_count;
|
||||
|
||||
if (vkCreateDescriptorPool(g_vk->getDevice(), &pool_info, NULL,
|
||||
&g_descriptor_pool) != VK_SUCCESS)
|
||||
throw std::runtime_error("createDescriptorPool failed");
|
||||
} // createDescriptorPool
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkan2dRenderer::createDescriptorSets()
|
||||
{
|
||||
g_descriptor_sets.resize(g_vk->getMaxFrameInFlight());
|
||||
std::vector<VkDescriptorSetLayout> layouts(g_descriptor_sets.size(),
|
||||
g_descriptor_set_layout);
|
||||
|
||||
VkDescriptorSetAllocateInfo alloc_info = {};
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
alloc_info.descriptorPool = g_descriptor_pool;
|
||||
alloc_info.descriptorSetCount = (uint32_t)(layouts.size());
|
||||
alloc_info.pSetLayouts = layouts.data();
|
||||
|
||||
if (vkAllocateDescriptorSets(g_vk->getDevice(), &alloc_info,
|
||||
g_descriptor_sets.data()) != VK_SUCCESS)
|
||||
throw std::runtime_error("vkAllocateDescriptorSets failed");
|
||||
} // createDescriptorSets
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkan2dRenderer::render()
|
||||
{
|
||||
std::array<VkClearValue, 2> clear_values = {};
|
||||
video::SColorf cf(g_vk->getClearColor());
|
||||
clear_values[0].color =
|
||||
{
|
||||
cf.getRed(), cf.getGreen(), cf.getBlue(), cf.getAlpha()
|
||||
};
|
||||
clear_values[1].depthStencil = {1.0f, 0};
|
||||
|
||||
VkRenderPassBeginInfo render_pass_info = {};
|
||||
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
render_pass_info.renderPass = g_vk->getRenderPass();
|
||||
render_pass_info.framebuffer =
|
||||
g_vk->getSwapChainFramebuffers()[g_vk->getCurrentImageIndex()];
|
||||
render_pass_info.renderArea.offset = {0, 0};
|
||||
render_pass_info.renderArea.extent = g_vk->getSwapChainExtent();
|
||||
render_pass_info.clearValueCount = (uint32_t)(clear_values.size());
|
||||
render_pass_info.pClearValues = &clear_values[0];
|
||||
|
||||
VkCommandBufferBeginInfo begin_info = {};
|
||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
|
||||
if (g_tex_map.empty())
|
||||
{
|
||||
VkResult result = vkBeginCommandBuffer(g_vk->getCurrentCommandBuffer(),
|
||||
&begin_info);
|
||||
if (result != VK_SUCCESS)
|
||||
return;
|
||||
|
||||
vkCmdBeginRenderPass(g_vk->getCurrentCommandBuffer(), &render_pass_info,
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
vkCmdEndRenderPass(g_vk->getCurrentCommandBuffer());
|
||||
vkEndCommandBuffer(g_vk->getCurrentCommandBuffer());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::pair<const irr::video::ITexture*, unsigned> > tex_map;
|
||||
for (auto& tex : g_tex_map)
|
||||
tex_map.emplace_back(tex.first, (unsigned)tex.second);
|
||||
|
||||
std::sort(tex_map.begin(), tex_map.end(),
|
||||
[](const std::pair<const irr::video::ITexture*, unsigned>& a,
|
||||
const std::pair<const irr::video::ITexture*, unsigned>& b)
|
||||
{
|
||||
return a.second < b.second;
|
||||
});
|
||||
|
||||
std::vector<VkDescriptorImageInfo> image_infos;
|
||||
for (auto& tex : tex_map)
|
||||
{
|
||||
VkDescriptorImageInfo image_info;
|
||||
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
image_info.imageView = (VkImageView)tex.first->getTextureHandler();
|
||||
image_info.sampler = g_vk->getSampler(GVS_NEAREST);
|
||||
image_infos.push_back(image_info);
|
||||
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();
|
||||
|
||||
vkUpdateDescriptorSets(g_vk->getDevice(), 1, &write_descriptor_set, 0,
|
||||
NULL);
|
||||
|
||||
VkDeviceSize offsets[] = {0};
|
||||
VkBuffer vertex_buffer = VK_NULL_HANDLE;
|
||||
VkBuffer indices_buffer = VK_NULL_HANDLE;
|
||||
|
||||
VkResult result = vkBeginCommandBuffer(g_vk->getCurrentCommandBuffer(),
|
||||
&begin_info);
|
||||
if (result != VK_SUCCESS)
|
||||
goto end;
|
||||
|
||||
g_tris_buffer->setCurrentData(g_tris_queue.data(),
|
||||
g_tris_queue.size() * sizeof(Tri));
|
||||
g_tris_index_buffer->setCurrentData(g_tris_index_queue.data(),
|
||||
g_tris_index_queue.size() * sizeof(uint16_t));
|
||||
|
||||
vkCmdBeginRenderPass(g_vk->getCurrentCommandBuffer(), &render_pass_info,
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vertex_buffer = g_tris_buffer->getCurrentBuffer();
|
||||
indices_buffer = g_tris_index_buffer->getCurrentBuffer();
|
||||
|
||||
if (vertex_buffer == VK_NULL_HANDLE || indices_buffer == VK_NULL_HANDLE)
|
||||
goto end_cmd;
|
||||
|
||||
vkCmdBindPipeline(g_vk->getCurrentCommandBuffer(),
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, g_graphics_pipeline);
|
||||
|
||||
vkCmdBindVertexBuffers(g_vk->getCurrentCommandBuffer(), 0, 1,
|
||||
&vertex_buffer, offsets);
|
||||
|
||||
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);
|
||||
|
||||
vkCmdDrawIndexed(g_vk->getCurrentCommandBuffer(),
|
||||
(uint32_t)(g_tris_index_queue.size()), 1, 0, 0, 0);
|
||||
|
||||
end_cmd:
|
||||
vkCmdEndRenderPass(g_vk->getCurrentCommandBuffer());
|
||||
vkEndCommandBuffer(g_vk->getCurrentCommandBuffer());
|
||||
|
||||
end:
|
||||
g_tex_map.clear();
|
||||
g_tris_queue.clear();
|
||||
g_tris_index_queue.clear();
|
||||
} // render
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkan2dRenderer::addVerticesIndices(irr::video::S3DVertex* vertices,
|
||||
unsigned vertices_count,
|
||||
uint16_t* indices,
|
||||
unsigned indices_count,
|
||||
const irr::video::ITexture* t)
|
||||
{
|
||||
if (g_tex_map.find(t) == g_tex_map.end())
|
||||
{
|
||||
unsigned pre_size = g_tex_map.size();
|
||||
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
|
||||
if (sampler_idx >= (int)GEVulkanShaderManager::getSamplerSize())
|
||||
sampler_idx = GEVulkanShaderManager::getSamplerSize() - 1;
|
||||
uint16_t last_index = (uint16_t)g_tris_queue.size();
|
||||
if (last_index + vertices_count > 65535)
|
||||
return;
|
||||
for (unsigned idx = 0; idx < vertices_count; idx++)
|
||||
{
|
||||
Tri t;
|
||||
const S3DVertex& vertex = vertices[idx];
|
||||
t.pos = core::vector2df(
|
||||
vertex.Pos.X / g_vk->getCurrentRenderTargetSize().Width,
|
||||
vertex.Pos.Y / g_vk->getCurrentRenderTargetSize().Height);
|
||||
t.pos = t.pos * 2.0f;
|
||||
t.pos -= 1.0f;
|
||||
t.color = vertex.Color;
|
||||
t.uv = vertex.TCoords;
|
||||
t.sampler_idx = sampler_idx;
|
||||
g_tris_queue.push_back(t);
|
||||
}
|
||||
for (unsigned idx = 0; idx < indices_count * 3; idx += 3)
|
||||
{
|
||||
g_tris_index_queue.push_back(last_index + indices[idx]);
|
||||
g_tris_index_queue.push_back(last_index + indices[idx + 1]);
|
||||
g_tris_index_queue.push_back(last_index + indices[idx + 2]);
|
||||
}
|
||||
} // addVerticesIndices
|
||||
|
||||
}
|
41
lib/graphics_engine/src/ge_vulkan_2d_renderer.hpp
Normal file
41
lib/graphics_engine/src/ge_vulkan_2d_renderer.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef HEADER_GE_VULKAN_2D_RENDERER_HPP
|
||||
#define HEADER_GE_VULKAN_2D_RENDERER_HPP
|
||||
|
||||
#include "vulkan_wrapper.h"
|
||||
|
||||
#include "ITexture.h"
|
||||
#include "S3DVertex.h"
|
||||
|
||||
namespace GE
|
||||
{
|
||||
class GEVulkanDriver;
|
||||
namespace GEVulkan2dRenderer
|
||||
{
|
||||
// ----------------------------------------------------------------------------
|
||||
void init(GEVulkanDriver*);
|
||||
// ----------------------------------------------------------------------------
|
||||
void destroy();
|
||||
// ----------------------------------------------------------------------------
|
||||
void createDescriptorSetLayout();
|
||||
// ----------------------------------------------------------------------------
|
||||
void createDescriptorPool();
|
||||
// ----------------------------------------------------------------------------
|
||||
void createDescriptorSets();
|
||||
// ----------------------------------------------------------------------------
|
||||
void createPipelineLayout();
|
||||
// ----------------------------------------------------------------------------
|
||||
void createGraphicsPipeline();
|
||||
// ----------------------------------------------------------------------------
|
||||
void createTrisBuffers();
|
||||
// ----------------------------------------------------------------------------
|
||||
void render();
|
||||
// ----------------------------------------------------------------------------
|
||||
void addVerticesIndices(irr::video::S3DVertex* vertices,
|
||||
unsigned vertices_count, uint16_t* indices,
|
||||
unsigned indices_count,
|
||||
const irr::video::ITexture* t);
|
||||
}; // GEVulkanRenderer
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,9 +1,12 @@
|
||||
#include "ge_vulkan_driver.hpp"
|
||||
|
||||
#include "ge_vulkan_2d_renderer.hpp"
|
||||
#include "ge_vulkan_features.hpp"
|
||||
#include "ge_main.hpp"
|
||||
#include "ge_vulkan_shader_manager.hpp"
|
||||
#include "ge_vulkan_texture.hpp"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_VULKAN_
|
||||
const unsigned int MAX_FRAMES_IN_FLIGHT = 2;
|
||||
#include "SDL_vulkan.h"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
@ -453,6 +456,10 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
|
||||
m_properties = {};
|
||||
m_features = {};
|
||||
|
||||
m_current_frame = 0;
|
||||
m_image_index = 0;
|
||||
m_clear_color = video::SColor(0);
|
||||
|
||||
createInstance(window);
|
||||
|
||||
#if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK)
|
||||
@ -475,6 +482,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
|
||||
|
||||
m_device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
findPhysicalDevice();
|
||||
GEVulkanFeatures::init(this);
|
||||
createDevice();
|
||||
|
||||
#if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK)
|
||||
@ -493,13 +501,19 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
|
||||
createCommandPool();
|
||||
createCommandBuffers();
|
||||
createSamplers();
|
||||
createRenderPass();
|
||||
createFramebuffers();
|
||||
GEVulkanShaderManager::init(this);
|
||||
// For GEVulkanDynamicBuffer
|
||||
GE::setVideoDriver(this);
|
||||
GEVulkan2dRenderer::init(this);
|
||||
os::Printer::log("Vulkan version", getVulkanVersionString().c_str());
|
||||
os::Printer::log("Vulkan vendor", getVendorInfo().c_str());
|
||||
os::Printer::log("Vulkan renderer", m_properties.deviceName);
|
||||
os::Printer::log("Vulkan driver version", getDriverVersionString().c_str());
|
||||
for (const char* ext : m_device_extensions)
|
||||
os::Printer::log("Vulkan enabled extension", ext);
|
||||
GEVulkanFeatures::printStats();
|
||||
} // GEVulkanDriver
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -510,6 +524,7 @@ GEVulkanDriver::~GEVulkanDriver()
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDriver::destroyVulkan()
|
||||
{
|
||||
GEVulkan2dRenderer::destroy();
|
||||
GEVulkanShaderManager::destroy();
|
||||
delete m_vk.get();
|
||||
m_vk.release();
|
||||
@ -518,6 +533,9 @@ void GEVulkanDriver::destroyVulkan()
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDriver::createInstance(SDL_Window* window)
|
||||
{
|
||||
#define VK_MAKE_API_VERSION(variant, major, minor, patch) \
|
||||
((((uint32_t)(variant)) << 29) | (((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch)))
|
||||
|
||||
#if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK)
|
||||
if (gladLoadVulkanUserPtr(NULL, (GLADuserptrloadfunc)loader, NULL) == 0)
|
||||
{
|
||||
@ -531,10 +549,43 @@ void GEVulkanDriver::createInstance(SDL_Window* window)
|
||||
std::vector<const char*> extensions(count, NULL);
|
||||
if (!SDL_Vulkan_GetInstanceExtensions(window, &count, extensions.data()))
|
||||
throw std::runtime_error("SDL_Vulkan_GetInstanceExtensions failed with extensions vector");
|
||||
|
||||
uint32_t vk_version = 0;
|
||||
bool vulkan_1_1 = false;
|
||||
#if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK)
|
||||
PFN_vkEnumerateInstanceVersion e_ver = (PFN_vkEnumerateInstanceVersion)
|
||||
vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
|
||||
vulkan_1_1 = (e_ver && e_ver(&vk_version) == VK_SUCCESS &&
|
||||
vk_version >= VK_MAKE_API_VERSION(0, 1, 1, 0));
|
||||
#else
|
||||
vulkan_1_1 = (vkEnumerateInstanceVersion(&vk_version) == VK_SUCCESS &&
|
||||
vk_version >= VK_MAKE_API_VERSION(0, 1, 1, 0));
|
||||
#endif
|
||||
|
||||
uint32_t layer_count = 0;
|
||||
vkEnumerateInstanceLayerProperties(&layer_count, NULL);
|
||||
std::vector<VkLayerProperties> available_layers(layer_count);
|
||||
vkEnumerateInstanceLayerProperties(&layer_count, available_layers.data());
|
||||
|
||||
std::vector<const char*> enabled_validation_layers;
|
||||
#ifdef ENABLE_VALIDATION
|
||||
for (VkLayerProperties& prop : available_layers)
|
||||
{
|
||||
if (std::string(prop.layerName) == "VK_LAYER_KHRONOS_validation")
|
||||
enabled_validation_layers.push_back("VK_LAYER_KHRONOS_validation");
|
||||
}
|
||||
#endif
|
||||
|
||||
VkInstanceCreateInfo create_info = {};
|
||||
VkApplicationInfo app_info = {};
|
||||
if (vulkan_1_1)
|
||||
app_info.apiVersion = vk_version;
|
||||
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
create_info.enabledExtensionCount = extensions.size();
|
||||
create_info.ppEnabledExtensionNames = extensions.data();
|
||||
create_info.pApplicationInfo = &app_info;
|
||||
create_info.enabledLayerCount = enabled_validation_layers.size();
|
||||
create_info.ppEnabledLayerNames = enabled_validation_layers.data();
|
||||
VkResult result = vkCreateInstance(&create_info, NULL, &m_vk->instance);
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("vkCreateInstance failed");
|
||||
@ -709,6 +760,15 @@ void GEVulkanDriver::createDevice()
|
||||
throw std::runtime_error("doesn't support shaderSampledImageArrayDynamicIndexing");
|
||||
device_features.shaderSampledImageArrayDynamicIndexing = VK_TRUE;
|
||||
|
||||
VkPhysicalDeviceVulkan12Features vulkan12_features = {};
|
||||
vulkan12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
|
||||
vulkan12_features.descriptorIndexing =
|
||||
GEVulkanFeatures::supportsDescriptorIndexing();
|
||||
vulkan12_features.shaderSampledImageArrayNonUniformIndexing =
|
||||
GEVulkanFeatures::supportsNonUniformIndexing();
|
||||
vulkan12_features.descriptorBindingPartiallyBound =
|
||||
GEVulkanFeatures::supportsPartiallyBound();
|
||||
|
||||
if (m_features.samplerAnisotropy == VK_TRUE)
|
||||
device_features.samplerAnisotropy = VK_TRUE;
|
||||
|
||||
@ -720,6 +780,7 @@ void GEVulkanDriver::createDevice()
|
||||
create_info.enabledExtensionCount = m_device_extensions.size();
|
||||
create_info.ppEnabledExtensionNames = &m_device_extensions[0];
|
||||
create_info.enabledLayerCount = 0;
|
||||
create_info.pNext = &vulkan12_features;
|
||||
|
||||
VkResult result = vkCreateDevice(m_physical_device, &create_info, NULL, &m_vk->device);
|
||||
|
||||
@ -898,6 +959,8 @@ found_mode:
|
||||
|
||||
m_swap_chain_image_format = surface_format.format;
|
||||
m_swap_chain_extent = image_extent;
|
||||
ScreenSize.Width = m_swap_chain_extent.width;
|
||||
ScreenSize.Height = m_swap_chain_extent.height;
|
||||
|
||||
for (unsigned int i = 0; i < m_vk->swap_chain_images.size(); i++)
|
||||
{
|
||||
@ -936,7 +999,7 @@ void GEVulkanDriver::createSyncObjects()
|
||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
for (unsigned int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
for (unsigned int i = 0; i < getMaxFrameInFlight(); i++)
|
||||
{
|
||||
VkSemaphore image_available_semaphore;
|
||||
VkResult result = vkCreateSemaphore(m_vk->device, &semaphore_info, NULL,
|
||||
@ -977,6 +1040,7 @@ void GEVulkanDriver::createCommandPool()
|
||||
VkCommandPoolCreateInfo pool_info = {};
|
||||
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
pool_info.queueFamilyIndex = m_graphics_family;
|
||||
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
|
||||
VkResult result = vkCreateCommandPool(m_vk->device, &pool_info, NULL,
|
||||
&m_vk->command_pool);
|
||||
@ -988,7 +1052,7 @@ void GEVulkanDriver::createCommandPool()
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDriver::createCommandBuffers()
|
||||
{
|
||||
std::vector<VkCommandBuffer> buffers(MAX_FRAMES_IN_FLIGHT);
|
||||
std::vector<VkCommandBuffer> buffers(getMaxFrameInFlight());
|
||||
|
||||
VkCommandBufferAllocateInfo alloc_info = {};
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
@ -1033,6 +1097,84 @@ void GEVulkanDriver::createSamplers()
|
||||
m_vk->samplers[GVS_NEAREST] = sampler;
|
||||
} // createSamplers
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDriver::createRenderPass()
|
||||
{
|
||||
VkAttachmentDescription color_attachment = {};
|
||||
color_attachment.format = m_swap_chain_image_format;
|
||||
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
VkAttachmentReference color_attachment_ref = {};
|
||||
color_attachment_ref.attachment = 0;
|
||||
color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription subpass = {};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &color_attachment_ref;
|
||||
|
||||
VkSubpassDependency dependency = {};
|
||||
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
dependency.dstSubpass = 0;
|
||||
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependency.srcAccessMask = 0;
|
||||
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
std::array<VkAttachmentDescription, 1> attachments = { color_attachment };
|
||||
VkRenderPassCreateInfo render_pass_info = {};
|
||||
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
render_pass_info.attachmentCount = (uint32_t)(attachments.size());
|
||||
render_pass_info.pAttachments = &attachments[0];
|
||||
render_pass_info.subpassCount = 1;
|
||||
render_pass_info.pSubpasses = &subpass;
|
||||
render_pass_info.dependencyCount = 1;
|
||||
render_pass_info.pDependencies = &dependency;
|
||||
|
||||
VkResult result = vkCreateRenderPass(m_vk->device, &render_pass_info, NULL,
|
||||
&m_vk->render_pass);
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("vkCreateRenderPass failed");
|
||||
} // createRenderPass
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDriver::createFramebuffers()
|
||||
{
|
||||
const std::vector<VkImageView>& image_views = m_vk->swap_chain_image_views;
|
||||
for (unsigned int i = 0; i < image_views.size(); i++)
|
||||
{
|
||||
std::array<VkImageView, 1> attachments =
|
||||
{
|
||||
image_views[i]
|
||||
};
|
||||
|
||||
VkFramebufferCreateInfo framebuffer_info = {};
|
||||
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebuffer_info.renderPass = m_vk->render_pass;
|
||||
framebuffer_info.attachmentCount = (uint32_t)(attachments.size());
|
||||
framebuffer_info.pAttachments = &attachments[0];
|
||||
framebuffer_info.width = m_swap_chain_extent.width;
|
||||
framebuffer_info.height = m_swap_chain_extent.height;
|
||||
framebuffer_info.layers = 1;
|
||||
|
||||
VkFramebuffer swap_chain_framebuffer = VK_NULL_HANDLE;
|
||||
VkResult result = vkCreateFramebuffer(m_vk->device, &framebuffer_info,
|
||||
NULL, &swap_chain_framebuffer);
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("vkCreateFramebuffer failed");
|
||||
|
||||
m_vk->swap_chain_framebuffers.push_back(swap_chain_framebuffer);
|
||||
}
|
||||
} // createFramebuffers
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GEVulkanDriver::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties,
|
||||
@ -1087,6 +1229,19 @@ bool GEVulkanDriver::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
return true;
|
||||
} // createBuffer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDriver::copyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer,
|
||||
VkDeviceSize size)
|
||||
{
|
||||
VkCommandBuffer command_buffer = beginSingleTimeCommands();
|
||||
|
||||
VkBufferCopy copy_region = {};
|
||||
copy_region.size = size;
|
||||
vkCmdCopyBuffer(command_buffer, src_buffer, dst_buffer, 1, ©_region);
|
||||
|
||||
endSingleTimeCommands(command_buffer);
|
||||
} // copyBuffer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
VkCommandBuffer GEVulkanDriver::beginSingleTimeCommands()
|
||||
{
|
||||
@ -1130,6 +1285,418 @@ void GEVulkanDriver::OnResize(const core::dimension2d<u32>& size)
|
||||
CNullDriver::OnResize(size);
|
||||
} // OnResize
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GEVulkanDriver::beginScene(bool backBuffer, bool zBuffer, SColor color,
|
||||
const SExposedVideoData& videoData,
|
||||
core::rect<s32>* sourceRect)
|
||||
{
|
||||
if (!video::CNullDriver::beginScene(backBuffer, zBuffer, color, videoData,
|
||||
sourceRect))
|
||||
return false;
|
||||
|
||||
m_clear_color = color;
|
||||
VkFence fence = m_vk->in_flight_fences[m_current_frame];
|
||||
vkWaitForFences(m_vk->device, 1, &fence, VK_TRUE,
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
vkResetFences(m_vk->device, 1, &fence);
|
||||
|
||||
VkSemaphore semaphore = m_vk->image_available_semaphores[m_current_frame];
|
||||
VkResult result = vkAcquireNextImageKHR(m_vk->device, m_vk->swap_chain,
|
||||
std::numeric_limits<uint64_t>::max(), semaphore, VK_NULL_HANDLE,
|
||||
&m_image_index);
|
||||
|
||||
return (result != VK_ERROR_OUT_OF_DATE_KHR);
|
||||
} // beginScene
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GEVulkanDriver::endScene()
|
||||
{
|
||||
GEVulkan2dRenderer::render();
|
||||
|
||||
VkSemaphore wait_semaphores[] = {m_vk->image_available_semaphores[m_current_frame]};
|
||||
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||
VkSemaphore signal_semaphores[] = {m_vk->render_finished_semaphores[m_current_frame]};
|
||||
|
||||
VkSubmitInfo submit_info = {};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.waitSemaphoreCount = 1;
|
||||
submit_info.pWaitSemaphores = wait_semaphores;
|
||||
submit_info.pWaitDstStageMask = wait_stages;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &m_vk->command_buffers[m_current_frame];
|
||||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores = signal_semaphores;
|
||||
|
||||
VkResult result = vkQueueSubmit(m_graphics_queue, 1, &submit_info,
|
||||
m_vk->in_flight_fences[m_current_frame]);
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
return false;
|
||||
|
||||
VkSemaphore semaphores[] =
|
||||
{
|
||||
m_vk->render_finished_semaphores[m_current_frame]
|
||||
};
|
||||
VkSwapchainKHR swap_chains[] =
|
||||
{
|
||||
m_vk->swap_chain
|
||||
};
|
||||
|
||||
VkPresentInfoKHR present_info = {};
|
||||
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
present_info.waitSemaphoreCount = 1;
|
||||
present_info.pWaitSemaphores = semaphores;
|
||||
present_info.swapchainCount = 1;
|
||||
present_info.pSwapchains = swap_chains;
|
||||
present_info.pImageIndices = &m_image_index;
|
||||
|
||||
m_current_frame = (m_current_frame + 1) % getMaxFrameInFlight();
|
||||
|
||||
result = vkQueuePresentKHR(m_present_queue, &present_info);
|
||||
|
||||
if (!video::CNullDriver::endScene())
|
||||
return false;
|
||||
|
||||
return (result != VK_ERROR_OUT_OF_DATE_KHR && result != VK_SUBOPTIMAL_KHR);
|
||||
} // endScene
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDriver::draw2DVertexPrimitiveList(const void* vertices,
|
||||
u32 vertexCount,
|
||||
const void* indexList,
|
||||
u32 primitiveCount,
|
||||
E_VERTEX_TYPE vType,
|
||||
scene::E_PRIMITIVE_TYPE pType,
|
||||
E_INDEX_TYPE iType)
|
||||
{
|
||||
const GEVulkanTexture* texture =
|
||||
dynamic_cast<const GEVulkanTexture*>(Material.getTexture(0));
|
||||
if (!texture)
|
||||
return;
|
||||
if (vType != EVT_STANDARD || iType != EIT_16BIT)
|
||||
return;
|
||||
if (pType == irr::scene::EPT_TRIANGLES)
|
||||
{
|
||||
S3DVertex* v = (S3DVertex*)vertices;
|
||||
u16* i = (u16*)indexList;
|
||||
GEVulkan2dRenderer::addVerticesIndices(v, vertexCount, i,
|
||||
primitiveCount, texture);
|
||||
}
|
||||
} // draw2DVertexPrimitiveList
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDriver::draw2DImage(const video::ITexture* tex,
|
||||
const core::position2d<s32>& destPos,
|
||||
const core::rect<s32>& sourceRect,
|
||||
const core::rect<s32>* clipRect,
|
||||
SColor color, bool useAlphaChannelOfTexture)
|
||||
{
|
||||
const GEVulkanTexture* texture = dynamic_cast<const GEVulkanTexture*>(tex);
|
||||
if (!texture)
|
||||
return;
|
||||
|
||||
if (!sourceRect.isValid())
|
||||
return;
|
||||
|
||||
core::position2d<s32> targetPos = destPos;
|
||||
core::position2d<s32> sourcePos = sourceRect.UpperLeftCorner;
|
||||
// This needs to be signed as it may go negative.
|
||||
core::dimension2d<s32> sourceSize(sourceRect.getSize());
|
||||
|
||||
if (clipRect)
|
||||
{
|
||||
if (targetPos.X < clipRect->UpperLeftCorner.X)
|
||||
{
|
||||
sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X;
|
||||
if (sourceSize.Width <= 0)
|
||||
return;
|
||||
|
||||
sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X;
|
||||
targetPos.X = clipRect->UpperLeftCorner.X;
|
||||
}
|
||||
|
||||
if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X)
|
||||
{
|
||||
sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X;
|
||||
if (sourceSize.Width <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetPos.Y < clipRect->UpperLeftCorner.Y)
|
||||
{
|
||||
sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y;
|
||||
if (sourceSize.Height <= 0)
|
||||
return;
|
||||
|
||||
sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y;
|
||||
targetPos.Y = clipRect->UpperLeftCorner.Y;
|
||||
}
|
||||
|
||||
if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y)
|
||||
{
|
||||
sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y;
|
||||
if (sourceSize.Height <= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// clip these coordinates
|
||||
|
||||
if (targetPos.X<0)
|
||||
{
|
||||
sourceSize.Width += targetPos.X;
|
||||
if (sourceSize.Width <= 0)
|
||||
return;
|
||||
|
||||
sourcePos.X -= targetPos.X;
|
||||
targetPos.X = 0;
|
||||
}
|
||||
|
||||
const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
|
||||
|
||||
if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width)
|
||||
{
|
||||
sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width;
|
||||
if (sourceSize.Width <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetPos.Y<0)
|
||||
{
|
||||
sourceSize.Height += targetPos.Y;
|
||||
if (sourceSize.Height <= 0)
|
||||
return;
|
||||
|
||||
sourcePos.Y -= targetPos.Y;
|
||||
targetPos.Y = 0;
|
||||
}
|
||||
|
||||
if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height)
|
||||
{
|
||||
sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height;
|
||||
if (sourceSize.Height <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// ok, we've clipped everything.
|
||||
// now draw it.
|
||||
|
||||
core::rect<f32> tcoords;
|
||||
tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)) / texture->getSize().Width ;
|
||||
tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)) / texture->getSize().Height;
|
||||
tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + ((f32)(sourceSize.Width) / texture->getSize().Width);
|
||||
tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + ((f32)(sourceSize.Height) / texture->getSize().Height);
|
||||
|
||||
const core::rect<s32> poss(targetPos, sourceSize);
|
||||
|
||||
S3DVertex vtx[4];
|
||||
vtx[0] = S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, color,
|
||||
tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
|
||||
vtx[1] = S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, color,
|
||||
tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
|
||||
vtx[2] = S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, color,
|
||||
tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
|
||||
vtx[3] = S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, color,
|
||||
tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
|
||||
|
||||
u16 indices[6] = {0,1,2,0,2,3};
|
||||
|
||||
GEVulkan2dRenderer::addVerticesIndices(&vtx[0], 4, &indices[0], 2, texture);
|
||||
} // draw2DImage
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDriver::draw2DImage(const video::ITexture* tex,
|
||||
const core::rect<s32>& destRect,
|
||||
const core::rect<s32>& sourceRect,
|
||||
const core::rect<s32>* clipRect,
|
||||
const video::SColor* const colors,
|
||||
bool useAlphaChannelOfTexture)
|
||||
{
|
||||
const GEVulkanTexture* texture = dynamic_cast<const GEVulkanTexture*>(tex);
|
||||
if (!texture)
|
||||
return;
|
||||
|
||||
const core::dimension2d<u32>& ss = texture->getSize();
|
||||
core::rect<f32> tcoords;
|
||||
tcoords.UpperLeftCorner.X = (f32)sourceRect.UpperLeftCorner.X / (f32)ss.Width;
|
||||
tcoords.UpperLeftCorner.Y = (f32)sourceRect.UpperLeftCorner.Y / (f32)ss.Height;
|
||||
tcoords.LowerRightCorner.X = (f32)sourceRect.LowerRightCorner.X / (f32)ss.Width;
|
||||
tcoords.LowerRightCorner.Y = (f32)sourceRect.LowerRightCorner.Y / (f32)ss.Height;
|
||||
|
||||
const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
|
||||
|
||||
const video::SColor temp[4] =
|
||||
{
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF
|
||||
};
|
||||
|
||||
const video::SColor* const useColor = colors ? colors : temp;
|
||||
|
||||
S3DVertex vtx[4];
|
||||
vtx[0] = S3DVertex((f32)destRect.UpperLeftCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, useColor[0],
|
||||
tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
|
||||
vtx[1] = S3DVertex((f32)destRect.LowerRightCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, useColor[3],
|
||||
tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
|
||||
vtx[2] = S3DVertex((f32)destRect.LowerRightCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, useColor[2],
|
||||
tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
|
||||
vtx[3] = S3DVertex((f32)destRect.UpperLeftCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, useColor[1],
|
||||
tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
|
||||
|
||||
u16 indices[6] = {0,1,2,0,2,3};
|
||||
|
||||
GEVulkan2dRenderer::addVerticesIndices(&vtx[0], 4, &indices[0], 2, texture);
|
||||
} // draw2DImage
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDriver::draw2DImageBatch(const video::ITexture* tex,
|
||||
const core::array<core::position2d<s32> >& positions,
|
||||
const core::array<core::rect<s32> >& sourceRects,
|
||||
const core::rect<s32>* clipRect, SColor color,
|
||||
bool useAlphaChannelOfTexture)
|
||||
{
|
||||
const GEVulkanTexture* texture = dynamic_cast<const GEVulkanTexture*>(tex);
|
||||
if (!texture)
|
||||
return;
|
||||
|
||||
const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
|
||||
|
||||
core::array<S3DVertex> vtx(drawCount * 4);
|
||||
core::array<u16> indices(drawCount * 6);
|
||||
|
||||
for(u32 i = 0;i < drawCount;i++)
|
||||
{
|
||||
core::position2d<s32> targetPos = positions[i];
|
||||
core::position2d<s32> sourcePos = sourceRects[i].UpperLeftCorner;
|
||||
// This needs to be signed as it may go negative.
|
||||
core::dimension2d<s32> sourceSize(sourceRects[i].getSize());
|
||||
|
||||
if (clipRect)
|
||||
{
|
||||
if (targetPos.X < clipRect->UpperLeftCorner.X)
|
||||
{
|
||||
sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X;
|
||||
if (sourceSize.Width <= 0)
|
||||
continue;
|
||||
|
||||
sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X;
|
||||
targetPos.X = clipRect->UpperLeftCorner.X;
|
||||
}
|
||||
|
||||
if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X)
|
||||
{
|
||||
sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X;
|
||||
if (sourceSize.Width <= 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (targetPos.Y < clipRect->UpperLeftCorner.Y)
|
||||
{
|
||||
sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y;
|
||||
if (sourceSize.Height <= 0)
|
||||
continue;
|
||||
|
||||
sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y;
|
||||
targetPos.Y = clipRect->UpperLeftCorner.Y;
|
||||
}
|
||||
|
||||
if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y)
|
||||
{
|
||||
sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y;
|
||||
if (sourceSize.Height <= 0)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// clip these coordinates
|
||||
|
||||
if (targetPos.X<0)
|
||||
{
|
||||
sourceSize.Width += targetPos.X;
|
||||
if (sourceSize.Width <= 0)
|
||||
continue;
|
||||
|
||||
sourcePos.X -= targetPos.X;
|
||||
targetPos.X = 0;
|
||||
}
|
||||
|
||||
const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
|
||||
|
||||
if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width)
|
||||
{
|
||||
sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width;
|
||||
if (sourceSize.Width <= 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (targetPos.Y<0)
|
||||
{
|
||||
sourceSize.Height += targetPos.Y;
|
||||
if (sourceSize.Height <= 0)
|
||||
continue;
|
||||
|
||||
sourcePos.Y -= targetPos.Y;
|
||||
targetPos.Y = 0;
|
||||
}
|
||||
|
||||
if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height)
|
||||
{
|
||||
sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height;
|
||||
if (sourceSize.Height <= 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
// ok, we've clipped everything.
|
||||
// now draw it.
|
||||
|
||||
core::rect<f32> tcoords;
|
||||
tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)) / texture->getSize().Width ;
|
||||
tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)) / texture->getSize().Height;
|
||||
tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + ((f32)(sourceSize.Width) / texture->getSize().Width);
|
||||
tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + ((f32)(sourceSize.Height) / texture->getSize().Height);
|
||||
|
||||
const core::rect<s32> poss(targetPos, sourceSize);
|
||||
|
||||
vtx.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, color,
|
||||
tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y));
|
||||
vtx.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, color,
|
||||
tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y));
|
||||
vtx.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, color,
|
||||
tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y));
|
||||
vtx.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, color,
|
||||
tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y));
|
||||
|
||||
const u32 curPos = vtx.size()-4;
|
||||
indices.push_back(0+curPos);
|
||||
indices.push_back(1+curPos);
|
||||
indices.push_back(2+curPos);
|
||||
|
||||
indices.push_back(0+curPos);
|
||||
indices.push_back(2+curPos);
|
||||
indices.push_back(3+curPos);
|
||||
}
|
||||
|
||||
if (vtx.size())
|
||||
{
|
||||
GEVulkan2dRenderer::addVerticesIndices(vtx.pointer(), vtx.size(),
|
||||
indices.pointer(), indices.size() / 3, texture);
|
||||
}
|
||||
} // draw2DImageBatch
|
||||
|
||||
}
|
||||
|
||||
namespace irr
|
||||
|
227
lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp
Normal file
227
lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp
Normal file
@ -0,0 +1,227 @@
|
||||
#include "ge_vulkan_dynamic_buffer.hpp"
|
||||
|
||||
#include "ge_vulkan_driver.hpp"
|
||||
#include "ge_main.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace GE
|
||||
{
|
||||
VkMemoryPropertyFlags GEVulkanDynamicBuffer::m_host_flag = (VkMemoryPropertyFlags)-1;
|
||||
// ----------------------------------------------------------------------------
|
||||
GEVulkanDynamicBuffer::GEVulkanDynamicBuffer(GEVulkanDynamicBufferType t,
|
||||
VkBufferUsageFlags usage,
|
||||
size_t initial_size)
|
||||
{
|
||||
m_type = t;
|
||||
m_usage = usage;
|
||||
m_size = initial_size;
|
||||
|
||||
m_buffer = new VkBuffer[GEVulkanDriver::getMaxFrameInFlight()];
|
||||
m_memory = new VkDeviceMemory[GEVulkanDriver::getMaxFrameInFlight()];
|
||||
m_mapped_addr = new void*[GEVulkanDriver::getMaxFrameInFlight()];
|
||||
if (t == GVDBT_GPU_RAM)
|
||||
{
|
||||
m_staging_buffer = new VkBuffer[GEVulkanDriver::getMaxFrameInFlight()];
|
||||
m_staging_memory = new VkDeviceMemory[GEVulkanDriver::getMaxFrameInFlight()];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_staging_buffer = NULL;
|
||||
m_staging_memory = NULL;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < GEVulkanDriver::getMaxFrameInFlight(); i++)
|
||||
initPerFrame(i);
|
||||
} // GEVulkanDynamicBuffer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GEVulkanDynamicBuffer::~GEVulkanDynamicBuffer()
|
||||
{
|
||||
destroy();
|
||||
delete [] m_buffer;
|
||||
delete [] m_memory;
|
||||
delete [] m_staging_buffer;
|
||||
delete [] m_staging_memory;
|
||||
delete [] m_mapped_addr;
|
||||
} // ~GEVulkanDynamicBuffer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDynamicBuffer::initPerFrame(unsigned frame)
|
||||
{
|
||||
m_buffer[frame] = VK_NULL_HANDLE;
|
||||
m_memory[frame] = VK_NULL_HANDLE;
|
||||
m_mapped_addr[frame] = NULL;
|
||||
if (m_type == GVDBT_GPU_RAM)
|
||||
{
|
||||
m_staging_buffer[frame] = VK_NULL_HANDLE;
|
||||
m_staging_memory[frame] = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkBuffer host_buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory host_memory = VK_NULL_HANDLE;
|
||||
VkMemoryPropertyFlags host_flag = 0;
|
||||
if (m_host_flag == (VkFlags)-1)
|
||||
{
|
||||
// https://zeux.io/2020/02/27/writing-an-efficient-vulkan-renderer/
|
||||
m_host_flag = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
bool better_flag_exist = false;
|
||||
if (getVKDriver()->createBuffer(m_size,
|
||||
m_usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, m_host_flag,
|
||||
host_buffer, host_memory))
|
||||
{
|
||||
better_flag_exist = true;
|
||||
if (m_type == GVDBT_SYSTEM_RAM)
|
||||
goto succeed;
|
||||
}
|
||||
|
||||
if (host_buffer != VK_NULL_HANDLE)
|
||||
vkDestroyBuffer(getVKDriver()->getDevice(), host_buffer, NULL);
|
||||
host_buffer = VK_NULL_HANDLE;
|
||||
if (host_memory != VK_NULL_HANDLE)
|
||||
vkFreeMemory(getVKDriver()->getDevice(), host_memory, NULL);
|
||||
host_memory = VK_NULL_HANDLE;
|
||||
|
||||
if (!better_flag_exist)
|
||||
{
|
||||
m_host_flag = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
host_flag = m_host_flag;
|
||||
// From the above website:
|
||||
// This flag should be used to store staging buffers that are used to
|
||||
// populate static resources allocated with
|
||||
// VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with data.
|
||||
if (m_type == GVDBT_GPU_RAM)
|
||||
{
|
||||
host_flag = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
|
||||
if (!getVKDriver()->createBuffer(m_size,
|
||||
m_usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, host_flag,
|
||||
host_buffer, host_memory))
|
||||
{
|
||||
if (host_buffer != VK_NULL_HANDLE)
|
||||
vkDestroyBuffer(getVKDriver()->getDevice(), host_buffer, NULL);
|
||||
if (host_memory != VK_NULL_HANDLE)
|
||||
vkFreeMemory(getVKDriver()->getDevice(), host_memory, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
succeed:
|
||||
if (m_type == GVDBT_SYSTEM_RAM)
|
||||
{
|
||||
m_buffer[frame] = host_buffer;
|
||||
m_memory[frame] = host_memory;
|
||||
|
||||
if (vkMapMemory(getVKDriver()->getDevice(), m_memory[frame], 0, m_size,
|
||||
0, &m_mapped_addr[frame]) != VK_SUCCESS)
|
||||
{
|
||||
destroyPerFrame(frame);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
VkBuffer local_buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory local_memory = VK_NULL_HANDLE;
|
||||
if (!getVKDriver()->createBuffer(m_size,
|
||||
m_usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, local_buffer, local_memory))
|
||||
{
|
||||
if (host_buffer != VK_NULL_HANDLE)
|
||||
vkDestroyBuffer(getVKDriver()->getDevice(), host_buffer, NULL);
|
||||
if (host_memory != VK_NULL_HANDLE)
|
||||
vkFreeMemory(getVKDriver()->getDevice(), host_memory, NULL);
|
||||
if (local_buffer != VK_NULL_HANDLE)
|
||||
vkDestroyBuffer(getVKDriver()->getDevice(), local_buffer, NULL);
|
||||
if (local_memory != VK_NULL_HANDLE)
|
||||
vkFreeMemory(getVKDriver()->getDevice(), local_memory, NULL);
|
||||
return;
|
||||
}
|
||||
m_buffer[frame] = local_buffer;
|
||||
m_memory[frame] = local_memory;
|
||||
m_staging_buffer[frame] = host_buffer;
|
||||
m_staging_memory[frame] = host_memory;
|
||||
|
||||
if (vkMapMemory(getVKDriver()->getDevice(), m_staging_memory[frame], 0,
|
||||
m_size, 0, &m_mapped_addr[frame]) != VK_SUCCESS)
|
||||
{
|
||||
destroyPerFrame(frame);
|
||||
}
|
||||
} // initPerFrame
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDynamicBuffer::destroyPerFrame(unsigned frame)
|
||||
{
|
||||
if ((m_staging_memory && m_staging_memory[frame] != VK_NULL_HANDLE) ||
|
||||
m_memory[frame] != VK_NULL_HANDLE)
|
||||
{
|
||||
vkUnmapMemory(getVKDriver()->getDevice(), m_type == GVDBT_GPU_RAM ?
|
||||
m_staging_memory[frame] : m_memory[frame]);
|
||||
}
|
||||
|
||||
if (m_memory[frame] != VK_NULL_HANDLE)
|
||||
vkFreeMemory(getVKDriver()->getDevice(), m_memory[frame], NULL);
|
||||
if (m_buffer[frame] != VK_NULL_HANDLE)
|
||||
vkDestroyBuffer(getVKDriver()->getDevice(), m_buffer[frame], NULL);
|
||||
|
||||
m_buffer[frame] = VK_NULL_HANDLE;
|
||||
m_memory[frame] = VK_NULL_HANDLE;
|
||||
m_mapped_addr[frame] = NULL;
|
||||
|
||||
if (m_type == GVDBT_GPU_RAM)
|
||||
{
|
||||
if (m_staging_buffer[frame] != VK_NULL_HANDLE)
|
||||
vkDestroyBuffer(getVKDriver()->getDevice(), m_staging_buffer[frame], NULL);
|
||||
if (m_staging_memory[frame] != VK_NULL_HANDLE)
|
||||
vkFreeMemory(getVKDriver()->getDevice(), m_staging_memory[frame], NULL);
|
||||
m_staging_buffer[frame] = VK_NULL_HANDLE;
|
||||
m_staging_memory[frame] = VK_NULL_HANDLE;
|
||||
}
|
||||
} // destroyPerFrame
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDynamicBuffer::destroy()
|
||||
{
|
||||
vkDeviceWaitIdle(getVKDriver()->getDevice());
|
||||
for (unsigned i = 0; i < GEVulkanDriver::getMaxFrameInFlight(); i++)
|
||||
destroyPerFrame(i);
|
||||
} // destroy
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDynamicBuffer::setCurrentData(void* data, size_t size)
|
||||
{
|
||||
const unsigned cur_frame = getVKDriver()->getCurrentFrame();
|
||||
if (size > m_size)
|
||||
{
|
||||
destroy();
|
||||
m_size = size + 100;
|
||||
for (unsigned i = 0; i < GEVulkanDriver::getMaxFrameInFlight(); i++)
|
||||
initPerFrame(i);
|
||||
}
|
||||
if (m_mapped_addr[cur_frame] == NULL)
|
||||
return;
|
||||
memcpy(m_mapped_addr[cur_frame], data, size);
|
||||
if (m_type == GVDBT_GPU_RAM)
|
||||
{
|
||||
VkBufferCopy copy_region = {};
|
||||
copy_region.size = size;
|
||||
vkCmdCopyBuffer(getVKDriver()->getCurrentCommandBuffer(),
|
||||
m_staging_buffer[cur_frame], m_buffer[cur_frame], 1, ©_region);
|
||||
}
|
||||
} // setCurrentData
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
VkBuffer GEVulkanDynamicBuffer::getCurrentBuffer() const
|
||||
{
|
||||
return m_buffer[getVKDriver()->getCurrentFrame()];
|
||||
} // getCurrentBuffer
|
||||
|
||||
}
|
56
lib/graphics_engine/src/ge_vulkan_dynamic_buffer.hpp
Normal file
56
lib/graphics_engine/src/ge_vulkan_dynamic_buffer.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef HEADER_GE_VULKAN_DYNAMIC_BUFFER_HPP
|
||||
#define HEADER_GE_VULKAN_DYNAMIC_BUFFER_HPP
|
||||
|
||||
#include "vulkan_wrapper.h"
|
||||
|
||||
namespace GE
|
||||
{
|
||||
|
||||
enum GEVulkanDynamicBufferType : unsigned
|
||||
{
|
||||
GVDBT_GPU_RAM,
|
||||
GVDBT_SYSTEM_RAM
|
||||
};
|
||||
|
||||
class GEVulkanDynamicBuffer
|
||||
{
|
||||
private:
|
||||
VkBuffer* m_buffer;
|
||||
|
||||
VkDeviceMemory* m_memory;
|
||||
|
||||
VkBuffer* m_staging_buffer;
|
||||
|
||||
VkDeviceMemory* m_staging_memory;
|
||||
|
||||
void** m_mapped_addr;
|
||||
|
||||
VkBufferUsageFlags m_usage;
|
||||
|
||||
GEVulkanDynamicBufferType m_type;
|
||||
|
||||
static VkMemoryPropertyFlags m_host_flag;
|
||||
|
||||
size_t m_size;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void initPerFrame(unsigned frame);
|
||||
// ------------------------------------------------------------------------
|
||||
void destroyPerFrame(unsigned frame);
|
||||
// ------------------------------------------------------------------------
|
||||
void destroy();
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
GEVulkanDynamicBuffer(GEVulkanDynamicBufferType t,
|
||||
VkBufferUsageFlags usage, size_t initial_size);
|
||||
// ------------------------------------------------------------------------
|
||||
~GEVulkanDynamicBuffer();
|
||||
// ------------------------------------------------------------------------
|
||||
void setCurrentData(void* data, size_t size);
|
||||
// ------------------------------------------------------------------------
|
||||
VkBuffer getCurrentBuffer() const;
|
||||
}; // GEVulkanDynamicBuffer
|
||||
|
||||
}
|
||||
|
||||
#endif
|
90
lib/graphics_engine/src/ge_vulkan_features.cpp
Normal file
90
lib/graphics_engine/src/ge_vulkan_features.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include "ge_vulkan_features.hpp"
|
||||
|
||||
#include "ge_vulkan_driver.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../source/Irrlicht/os.h"
|
||||
|
||||
namespace GE
|
||||
{
|
||||
namespace GEVulkanFeatures
|
||||
{
|
||||
// ============================================================================
|
||||
// https://chunkstories.xyz/blog/a-note-on-descriptor-indexing
|
||||
bool g_supports_descriptor_indexing = false;
|
||||
bool g_supports_non_uniform_indexing = false;
|
||||
bool g_supports_partially_bound = false;
|
||||
} // GEVulkanFeatures
|
||||
|
||||
// ============================================================================
|
||||
void GEVulkanFeatures::init(GEVulkanDriver* vk)
|
||||
{
|
||||
uint32_t extension_count;
|
||||
vkEnumerateDeviceExtensionProperties(vk->getPhysicalDevice(), NULL,
|
||||
&extension_count, NULL);
|
||||
std::vector<VkExtensionProperties> extensions(extension_count);
|
||||
vkEnumerateDeviceExtensionProperties(vk->getPhysicalDevice(), NULL,
|
||||
&extension_count, &extensions[0]);
|
||||
|
||||
for (VkExtensionProperties& prop : extensions)
|
||||
{
|
||||
if (std::string(prop.extensionName) == "VK_EXT_descriptor_indexing")
|
||||
g_supports_descriptor_indexing = true;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceFeatures2 supported_features = {};
|
||||
supported_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||
VkPhysicalDeviceDescriptorIndexingFeatures descriptor_indexing_features = {};
|
||||
descriptor_indexing_features.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES;
|
||||
supported_features.pNext = &descriptor_indexing_features;
|
||||
|
||||
if (!vkGetPhysicalDeviceFeatures2)
|
||||
return;
|
||||
vkGetPhysicalDeviceFeatures2(vk->getPhysicalDevice(), &supported_features);
|
||||
if (supported_features.sType !=
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2)
|
||||
return;
|
||||
|
||||
g_supports_non_uniform_indexing = (descriptor_indexing_features
|
||||
.shaderSampledImageArrayNonUniformIndexing == VK_TRUE);
|
||||
g_supports_partially_bound = (descriptor_indexing_features
|
||||
.descriptorBindingPartiallyBound == VK_TRUE);
|
||||
} // init
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanFeatures::printStats()
|
||||
{
|
||||
os::Printer::log(
|
||||
"Vulkan supports VK_EXT_descriptor_indexing",
|
||||
g_supports_descriptor_indexing ? "true" : "false");
|
||||
os::Printer::log(
|
||||
"Vulkan descriptor indexes can be dynamically non-uniform",
|
||||
g_supports_non_uniform_indexing ? "true" : "false");
|
||||
os::Printer::log(
|
||||
"Vulkan descriptor can be partially bound",
|
||||
g_supports_partially_bound ? "true" : "false");
|
||||
} // printStats
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GEVulkanFeatures::supportsDescriptorIndexing()
|
||||
{
|
||||
return g_supports_descriptor_indexing;
|
||||
} // supportsDescriptorIndexing
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GEVulkanFeatures::supportsNonUniformIndexing()
|
||||
{
|
||||
return g_supports_non_uniform_indexing;
|
||||
} // supportsNonUniformIndexing
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GEVulkanFeatures::supportsPartiallyBound()
|
||||
{
|
||||
return g_supports_partially_bound;
|
||||
} // supportsPartiallyBound
|
||||
|
||||
}
|
25
lib/graphics_engine/src/ge_vulkan_features.hpp
Normal file
25
lib/graphics_engine/src/ge_vulkan_features.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef HEADER_GE_VULKAN_FEATURES_HPP
|
||||
#define HEADER_GE_VULKAN_FEATURES_HPP
|
||||
|
||||
#include "vulkan_wrapper.h"
|
||||
|
||||
namespace GE
|
||||
{
|
||||
class GEVulkanDriver;
|
||||
namespace GEVulkanFeatures
|
||||
{
|
||||
// ----------------------------------------------------------------------------
|
||||
void init(GEVulkanDriver*);
|
||||
// ----------------------------------------------------------------------------
|
||||
void printStats();
|
||||
// ----------------------------------------------------------------------------
|
||||
bool supportsDescriptorIndexing();
|
||||
// ----------------------------------------------------------------------------
|
||||
bool supportsNonUniformIndexing();
|
||||
// ----------------------------------------------------------------------------
|
||||
bool supportsPartiallyBound();
|
||||
}; // GEVulkanFeatures
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "ge_main.hpp"
|
||||
#include "ge_vulkan_driver.hpp"
|
||||
#include "ge_vulkan_features.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@ -12,6 +13,8 @@
|
||||
|
||||
namespace GE
|
||||
{
|
||||
namespace GEVulkanShaderManager
|
||||
{
|
||||
// ============================================================================
|
||||
GEVulkanDriver* g_vk = NULL;
|
||||
irr::io::IFileSystem* g_file_system = NULL;
|
||||
@ -21,6 +24,8 @@ uint32_t g_sampler_size = 0;
|
||||
|
||||
VkShaderModule g_2d_render_vert = VK_NULL_HANDLE;
|
||||
VkShaderModule g_2d_render_frag = VK_NULL_HANDLE;
|
||||
} // GEVulkanShaderManager
|
||||
|
||||
// ============================================================================
|
||||
void GEVulkanShaderManager::init(GEVulkanDriver* vk)
|
||||
{
|
||||
@ -37,6 +42,13 @@ void GEVulkanShaderManager::init(GEVulkanDriver* vk)
|
||||
std::ostringstream oss;
|
||||
oss << "#version 450\n";
|
||||
oss << "#define SAMPLER_SIZE " << g_sampler_size << "\n";
|
||||
if (GEVulkanFeatures::supportsDescriptorIndexing())
|
||||
{
|
||||
oss << "#extension GL_EXT_nonuniform_qualifier : enable\n";
|
||||
oss << "#define GE_SAMPLE_TEX_INDEX nonuniformEXT\n";
|
||||
}
|
||||
else
|
||||
oss << "#define GE_SAMPLE_TEX_INDEX int\n";
|
||||
g_predefines = oss.str();
|
||||
|
||||
// 2D rendering shader
|
||||
@ -99,4 +111,23 @@ VkShaderModule GEVulkanShaderManager::loadShader(shaderc_shader_kind kind,
|
||||
return shader_module;
|
||||
} // loadShader
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
unsigned GEVulkanShaderManager::getSamplerSize()
|
||||
{
|
||||
return g_sampler_size;
|
||||
} // getSamplerSize
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
VkShaderModule GEVulkanShaderManager::get2dRenderVert()
|
||||
{
|
||||
return g_2d_render_vert;
|
||||
} // get2dRenderVert
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
VkShaderModule GEVulkanShaderManager::get2dRenderFrag()
|
||||
{
|
||||
return g_2d_render_frag;
|
||||
} // get2dRenderFrag
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
}
|
||||
|
@ -16,6 +16,12 @@ void init(GEVulkanDriver*);
|
||||
void destroy();
|
||||
// ----------------------------------------------------------------------------
|
||||
VkShaderModule loadShader(shaderc_shader_kind, const std::string&);
|
||||
// ----------------------------------------------------------------------------
|
||||
VkShaderModule get2dRenderVert();
|
||||
// ----------------------------------------------------------------------------
|
||||
VkShaderModule get2dRenderFrag();
|
||||
// ----------------------------------------------------------------------------
|
||||
unsigned getSamplerSize();
|
||||
}; // GEVulkanShaderManager
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user