From d332496ed49b8f26a809cc4a380aac12c53990a1 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sun, 14 Nov 2021 00:35:08 +0000 Subject: [PATCH] Fix up some vulkan+openxr issues. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6123 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/renderer.c | 21 ++++++++++++++++----- engine/common/plugin.c | 1 + engine/gl/gl_vidsdl.c | 34 ++++++++++++++++++---------------- engine/vk/vk_backend.c | 34 +++++++++++++++++++++++++++------- engine/vk/vk_init.c | 39 ++++++++++++++++++++++++++++++++++++++- engine/vk/vkrenderer.h | 5 ++++- plugins/openxr.c | 4 ++++ 7 files changed, 108 insertions(+), 30 deletions(-) diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 94feeec96..ef76e4d18 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -1113,16 +1113,27 @@ qboolean R_RegisterRenderer(void *module, rendererinfo_t *ri) } static plugvrfuncs_t *vrfuncs; +static void *vrmodule; qboolean R_RegisterVRDriver(void *module, plugvrfuncs_t *vr) { - if (!vrfuncs) + if (!vr) { - vrfuncs = vr; - return true; + if (vrmodule == module) + { + vrfuncs = NULL; + vrmodule = NULL; + } + return false; } - Sys_Printf("unable to register renderer %s\n", vr->description); - return false; + if (vrfuncs && vrfuncs!=vr) + { + Con_Printf("unable to register renderer %s (%s already registered)\n", vr->description, vrfuncs->description); + return false; + } + vrfuncs = vr; + vrmodule = module; + return true; } diff --git a/engine/common/plugin.c b/engine/common/plugin.c index cfe996d2f..921aa8367 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -1538,6 +1538,7 @@ void Plug_Close(plugin_t *plug) #endif #ifdef HAVE_CLIENT S_UnregisterSoundInputModule(plug); + R_RegisterVRDriver(plug, NULL); Image_RegisterLoader(plug, NULL); Material_RegisterLoader(plug, NULL); #endif diff --git a/engine/gl/gl_vidsdl.c b/engine/gl/gl_vidsdl.c index edb52a1b6..82d7d89eb 100644 --- a/engine/gl/gl_vidsdl.c +++ b/engine/gl/gl_vidsdl.c @@ -24,6 +24,8 @@ SDL_Surface *sdlsurf; #endif +#include "vr.h" + extern cvar_t vid_vsync; extern cvar_t vid_hardwaregamma; extern cvar_t gl_lateswap; @@ -318,12 +320,20 @@ static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qr SDL_SetVideoMode(0, 0, 0, 0); //to get around some SDL bugs #endif -#ifdef OPENGL_SDL - if (qrenderer == QR_OPENGL) - { #if SDL_MAJOR_VERSION >= 2 + switch(qrenderer) + { + default: + return false; +#ifdef OPENGL_SDL + case QR_OPENGL: + if (info->vr) + Con_Printf(CON_ERROR"%s support is not available with SDL-OpenGL\n", info->vr->description); + info->vr = NULL; + + #if SDL_MAJOR_VERSION >= 2 SDL_GL_LoadLibrary(NULL); -#endif + #endif if (info->bpp >= 32) { @@ -347,7 +357,7 @@ static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qr if (info->stereo) SDL_GL_SetAttribute(SDL_GL_STEREO, 1); -#if SDL_MAJOR_VERSION >= 2 + #if SDL_MAJOR_VERSION >= 2 if (info->srgb) SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1); @@ -379,27 +389,18 @@ static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qr SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); else SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); -#endif + #endif if (info->multisample) { SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, info->multisample); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); } - } -#endif -#if SDL_MAJOR_VERSION >= 2 - switch(qrenderer) - { - default: - break; -#ifdef OPENGL_SDL - case QR_OPENGL: flags |= SDL_WINDOW_OPENGL; break; #endif #ifdef VULKAN_SDL - case QR_VULKAN: + case QR_VULKAN: flags |= SDL_WINDOW_VULKAN; break; #endif @@ -591,6 +592,7 @@ void GLVID_DeInit (void) #endif #ifdef VULKAN_SDL case QR_VULKAN: + VK_Shutdown(); break; #endif default: diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index 06606d966..42202c2e1 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -8,6 +8,7 @@ //FIXME: instead of switching rendertargets and back, we should be using an alternative queue. +#define PERMUTATION_BEM_VR (1u<<11) #define PERMUTATION_BEM_FP16 (1u<<12) #define PERMUTATION_BEM_MULTISAMPLE (1u<<13) #define PERMUTATION_BEM_DEPTHONLY (1u<<14) @@ -2501,6 +2502,8 @@ static void BE_CreatePipeline(program_t *p, unsigned int shaderflags, unsigned i i |= RP_MULTISAMPLE; if (permu&PERMUTATION_BEM_FP16) i |= RP_FP16; + if (permu&PERMUTATION_BEM_VR) + i |= RP_VR; pipeCreateInfo.renderPass = VK_GetRenderPass(i); pipeCreateInfo.subpass = 0; pipeCreateInfo.basePipelineHandle = VK_NULL_HANDLE; @@ -3217,6 +3220,8 @@ void VKBE_SelectMode(backendmode_t mode) shaderstate.modepermutation |= PERMUTATION_BEM_MULTISAMPLE; if (vk.rendertarg->rpassflags & RP_FP16) shaderstate.modepermutation |= PERMUTATION_BEM_FP16; + if (vk.rendertarg->rpassflags & RP_VR) + shaderstate.modepermutation |= PERMUTATION_BEM_VR; switch(mode) { @@ -4170,7 +4175,7 @@ void VKBE_RT_Gen(struct vk_rendertarg *targ, vk_image_t *colour, uint32_t width, } } - if (targ->framebuffer) + if (targ->framebuffer || targ->externalimage) { //schedule the old one to be destroyed at the end of the current frame. DIE OLD ONE, DIE! purge = VK_AtFrameEnd(VKBE_RT_Purge, NULL, sizeof(*purge)); purge->framebuffer = targ->framebuffer; @@ -4201,10 +4206,22 @@ void VKBE_RT_Gen(struct vk_rendertarg *targ, vk_image_t *colour, uint32_t width, targ->restartinfo.renderPass = VK_NULL_HANDLE; return; //destroyed } - targ->restartinfo.renderPass = VK_GetRenderPass(RP_FULLCLEAR|targ->rpassflags); + if (targ->externalimage) + { + VkFormat old = vk.backbufformat; + colour_imginfo.format = vk.backbufformat = colour->vkformat; + targ->rpassflags |= RP_VR; + targ->restartinfo.renderPass = VK_GetRenderPass(RP_FULLCLEAR|targ->rpassflags); - //colour buffer is always 1 sample. if multisampling then we have a hidden 'mscolour' image that is paired with the depth, resolvnig to the 'colour' image. - colour_imginfo.format = (targ->rpassflags&RP_FP16)?VK_FORMAT_R16G16B16A16_SFLOAT:vk.backbufformat; + vk.backbufformat = old; + } + else + { + targ->rpassflags &= ~RP_VR; + targ->restartinfo.renderPass = VK_GetRenderPass(RP_FULLCLEAR|targ->rpassflags); + + colour_imginfo.format = (targ->rpassflags&RP_FP16)?VK_FORMAT_R16G16B16A16_SFLOAT:vk.backbufformat; + } colour_imginfo.flags = 0; colour_imginfo.imageType = VK_IMAGE_TYPE_2D; colour_imginfo.extent.width = width; @@ -4212,6 +4229,7 @@ void VKBE_RT_Gen(struct vk_rendertarg *targ, vk_image_t *colour, uint32_t width, colour_imginfo.extent.depth = 1; colour_imginfo.mipLevels = 1; colour_imginfo.arrayLayers = 1; + //colour buffer is always 1 sample. if multisampling then we have a hidden 'mscolour' image that is paired with the depth, resolving to the 'colour' image. colour_imginfo.samples = VK_SAMPLE_COUNT_1_BIT; colour_imginfo.tiling = VK_IMAGE_TILING_OPTIMAL; colour_imginfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_SAMPLED_BIT; @@ -4220,7 +4238,9 @@ void VKBE_RT_Gen(struct vk_rendertarg *targ, vk_image_t *colour, uint32_t width, colour_imginfo.pQueueFamilyIndices = NULL; colour_imginfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; if (targ->externalimage) + { targ->colour.image = colour->image; + } else { VkAssert(vkCreateImage(vk.device, &colour_imginfo, vkallocationcb, &targ->colour.image)); @@ -4296,10 +4316,10 @@ void VKBE_RT_Gen(struct vk_rendertarg *targ, vk_image_t *colour, uint32_t width, lmsampinfo.unnormalizedCoordinates = VK_FALSE; lmsampinfo.compareEnable = VK_FALSE; - VkAssert(vkCreateSampler(vk.device, &lmsampinfo, NULL, &targ->colour.sampler)); + VK_CreateSamplerInfo(&lmsampinfo, &targ->colour); lmsampinfo.compareEnable = VK_TRUE; - VkAssert(vkCreateSampler(vk.device, &lmsampinfo, NULL, &targ->depth.sampler)); + VK_CreateSamplerInfo(&lmsampinfo, &targ->depth); } targ->colour.layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -5710,7 +5730,7 @@ void VKBE_BeginShadowmapFace(void) vkCmdSetScissor(vk.rendertarg->cbuf, 0, 1, &wrekt); //shadowmaps never multisample... - shaderstate.modepermutation &= ~(PERMUTATION_BEM_MULTISAMPLE|PERMUTATION_BEM_FP16); + shaderstate.modepermutation &= ~(PERMUTATION_BEM_MULTISAMPLE|PERMUTATION_BEM_FP16|PERMUTATION_BEM_VR); } #endif diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index dd86f0e4b..d16609905 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -1177,6 +1177,35 @@ static void VK_DestroySampler_FrameEnd(void *w) VK_DestroySampler(*(VkSampler*)w); } +void VK_CreateSamplerInfo(VkSamplerCreateInfo *info, vk_image_t *img) +{ + unsigned int flags = IF_RENDERTARGET; + struct vksamplers_s *ref; + + if (img->sampler) + VK_DestroySampler(img->sampler); + + + for (ref = vk.samplers; ref; ref = ref->next) + if (ref->flags == flags) + if (!memcmp(&ref->props, info, sizeof(*info))) + break; + + if (!ref) + { + ref = Z_Malloc(sizeof(*ref)); + ref->flags = flags; + ref->props = *info; + ref->next = vk.samplers; + ref->link = &vk.samplers; + if (vk.samplers) + vk.samplers->link = &ref->next; + vk.samplers = ref; + VkAssert(vkCreateSampler(vk.device, &ref->props, NULL, &ref->samp)); + } + ref->usages++; + img->sampler = ref->samp; +} void VK_CreateSampler(unsigned int flags, vk_image_t *img) { struct vksamplers_s *ref; @@ -2726,6 +2755,7 @@ void VK_R_RenderEye(texid_t image, vec4_t fovoverride, vec3_t eyeangorg[2]) VK_SetupViewPortProjection(false); rt = &postproc[postproc_buf++%countof(postproc)]; + rt->rpassflags |= RP_VR; VKBE_RT_Gen(rt, image?image->vkimage:NULL, 320, 200, false, RT_IMAGEFLAGS); VKBE_RT_Begin(rt); @@ -2763,6 +2793,7 @@ void VK_R_RenderEye(texid_t image, vec4_t fovoverride, vec3_t eyeangorg[2]) vk.rendertarg->depthcleared = false; VKBE_RT_End(rt); + rt->rpassflags &= ~RP_VR; } void VK_R_RenderView (void) @@ -3995,7 +4026,12 @@ VkRenderPass VK_GetRenderPass(int pass) if (color_reference.attachment != ~(uint32_t)0) { - attachments[color_reference.attachment].format = (pass&RP_FP16)?VK_FORMAT_R16G16B16A16_SFLOAT:vk.backbufformat; + if (pass&RP_FP16) + attachments[color_reference.attachment].format = VK_FORMAT_R16G16B16A16_SFLOAT; + else if (pass&RP_VR) + attachments[color_reference.attachment].format = vk.backbufformat; //FIXME + else + attachments[color_reference.attachment].format = vk.backbufformat; attachments[color_reference.attachment].samples = (pass & RP_MULTISAMPLE)?vk.multisamplebits:VK_SAMPLE_COUNT_1_BIT; // attachments[color_reference.attachment].loadOp = pass?VK_ATTACHMENT_LOAD_OP_LOAD:VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachments[color_reference.attachment].storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -5367,6 +5403,7 @@ void VK_Shutdown(void) Z_Free(ptr); } vkDestroyPipelineCache(vk.device, vk.pipelinecache, vkallocationcb); + vk.pipelinecache = VK_NULL_HANDLE; } while(vk.mempools) diff --git a/engine/vk/vkrenderer.h b/engine/vk/vkrenderer.h index 121db2ac4..f8dba7c36 100644 --- a/engine/vk/vkrenderer.h +++ b/engine/vk/vkrenderer.h @@ -219,6 +219,7 @@ typedef struct vk_image_s VkSampler sampler; VkImageLayout layout; + VkFormat vkformat; uint32_t width; uint32_t height; uint32_t layers; @@ -383,7 +384,8 @@ extern struct vulkaninfo_s #define RP_MULTISAMPLE (1u<<2) #define RP_PRESENTABLE (1u<<3) #define RP_FP16 (1u<<4) - VkRenderPass renderpass[1u<<5]; +#define RP_VR (1u<<5) //potentially a different colour format. + VkRenderPass renderpass[1u<<6]; VkSwapchainKHR swapchain; uint32_t bufferidx; @@ -517,6 +519,7 @@ struct stagingbuf vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t layers, uint32_t mips, uploadfmt_t encoding, unsigned int type, qboolean rendertarget, const char *debugname); void set_image_layout(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout old_image_layout, VkAccessFlags srcaccess, VkPipelineStageFlagBits srcstagemask, VkImageLayout new_image_layout, VkAccessFlags dstaccess, VkPipelineStageFlagBits dststagemask); void VK_CreateSampler(unsigned int flags, vk_image_t *img); +void VK_CreateSamplerInfo(VkSamplerCreateInfo *info, vk_image_t *img); void *VKBE_CreateStagingBuffer(struct stagingbuf *n, size_t size, VkBufferUsageFlags usage); VkBuffer VKBE_FinishStaging(struct stagingbuf *n, vk_poolmem_t *memptr); void *VK_FencedBegin(void (*passed)(void *work), size_t worksize); diff --git a/plugins/openxr.c b/plugins/openxr.c index 93ddc5c82..4d457fec0 100644 --- a/plugins/openxr.c +++ b/plugins/openxr.c @@ -240,6 +240,7 @@ static struct XrFrameState framestate; qboolean needrender; //we MUST call xrBegin before the next xrWait int srgb; //<0 = gamma-only. 0 = no srgb at all, >0 full srgb, including textures and stuff + int colourformat; unsigned int numactions; struct @@ -1346,6 +1347,7 @@ static qboolean XR_Begin(void) for (u = 0; u < swapfmts; u++) switch(fmts[u]) { case VK_FORMAT_R16G16B16A16_SFLOAT: Con_DPrintf("OpenXr fmt%u: %s\n", u, "VK_FORMAT_R16G16B16A16_SFLOAT"); if (xr.srgb) fmttouse = fmts[u],u=swapfmts; break; + case VK_FORMAT_A2B10G10R10_UNORM_PACK32:Con_DPrintf("OpenXr fmt%u: %s\n", u, "VK_FORMAT_A2B10G10R10_UNORM_PACK32"); if (!xr.srgb) fmttouse = fmts[u],u=swapfmts; break; case VK_FORMAT_B8G8R8A8_UNORM: Con_DPrintf("OpenXr fmt%u: %s\n", u, "VK_FORMAT_B8G8R8A8_UNORM"); if (!xr.srgb) fmttouse = fmts[u],u=swapfmts; break; case VK_FORMAT_R8G8B8A8_UNORM: Con_DPrintf("OpenXr fmt%u: %s\n", u, "VK_FORMAT_R8G8B8A8_UNORM"); if (!xr.srgb) fmttouse = fmts[u],u=swapfmts; break; case VK_FORMAT_B8G8R8A8_SRGB: Con_DPrintf("OpenXr fmt%u: %s\n", u, "VK_FORMAT_B8G8R8A8_SRGB"); if (xr.srgb) fmttouse = fmts[u],u=swapfmts; break; @@ -1382,6 +1384,7 @@ static qboolean XR_Begin(void) Con_Printf("fmt%u: %u / %x\n", u, (unsigned)fmts[u], (unsigned)fmts[u]); } + xr.colourformat = fmttouse; for (u = 0; u < xr.viewcount; u++) { XrSwapchainCreateInfo swapinfo = {XR_TYPE_SWAPCHAIN_CREATE_INFO}; @@ -1462,6 +1465,7 @@ static qboolean XR_Begin(void) for (i = 0; i < xr.eye[u].numswapimages; i++) { xr.eye[u].swapimages[i].vkimage = &vkimg[i]; + vkimg[i].vkformat = fmttouse; vkimg[i].image = xrimg[i].image; //vkimg[i].mem.* = 0; vkimg[i].view = VK_NULL_HANDLE;