Files
2025-01-29 10:55:49 +01:00

332 lines
13 KiB
C

#include "vulkan.h"
#include "rendertarget.h"
#include <kinc/graphics5/rendertarget.h>
#include <kinc/graphics5/texture.h>
#include <kinc/log.h>
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);
}
}