diff --git a/framework/gui.cpp b/framework/gui.cpp index 40cf4b7974..48e8dc3851 100644 --- a/framework/gui.cpp +++ b/framework/gui.cpp @@ -1245,4 +1245,16 @@ void Drawer::text(const char *formatstr, ...) va_end(args); } +bool Drawer::color_picker(const char *caption, float *color, ImGuiColorEditFlags flags, uint16_t width) +{ + bool res = ImGui::ColorEdit4(caption, color, flags); + if (res) + { + dirty = true; + }; + return res; +} + + + } // namespace vkb diff --git a/framework/gui.h b/framework/gui.h index 1793d14780..1519797863 100644 --- a/framework/gui.h +++ b/framework/gui.h @@ -173,6 +173,8 @@ class Drawer */ void text(const char *formatstr, ...); + bool color_picker(const char *caption, float *color, ImGuiColorEditFlags flags, uint16_t width = 0); + private: bool dirty{false}; }; diff --git a/samples/extensions/dynamic_blending/CMakeLists.txt b/samples/extensions/dynamic_blending/CMakeLists.txt new file mode 100644 index 0000000000..ec095c10f9 --- /dev/null +++ b/samples/extensions/dynamic_blending/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (c) 2019, Arm Limited and Contributors +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 the "License"; +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +get_filename_component(FOLDER_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) +get_filename_component(PARENT_DIR ${CMAKE_CURRENT_LIST_DIR} PATH) +get_filename_component(CATEGORY_NAME ${PARENT_DIR} NAME) + +add_sample( + ID ${FOLDER_NAME} + CATEGORY ${CATEGORY_NAME} + AUTHOR "Khronos" + NAME "dynamic_blending" + DESCRIPTION "Sample description" + SHADER_FILES_GLSL + "dynamic_blending/blending.vert" + "dynamic_blending/blending.frag" +) diff --git a/samples/extensions/dynamic_blending/dynamic_blending.cpp b/samples/extensions/dynamic_blending/dynamic_blending.cpp new file mode 100644 index 0000000000..7f23e26a58 --- /dev/null +++ b/samples/extensions/dynamic_blending/dynamic_blending.cpp @@ -0,0 +1,481 @@ +/* Copyright (c) 2023, Mobica + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dynamic_blending.h" + +#include "common/vk_common.h" +#include "gui.h" + +DynamicBlending::DynamicBlending() +{ + add_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + add_device_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + add_device_extension(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME); + add_device_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); + add_device_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); + + title = "Dynamic blending"; +} + +DynamicBlending::~DynamicBlending() +{ + if (device) + { + // NYI + } +} + +bool DynamicBlending::prepare(const vkb::ApplicationOptions &options) +{ + if (!ApiVulkanSample::prepare(options)) + { + return false; + } + + camera.type = vkb::CameraType::LookAt; + camera.set_position({0.0f, 0.0f, -5.0f}); + camera.set_rotation({-15.0f, 15.0f, 0.0f}); + camera.set_perspective(45.0f, static_cast(width) / static_cast(height), 256.0f, 0.1f); + + prepare_uniform_buffers(); + prepare_scene(); + setup_descriptor_pool(); + create_descriptor_set_layout(); + create_descriptor_set(); + create_pipelines(); + build_command_buffers(); + + prepared = true; + + return true; +} + +void DynamicBlending::prepare_scene() { + vertices = { + {{-1.0f, -1.0f, 1.0f}, {0.0f, 0.0f}}, + {{1.0f, -1.0f, 1.0f}, {1.0f, 0.0f}}, + {{1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}}, + {{-1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}, + + {{-1.0f, -1.0f, -1.0f},{0.0f, 0.0f}}, + {{1.0f, -1.0f, -1.0f}, {1.0f, 0.0f}}, + {{1.0f, 1.0f, -1.0f}, {1.0f, 1.0f}}, + {{-1.0f, 1.0f, -1.0f}, {0.0f, 1.0f}}, + }; + + std::vector indices = { + 6, 5, 4, 4, 7, 6, + 0, 1, 2, 2, 3, 0 + }; + + index_count = static_cast(indices.size()); + + vertex_buffer_size = vertices.size() * sizeof(Vertex); + auto index_buffer_size = indices.size() * sizeof(uint32_t); + + vertex_buffer = std::make_unique(get_device(), + vertex_buffer_size, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VMA_MEMORY_USAGE_GPU_TO_CPU); + vertex_buffer->update(vertices.data(), vertex_buffer_size); + + index_buffer = std::make_unique(get_device(), + index_buffer_size, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + VMA_MEMORY_USAGE_GPU_TO_CPU); + index_buffer->update(indices.data(), index_buffer_size); + + face_preferences[0].index_offset = 0; + face_preferences[0].index_count = index_count / 2; + face_preferences[0].color_bit_enabled = {true, true, true, true}; + face_preferences[0].color = {{ + {1.0f, 0.0f, 0.0f, 1.0f}, + {0.0f, 1.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 1.0f, 1.0f}, + {0.0f, 0.0f, 0.0f, 1.0f} + }}; + + face_preferences[1].index_offset = index_count / 2; + face_preferences[1].index_count = index_count / 2; + face_preferences[1].color_bit_enabled = {true, true, true, true}; + face_preferences[1].color = {{ + {0.0f, 1.0f, 1.0f, 1.0f}, + {1.0f, 0.0f, 1.0f, 1.0f}, + {1.0f, 1.0f, 0.0f, 1.0f}, + {1.0f, 1.0f, 1.0f, 1.0f} + }}; + +} + +void DynamicBlending::request_gpu_features(vkb::PhysicalDevice &gpu) +{ + { + auto &features = gpu.request_extension_features(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT); + features.extendedDynamicState3ColorWriteMask = VK_TRUE; + features.extendedDynamicState3ColorBlendEnable = VK_TRUE; + features.extendedDynamicState3ColorBlendAdvanced = VK_TRUE; + features.extendedDynamicState3ColorBlendEquation = VK_TRUE; + } + { + blend_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT; + blend_properties.pNext = VK_NULL_HANDLE; + + VkPhysicalDeviceProperties2 device_properties2 = {}; + device_properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + device_properties2.pNext = &blend_properties; + vkGetPhysicalDeviceProperties2(gpu.get_handle(), &device_properties2); + + } +} + +void DynamicBlending::prepare_uniform_buffers() { + camera_ubo = std::make_unique(get_device(), sizeof(CameraUbo), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU); + color_ubo = std::make_unique(get_device(), sizeof(ColorUbo), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU); + +} + +void DynamicBlending::update_uniform_buffers() { + CameraUbo cam; + cam.model = glm::mat4(1.0f); + cam.model = glm::translate(cam.model, glm::vec3(0.0f)); + cam.view = camera.matrices.view; + cam.projection = camera.matrices.perspective; + + camera_ubo->convert_and_update(cam); + + update_color(); + + glm::mat4 invView = glm::inverse(camera.matrices.view); + glm::vec4 plane0(vertices[0].pos[0], vertices[0].pos[1], vertices[0].pos[2], 1.0f); + glm::vec4 plane1(vertices[4].pos[0], vertices[4].pos[1], vertices[4].pos[2], 1.0f); + + plane0 = invView * plane0; + plane1 = invView * plane1; + + reverse = plane0.z < plane1.z; + + build_command_buffers(); +} + + +void DynamicBlending::setup_descriptor_pool() { + std::vector pool_sizes = { + vkb::initializers::descriptor_pool_size(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2u), + }; + + VkDescriptorPoolCreateInfo descriptor_pool_create_info = + vkb::initializers::descriptor_pool_create_info( + static_cast(pool_sizes.size()), + pool_sizes.data(), + pool_sizes.size()); + VK_CHECK(vkCreateDescriptorPool(get_device().get_handle(), &descriptor_pool_create_info, nullptr, &descriptor_pool)); +} + +void DynamicBlending::create_descriptor_set_layout() { + std::vector set_layout_bindings = { + vkb::initializers::descriptor_set_layout_binding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0u), + vkb::initializers::descriptor_set_layout_binding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 1u) + }; + + VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info = vkb::initializers::descriptor_set_layout_create_info(set_layout_bindings); + VK_CHECK(vkCreateDescriptorSetLayout(get_device().get_handle(), &descriptor_set_layout_create_info, nullptr, &descriptor_set_layout)); + + VkPipelineLayoutCreateInfo pipeline_layout_create_info = vkb::initializers::pipeline_layout_create_info(&descriptor_set_layout); + VK_CHECK(vkCreatePipelineLayout(get_device().get_handle(), &pipeline_layout_create_info, nullptr, &pipeline_layout)); +} + +void DynamicBlending::create_descriptor_set() { + VkDescriptorSetAllocateInfo alloc_info = vkb::initializers::descriptor_set_allocate_info(descriptor_pool, &descriptor_set_layout, 1u); + VK_CHECK(vkAllocateDescriptorSets(get_device().get_handle(), &alloc_info, &descriptor_set)); + + VkDescriptorBufferInfo buffer_descriptor = create_descriptor(*camera_ubo); + VkDescriptorBufferInfo color_descriptor = create_descriptor(*color_ubo); + + std::vector write_descriptor_sets = { + vkb::initializers::write_descriptor_set(descriptor_set, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0u, &buffer_descriptor), + vkb::initializers::write_descriptor_set(descriptor_set, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u, &color_descriptor), + }; + + vkUpdateDescriptorSets(get_device().get_handle(), static_cast(write_descriptor_sets.size()), write_descriptor_sets.data(), 0u, nullptr); +} + +void DynamicBlending::create_pipelines() { + VkPipelineInputAssemblyStateCreateInfo input_assembly_state = + vkb::initializers::pipeline_input_assembly_state_create_info( + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + 0, + VK_FALSE); + + VkPipelineRasterizationStateCreateInfo rasterization_state = + vkb::initializers::pipeline_rasterization_state_create_info( + VK_POLYGON_MODE_FILL, + VK_CULL_MODE_NONE, + VK_FRONT_FACE_COUNTER_CLOCKWISE, + 0); + + VkPipelineColorBlendAttachmentState blend_attachment_state = + vkb::initializers::pipeline_color_blend_attachment_state( + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + VK_TRUE); + + blend_attachment_state.blendEnable = VK_TRUE; + blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; + blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; + blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + + VkPipelineColorBlendAdvancedStateCreateInfoEXT blendAdvancedEXT{}; + blendAdvancedEXT.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT; + blendAdvancedEXT.blendOverlap = VK_BLEND_OVERLAP_UNCORRELATED_EXT; + + VkPipelineColorBlendStateCreateInfo color_blend_state = + vkb::initializers::pipeline_color_blend_state_create_info( + 1, + &blend_attachment_state); + + color_blend_state.logicOpEnable = VK_FALSE; + color_blend_state.pNext = &blendAdvancedEXT; + + VkPipelineDepthStencilStateCreateInfo depth_stencil_state = + vkb::initializers::pipeline_depth_stencil_state_create_info( + VK_TRUE, + VK_TRUE, + VK_COMPARE_OP_GREATER); + + VkPipelineViewportStateCreateInfo viewport_state = + vkb::initializers::pipeline_viewport_state_create_info(1, 1, 0); + + VkPipelineMultisampleStateCreateInfo multisample_state = + vkb::initializers::pipeline_multisample_state_create_info( + VK_SAMPLE_COUNT_1_BIT, + 0); + + std::vector dynamic_state_enables = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT, + // NYI + // VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT, + // VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT, + // VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT + }; + + VkPipelineDynamicStateCreateInfo dynamic_state = + vkb::initializers::pipeline_dynamic_state_create_info( + dynamic_state_enables.data(), + static_cast(dynamic_state_enables.size()), + 0); + + + const std::vector vertex_input_bindings = { + vkb::initializers::vertex_input_binding_description(0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX), + }; + const std::vector vertex_input_attributes = { + vkb::initializers::vertex_input_attribute_description(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, pos)), + vkb::initializers::vertex_input_attribute_description(0, 1, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, uv)), + }; + + VkPipelineVertexInputStateCreateInfo vertex_input_state = vkb::initializers::pipeline_vertex_input_state_create_info(); + vertex_input_state.vertexBindingDescriptionCount = static_cast(vertex_input_bindings.size()); + vertex_input_state.pVertexBindingDescriptions = vertex_input_bindings.data(); + vertex_input_state.vertexAttributeDescriptionCount = static_cast(vertex_input_attributes.size()); + vertex_input_state.pVertexAttributeDescriptions = vertex_input_attributes.data(); + + std::array shader_stages{}; + shader_stages[0] = load_shader("dynamic_blending/blending.vert", VK_SHADER_STAGE_VERTEX_BIT); + shader_stages[1] = load_shader("dynamic_blending/blending.frag", VK_SHADER_STAGE_FRAGMENT_BIT); + + VkGraphicsPipelineCreateInfo graphics_create{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; + graphics_create.pNext = VK_NULL_HANDLE; + graphics_create.renderPass = render_pass; + graphics_create.pInputAssemblyState = &input_assembly_state; + graphics_create.pRasterizationState = &rasterization_state; + graphics_create.pColorBlendState = &color_blend_state; + graphics_create.pMultisampleState = &multisample_state; + graphics_create.pViewportState = &viewport_state; + graphics_create.pDepthStencilState = &depth_stencil_state; + graphics_create.pDynamicState = &dynamic_state; + graphics_create.pVertexInputState = &vertex_input_state; + graphics_create.pTessellationState = VK_NULL_HANDLE; + graphics_create.stageCount = 2; + graphics_create.pStages = shader_stages.data(); + graphics_create.layout = pipeline_layout; + + VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), + pipeline_cache, + 1, + &graphics_create, + VK_NULL_HANDLE, + &pipeline)); +} + +void DynamicBlending::update_color() { + for(uint32_t face = 0; face < 2; ++face) + for(uint32_t vertex = 0; vertex < 4; ++vertex) { + auto &input_color = face_preferences[face].color[vertex]; + color.data[face * 4 + vertex] = glm::vec4(input_color[0], input_color[1], input_color[2], input_color[3]); + } + color_ubo->convert_and_update(color); +} + +void DynamicBlending::update_color_uniform() { + update_color(); + build_command_buffers(); +} + +void DynamicBlending::build_command_buffers() +{ + VkCommandBufferBeginInfo command_buffer_begin_info = vkb::initializers::command_buffer_begin_info(); + + std::array clear_values; + clear_values[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; + clear_values[1].depthStencil = {0.0f, 0u}; + + VkRenderPassBeginInfo render_pass_begin_info = vkb::initializers::render_pass_begin_info(); + render_pass_begin_info.renderPass = render_pass; + render_pass_begin_info.renderArea.extent.width = width; + render_pass_begin_info.renderArea.extent.height = height; + render_pass_begin_info.clearValueCount = static_cast(clear_values.size()); + render_pass_begin_info.pClearValues = clear_values.data(); + + for (uint32_t i = 0u; i < draw_cmd_buffers.size(); ++i) + { + render_pass_begin_info.framebuffer = framebuffers[i]; + auto &cmd_buff = draw_cmd_buffers[i]; + + VK_CHECK(vkBeginCommandBuffer(cmd_buff, &command_buffer_begin_info)); + + vkCmdBeginRenderPass(cmd_buff, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = vkb::initializers::viewport(static_cast(width), static_cast(height), 0.0f, 1.0f); + vkCmdSetViewport(cmd_buff, 0u, 1u, &viewport); + + VkRect2D scissor = vkb::initializers::rect2D(width, height, 0, 0); + vkCmdSetScissor(cmd_buff, 0u, 1u, &scissor); + + { + vkCmdBindDescriptorSets(cmd_buff, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 1u, &descriptor_set, 0u, nullptr); + vkCmdBindPipeline(cmd_buff, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + + VkDeviceSize offsets[1] = {0}; + vkCmdBindVertexBuffers(draw_cmd_buffers[i], 0, 1, vertex_buffer->get(), offsets); + vkCmdBindIndexBuffer(draw_cmd_buffers[i], index_buffer->get_handle(), 0, VK_INDEX_TYPE_UINT32); + + if(reverse) { + build_command_buffer_for_plane(cmd_buff, face_preferences[1]); + build_command_buffer_for_plane(cmd_buff, face_preferences[0]); + } + else { + build_command_buffer_for_plane(cmd_buff, face_preferences[0]); + build_command_buffer_for_plane(cmd_buff, face_preferences[1]); + } + } + + draw_ui(cmd_buff); + + + vkCmdEndRenderPass(cmd_buff); + + VK_CHECK(vkEndCommandBuffer(cmd_buff)); + } +} + +void DynamicBlending::build_command_buffer_for_plane(VkCommandBuffer &command_buffer, FacePreferences preferences) { + std::array color_bit = { + (preferences.color_bit_enabled[0] ? VK_COLOR_COMPONENT_R_BIT : 0u) | + (preferences.color_bit_enabled[1] ? VK_COLOR_COMPONENT_G_BIT : 0u) | + (preferences.color_bit_enabled[2] ? VK_COLOR_COMPONENT_B_BIT : 0u) | + (preferences.color_bit_enabled[3] ? VK_COLOR_COMPONENT_A_BIT : 0u) + }; + vkCmdSetColorWriteMaskEXT(command_buffer, 0, 1, color_bit.data()); + vkCmdDrawIndexed(command_buffer, preferences.index_count, 1, preferences.index_offset, 0, 0); +} + + +void DynamicBlending::on_update_ui_overlay(vkb::Drawer &drawer) +{ + FacePreferences ¤t_plane = face_preferences[current_face_index]; + if (drawer.button("Switch face")) { + + current_face_index = current_face_index == 0 ? 1 : 0; + on_update_ui_overlay(drawer); + } + if (drawer.header(current_face_index == 0 ? "Far face" : "Close face")) + { + if (drawer.color_picker("Top left", current_plane.color[0], ImGuiColorEditFlags_None, 200)) + { + update_color_uniform(); + } + if (drawer.color_picker("Top right", current_plane.color[1], ImGuiColorEditFlags_None, 200)) + { + update_color_uniform(); + } + if (drawer.color_picker("Bottom left", current_plane.color[2], ImGuiColorEditFlags_None, 200)) + { + update_color_uniform(); + } + if (drawer.color_picker("Bottom right", current_plane.color[3], ImGuiColorEditFlags_None, 200)) + { + update_color_uniform(); + } + if (drawer.checkbox("Red", ¤t_plane.color_bit_enabled[0])) + { + update_color_uniform(); + } + if (drawer.checkbox("Green",¤t_plane.color_bit_enabled[1])) + { + update_color_uniform(); + } + if (drawer.checkbox("Blue", ¤t_plane.color_bit_enabled[2])) + { + update_color_uniform(); + } + } +} + +void DynamicBlending::render(float delta_time) +{ + if (!prepared) + { + return; + } + draw(); + if (camera.updated) + { + update_uniform_buffers(); + } +} + +void DynamicBlending::draw() +{ + ApiVulkanSample::prepare_frame(); + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &draw_cmd_buffers[current_buffer]; + + VK_CHECK(vkQueueSubmit(queue, 1u, &submit_info, VK_NULL_HANDLE)); + ApiVulkanSample::submit_frame(); + + VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; +} + + +std::unique_ptr create_dynamic_blending() +{ + return std::make_unique(); +} diff --git a/samples/extensions/dynamic_blending/dynamic_blending.h b/samples/extensions/dynamic_blending/dynamic_blending.h new file mode 100644 index 0000000000..4d23e81e0e --- /dev/null +++ b/samples/extensions/dynamic_blending/dynamic_blending.h @@ -0,0 +1,112 @@ +/* Copyright (c) 2023, Mobica + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "api_vulkan_sample.h" + +class DynamicBlending : public ApiVulkanSample +{ + public: + DynamicBlending(); + ~DynamicBlending(); + + void render(float delta_time) override; + void build_command_buffers() override; + bool prepare(const vkb::ApplicationOptions &options) override; + void request_gpu_features(vkb::PhysicalDevice &gpu) override; + void on_update_ui_overlay(vkb::Drawer &drawer) override; + + void prepare_scene(); + void setup_descriptor_pool(); + void create_descriptor_set_layout(); + void create_descriptor_set(); + void create_pipelines(); + void prepare_uniform_buffers(); + void update_uniform_buffers(); + void update_color_uniform(); + void draw(); + +private: + VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT blend_properties; + + bool reverse = false; + + VkCommandBuffer copy_cmd; + + struct Texture { + VkImage image; + VkDeviceMemory memory; + VkImageView view; + VkSampler sampler; + } texture; + + struct FacePreferences { + uint16_t index_offset; + uint16_t index_count; + std::array color_bit_enabled; + std::array color; + } face_preferences[2]; + + struct Vertex + { + std::array pos; + std::array uv; + }; + + struct CameraUbo + { + alignas(16) glm::mat4 projection; + alignas(16) glm::mat4 view; + alignas(16) glm::mat4 model; + }; + + struct ColorUbo + { + alignas(32) glm::vec4 data[8]; + }; + + struct + { + std::unique_ptr common; + } uniform_buffers; + + std::unique_ptr vertex_buffer; + std::unique_ptr index_buffer; + uint32_t index_count = 0; + + std::vector vertices; + uint32_t vertex_buffer_size; + uint8_t current_face_index = 1; + + std::unique_ptr camera_ubo; + std::array color_bit; + + ColorUbo color; + std::unique_ptr color_ubo; + + VkDescriptorPool descriptor_pool; + VkDescriptorSetLayout descriptor_set_layout; + VkPipelineLayout pipeline_layout; + VkDescriptorSet descriptor_set; + VkPipeline pipeline; + + void build_command_buffer_for_plane(VkCommandBuffer &command_buffer, FacePreferences preferences); + void update_color(); +}; + +std::unique_ptr create_dynamic_blending(); diff --git a/shaders/dynamic_blending/blending.frag b/shaders/dynamic_blending/blending.frag new file mode 100644 index 0000000000..73eea247fe --- /dev/null +++ b/shaders/dynamic_blending/blending.frag @@ -0,0 +1,56 @@ +#version 450 +/* Copyright (c) 2023, Mobica Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +layout (binding = 1) uniform Col +{ + vec4 data[8]; +} color; + + +layout (location = 0) in vec2 inUV; +layout (location = 1) flat in uint colorOffset; + +layout (location = 0) out vec4 outColor; + +vec4 sampleTexture(vec2 uv) +{ + vec4 c00 = color.data[0 + colorOffset]; + vec4 c01 = color.data[1 + colorOffset]; + vec4 c02 = color.data[2 + colorOffset]; + vec4 c03 = color.data[3 + colorOffset]; + + vec4 b0 = mix(c00, c01, uv.x); + vec4 b1 = mix(c02, c03, uv.x); + + vec4 p0 = mix(b0, b1, uv.y); + + return p0; +} + +void main() +{ + outColor = sampleTexture(inUV); +} + + + + + + + + diff --git a/shaders/dynamic_blending/blending.vert b/shaders/dynamic_blending/blending.vert new file mode 100644 index 0000000000..2707a08607 --- /dev/null +++ b/shaders/dynamic_blending/blending.vert @@ -0,0 +1,37 @@ +#version 450 +/* Copyright (c) 2023, Mobica Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec2 inUv; + +layout (binding = 0) uniform Ubo +{ + mat4 projection; + mat4 view; + mat4 model; +} ubo; + +layout (location = 0) out vec2 outUV; +layout (location = 1) out uint colorOffset; + +void main() +{ + outUV = inUv; + colorOffset = inPos.z == 1.0f ? 4 : 0; + gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPos.xyz, 1.0f); +}