#include "vulkan.h" #include "rendertarget.h" #include #include #include extern uint32_t swapchainImageCount; extern kinc_g5_texture_t *vulkanTextures[16]; extern kinc_g5_render_target_t *vulkanRenderTargets[16]; bool memory_type_from_properties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex); void setup_init_cmd(); /*static VkFormat convert_format(kinc_g5_render_target_format_t format) { switch (format) { case KINC_G5_RENDER_TARGET_FORMAT_128BIT_FLOAT: return VK_FORMAT_R32G32B32A32_SFLOAT; case KINC_G5_RENDER_TARGET_FORMAT_64BIT_FLOAT: return VK_FORMAT_R16G16B16A16_SFLOAT; case KINC_G5_RENDER_TARGET_FORMAT_32BIT_RED_FLOAT: return VK_FORMAT_R32_SFLOAT; case KINC_G5_RENDER_TARGET_FORMAT_16BIT_RED_FLOAT: return VK_FORMAT_R16_SFLOAT; case KINC_G5_RENDER_TARGET_FORMAT_8BIT_RED: return VK_FORMAT_R8_UNORM; case KINC_G5_RENDER_TARGET_FORMAT_32BIT: default: return VK_FORMAT_B8G8R8A8_UNORM; } }*/ void setImageLayout(VkCommandBuffer _buffer, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout) { VkImageMemoryBarrier imageMemoryBarrier = {0}; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.pNext = NULL; imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; imageMemoryBarrier.oldLayout = oldImageLayout; imageMemoryBarrier.newLayout = newImageLayout; imageMemoryBarrier.image = image; imageMemoryBarrier.subresourceRange.aspectMask = aspectMask; imageMemoryBarrier.subresourceRange.baseMipLevel = 0; imageMemoryBarrier.subresourceRange.levelCount = 1; imageMemoryBarrier.subresourceRange.layerCount = 1; if (oldImageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; } if (oldImageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { imageMemoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; } if (oldImageLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; } if (oldImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; } if (newImageLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; } if (newImageLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { if (oldImageLayout != VK_IMAGE_LAYOUT_UNDEFINED) imageMemoryBarrier.srcAccessMask = imageMemoryBarrier.srcAccessMask | VK_ACCESS_TRANSFER_READ_BIT; imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; } if (newImageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; if (oldImageLayout != VK_IMAGE_LAYOUT_UNDEFINED) imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; } if (newImageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; } if (newImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { if (oldImageLayout != VK_IMAGE_LAYOUT_UNDEFINED) imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; } VkPipelineStageFlags srcStageFlags = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; VkPipelineStageFlags dstStageFlags = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; vkCmdPipelineBarrier(_buffer, srcStageFlags, dstStageFlags, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier); } static void render_target_init(kinc_g5_render_target_t *target, int width, int height, kinc_g5_render_target_format_t format, int depthBufferBits, int stencilBufferBits, int samples_per_pixel, int framebuffer_index) { target->width = width; target->height = height; target->framebuffer_index = framebuffer_index; target->texWidth = width; target->texHeight = height; target->impl.format = convert_format(format); target->impl.depthBufferBits = depthBufferBits; target->impl.stage = 0; target->impl.stage_depth = -1; target->impl.readbackBufferCreated = false; if (framebuffer_index < 0) { { VkFormatProperties formatProperties; VkResult err; vkGetPhysicalDeviceFormatProperties(vk_ctx.gpu, target->impl.format, &formatProperties); assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT); VkImageCreateInfo image = {0}; image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image.pNext = NULL; image.imageType = VK_IMAGE_TYPE_2D; image.format = target->impl.format; image.extent.width = width; image.extent.height = height; image.extent.depth = 1; image.mipLevels = 1; image.arrayLayers = 1; image.samples = VK_SAMPLE_COUNT_1_BIT; image.tiling = VK_IMAGE_TILING_OPTIMAL; image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; image.flags = 0; VkImageViewCreateInfo colorImageView = {0}; colorImageView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; colorImageView.pNext = NULL; colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D; colorImageView.format = target->impl.format; colorImageView.flags = 0; colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; colorImageView.subresourceRange.baseMipLevel = 0; colorImageView.subresourceRange.levelCount = 1; colorImageView.subresourceRange.baseArrayLayer = 0; colorImageView.subresourceRange.layerCount = 1; err = vkCreateImage(vk_ctx.device, &image, NULL, &target->impl.sourceImage); assert(!err); VkMemoryRequirements memoryRequirements; vkGetImageMemoryRequirements(vk_ctx.device, target->impl.sourceImage, &memoryRequirements); VkMemoryAllocateInfo allocationInfo = {0}; allocationInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocationInfo.pNext = NULL; allocationInfo.memoryTypeIndex = 0; allocationInfo.allocationSize = memoryRequirements.size; bool pass = memory_type_from_properties(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocationInfo.memoryTypeIndex); assert(pass); err = vkAllocateMemory(vk_ctx.device, &allocationInfo, NULL, &target->impl.sourceMemory); assert(!err); err = vkBindImageMemory(vk_ctx.device, target->impl.sourceImage, target->impl.sourceMemory, 0); assert(!err); setup_init_cmd(); setImageLayout(vk_ctx.setup_cmd, target->impl.sourceImage, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); flush_init_cmd(); colorImageView.image = target->impl.sourceImage; err = vkCreateImageView(vk_ctx.device, &colorImageView, NULL, &target->impl.sourceView); assert(!err); } if (depthBufferBits > 0) { const VkFormat depth_format = VK_FORMAT_D16_UNORM; VkImageCreateInfo image = {0}; image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image.pNext = NULL; image.imageType = VK_IMAGE_TYPE_2D; image.format = depth_format; image.extent.width = width; image.extent.height = height; image.extent.depth = 1; image.mipLevels = 1; image.arrayLayers = 1; image.samples = VK_SAMPLE_COUNT_1_BIT; image.tiling = VK_IMAGE_TILING_OPTIMAL; image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; image.flags = 0; VkResult err = vkCreateImage(vk_ctx.device, &image, NULL, &target->impl.depthImage); assert(!err); VkMemoryAllocateInfo mem_alloc = {0}; mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; mem_alloc.pNext = NULL; mem_alloc.allocationSize = 0; mem_alloc.memoryTypeIndex = 0; VkImageViewCreateInfo view = {0}; view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; view.pNext = NULL; view.image = target->impl.depthImage; view.format = depth_format; view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; view.subresourceRange.baseMipLevel = 0; view.subresourceRange.levelCount = 1; view.subresourceRange.baseArrayLayer = 0; view.subresourceRange.layerCount = 1; view.flags = 0; view.viewType = VK_IMAGE_VIEW_TYPE_2D; VkMemoryRequirements mem_reqs = {0}; bool pass; /* get memory requirements for this object */ vkGetImageMemoryRequirements(vk_ctx.device, target->impl.depthImage, &mem_reqs); /* select memory size and type */ mem_alloc.allocationSize = mem_reqs.size; pass = memory_type_from_properties(mem_reqs.memoryTypeBits, 0, /* No requirements */ &mem_alloc.memoryTypeIndex); assert(pass); /* allocate memory */ err = vkAllocateMemory(vk_ctx.device, &mem_alloc, NULL, &target->impl.depthMemory); assert(!err); /* bind memory */ err = vkBindImageMemory(vk_ctx.device, target->impl.depthImage, target->impl.depthMemory, 0); assert(!err); setup_init_cmd(); setImageLayout(vk_ctx.setup_cmd, target->impl.depthImage, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); flush_init_cmd(); /* create image view */ err = vkCreateImageView(vk_ctx.device, &view, NULL, &target->impl.depthView); assert(!err); } VkImageView attachments[2]; attachments[0] = target->impl.sourceView; if (depthBufferBits > 0) { attachments[1] = target->impl.depthView; } VkFramebufferCreateInfo fbufCreateInfo = {0}; fbufCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; fbufCreateInfo.pNext = NULL; if (framebuffer_index >= 0) { fbufCreateInfo.renderPass = vk_ctx.windows[vk_ctx.current_window].framebuffer_render_pass; } else if (depthBufferBits > 0) { fbufCreateInfo.renderPass = vk_ctx.windows[vk_ctx.current_window].rendertarget_render_pass_with_depth; } else { fbufCreateInfo.renderPass = vk_ctx.windows[vk_ctx.current_window].rendertarget_render_pass; } fbufCreateInfo.attachmentCount = depthBufferBits > 0 ? 2 : 1; fbufCreateInfo.pAttachments = attachments; fbufCreateInfo.width = width; fbufCreateInfo.height = height; fbufCreateInfo.layers = 1; VkResult err = vkCreateFramebuffer(vk_ctx.device, &fbufCreateInfo, NULL, &target->impl.framebuffer); assert(!err); } } void kinc_g5_render_target_init_with_multisampling(kinc_g5_render_target_t *target, int width, int height, kinc_g5_render_target_format_t format, int depthBufferBits, int stencilBufferBits, int samples_per_pixel) { render_target_init(target, width, height, format, depthBufferBits, stencilBufferBits, samples_per_pixel, -1); } static int framebuffer_count = 0; void kinc_g5_render_target_init_framebuffer_with_multisampling(kinc_g5_render_target_t *target, int width, int height, kinc_g5_render_target_format_t format, int depthBufferBits, int stencilBufferBits, int samples_per_pixel) { render_target_init(target, width, height, format, depthBufferBits, stencilBufferBits, samples_per_pixel, framebuffer_count); framebuffer_count += 1; } void kinc_g5_render_target_init_cube_with_multisampling(kinc_g5_render_target_t *target, int cubeMapSize, kinc_g5_render_target_format_t format, int depthBufferBits, int stencilBufferBits, int samples_per_pixel) {} void kinc_g5_render_target_destroy(kinc_g5_render_target_t *target) { if (target->framebuffer_index >= 0) { framebuffer_count -= 1; } else { vkDestroyFramebuffer(vk_ctx.device, target->impl.framebuffer, NULL); if (target->impl.depthBufferBits > 0) { vkDestroyImageView(vk_ctx.device, target->impl.depthView, NULL); vkDestroyImage(vk_ctx.device, target->impl.depthImage, NULL); vkFreeMemory(vk_ctx.device, target->impl.depthMemory, NULL); } vkDestroyImageView(vk_ctx.device, target->impl.sourceView, NULL); vkDestroyImage(vk_ctx.device, target->impl.sourceImage, NULL); vkFreeMemory(vk_ctx.device, target->impl.sourceMemory, NULL); } } void kinc_g5_render_target_set_depth_stencil_from(kinc_g5_render_target_t *target, kinc_g5_render_target_t *source) { target->impl.depthImage = source->impl.depthImage; target->impl.depthMemory = source->impl.depthMemory; target->impl.depthView = source->impl.depthView; target->impl.depthBufferBits = source->impl.depthBufferBits; // vkDestroyFramebuffer(vk_ctx.device, target->impl.framebuffer, nullptr); { VkImageView attachments[2]; attachments[0] = target->impl.sourceView; if (target->impl.depthBufferBits > 0) { attachments[1] = target->impl.depthView; } VkFramebufferCreateInfo fbufCreateInfo = {0}; fbufCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; fbufCreateInfo.pNext = NULL; if (target->impl.depthBufferBits > 0) { fbufCreateInfo.renderPass = vk_ctx.windows[vk_ctx.current_window].rendertarget_render_pass_with_depth; } else { fbufCreateInfo.renderPass = vk_ctx.windows[vk_ctx.current_window].rendertarget_render_pass; } fbufCreateInfo.attachmentCount = target->impl.depthBufferBits > 0 ? 2 : 1; fbufCreateInfo.pAttachments = attachments; fbufCreateInfo.width = target->width; fbufCreateInfo.height = target->height; fbufCreateInfo.layers = 1; VkResult err = vkCreateFramebuffer(vk_ctx.device, &fbufCreateInfo, NULL, &target->impl.framebuffer); assert(!err); } }