100class RenderInterface_VK :
public Rml::RenderInterface {
103 static constexpr uint32_t kFramesInFlight = 3;
104 static constexpr VkDeviceSize kVideoMemoryForAllocation = 64 * 1024 * 1024;
108 float m_v[6][4] = {};
111 RenderInterface_VK();
112 ~RenderInterface_VK();
118 VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family_index, VkQueue queue,
119 VkFormat color_format, VkFormat depth_stencil_format, std::mutex* submit_mutex,
120 VkPipelineCache pipeline_cache = VK_NULL_HANDLE
126 std::shared_ptr<const void>
OnFrameBegin(uint32_t frame_index);
136 void SetViewport(
int width,
int height);
140 Rml::CompiledGeometryHandle CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices)
override;
141 void RenderGeometry(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation, Rml::TextureHandle texture)
override;
142 void ReleaseGeometry(Rml::CompiledGeometryHandle geometry)
override;
144 Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions,
const Rml::String& source)
override;
145 Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source_data, Rml::Vector2i source_dimensions)
override;
146 void ReleaseTexture(Rml::TextureHandle texture_handle)
override;
148 void EnableScissorRegion(
bool enable)
override;
149 void SetScissorRegion(Rml::Rectanglei region)
override;
151 void SetTransform(
const Rml::Matrix4f* transform)
override;
155 void EnableClipMask(
bool enable)
override;
156 void RenderToClipMask(
157 Rml::ClipMaskOperation operation, Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation
160 Rml::LayerHandle PushLayer()
override;
161 void CompositeLayers(
162 Rml::LayerHandle source, Rml::LayerHandle destination, Rml::BlendMode blend_mode,
163 Rml::Span<const Rml::CompiledFilterHandle> filters
165 void PopLayer()
override;
167 Rml::TextureHandle SaveLayerAsTexture()
override;
168 Rml::CompiledFilterHandle SaveLayerAsMaskImage()
override;
170 Rml::CompiledFilterHandle CompileFilter(
const Rml::String& name,
const Rml::Dictionary& parameters)
override;
171 void ReleaseFilter(Rml::CompiledFilterHandle filter)
override;
173 Rml::CompiledShaderHandle CompileShader(
const Rml::String& name,
const Rml::Dictionary& parameters)
override;
175 Rml::CompiledShaderHandle shader, Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation,
176 Rml::TextureHandle texture
178 void ReleaseShader(Rml::CompiledShaderHandle shader)
override;
181 enum class shader_type_t :
int {
186 enum class shader_id_t :
int {
188 Fragment_WithoutTextures,
189 Fragment_WithTextures
192 struct shader_vertex_user_data_t {
194 Rml::Matrix4f m_transform;
195 Rml::Vector2f m_translate;
198 struct texture_data_t {
199 VkImage m_p_vk_image;
200 VkImageView m_p_vk_image_view;
201 VkSampler m_p_vk_sampler;
202 VkDescriptorSet m_p_vk_descriptor_set;
203 VmaAllocation m_p_vma_allocation;
206 struct geometry_handle_t {
210 bool m_transparent =
false;
212 VkDescriptorBufferInfo m_p_vertex;
213 VkDescriptorBufferInfo m_p_index;
217 VmaVirtualAllocation m_p_vertex_allocation;
218 VmaVirtualAllocation m_p_index_allocation;
221 struct buffer_data_t {
222 VkBuffer m_p_vk_buffer;
223 VmaAllocation m_p_vma_allocation;
227 struct effect_image_t {
228 VkImage m_p_image =
nullptr;
229 VkImageView m_p_view =
nullptr;
230 VmaAllocation m_p_allocation =
nullptr;
231 VkDescriptorSet m_p_descriptor_set =
nullptr;
232 VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
236 static bool IsValidEffectImage(
const effect_image_t& image);
240 uint64_t m_generation = 0;
241 uint64_t m_last_used_frame = 0;
242 VkExtent2D m_extent {};
243 std::deque<effect_image_t> m_layers;
244 effect_image_t m_postprocess[3];
245 effect_image_t m_blend_mask;
246 Rml::Vector<effect_image_t> m_outputs;
247 effect_image_t m_stencil;
248 uint32_t m_outputs_used = 0;
251 enum class FilterType {
260 struct CompiledFilter {
261 FilterType m_type = FilterType::Invalid;
262 float m_blend_factor = 1.f;
264 Rml::Vector2f m_offset;
265 Rml::ColourbPremultiplied m_color;
266 Rml::Matrix4f m_color_matrix;
269 struct CompiledShader {
271 VkDescriptorBufferInfo m_buffer = {};
272 VmaVirtualAllocation m_allocation =
nullptr;
276 struct gradient_data_std140_t {
278 int32_t m_num_stops = 0;
281 float m_padding[2] = {};
282 float m_stop_colors[16][4] = {};
283 float m_stop_positions[16] = {};
286 static_assert(
sizeof(gradient_data_std140_t) == 352,
"must match the std140 layout in ui_effects.slang");
288 class UploadResourceManager {
290 UploadResourceManager()
293 m_p_command_buffer {},
295 m_p_graphics_queue {},
296 m_p_submit_mutex {} { }
298 ~UploadResourceManager() { }
300 void Initialize(VkDevice p_device, VkQueue p_queue, uint32_t queue_family_index, std::mutex* p_submit_mutex) {
301 RMLUI_VK_ASSERTMSG(p_queue,
"you have to pass a valid VkQueue");
302 RMLUI_VK_ASSERTMSG(p_device,
"you have to pass a valid VkDevice for creation resources");
304 m_p_device = p_device;
305 m_p_graphics_queue = p_queue;
306 m_p_submit_mutex = p_submit_mutex;
308 Create_All(queue_family_index);
312 vkDestroyFence(m_p_device, m_p_fence,
nullptr);
313 vkDestroyCommandPool(m_p_device, m_p_command_pool,
nullptr);
316 template<
typename Func>
317 void UploadToGPU(Func&& p_user_commands)
noexcept {
318 RMLUI_VK_ASSERTMSG(m_p_command_buffer,
"you didn't initialize VkCommandBuffer");
320 VkCommandBufferBeginInfo info_command = {};
322 info_command.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
323 info_command.pNext =
nullptr;
324 info_command.pInheritanceInfo =
nullptr;
325 info_command.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
327 VkResult status = vkBeginCommandBuffer(m_p_command_buffer, &info_command);
329 RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS,
"failed to vkBeginCommandBuffer");
331 p_user_commands(m_p_command_buffer);
333 status = vkEndCommandBuffer(m_p_command_buffer);
335 RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS,
"faield to vkEndCommandBuffer");
342 void Create_Fence() noexcept {
343 VkFenceCreateInfo info = {};
344 info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
345 info.pNext =
nullptr;
348 VkResult status = vkCreateFence(m_p_device, &info,
nullptr, &m_p_fence);
350 RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS,
"failed to vkCreateFence");
353 void Create_CommandBuffer() noexcept {
354 RMLUI_VK_ASSERTMSG(m_p_command_pool,
"you have to initialize VkCommandPool before calling this method!");
356 VkCommandBufferAllocateInfo info = {};
357 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
358 info.pNext =
nullptr;
359 info.commandPool = m_p_command_pool;
360 info.commandBufferCount = 1;
361 info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
363 VkResult status = vkAllocateCommandBuffers(m_p_device, &info, &m_p_command_buffer);
365 RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS,
"failed to vkAllocateCommandBuffers");
368 void Create_CommandPool(uint32_t queue_family_index)
noexcept {
369 VkCommandPoolCreateInfo info = {};
371 info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
372 info.pNext =
nullptr;
373 info.queueFamilyIndex = queue_family_index;
376 VkResult status = vkCreateCommandPool(m_p_device, &info,
nullptr, &m_p_command_pool);
378 RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS,
"failed to vkCreateCommandPool");
381 void Create_All(uint32_t queue_family_index)
noexcept {
383 Create_CommandPool(queue_family_index);
384 Create_CommandBuffer();
387 void Wait() noexcept {
388 RMLUI_VK_ASSERTMSG(m_p_fence,
"you must initialize your VkFence");
390 vkWaitForFences(m_p_device, 1, &m_p_fence, VK_TRUE, UINT64_MAX);
391 vkResetFences(m_p_device, 1, &m_p_fence);
392 vkResetCommandPool(m_p_device, m_p_command_pool, 0);
395 void Submit() noexcept {
396 VkCommandBufferSubmitInfo command_info = {};
397 command_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO;
398 command_info.commandBuffer = m_p_command_buffer;
400 VkSubmitInfo2 info = {};
401 info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2;
402 info.commandBufferInfoCount = 1;
403 info.pCommandBufferInfos = &command_info;
406 std::unique_lock<std::mutex> lock;
407 if (m_p_submit_mutex) {
408 lock = std::unique_lock<std::mutex>(*m_p_submit_mutex);
411 auto status = vkQueueSubmit2(m_p_graphics_queue, 1, &info, m_p_fence);
413 RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS,
"failed to vkQueueSubmit2");
419 VkCommandBuffer m_p_command_buffer;
420 VkCommandPool m_p_command_pool;
421 VkQueue m_p_graphics_queue;
422 std::mutex* m_p_submit_mutex;
432 VkDeviceSize byte_size, VkDeviceSize device_min_uniform_alignment, VmaAllocator p_allocator, VkDevice p_device
434 void Shutdown() noexcept;
436 bool Alloc_GeneralBuffer(
437 VkDeviceSize size,
void** p_data, VkDescriptorBufferInfo* p_out, VmaVirtualAllocation* p_alloc
439 bool Alloc_VertexBuffer(
440 uint32_t number_of_elements, uint32_t stride_in_bytes,
void** p_data, VkDescriptorBufferInfo* p_out,
441 VmaVirtualAllocation* p_alloc
443 bool Alloc_IndexBuffer(
444 uint32_t number_of_elements, uint32_t stride_in_bytes,
void** p_data, VkDescriptorBufferInfo* p_out,
445 VmaVirtualAllocation* p_alloc
447 void Flush(const VkDescriptorBufferInfo& range) noexcept;
450 SetDescriptorSet(uint32_t binding_index, uint32_t size, VkDescriptorType descriptor_type, VkDescriptorSet p_set) noexcept;
451 void SetDescriptorSet(
452 uint32_t binding_index, VkDescriptorBufferInfo* p_info, VkDescriptorType descriptor_type, VkDescriptorSet p_set
454 void SetDescriptorSet(
455 uint32_t binding_index, VkSampler p_sampler, VkImageLayout layout, VkImageView p_view, VkDescriptorType descriptor_type,
456 VkDescriptorSet p_set
459 void Free_GeometryHandle(geometry_handle_t* p_valid_geometry_handle) noexcept;
460 void Free_Allocation(VmaVirtualAllocation allocation) noexcept;
463 VkDeviceSize m_memory_total_size;
464 VkDeviceSize m_device_min_uniform_alignment;
467 VmaAllocation m_p_buffer_alloc;
469 VmaAllocator m_p_vk_allocator;
470 VmaVirtualBlock m_p_block;
475 class CommandBufferRing {
479 void Initialize(VkDevice p_device, uint32_t queue_index_graphics)
noexcept;
480 void Shutdown(MemoryPool& memory_pool);
483 std::shared_ptr<const void> AcquireSlot(MemoryPool& memory_pool);
484 VkCommandBuffer GetNextSecondaryBuffer();
486 void AddCurrentSlotAllocation(VmaVirtualAllocation allocation);
487 void AddCurrentSlotGeneration(uint64_t generation);
488 void AddCurrentSlotResource(std::shared_ptr<const void> resource);
489 bool IsGenerationReferenced(uint64_t generation)
const;
493 VkCommandPool m_command_pool =
nullptr;
494 Rml::Vector<VkCommandBuffer> m_command_buffers;
496 std::shared_ptr<const int> m_guard;
497 Rml::Vector<VmaVirtualAllocation> m_transient_allocations;
498 Rml::Vector<uint64_t> m_generations;
499 Rml::Vector<std::shared_ptr<const void>> m_resources;
505 uint32_t m_queue_index;
506 Slot* m_p_current_slot;
507 Rml::Vector<Rml::UniquePtr<Slot>> m_slots;
510 class DescriptorPoolManager {
512 DescriptorPoolManager() =
default;
514 ~DescriptorPoolManager() {
515 RMLUI_VK_ASSERTMSG(m_allocations.empty(),
"something is wrong. You didn't free some VkDescriptorSet");
519 VkDevice p_device, uint32_t count_uniform_buffer, uint32_t count_image_sampler, uint32_t count_sampler,
520 uint32_t count_storage_buffer
522 RMLUI_VK_ASSERTMSG(p_device,
"you can't pass an invalid VkDevice here");
523 m_p_device = p_device;
525 VkDescriptorPoolSize {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, count_uniform_buffer},
526 VkDescriptorPoolSize { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, count_uniform_buffer},
527 VkDescriptorPoolSize {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, count_image_sampler},
528 VkDescriptorPoolSize { VK_DESCRIPTOR_TYPE_SAMPLER, count_sampler},
529 VkDescriptorPoolSize { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, count_storage_buffer},
531 m_max_sets_per_pool =
532 std::max<uint32_t>(count_uniform_buffer + count_image_sampler + count_sampler + count_storage_buffer, 64);
533 RMLUI_VK_ASSERTMSG(CreatePool(),
"failed to create the initial descriptor pool");
536 void Shutdown(VkDevice p_device) {
537 RMLUI_VK_ASSERTMSG(p_device,
"you can't pass an invalid VkDevice here");
538 for (VkDescriptorPool pool : m_pools) {
539 vkDestroyDescriptorPool(p_device, pool,
nullptr);
541 m_allocations.clear();
543 m_p_device =
nullptr;
546 uint32_t Get_AllocatedDescriptorCount() const noexcept {
return static_cast<uint32_t
>(m_allocations.size()); }
548 bool Alloc_Descriptor(
549 VkDevice p_device, VkDescriptorSetLayout* p_layouts, VkDescriptorSet* p_sets, uint32_t descriptor_count_for_creation = 1
552 p_layouts,
"you have to pass a valid and initialized VkDescriptorSetLayout (probably you must create it)"
554 RMLUI_VK_ASSERTMSG(p_device,
"you must pass a valid VkDevice here");
555 if (!p_layouts || !p_sets || descriptor_count_for_creation == 0) {
559 VkDescriptorSetAllocateInfo info = {};
560 info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
561 info.pNext =
nullptr;
562 info.descriptorSetCount = descriptor_count_for_creation;
563 info.pSetLayouts = p_layouts;
565 auto try_allocate = [&](VkDescriptorPool pool) {
566 info.descriptorPool = pool;
567 const VkResult status = vkAllocateDescriptorSets(p_device, &info, p_sets);
568 if (status == VK_SUCCESS) {
569 for (uint32_t i = 0; i < descriptor_count_for_creation; i++) {
570 m_allocations.push_back({p_sets[i], pool});
576 for (VkDescriptorPool pool : m_pools) {
577 const VkResult status = try_allocate(pool);
578 if (status == VK_SUCCESS) {
581 if (status != VK_ERROR_OUT_OF_POOL_MEMORY && status != VK_ERROR_FRAGMENTED_POOL) {
582 RMLUI_VK_ASSERTMSG(
false,
"failed to vkAllocateDescriptorSets");
590 return try_allocate(m_pools.back()) == VK_SUCCESS;
593 void Free_Descriptors(VkDevice p_device, VkDescriptorSet* p_sets, uint32_t descriptor_count = 1) noexcept {
594 RMLUI_VK_ASSERTMSG(p_device,
"you must pass a valid VkDevice here");
600 for (uint32_t i = 0; i < descriptor_count; i++) {
601 const VkDescriptorSet set = p_sets[i];
606 auto allocation = std::find_if(m_allocations.begin(), m_allocations.end(), [set](
const Allocation& candidate) {
607 return candidate.m_set == set;
609 if (allocation == m_allocations.end()) {
610 RMLUI_VK_ASSERTMSG(
false,
"descriptor set was not allocated by this manager");
614 vkFreeDescriptorSets(p_device, allocation->m_pool, 1, &set);
615 m_allocations.erase(allocation);
622 VkDescriptorSet m_set =
nullptr;
623 VkDescriptorPool m_pool =
nullptr;
626 bool CreatePool() noexcept {
627 VkDescriptorPoolCreateInfo info = {};
628 info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
629 info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
630 info.maxSets = m_max_sets_per_pool;
631 info.poolSizeCount =
static_cast<uint32_t
>(m_pool_sizes.size());
632 info.pPoolSizes = m_pool_sizes.data();
634 VkDescriptorPool pool =
nullptr;
635 const VkResult status = vkCreateDescriptorPool(m_p_device, &info,
nullptr, &pool);
636 if (status != VK_SUCCESS) {
637 RMLUI_VK_ASSERTMSG(
false,
"failed to vkCreateDescriptorPool");
640 m_pools.push_back(pool);
644 VkDevice m_p_device =
nullptr;
645 uint32_t m_max_sets_per_pool = 0;
646 std::array<VkDescriptorPoolSize, 5> m_pool_sizes {};
647 Rml::Vector<VkDescriptorPool> m_pools;
648 Rml::Vector<Allocation> m_allocations;
652 Rml::TextureHandle CreateTexture(Rml::Span<const Rml::byte> source, Rml::Vector2i dimensions,
const Rml::String& name);
654 void Initialize_Resources_Toast(VkQueue queue)
noexcept;
655 void Destroy_Resources() noexcept;
657 void CreateShaders() noexcept;
658 void CreateDescriptorSetLayout() noexcept;
659 void CreatePipelineLayout() noexcept;
660 void CreateDescriptorSets() noexcept;
661 void CreateSamplers() noexcept;
662 void Create_Pipelines() noexcept;
664 buffer_data_t CreateResource_StagingBuffer(VkDeviceSize size, VkBufferUsageFlags flags) noexcept;
665 void DestroyResource_StagingBuffer(const buffer_data_t& data) noexcept;
667 void Destroy_Texture(const texture_data_t& p_texture) noexcept;
668 bool RetainResource(const
void* resource);
669 void ReleaseResource(const
void* resource);
671 void Destroy_Pipelines() noexcept;
672 void DestroyDescriptorSets() noexcept;
673 void DestroyPipelineLayout() noexcept;
674 void DestroySamplers() noexcept;
676 void CreateEffectResources() noexcept;
677 void DestroyEffectResources() noexcept;
679 LayerPool& AcquirePool(VkExtent2D extent);
680 void DestroyPool(LayerPool& pool) noexcept;
681 void RetireUnusedPools() noexcept;
682 effect_image_t CreateEffectImage(VkExtent2D extent, VkFormat format, VkImageUsageFlags usage) noexcept;
683 void DestroyEffectImage(effect_image_t& image) noexcept;
685 void TransitionEffectImage(effect_image_t& image, VkImageLayout new_layout);
686 void BeginLayerScope(effect_image_t& target,
bool clear_color,
bool clear_stencil);
687 void BeginEffectScope(effect_image_t& target,
bool clear_color, VkRect2D render_area,
bool use_clip_stencil = false);
690 void SuspendLayerScope();
691 void ResumeLayerScope();
693 void RenderFullscreenPass(
694 VkPipeline pipeline, effect_image_t& destination, effect_image_t& source, effect_image_t* mask, const effects_push_t& push,
695 bool clear_destination, VkRect2D render_area, VkViewport viewport,
bool use_clip_stencil = false
698 void RenderFilters(Rml::Span<const Rml::CompiledFilterHandle> filter_handles);
699 void RenderBlur(
float sigma, LayerPool& pool,
int source_destination,
int temp);
701 VkRect2D CurrentScissor() const;
703 void ClearClipStencil(uint32_t value);
704 VkDescriptorSet GetEffectDescriptorSet(effect_image_t& image) noexcept;
707 bool m_is_apply_to_regular_geometry_stencil;
708 bool m_is_use_scissor_specified;
709 bool m_is_use_stencil_pipeline;
714 uint32_t m_queue_index_graphics;
715 uint32_t m_frame_index;
717 VkInstance m_p_instance;
719 VkPipelineCache m_p_pipeline_cache = VK_NULL_HANDLE;
720 VkPhysicalDevice m_p_physical_device;
721 VmaAllocator m_p_allocator;
723 VkCommandBuffer m_p_current_command_buffer;
725 VkFormat m_color_attachment_format;
726 VkFormat m_depth_stencil_attachment_format;
727 std::mutex* m_p_submit_mutex;
729 VkDescriptorSetLayout m_p_descriptor_set_layout_vertex_transform;
730 VkDescriptorSetLayout m_p_descriptor_set_layout_texture;
731 VkPipelineLayout m_p_pipeline_layout;
732 VkPipeline m_p_pipeline_with_textures;
733 VkPipeline m_p_pipeline_without_textures;
734 VkPipeline m_p_pipeline_stencil_for_region_where_geometry_will_be_drawn;
735 VkPipeline m_p_pipeline_stencil_for_regular_geometry_that_applied_to_region_with_textures;
736 VkPipeline m_p_pipeline_stencil_for_regular_geometry_that_applied_to_region_without_textures;
737 VkDescriptorSet m_p_descriptor_set;
738 VkSampler m_p_sampler_linear;
742 VkRect2D m_scissor_original;
743 VkViewport m_viewport;
745 shader_vertex_user_data_t m_user_data_for_vertex_shader;
747 Rml::Matrix4f m_projection;
748 Rml::Vector<VkShaderModule> m_shaders;
749 std::unordered_map<const
void*, std::shared_ptr<const
void>> m_live_resources;
751 CommandBufferRing m_command_buffer_ring;
752 MemoryPool m_memory_pool;
753 UploadResourceManager m_upload_manager;
754 DescriptorPoolManager m_manager_descriptors;
756 uint64_t m_pool_generation = 0;
757 uint64_t m_pool_frame = 0;
758 Rml::Vector<Rml::UniquePtr<LayerPool>> m_pools;
759 Rml::Vector<Rml::UniquePtr<LayerPool>> m_retired_pools;
760 LayerPool* m_p_current_pool =
nullptr;
763 Rml::Vector<effect_image_t*> m_layer_stack;
764 uint32_t m_stack_layers_used = 0;
765 bool m_scope_active = false;
766 effect_image_t* m_p_scope_target =
nullptr;
767 int m_stencil_test_value = 1;
768 VkImageView m_p_last_output_view =
nullptr;
770 VkSampler m_p_sampler_clamp =
nullptr;
774 VkDescriptorSetLayout m_p_layout_effect_texture =
nullptr;
775 VkPipelineLayout m_p_pipeline_layout_effects =
nullptr;
776 VkPipeline m_p_pipeline_passthrough_blend =
nullptr;
777 VkPipeline m_p_pipeline_passthrough_noblend =
nullptr;
778 VkPipeline m_p_pipeline_passthrough_blend_stencil =
nullptr;
779 VkPipeline m_p_pipeline_passthrough_noblend_stencil =
nullptr;
780 VkPipeline m_p_pipeline_colormatrix =
nullptr;
781 VkPipeline m_p_pipeline_blendmask =
nullptr;
782 VkPipeline m_p_pipeline_blur =
nullptr;
783 VkPipeline m_p_pipeline_dropshadow =
nullptr;
787 VkDescriptorSetLayout m_p_layout_gradient_data =
nullptr;
788 VkPipelineLayout m_p_pipeline_layout_gradient =
nullptr;
789 VkPipeline m_p_pipeline_gradient =
nullptr;
790 VkPipeline m_p_pipeline_gradient_stencil =
nullptr;
791 VkDescriptorSet m_p_descriptor_set_gradient =
nullptr;
795 VkPipeline m_p_pipeline_clip_write_incr =
nullptr;
796 bool m_clip_incr = false;
797 uint32_t m_clip_write_value = 1;
799 VkShaderModule m_p_effects_shader_module =
nullptr;