move swapchain to framectl; make validation errors crash process early

This commit is contained in:
Ivan Avdeev 2021-01-18 10:54:48 -08:00
parent 4d6739da0a
commit d4c463c507
7 changed files with 359 additions and 324 deletions

View File

@ -4,6 +4,7 @@
#include "vk_core.h"
#include "vk_common.h"
#include "vk_textures.h"
#include "vk_framectl.h"
#include "com_strings.h"
#include "eiface.h"
@ -71,6 +72,7 @@ void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, f
g2d.batch[g2d.current_batch].texture = texnum;
g2d.batch[g2d.current_batch].vertex_offset = g2d.num_pics;
g2d.batch[g2d.current_batch].vertex_count = 0;
}
if (g2d.num_pics + 6 > g2d.max_pics)
@ -83,8 +85,8 @@ void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, f
{
vertex_2d_t *p = ((vertex_2d_t*)(g2d.pics_buffer.mapped)) + g2d.num_pics;
const float vw = vk_core.swapchain.create_info.imageExtent.width;
const float vh = vk_core.swapchain.create_info.imageExtent.height;
const float vw = vk_frame.create_info.imageExtent.width;
const float vh = vk_frame.create_info.imageExtent.height;
const float x1 = (x / vw)*2.f - 1.f;
const float y1 = (y / vh)*2.f - 1.f;
const float x2 = ((x + w) / vw)*2.f - 1.f;
@ -142,13 +144,13 @@ static VkPipeline createPipeline( void )
VkViewport viewport = {
.x = 0, .y = 0,
.width = (float)vk_core.swapchain.create_info.imageExtent.width,
.height = (float)vk_core.swapchain.create_info.imageExtent.height,
.width = (float)vk_frame.create_info.imageExtent.width,
.height = (float)vk_frame.create_info.imageExtent.height,
.minDepth = 0.f, .maxDepth = 1.f,
};
VkRect2D scissor = {
.offset = {0},
.extent = vk_core.swapchain.create_info.imageExtent,
.extent = vk_frame.create_info.imageExtent,
};
VkPipelineViewportStateCreateInfo viewport_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
@ -201,7 +203,7 @@ static VkPipeline createPipeline( void )
.pColorBlendState = &color_blend,
.pDepthStencilState = &depth,
//.layout = material->pipeline_layout,
.renderPass = vk_core.render_pass,
.renderPass = vk_frame.render_pass,
.subpass = 0,
};
@ -244,6 +246,7 @@ void vk2dBegin( void )
{
g2d.num_pics = 0;
g2d.current_batch = 0;
g2d.batch[0].vertex_count = 0;
}
void vk2dEnd( void )

View File

@ -4,6 +4,7 @@
#include "vk_2d.h"
#include "vk_renderstate.h"
#include "vk_buffer.h"
#include "vk_framectl.h"
#include "xash3d_types.h"
#include "cvardef.h"
@ -25,23 +26,6 @@
X(vkEnumerateInstanceVersion) \
X(vkCreateInstance) \
#define INSTANCE_FUNCS(X) \
X(vkDestroyInstance) \
X(vkEnumeratePhysicalDevices) \
X(vkGetPhysicalDeviceProperties) \
X(vkGetPhysicalDeviceProperties2) \
X(vkGetPhysicalDeviceFeatures2) \
X(vkGetPhysicalDeviceQueueFamilyProperties) \
X(vkGetPhysicalDeviceSurfaceSupportKHR) \
X(vkGetPhysicalDeviceMemoryProperties) \
X(vkGetPhysicalDeviceSurfacePresentModesKHR) \
X(vkGetPhysicalDeviceSurfaceFormatsKHR) \
X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
X(vkCreateDevice) \
X(vkGetDeviceProcAddr) \
X(vkDestroyDevice) \
X(vkDestroySurfaceKHR) \
#define INSTANCE_DEBUG_FUNCS(X) \
X(vkCreateDebugUtilsMessengerEXT) \
X(vkDestroyDebugUtilsMessengerEXT) \
@ -140,12 +124,10 @@ VkBool32 debugCallback(
// TODO better messages, not only errors, what are other arguments for, ...
if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
gEngine.Con_Printf(S_ERROR "Validation: %s\n", pCallbackData->pMessage);
#ifdef DEBUG
#ifdef _MSC_VER
__debugbreak();
#else
__builtin_trap();
#endif
#endif
}
return VK_FALSE;
@ -262,7 +244,7 @@ static qboolean createInstance( void )
return true;
}
qboolean createDevice( void )
qboolean pickAndCreateDevice( void )
{
VkPhysicalDevice *physical_devices = NULL;
uint32_t num_physical_devices = 0;
@ -296,7 +278,7 @@ qboolean createDevice( void )
if (!(queue_family_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
continue;
vkGetPhysicalDeviceSurfaceSupportKHR(physical_devices[i], j, vk_core.surface, &present);
vkGetPhysicalDeviceSurfaceSupportKHR(physical_devices[i], j, vk_core.surface.surface, &present);
if (!present)
continue;
@ -358,7 +340,7 @@ qboolean createDevice( void )
return true;
}
const char *presentModeName(VkPresentModeKHR present_mode)
static const char *presentModeName(VkPresentModeKHR present_mode)
{
switch (present_mode)
{
@ -372,172 +354,27 @@ const char *presentModeName(VkPresentModeKHR present_mode)
}
}
static qboolean createRenderPass( void ) {
VkAttachmentDescription attachments[] = {{
.format = VK_FORMAT_B8G8R8A8_SRGB,// FIXME too early swapchain.create_info.imageFormat;
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
//.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
//attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
/*}, {
// Depth
.format = g.depth_format,
.samples = VK_SAMPLE_COUNT_1_BIT,
//attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
//attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
*/
}};
VkAttachmentReference color_attachment = {
.attachment = 0,
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
};
/*
VkAttachmentReference depth_attachment = {0};
depth_attachment.attachment = 1;
depth_attachment.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
*/
VkSubpassDescription subdesc = {
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.colorAttachmentCount = 1,
.pColorAttachments = &color_attachment,
//.pDepthStencilAttachment = &depth_attachment,
};
VkRenderPassCreateInfo rpci = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.attachmentCount = ARRAYSIZE(attachments),
.pAttachments = attachments,
.subpassCount = 1,
.pSubpasses = &subdesc,
};
XVK_CHECK(vkCreateRenderPass(vk_core.device, &rpci, NULL, &vk_core.render_pass));
return true;
}
static qboolean createSwapchain( void )
static qboolean initSurface( void )
{
VkSwapchainCreateInfoKHR *create_info = &vk_core.swapchain.create_info;
XVK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_core.physical_device.device, vk_core.surface.surface, &vk_core.surface.num_present_modes, vk_core.surface.present_modes));
vk_core.surface.present_modes = Mem_Malloc(vk_core.pool, sizeof(*vk_core.surface.present_modes) * vk_core.surface.num_present_modes);
XVK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_core.physical_device.device, vk_core.surface.surface, &vk_core.surface.num_present_modes, vk_core.surface.present_modes));
uint32_t num_surface_formats = 0;
VkSurfaceFormatKHR *surface_formats = NULL;
uint32_t num_present_modes = 0;
VkPresentModeKHR *present_modes = NULL;
const uint32_t prev_num_images = vk_core.swapchain.num_images;
XVK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_core.physical_device.device, vk_core.surface, &num_present_modes, present_modes));
present_modes = Mem_Malloc(vk_core.pool, sizeof(*present_modes) * num_present_modes);
XVK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_core.physical_device.device, vk_core.surface, &num_present_modes, present_modes));
gEngine.Con_Reportf("Supported surface present modes: %u\n", num_present_modes);
for (uint32_t i = 0; i < num_present_modes; ++i)
gEngine.Con_Printf("Supported surface present modes: %u\n", vk_core.surface.num_present_modes);
for (uint32_t i = 0; i < vk_core.surface.num_present_modes; ++i)
{
gEngine.Con_Reportf("\t%u: %s (%u)\n", i, presentModeName(present_modes[i]), present_modes[i]);
gEngine.Con_Reportf("\t%u: %s (%u)\n", i, presentModeName(vk_core.surface.present_modes[i]), vk_core.surface.present_modes[i]);
}
XVK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_core.physical_device.device, vk_core.surface, &num_surface_formats, surface_formats));
surface_formats = Mem_Malloc(vk_core.pool, sizeof(*surface_formats) * num_surface_formats);
XVK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_core.physical_device.device, vk_core.surface, &num_surface_formats, surface_formats));
XVK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_core.physical_device.device, vk_core.surface.surface, &vk_core.surface.num_surface_formats, vk_core.surface.surface_formats));
vk_core.surface.surface_formats = Mem_Malloc(vk_core.pool, sizeof(*vk_core.surface.surface_formats) * vk_core.surface.num_surface_formats);
XVK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_core.physical_device.device, vk_core.surface.surface, &vk_core.surface.num_surface_formats, vk_core.surface.surface_formats));
gEngine.Con_Reportf("Supported surface formats: %u\n", num_surface_formats);
for (uint32_t i = 0; i < num_surface_formats; ++i)
gEngine.Con_Reportf("Supported surface formats: %u\n", vk_core.surface.num_surface_formats);
for (uint32_t i = 0; i < vk_core.surface.num_surface_formats; ++i)
{
// TODO symbolicate
gEngine.Con_Reportf("\t%u: %u %u\n", surface_formats[i].format, surface_formats[i].colorSpace);
}
XVK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_core.physical_device.device, vk_core.surface, &vk_core.swapchain.surface_caps));
create_info->sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
create_info->pNext = NULL;
create_info->surface = vk_core.surface;
create_info->imageFormat = VK_FORMAT_B8G8R8A8_SRGB; // TODO get from surface_formats
create_info->imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; // TODO get from surface_formats
create_info->imageExtent.width = vk_core.swapchain.surface_caps.currentExtent.width;
create_info->imageExtent.height = vk_core.swapchain.surface_caps.currentExtent.height;
create_info->imageArrayLayers = 1;
create_info->imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
create_info->imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
create_info->preTransform = vk_core.swapchain.surface_caps.currentTransform;
create_info->compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
create_info->presentMode = VK_PRESENT_MODE_FIFO_KHR; // TODO caps, MAILBOX is better
//create_info->presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; // TODO caps, MAILBOX is better
create_info->clipped = VK_TRUE;
create_info->oldSwapchain = vk_core.swapchain.swapchain;
create_info->minImageCount = vk_core.swapchain.surface_caps.minImageCount + 3;
if (vk_core.swapchain.surface_caps.maxImageCount && create_info->minImageCount > vk_core.swapchain.surface_caps.maxImageCount)
create_info->minImageCount = vk_core.swapchain.surface_caps.maxImageCount;
XVK_CHECK(vkCreateSwapchainKHR(vk_core.device, create_info, NULL, &vk_core.swapchain.swapchain));
Mem_Free(present_modes);
Mem_Free(surface_formats);
vk_core.swapchain.num_images = 0;
XVK_CHECK(vkGetSwapchainImagesKHR(vk_core.device, vk_core.swapchain.swapchain, &vk_core.swapchain.num_images, NULL));
if (prev_num_images != vk_core.swapchain.num_images)
{
if (vk_core.swapchain.images)
{
Mem_Free(vk_core.swapchain.images);
Mem_Free(vk_core.swapchain.image_views);
Mem_Free(vk_core.swapchain.framebuffers);
}
vk_core.swapchain.images = Mem_Malloc(vk_core.pool, sizeof(*vk_core.swapchain.images) * vk_core.swapchain.num_images);
vk_core.swapchain.image_views = Mem_Malloc(vk_core.pool, sizeof(*vk_core.swapchain.image_views) * vk_core.swapchain.num_images);
vk_core.swapchain.framebuffers = Mem_Malloc(vk_core.pool, sizeof(*vk_core.swapchain.framebuffers) * vk_core.swapchain.num_images);
}
XVK_CHECK(vkGetSwapchainImagesKHR(vk_core.device, vk_core.swapchain.swapchain, &vk_core.swapchain.num_images, vk_core.swapchain.images));
for (uint32_t i = 0; i < vk_core.swapchain.num_images; ++i) {
VkImageViewCreateInfo ivci = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = vk_core.swapchain.create_info.imageFormat,
.image = vk_core.swapchain.images[i],
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.levelCount = 1,
.subresourceRange.layerCount = 1,
};
XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, vk_core.swapchain.image_views + i));
{
const VkImageView attachments[] = {
vk_core.swapchain.image_views[i],
//g.depth_image_view
};
VkFramebufferCreateInfo fbci = {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.renderPass = vk_core.render_pass,
.attachmentCount = ARRAYSIZE(attachments),
.pAttachments = attachments,
.width = vk_core.swapchain.create_info.imageExtent.width,
.height = vk_core.swapchain.create_info.imageExtent.height,
.layers = 1,
};
XVK_CHECK(vkCreateFramebuffer(vk_core.device, &fbci, NULL, vk_core.swapchain.framebuffers + i));
}
gEngine.Con_Reportf("\t%u: %u %u\n", i, vk_core.surface.surface_formats[i].format, vk_core.surface.surface_formats[i].colorSpace);
}
return true;
@ -631,6 +468,8 @@ static qboolean initDescriptorPool( void )
qboolean R_VkInit( void )
{
// FIXME !!!! handle initialization errors properly: destroy what has already been created
vk_core.debug = !!(gEngine.Sys_CheckParm("-vkdebug") || gEngine.Sys_CheckParm("-gldebug"));
if( !gEngine.R_Init_Video( REF_VULKAN )) // request Vulkan surface
@ -664,21 +503,17 @@ qboolean R_VkInit( void )
if (!createInstance())
return false;
vk_core.surface = gEngine.VK_CreateSurface(vk_core.instance);
if (!vk_core.surface)
vk_core.surface.surface = gEngine.VK_CreateSurface(vk_core.instance);
if (!vk_core.surface.surface)
{
gEngine.Con_Printf( S_ERROR "Cannot create Vulkan surface\n" );
// FIXME destroy surface
return false;
}
if (!createDevice())
if (!pickAndCreateDevice())
return false;
if (!createRenderPass())
return false;
if (!createSwapchain())
if (!initSurface())
return false;
if (!createCommandPool())
@ -687,8 +522,6 @@ qboolean R_VkInit( void )
if (!createBuffer(&vk_core.staging, 16 * 1024 * 1024, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
return false;
// TODO initAllocator()
{
VkSamplerCreateInfo sci = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
@ -707,15 +540,18 @@ qboolean R_VkInit( void )
XVK_CHECK(vkCreateSampler(vk_core.device, &sci, NULL, &vk_core.default_sampler));
}
// TODO ...
if (!initDescriptorPool())
return false;
initTextures();
if (!initVk2d())
if (!VK_FrameCtlInit())
return false;
if (!renderstateInit())
// All below need render_pass
if (!initVk2d())
return false;
return true;
@ -723,24 +559,19 @@ qboolean R_VkInit( void )
void R_VkShutdown( void )
{
deinitVk2d();
VK_FrameCtlShutdown();
destroyTextures();
renderstateDestroy();
deinitVk2d();
vkDestroyDescriptorPool(vk_core.device, vk_core.descriptor_pool.pool, NULL);
vkDestroyDescriptorSetLayout(vk_core.device, vk_core.descriptor_pool.one_texture_layout, NULL);
vkDestroySampler(vk_core.device, vk_core.default_sampler, NULL);
destroyBuffer(&vk_core.staging);
vkDestroyCommandPool(vk_core.device, vk_core.command_pool, NULL);
for (uint32_t i = 0; i < vk_core.swapchain.num_images; ++i)
{
vkDestroyImageView(vk_core.device, vk_core.swapchain.image_views[i], NULL);
vkDestroyFramebuffer(vk_core.device, vk_core.swapchain.framebuffers[i], NULL);
}
vkDestroySwapchainKHR(vk_core.device, vk_core.swapchain.swapchain, NULL);
vkDestroyRenderPass(vk_core.device, vk_core.render_pass, NULL);
vkDestroyDevice(vk_core.device, NULL);
if (vk_core.debug_messenger)
@ -748,7 +579,9 @@ void R_VkShutdown( void )
vkDestroyDebugUtilsMessengerEXT(vk_core.instance, vk_core.debug_messenger, NULL);
}
vkDestroySurfaceKHR(vk_core.instance, vk_core.surface, NULL);
Mem_Free(vk_core.surface.present_modes);
Mem_Free(vk_core.surface.surface_formats);
vkDestroySurfaceKHR(vk_core.instance, vk_core.surface.surface, NULL);
vkDestroyInstance(vk_core.instance, NULL);
Mem_FreePool(&vk_core.pool);
}

View File

@ -62,24 +62,19 @@ typedef struct vulkan_core_s {
byte *pool;
qboolean debug;
VkSurfaceKHR surface;
struct {
VkSurfaceKHR surface;
uint32_t num_surface_formats;
VkSurfaceFormatKHR *surface_formats;
uint32_t num_present_modes;
VkPresentModeKHR *present_modes;
} surface;
physical_device_t physical_device;
VkDevice device;
VkQueue queue;
VkRenderPass render_pass;
struct {
VkSurfaceCapabilitiesKHR surface_caps;
VkSwapchainCreateInfoKHR create_info;
VkSwapchainKHR swapchain;
uint32_t num_images;
VkImage *images;
VkImageView *image_views;
VkFramebuffer *framebuffers;
} swapchain;
VkCommandPool command_pool;
VkCommandBuffer cb;
@ -103,6 +98,23 @@ const char *resultName(VkResult result);
} \
} while(0)
#define INSTANCE_FUNCS(X) \
X(vkDestroyInstance) \
X(vkEnumeratePhysicalDevices) \
X(vkGetPhysicalDeviceProperties) \
X(vkGetPhysicalDeviceProperties2) \
X(vkGetPhysicalDeviceFeatures2) \
X(vkGetPhysicalDeviceQueueFamilyProperties) \
X(vkGetPhysicalDeviceSurfaceSupportKHR) \
X(vkGetPhysicalDeviceMemoryProperties) \
X(vkGetPhysicalDeviceSurfacePresentModesKHR) \
X(vkGetPhysicalDeviceSurfaceFormatsKHR) \
X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
X(vkCreateDevice) \
X(vkGetDeviceProcAddr) \
X(vkDestroyDevice) \
X(vkDestroySurfaceKHR) \
#define DEVICE_FUNCS(X) \
X(vkGetDeviceQueue) \
X(vkCreateSwapchainKHR) \
@ -163,7 +175,9 @@ const char *resultName(VkResult result);
X(vkCreateDescriptorSetLayout) \
X(vkAllocateDescriptorSets) \
X(vkUpdateDescriptorSets) \
X(vkDestroyDescriptorSetLayout) \
#define X(f) extern PFN_##f f;
DEVICE_FUNCS(X)
INSTANCE_FUNCS(X)
#undef X

262
ref_vk/vk_framectl.c Normal file
View File

@ -0,0 +1,262 @@
#include "vk_framectl.h"
#include "vk_2d.h"
#include "eiface.h"
vk_framectl_t vk_frame = {0};
static struct
{
VkSemaphore image_available;
VkSemaphore done;
VkFence fence;
} g_frame;
static qboolean createRenderPass( void ) {
VkAttachmentDescription attachments[] = {{
.format = VK_FORMAT_B8G8R8A8_SRGB,// FIXME too early swapchain.create_info.imageFormat;
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
//.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
//attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
/*}, {
// Depth
.format = g.depth_format,
.samples = VK_SAMPLE_COUNT_1_BIT,
//attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
//attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
*/
}};
VkAttachmentReference color_attachment = {
.attachment = 0,
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
};
/*
VkAttachmentReference depth_attachment = {0};
depth_attachment.attachment = 1;
depth_attachment.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
*/
VkSubpassDescription subdesc = {
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.colorAttachmentCount = 1,
.pColorAttachments = &color_attachment,
//.pDepthStencilAttachment = &depth_attachment,
};
VkRenderPassCreateInfo rpci = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.attachmentCount = ARRAYSIZE(attachments),
.pAttachments = attachments,
.subpassCount = 1,
.pSubpasses = &subdesc,
};
XVK_CHECK(vkCreateRenderPass(vk_core.device, &rpci, NULL, &vk_frame.render_pass));
return true;
}
static qboolean createSwapchain( void )
{
VkSwapchainCreateInfoKHR *create_info = &vk_frame.create_info;
const uint32_t prev_num_images = vk_frame.num_images;
XVK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_core.physical_device.device, vk_core.surface.surface, &vk_frame.surface_caps));
create_info->sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
create_info->pNext = NULL;
create_info->surface = vk_core.surface.surface;
create_info->imageFormat = VK_FORMAT_B8G8R8A8_SRGB; // TODO get from surface_formats
create_info->imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; // TODO get from surface_formats
create_info->imageExtent.width = vk_frame.surface_caps.currentExtent.width;
create_info->imageExtent.height = vk_frame.surface_caps.currentExtent.height;
create_info->imageArrayLayers = 1;
create_info->imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
create_info->imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
create_info->preTransform = vk_frame.surface_caps.currentTransform;
create_info->compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
create_info->presentMode = VK_PRESENT_MODE_FIFO_KHR; // TODO caps, MAILBOX is better
//create_info->presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; // TODO caps, MAILBOX is better
create_info->clipped = VK_TRUE;
create_info->oldSwapchain = vk_frame.swapchain;
create_info->minImageCount = vk_frame.surface_caps.minImageCount + 3;
if (vk_frame.surface_caps.maxImageCount && create_info->minImageCount > vk_frame.surface_caps.maxImageCount)
create_info->minImageCount = vk_frame.surface_caps.maxImageCount;
XVK_CHECK(vkCreateSwapchainKHR(vk_core.device, create_info, NULL, &vk_frame.swapchain));
vk_frame.num_images = 0;
XVK_CHECK(vkGetSwapchainImagesKHR(vk_core.device, vk_frame.swapchain, &vk_frame.num_images, NULL));
if (prev_num_images != vk_frame.num_images)
{
if (vk_frame.images)
{
Mem_Free(vk_frame.images);
Mem_Free(vk_frame.image_views);
Mem_Free(vk_frame.framebuffers);
}
vk_frame.images = Mem_Malloc(vk_core.pool, sizeof(*vk_frame.images) * vk_frame.num_images);
vk_frame.image_views = Mem_Malloc(vk_core.pool, sizeof(*vk_frame.image_views) * vk_frame.num_images);
vk_frame.framebuffers = Mem_Malloc(vk_core.pool, sizeof(*vk_frame.framebuffers) * vk_frame.num_images);
}
XVK_CHECK(vkGetSwapchainImagesKHR(vk_core.device, vk_frame.swapchain, &vk_frame.num_images, vk_frame.images));
for (uint32_t i = 0; i < vk_frame.num_images; ++i) {
VkImageViewCreateInfo ivci = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = vk_frame.create_info.imageFormat,
.image = vk_frame.images[i],
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.levelCount = 1,
.subresourceRange.layerCount = 1,
};
XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, vk_frame.image_views + i));
{
const VkImageView attachments[] = {
vk_frame.image_views[i],
//g.depth_image_view
};
VkFramebufferCreateInfo fbci = {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.renderPass = vk_frame.render_pass,
.attachmentCount = ARRAYSIZE(attachments),
.pAttachments = attachments,
.width = vk_frame.create_info.imageExtent.width,
.height = vk_frame.create_info.imageExtent.height,
.layers = 1,
};
XVK_CHECK(vkCreateFramebuffer(vk_core.device, &fbci, NULL, vk_frame.framebuffers + i));
}
}
return true;
}
void R_BeginFrame( qboolean clearScene )
{
gEngine.Con_Printf(S_WARN "VK FIXME: %s(%d)\n", __FUNCTION__, clearScene);
vk2dBegin();
}
void R_RenderScene( void )
{
gEngine.Con_Printf(S_WARN "VK FIXME: %s\n", __FUNCTION__);
}
void R_EndFrame( void )
{
//gEngine.Con_Printf(S_WARN "VK FIXME: %s\n", __FUNCTION__);
uint32_t swapchain_image_index;
VkClearValue clear_value[] = {
{.color = {{1., 0., 0., 0.}}},
//{.depthStencil = {1., 0.}}
};
VkRenderPassBeginInfo rpbi = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = vk_frame.render_pass,
.renderArea.extent.width = vk_frame.create_info.imageExtent.width,
.renderArea.extent.height = vk_frame.create_info.imageExtent.height,
.clearValueCount = ARRAYSIZE(clear_value),
.pClearValues = clear_value,
};
VkPipelineStageFlags stageflags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo subinfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = NULL,
.commandBufferCount = 1,
.pCommandBuffers = &vk_core.cb,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &g_frame.image_available,
.signalSemaphoreCount = 1,
.pSignalSemaphores = &g_frame.done,
.pWaitDstStageMask = &stageflags,
};
VkPresentInfoKHR presinfo = {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.pSwapchains = &vk_frame.swapchain,
.pImageIndices = &swapchain_image_index,
.swapchainCount = 1,
.pWaitSemaphores = &g_frame.done,
.waitSemaphoreCount = 1,
};
XVK_CHECK(vkAcquireNextImageKHR(vk_core.device, vk_frame.swapchain, UINT64_MAX, g_frame.image_available,
VK_NULL_HANDLE, &swapchain_image_index));
rpbi.framebuffer = vk_frame.framebuffers[swapchain_image_index];
{
VkCommandBufferBeginInfo beginfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
};
XVK_CHECK(vkBeginCommandBuffer(vk_core.cb, &beginfo));
}
vkCmdBeginRenderPass(vk_core.cb, &rpbi, VK_SUBPASS_CONTENTS_INLINE);
vk2dEnd();
vkCmdEndRenderPass(vk_core.cb);
XVK_CHECK(vkEndCommandBuffer(vk_core.cb));
XVK_CHECK(vkQueueSubmit(vk_core.queue, 1, &subinfo, g_frame.fence));
XVK_CHECK(vkQueuePresentKHR(vk_core.queue, &presinfo));
// TODO bad sync
XVK_CHECK(vkWaitForFences(vk_core.device, 1, &g_frame.fence, VK_TRUE, INT64_MAX));
XVK_CHECK(vkResetFences(vk_core.device, 1, &g_frame.fence));
}
qboolean VK_FrameCtlInit( void )
{
if (!createRenderPass())
return false;
if (!createSwapchain())
return false;
g_frame.image_available = createSemaphore();
g_frame.done = createSemaphore();
g_frame.fence = createFence();
return true;
}
void VK_FrameCtlShutdown( void )
{
destroyFence(g_frame.fence);
destroySemaphore(g_frame.done);
destroySemaphore(g_frame.image_available);
for (uint32_t i = 0; i < vk_frame.num_images; ++i)
{
vkDestroyImageView(vk_core.device, vk_frame.image_views[i], NULL);
vkDestroyFramebuffer(vk_core.device, vk_frame.framebuffers[i], NULL);
}
vkDestroySwapchainKHR(vk_core.device, vk_frame.swapchain, NULL);
vkDestroyRenderPass(vk_core.device, vk_frame.render_pass, NULL);
}

25
ref_vk/vk_framectl.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "vk_core.h"
#include "xash3d_types.h"
typedef struct vk_framectl_s {
VkRenderPass render_pass;
VkSurfaceCapabilitiesKHR surface_caps;
VkSwapchainCreateInfoKHR create_info;
VkSwapchainKHR swapchain;
uint32_t num_images;
VkImage *images;
VkImageView *image_views;
VkFramebuffer *framebuffers;
} vk_framectl_t;
extern vk_framectl_t vk_frame;
qboolean VK_FrameCtlInit( void );
void VK_FrameCtlShutdown( void );
void R_BeginFrame( qboolean clearScene );
void R_RenderScene( void );
void R_EndFrame( void );

View File

@ -21,13 +21,6 @@ typedef struct render_state_s {
int blending_mode; // kRenderNormal, ...
} render_state_t;
static struct
{
VkSemaphore image_available;
VkSemaphore done;
VkFence fence;
} grs;
render_state_t render_state = {0};
static const char *renderModeName(int mode)
@ -70,95 +63,3 @@ void R_Set2DMode( qboolean enable )
render_state.mode_2d = enable;
}
void R_BeginFrame( qboolean clearScene )
{
gEngine.Con_Printf(S_WARN "VK FIXME: %s(%d)\n", __FUNCTION__, clearScene);
vk2dBegin();
}
void R_RenderScene( void )
{
gEngine.Con_Printf(S_WARN "VK FIXME: %s\n", __FUNCTION__);
}
void R_EndFrame( void )
{
//gEngine.Con_Printf(S_WARN "VK FIXME: %s\n", __FUNCTION__);
uint32_t swapchain_image_index;
VkClearValue clear_value[] = {
{.color = {{1., 0., 0., 0.}}},
//{.depthStencil = {1., 0.}}
};
VkRenderPassBeginInfo rpbi = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = vk_core.render_pass,
.renderArea.extent.width = vk_core.swapchain.create_info.imageExtent.width,
.renderArea.extent.height = vk_core.swapchain.create_info.imageExtent.height,
.clearValueCount = ARRAYSIZE(clear_value),
.pClearValues = clear_value,
};
VkPipelineStageFlags stageflags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo subinfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = NULL,
.commandBufferCount = 1,
.pCommandBuffers = &vk_core.cb,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &grs.image_available,
.signalSemaphoreCount = 1,
.pSignalSemaphores = &grs.done,
.pWaitDstStageMask = &stageflags,
};
VkPresentInfoKHR presinfo = {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.pSwapchains = &vk_core.swapchain.swapchain,
.pImageIndices = &swapchain_image_index,
.swapchainCount = 1,
.pWaitSemaphores = &grs.done,
.waitSemaphoreCount = 1,
};
XVK_CHECK(vkAcquireNextImageKHR(vk_core.device, vk_core.swapchain.swapchain, UINT64_MAX, grs.image_available,
VK_NULL_HANDLE, &swapchain_image_index));
rpbi.framebuffer = vk_core.swapchain.framebuffers[swapchain_image_index];
{
VkCommandBufferBeginInfo beginfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
};
XVK_CHECK(vkBeginCommandBuffer(vk_core.cb, &beginfo));
}
vkCmdBeginRenderPass(vk_core.cb, &rpbi, VK_SUBPASS_CONTENTS_INLINE);
vk2dEnd();
vkCmdEndRenderPass(vk_core.cb);
XVK_CHECK(vkEndCommandBuffer(vk_core.cb));
XVK_CHECK(vkQueueSubmit(vk_core.queue, 1, &subinfo, grs.fence));
XVK_CHECK(vkQueuePresentKHR(vk_core.queue, &presinfo));
// TODO bad sync
XVK_CHECK(vkWaitForFences(vk_core.device, 1, &grs.fence, VK_TRUE, INT64_MAX));
XVK_CHECK(vkResetFences(vk_core.device, 1, &grs.fence));
}
qboolean renderstateInit( void )
{
grs.image_available = createSemaphore();
grs.done = createSemaphore();
grs.fence = createFence();
return true;
}
void renderstateDestroy( void )
{
destroyFence(grs.fence);
destroySemaphore(grs.done);
destroySemaphore(grs.image_available);
}

View File

@ -9,6 +9,3 @@ void R_Set2DMode( qboolean enable );
void R_BeginFrame( qboolean clearScene );
void R_RenderScene( void );
void R_EndFrame( void );
qboolean renderstateInit( void );
void renderstateDestroy( void );