From 64199afefaa80bd0d9cacaa11081efce6c560289 Mon Sep 17 00:00:00 2001 From: temx Date: Sat, 21 Jan 2023 15:56:39 +0100 Subject: [PATCH] Add viewport based scaling support --- Quake/draw.h | 1 + Quake/gl_draw.c | 19 ++- Quake/gl_rmain.c | 14 +- Quake/gl_rmisc.c | 19 ++- Quake/gl_screen.c | 6 +- Quake/gl_vidsdl.c | 342 +++++++++++++++++++++++++------------ Quake/glquake.h | 4 +- Shaders/screen_effects.inc | 3 +- 8 files changed, 278 insertions(+), 130 deletions(-) diff --git a/Quake/draw.h b/Quake/draw.h index 28276b88e..480fa0e8f 100644 --- a/Quake/draw.h +++ b/Quake/draw.h @@ -46,6 +46,7 @@ qpic_t *Draw_TryCachePic (const char *path, unsigned int texflags); void Draw_NewGame (void); void GL_Viewport (cb_context_t *cbx, float x, float y, float width, float height, float min_depth, float max_depth); +void GL_Viewport_Scale (cb_context_t *cbx, float x, float y, float width, float height, float min_depth, float max_depth, int scale); void GL_SetCanvas (cb_context_t *cbx, canvastype newcanvas); // johnfitz #endif /* _QUAKE_DRAW_H */ diff --git a/Quake/gl_draw.c b/Quake/gl_draw.c index afdef7866..ae24a47fe 100644 --- a/Quake/gl_draw.c +++ b/Quake/gl_draw.c @@ -954,12 +954,23 @@ GL_Viewport ================ */ void GL_Viewport (cb_context_t *cbx, float x, float y, float width, float height, float min_depth, float max_depth) +{ + GL_Viewport_Scale (cbx, x, y, width, height, min_depth, max_depth, 1); +} + +/* +================ +GL_Viewport_Scale +================ +*/ +void GL_Viewport_Scale (cb_context_t *cbx, float x, float y, float width, float height, float min_depth, float max_depth, int scale) { VkViewport viewport; - viewport.x = x; - viewport.y = vid.height - (y + height); - viewport.width = width; - viewport.height = height; + // when using scale, always put the viewport flush against the corner (even when viewsize < 100) for simplicity + viewport.x = scale == 1 ? x : 0; + viewport.y = scale == 1 ? vid.height - (y + height) : 0; + viewport.width = (width + scale - 1) / scale; + viewport.height = (height + scale - 1) / scale; viewport.minDepth = min_depth; viewport.maxDepth = max_depth; diff --git a/Quake/gl_rmain.c b/Quake/gl_rmain.c index 6dce0d003..07c17c352 100644 --- a/Quake/gl_rmain.c +++ b/Quake/gl_rmain.c @@ -31,7 +31,8 @@ int r_framecount; // used for dlight push checking mplane_t frustum[4]; qboolean render_warp; -int render_scale; +int render_scale = 1; // used ( > 1 ) when r_simplescale = 0, done in screen effects from a full res main view +int simple_scale = 1; // used ( > 1 ) when r_simplescale = 1, done adjusting the viewport size and upsacaling after screen effects // johnfitz -- rendering statistics atomic_uint32_t rs_brushpolys, rs_aliaspolys, rs_skypolys, rs_particles, rs_fogpolys; @@ -108,6 +109,7 @@ float map_fallbackalpha; qboolean r_drawworld_cheatsafe, r_fullbright_cheatsafe, r_lightmap_cheatsafe; // johnfitz cvar_t r_scale = {"r_scale", "1", CVAR_ARCHIVE}; +cvar_t r_simplescale = {"r_simplescale", "1", CVAR_ARCHIVE}; cvar_t r_gpulightmapupdate = {"r_gpulightmapupdate", "1", CVAR_NONE}; cvar_t r_rtshadows = {"r_rtshadows", "1", CVAR_ARCHIVE}; @@ -349,7 +351,8 @@ R_SetupContext */ static void R_SetupContext (cb_context_t *cbx) { - GL_Viewport (cbx, r_refdef.vrect.x, glheight - r_refdef.vrect.y - r_refdef.vrect.height, r_refdef.vrect.width, r_refdef.vrect.height, 0.0f, 1.0f); + GL_Viewport_Scale ( + cbx, r_refdef.vrect.x, glheight - r_refdef.vrect.y - r_refdef.vrect.height, r_refdef.vrect.width, r_refdef.vrect.height, 0.0f, 1.0f, simple_scale); R_BindPipeline (cbx, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.basic_blend_pipeline[cbx->render_pass_index]); R_PushConstants (cbx, VK_SHADER_STAGE_ALL_GRAPHICS, 0, 16 * sizeof (float), vulkan_globals.view_projection_matrix); } @@ -381,7 +384,6 @@ static void R_SetupViewBeforeMark (void *unused) r_fovx = r_refdef.fov_x; r_fovy = r_refdef.fov_y; render_warp = false; - render_scale = (int)r_scale.value; if (r_waterwarp.value) { @@ -516,14 +518,16 @@ void R_DrawViewModel (cb_context_t *cbx) R_BeginDebugUtilsLabel (cbx, "View Model"); // hack the depth range to prevent view model from poking into walls - GL_Viewport (cbx, r_refdef.vrect.x, glheight - r_refdef.vrect.y - r_refdef.vrect.height, r_refdef.vrect.width, r_refdef.vrect.height, 0.7f, 1.0f); + GL_Viewport_Scale ( + cbx, r_refdef.vrect.x, glheight - r_refdef.vrect.y - r_refdef.vrect.height, r_refdef.vrect.width, r_refdef.vrect.height, 0.7f, 1.0f, simple_scale); int aliaspolys = 0; R_DrawAliasModel (cbx, currententity, &aliaspolys); Atomic_AddUInt32 (&rs_aliaspolys, aliaspolys); Atomic_IncrementUInt32 (&rs_aliaspasses); - GL_Viewport (cbx, r_refdef.vrect.x, glheight - r_refdef.vrect.y - r_refdef.vrect.height, r_refdef.vrect.width, r_refdef.vrect.height, 0.0f, 1.0f); + GL_Viewport_Scale ( + cbx, r_refdef.vrect.x, glheight - r_refdef.vrect.y - r_refdef.vrect.height, r_refdef.vrect.width, r_refdef.vrect.height, 0.0f, 1.0f, simple_scale); R_EndDebugUtilsLabel (cbx); } diff --git a/Quake/gl_rmisc.c b/Quake/gl_rmisc.c index d308ace04..02b4b1e65 100644 --- a/Quake/gl_rmisc.c +++ b/Quake/gl_rmisc.c @@ -1626,7 +1626,7 @@ void R_CreatePipelineLayouts () ZEROED_STRUCT (VkPushConstantRange, push_constant_range); push_constant_range.offset = 0; - push_constant_range.size = 3 * sizeof (uint32_t) + 8 * sizeof (float); + push_constant_range.size = 3 * sizeof (uint32_t) + 10 * sizeof (float); push_constant_range.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; ZEROED_STRUCT (VkPipelineLayoutCreateInfo, pipeline_layout_create_info); @@ -1896,12 +1896,15 @@ void R_InitSamplers () } } - if (r_scale.value >= 8) - lod_bias += 3.0f; - else if (r_scale.value >= 4) - lod_bias += 2.0f; - else if (r_scale.value >= 2) - lod_bias += 1.0f; + if (r_simplescale.value == 0) + { + if (r_scale.value >= 8) + lod_bias += 3.0f; + else if (r_scale.value >= 4) + lod_bias += 2.0f; + else if (r_scale.value >= 2) + lod_bias += 1.0f; + } } lod_bias += gl_lodbias.value; @@ -3409,9 +3412,11 @@ void R_Init (void) Cvar_RegisterVariable (&r_telealpha); Cvar_RegisterVariable (&r_slimealpha); Cvar_RegisterVariable (&r_scale); + Cvar_RegisterVariable (&r_simplescale); Cvar_RegisterVariable (&r_lodbias); Cvar_RegisterVariable (&gl_lodbias); Cvar_SetCallback (&r_scale, R_ScaleChanged_f); + Cvar_SetCallback (&r_simplescale, R_ScaleChanged_f); Cvar_SetCallback (&r_lodbias, R_ScaleChanged_f); Cvar_SetCallback (&gl_lodbias, R_ScaleChanged_f); Cvar_SetCallback (&r_lavaalpha, R_SetLavaalpha_f); diff --git a/Quake/gl_screen.c b/Quake/gl_screen.c index c1cbb1f7d..18250419e 100644 --- a/Quake/gl_screen.c +++ b/Quake/gl_screen.c @@ -1211,9 +1211,6 @@ void SCR_UpdateScreen (qboolean use_tasks) } } - if (vid.recalc_refdef) - SCR_CalcRefdef (); - // decide on the height of the console con_forcedup = !cl.worldmodel || cls.signon != SIGNONS; @@ -1224,6 +1221,9 @@ void SCR_UpdateScreen (qboolean use_tasks) return; } + if (vid.recalc_refdef) + SCR_CalcRefdef (); + if (use_tasks) { if (prev_end_rendering_task != INVALID_TASK_HANDLE) diff --git a/Quake/gl_vidsdl.c b/Quake/gl_vidsdl.c index bdf4aaf86..8c85df010 100644 --- a/Quake/gl_vidsdl.c +++ b/Quake/gl_vidsdl.c @@ -1595,11 +1595,17 @@ static void GL_CreateColorBuffer (void) image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; - image_create_info.usage = - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; + image_create_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; for (i = 0; i < NUM_COLOR_BUFFERS; ++i) { + if (i == 1) + { + image_create_info.usage &= ~VK_IMAGE_USAGE_TRANSFER_DST_BIT; + image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } + assert (vulkan_globals.color_buffers[i] == VK_NULL_HANDLE); err = vkCreateImage (vulkan_globals.device, &image_create_info, NULL, &vulkan_globals.color_buffers[i]); if (err != VK_SUCCESS) @@ -1780,18 +1786,13 @@ void GL_UpdateDescriptorSets (void) input_attachment_write.pImageInfo = &image_info; vkUpdateDescriptorSets (vulkan_globals.device, 1, &input_attachment_write, 0, NULL); - if (vulkan_globals.screen_effects_desc_set != VK_NULL_HANDLE) - R_FreeDescriptorSet (vulkan_globals.screen_effects_desc_set, &vulkan_globals.input_attachment_set_layout); - vulkan_globals.screen_effects_desc_set = R_AllocateDescriptorSet (&vulkan_globals.screen_effects_set_layout); - - ZEROED_STRUCT (VkDescriptorImageInfo, input_image_info); - input_image_info.imageView = color_buffers_view[1]; - input_image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - input_image_info.sampler = vulkan_globals.linear_sampler; - - ZEROED_STRUCT (VkDescriptorImageInfo, output_image_info); - output_image_info.imageView = color_buffers_view[0]; - output_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + if (vulkan_globals.screen_effects_desc_set[0] != VK_NULL_HANDLE) + { + R_FreeDescriptorSet (vulkan_globals.screen_effects_desc_set[0], &vulkan_globals.input_attachment_set_layout); + R_FreeDescriptorSet (vulkan_globals.screen_effects_desc_set[1], &vulkan_globals.input_attachment_set_layout); + } + vulkan_globals.screen_effects_desc_set[0] = R_AllocateDescriptorSet (&vulkan_globals.screen_effects_set_layout); + vulkan_globals.screen_effects_desc_set[1] = R_AllocateDescriptorSet (&vulkan_globals.screen_effects_set_layout); ZEROED_STRUCT (VkDescriptorBufferInfo, palette_octree_info); palette_octree_info.buffer = palette_octree_buffer; @@ -1803,48 +1804,60 @@ void GL_UpdateDescriptorSets (void) blue_noise_image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; blue_noise_image_info.sampler = vulkan_globals.linear_sampler; - ZEROED_STRUCT_ARRAY (VkWriteDescriptorSet, screen_effects_writes, 5); - screen_effects_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - screen_effects_writes[0].dstBinding = 0; - screen_effects_writes[0].dstArrayElement = 0; - screen_effects_writes[0].descriptorCount = 1; - screen_effects_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - screen_effects_writes[0].dstSet = vulkan_globals.screen_effects_desc_set; - screen_effects_writes[0].pImageInfo = &input_image_info; - - screen_effects_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - screen_effects_writes[1].dstBinding = 1; - screen_effects_writes[1].dstArrayElement = 0; - screen_effects_writes[1].descriptorCount = 1; - screen_effects_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - screen_effects_writes[1].dstSet = vulkan_globals.screen_effects_desc_set; - screen_effects_writes[1].pImageInfo = &blue_noise_image_info; - - screen_effects_writes[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - screen_effects_writes[2].dstBinding = 2; - screen_effects_writes[2].dstArrayElement = 0; - screen_effects_writes[2].descriptorCount = 1; - screen_effects_writes[2].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - screen_effects_writes[2].dstSet = vulkan_globals.screen_effects_desc_set; - screen_effects_writes[2].pImageInfo = &output_image_info; - - screen_effects_writes[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - screen_effects_writes[3].dstBinding = 3; - screen_effects_writes[3].dstArrayElement = 0; - screen_effects_writes[3].descriptorCount = 1; - screen_effects_writes[3].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; - screen_effects_writes[3].dstSet = vulkan_globals.screen_effects_desc_set; - screen_effects_writes[3].pTexelBufferView = &palette_buffer_view; - - screen_effects_writes[4].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - screen_effects_writes[4].dstBinding = 4; - screen_effects_writes[4].dstArrayElement = 0; - screen_effects_writes[4].descriptorCount = 1; - screen_effects_writes[4].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - screen_effects_writes[4].dstSet = vulkan_globals.screen_effects_desc_set; - screen_effects_writes[4].pBufferInfo = &palette_octree_info; - - vkUpdateDescriptorSets (vulkan_globals.device, countof (screen_effects_writes), screen_effects_writes, 0, NULL); + for (int i = 0; i < 2; i++) + { + ZEROED_STRUCT (VkDescriptorImageInfo, input_image_info); + input_image_info.imageView = color_buffers_view[1 - i]; + input_image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + input_image_info.sampler = vulkan_globals.linear_sampler; + + ZEROED_STRUCT (VkDescriptorImageInfo, output_image_info); + output_image_info.imageView = color_buffers_view[i]; + output_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + + ZEROED_STRUCT_ARRAY (VkWriteDescriptorSet, screen_effects_writes, 5); + screen_effects_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + screen_effects_writes[0].dstBinding = 0; + screen_effects_writes[0].dstArrayElement = 0; + screen_effects_writes[0].descriptorCount = 1; + screen_effects_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + screen_effects_writes[0].dstSet = vulkan_globals.screen_effects_desc_set[i]; + screen_effects_writes[0].pImageInfo = &input_image_info; + + screen_effects_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + screen_effects_writes[1].dstBinding = 1; + screen_effects_writes[1].dstArrayElement = 0; + screen_effects_writes[1].descriptorCount = 1; + screen_effects_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + screen_effects_writes[1].dstSet = vulkan_globals.screen_effects_desc_set[i]; + screen_effects_writes[1].pImageInfo = &blue_noise_image_info; + + screen_effects_writes[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + screen_effects_writes[2].dstBinding = 2; + screen_effects_writes[2].dstArrayElement = 0; + screen_effects_writes[2].descriptorCount = 1; + screen_effects_writes[2].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + screen_effects_writes[2].dstSet = vulkan_globals.screen_effects_desc_set[i]; + screen_effects_writes[2].pImageInfo = &output_image_info; + + screen_effects_writes[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + screen_effects_writes[3].dstBinding = 3; + screen_effects_writes[3].dstArrayElement = 0; + screen_effects_writes[3].descriptorCount = 1; + screen_effects_writes[3].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + screen_effects_writes[3].dstSet = vulkan_globals.screen_effects_desc_set[i]; + screen_effects_writes[3].pTexelBufferView = &palette_buffer_view; + + screen_effects_writes[4].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + screen_effects_writes[4].dstBinding = 4; + screen_effects_writes[4].dstArrayElement = 0; + screen_effects_writes[4].descriptorCount = 1; + screen_effects_writes[4].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + screen_effects_writes[4].dstSet = vulkan_globals.screen_effects_desc_set[i]; + screen_effects_writes[4].pBufferInfo = &palette_octree_info; + + vkUpdateDescriptorSets (vulkan_globals.device, countof (screen_effects_writes), screen_effects_writes, 0, NULL); + } #if defined(_DEBUG) if (vulkan_globals.ray_query) @@ -1853,6 +1866,10 @@ void GL_UpdateDescriptorSets (void) R_FreeDescriptorSet (vulkan_globals.ray_debug_desc_set, &vulkan_globals.ray_debug_set_layout); vulkan_globals.ray_debug_desc_set = R_AllocateDescriptorSet (&vulkan_globals.ray_debug_set_layout); + ZEROED_STRUCT (VkDescriptorImageInfo, output_image_info); + output_image_info.imageView = color_buffers_view[0]; + output_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + ZEROED_STRUCT_ARRAY (VkWriteDescriptorSet, ray_debug_writes, 2); ray_debug_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -2237,8 +2254,10 @@ static void GL_DestroyRenderResources (void) R_FreeDescriptorSet (postprocess_descriptor_set, &vulkan_globals.input_attachment_set_layout); postprocess_descriptor_set = VK_NULL_HANDLE; - R_FreeDescriptorSet (vulkan_globals.screen_effects_desc_set, &vulkan_globals.screen_effects_set_layout); - vulkan_globals.screen_effects_desc_set = VK_NULL_HANDLE; + R_FreeDescriptorSet (vulkan_globals.screen_effects_desc_set[0], &vulkan_globals.screen_effects_set_layout); + R_FreeDescriptorSet (vulkan_globals.screen_effects_desc_set[1], &vulkan_globals.screen_effects_set_layout); + vulkan_globals.screen_effects_desc_set[0] = VK_NULL_HANDLE; + vulkan_globals.screen_effects_desc_set[1] = VK_NULL_HANDLE; if (msaa_color_buffer) { @@ -2453,6 +2472,9 @@ qboolean GL_BeginRendering (qboolean use_tasks, task_handle_t *begin_rendering_t else GL_BeginRenderingTask (NULL); + render_scale = r_simplescale.value ? 1 : CLAMP (1, (int)r_scale.value, 8); + simple_scale = r_simplescale.value ? CLAMP (1, (int)r_scale.value, 32) : 1; + return true; } @@ -2518,6 +2540,8 @@ typedef struct screen_effect_constants_s uint32_t clamp_size_y; float screen_size_rcp_x; float screen_size_rcp_y; + float scale_rcp_x; + float scale_rcp_y; float aspect_ratio; float time; uint32_t flags; @@ -2553,9 +2577,11 @@ typedef struct end_rendering_parms_s qboolean render_warp : 1; qboolean vid_palettize : 1; qboolean menu : 1; - qboolean ray_debug : 1; uint32_t render_scale : 4; uint32_t vid_height : 20; + uint32_t simple_scale : 6; + qboolean ray_debug : 1; + glRect_t bounds; float time; uint8_t v_blend[4]; vec3_t origin; @@ -2572,12 +2598,98 @@ typedef struct end_rendering_parms_s #define SCREEN_EFFECT_FLAG_PALETTIZE 0x8 #define SCREEN_EFFECT_FLAG_MENU 0x10 +/* +=============== +GL_SimpleScale +=============== +*/ +static void GL_SimpleScale (cb_context_t *cbx, end_rendering_parms_t *parms, qboolean effects) +{ + VkImageMemoryBarrier image_barriers[2]; + image_barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_barriers[0].pNext = NULL; + image_barriers[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_barriers[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barriers[0].image = vulkan_globals.color_buffers[0]; + image_barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_barriers[0].subresourceRange.baseMipLevel = 0; + image_barriers[0].subresourceRange.levelCount = 1; + image_barriers[0].subresourceRange.baseArrayLayer = 0; + image_barriers[0].subresourceRange.layerCount = 1; + + image_barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_barriers[1].pNext = NULL; + image_barriers[1].srcAccessMask = effects ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + image_barriers[1].dstAccessMask = effects ? VK_ACCESS_TRANSFER_READ_BIT : VK_ACCESS_TRANSFER_WRITE_BIT; + image_barriers[1].oldLayout = effects ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + image_barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + image_barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barriers[1].image = vulkan_globals.color_buffers[1]; + image_barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_barriers[1].subresourceRange.baseMipLevel = 0; + image_barriers[1].subresourceRange.levelCount = 1; + image_barriers[1].subresourceRange.baseArrayLayer = 0; + image_barriers[1].subresourceRange.layerCount = 1; + + VkMemoryBarrier memory_barrier; + memory_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + memory_barrier.pNext = NULL; + memory_barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; + + vkCmdPipelineBarrier ( + cbx->cb, (!effects ? VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT : 0) | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, + !effects ? 1 : 0, &memory_barrier, 0, NULL, 2, image_barriers); + + ZEROED_STRUCT (VkImageBlit, region); + region.srcOffsets[1].x = (parms->bounds.w + parms->simple_scale - 1) / parms->simple_scale; + region.srcOffsets[1].y = (parms->bounds.h + parms->simple_scale - 1) / parms->simple_scale; + region.srcOffsets[1].z = 1; + region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.srcSubresource.layerCount = 1; + region.srcSubresource.mipLevel = 0; + region.dstOffsets[0].x = parms->bounds.l; + region.dstOffsets[0].y = parms->bounds.t; + region.dstOffsets[1].x = parms->bounds.l + parms->bounds.w; + region.dstOffsets[1].y = parms->bounds.t + parms->bounds.h; + region.dstOffsets[1].z = 1; + region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.dstSubresource.layerCount = 1; + region.dstSubresource.mipLevel = 0; + + vkCmdBlitImage ( + cbx->cb, vulkan_globals.color_buffers[1], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vulkan_globals.color_buffers[0], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ®ion, VK_FILTER_NEAREST); + + image_barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_barriers[0].pNext = NULL; + image_barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_barriers[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + image_barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_barriers[0].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + image_barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barriers[0].image = vulkan_globals.color_buffers[0]; + image_barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_barriers[0].subresourceRange.baseMipLevel = 0; + image_barriers[0].subresourceRange.levelCount = 1; + image_barriers[0].subresourceRange.baseArrayLayer = 0; + image_barriers[0].subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier (cbx->cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, image_barriers); +} + /* =============== GL_ScreenEffects =============== */ -static void GL_ScreenEffects (cb_context_t *cbx, qboolean enabled, end_rendering_parms_t *parms) +static void GL_ScreenEffects (cb_context_t *cbx, qboolean enabled, qboolean source_buffer, end_rendering_parms_t *parms) { if (enabled) { @@ -2592,7 +2704,7 @@ static void GL_ScreenEffects (cb_context_t *cbx, qboolean enabled, end_rendering image_barriers[0].newLayout = VK_IMAGE_LAYOUT_GENERAL; image_barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barriers[0].image = vulkan_globals.color_buffers[0]; + image_barriers[0].image = vulkan_globals.color_buffers[source_buffer ? 0 : 1]; image_barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; image_barriers[0].subresourceRange.baseMipLevel = 0; image_barriers[0].subresourceRange.levelCount = 1; @@ -2607,7 +2719,7 @@ static void GL_ScreenEffects (cb_context_t *cbx, qboolean enabled, end_rendering image_barriers[1].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; image_barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barriers[1].image = vulkan_globals.color_buffers[1]; + image_barriers[1].image = vulkan_globals.color_buffers[source_buffer]; image_barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; image_barriers[1].subresourceRange.baseMipLevel = 0; image_barriers[1].subresourceRange.levelCount = 1; @@ -2639,11 +2751,16 @@ static void GL_ScreenEffects (cb_context_t *cbx, qboolean enabled, end_rendering R_BindPipeline (cbx, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); + uint32_t width = parms->simple_scale > 1 && !parms->ray_debug ? (parms->bounds.w + parms->simple_scale - 1) / parms->simple_scale : parms->vid_width; + uint32_t height = parms->simple_scale > 1 && !parms->ray_debug ? (parms->bounds.h + parms->simple_scale - 1) / parms->simple_scale : parms->vid_height; + #if defined(_DEBUG) if (!parms->ray_debug || !bmodel_tlas) #endif { - vkCmdBindDescriptorSets (cbx->cb, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->layout.handle, 0, 1, &vulkan_globals.screen_effects_desc_set, 0, NULL); + vkCmdBindDescriptorSets ( + cbx->cb, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->layout.handle, 0, 1, &vulkan_globals.screen_effects_desc_set[source_buffer ? 0 : 1], 0, + NULL); uint32_t screen_effect_flags = 0; if (parms->render_warp) @@ -2660,11 +2777,13 @@ static void GL_ScreenEffects (cb_context_t *cbx, qboolean enabled, end_rendering screen_effect_flags |= SCREEN_EFFECT_FLAG_MENU; const screen_effect_constants_t push_constants = { - parms->vid_width - 1, - parms->vid_height - 1, - 1.0f / (float)parms->vid_width, - 1.0f / (float)parms->vid_height, - (float)parms->vid_width / (float)parms->vid_height, + width - 1, + height - 1, + 1.0f / (float)width, + 1.0f / (float)height, + (float)width / (float)parms->vid_width, + (float)height / (float)parms->vid_height, + (float)width / (float)height, parms->time, screen_effect_flags, (float)parms->v_blend[0] / 255.0f, @@ -2680,49 +2799,44 @@ static void GL_ScreenEffects (cb_context_t *cbx, qboolean enabled, end_rendering vkCmdBindDescriptorSets (cbx->cb, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->layout.handle, 0, 1, &vulkan_globals.ray_debug_desc_set, 0, NULL); const ray_debug_constants_t push_constants = { - 1.0f / (float)parms->vid_width, - 1.0f / (float)parms->vid_height, - (float)parms->vid_width / (float)parms->vid_height, - parms->origin[0], - parms->origin[1], - parms->origin[2], - parms->forward[0], - parms->forward[1], - parms->forward[2], - parms->right[0], - parms->right[1], - parms->right[2], - parms->down[0], - parms->down[1], - parms->down[2], + 1.0f / (float)width, 1.0f / (float)height, (float)width / (float)height, + parms->origin[0], parms->origin[1], parms->origin[2], + parms->forward[0], parms->forward[1], parms->forward[2], + parms->right[0], parms->right[1], parms->right[2], + parms->down[0], parms->down[1], parms->down[2], }; R_PushConstants (cbx, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof (push_constants), &push_constants); } #endif - vkCmdDispatch (cbx->cb, (parms->vid_width + 7) / 8, (parms->vid_height + 7) / 8, 1); - - image_barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - image_barriers[0].pNext = NULL; - image_barriers[0].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - image_barriers[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - image_barriers[0].oldLayout = VK_IMAGE_LAYOUT_GENERAL; - image_barriers[0].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - image_barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barriers[0].image = vulkan_globals.color_buffers[0]; - image_barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_barriers[0].subresourceRange.baseMipLevel = 0; - image_barriers[0].subresourceRange.levelCount = 1; - image_barriers[0].subresourceRange.baseArrayLayer = 0; - image_barriers[0].subresourceRange.layerCount = 1; + vkCmdDispatch (cbx->cb, (width + 7) / 8, (height + 7) / 8, 1); - vkCmdPipelineBarrier ( - cbx->cb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, image_barriers); + if (source_buffer) + { + image_barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_barriers[0].pNext = NULL; + image_barriers[0].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + image_barriers[0].dstAccessMask = + source_buffer == 0 ? VK_ACCESS_TRANSFER_READ_BIT : VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + image_barriers[0].oldLayout = VK_IMAGE_LAYOUT_GENERAL; + image_barriers[0].newLayout = source_buffer == 0 ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + image_barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barriers[0].image = vulkan_globals.color_buffers[source_buffer ? 0 : 1]; + image_barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_barriers[0].subresourceRange.baseMipLevel = 0; + image_barriers[0].subresourceRange.levelCount = 1; + image_barriers[0].subresourceRange.baseArrayLayer = 0; + image_barriers[0].subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier ( + cbx->cb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + source_buffer == 0 ? VK_PIPELINE_STAGE_TRANSFER_BIT : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, image_barriers); + } R_EndDebugUtilsLabel (cbx); } - else + else if (source_buffer == 0) { VkMemoryBarrier memory_barrier; memory_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; @@ -2778,8 +2892,8 @@ static void GL_EndRenderingTask (end_rendering_parms_t *parms) VkRect2D render_area; render_area.offset.x = 0; render_area.offset.y = 0; - render_area.extent.width = parms->vid_width; - render_area.extent.height = parms->vid_height; + render_area.extent.width = parms->simple_scale > 1 ? (parms->bounds.w + parms->simple_scale - 1) / parms->simple_scale : parms->vid_width; + render_area.extent.height = parms->simple_scale > 1 ? (parms->bounds.h + parms->simple_scale - 1) / parms->simple_scale : parms->vid_height; VkClearValue depth_clear_value; depth_clear_value.depthStencil.depth = 0.0f; @@ -2794,12 +2908,13 @@ static void GL_EndRenderingTask (end_rendering_parms_t *parms) const qboolean screen_effects = parms->render_warp || (parms->render_scale >= 2) || parms->vid_palettize || (gl_polyblend.value && parms->v_blend[3]) || parms->menu || parms->ray_debug; + const qboolean source_buffer = parms->ray_debug || screen_effects != (parms->simple_scale > 1); { const qboolean resolve = (vulkan_globals.sample_count != VK_SAMPLE_COUNT_1_BIT); ZEROED_STRUCT (VkRenderPassBeginInfo, render_pass_begin_info); render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin_info.renderPass = vulkan_globals.secondary_cb_contexts[CBX_WORLD_0].render_pass; - render_pass_begin_info.framebuffer = main_framebuffers[screen_effects ? 1 : 0]; + render_pass_begin_info.framebuffer = main_framebuffers[source_buffer ? 1 : 0]; render_pass_begin_info.renderArea = render_area; render_pass_begin_info.clearValueCount = resolve ? 3 : 2; render_pass_begin_info.pClearValues = clear_values; @@ -2812,8 +2927,15 @@ static void GL_EndRenderingTask (end_rendering_parms_t *parms) vkCmdEndRenderPass (primary_cb); } - GL_ScreenEffects (&vulkan_globals.primary_cb_context, screen_effects, parms); + GL_ScreenEffects (&vulkan_globals.primary_cb_context, screen_effects, source_buffer, parms); + + if (parms->simple_scale > 1 && !parms->ray_debug) + GL_SimpleScale (&vulkan_globals.primary_cb_context, parms, screen_effects); + render_area.offset.x = 0; + render_area.offset.y = 0; + render_area.extent.width = parms->vid_width; + render_area.extent.height = parms->vid_height; { ZEROED_STRUCT (VkRenderPassBeginInfo, render_pass_begin_info); render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; @@ -2893,12 +3015,14 @@ task_handle_t GL_EndRendering (qboolean use_tasks, qboolean swapchain) .render_warp = render_warp, .vid_palettize = vid_palettize.value != 0, .menu = key_dest == key_menu, + .render_scale = render_scale, + .vid_width = vid.width, + .vid_height = vid.height, + .simple_scale = simple_scale, #if defined(_DEBUG) .ray_debug = r_raydebug.value && (bmodel_tlas != VK_NULL_HANDLE), #endif - .render_scale = CLAMP (0, render_scale, 8), - .vid_width = vid.width, - .vid_height = vid.height, + .bounds = {r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height}, .time = fmod (cl.time, 2.0 * M_PI), .v_blend[0] = v_blend[0], .v_blend[1] = v_blend[1], diff --git a/Quake/glquake.h b/Quake/glquake.h index f28afe346..ad4887176 100644 --- a/Quake/glquake.h +++ b/Quake/glquake.h @@ -306,7 +306,7 @@ typedef struct vulkan_desc_set_layout_t ubo_set_layout; vulkan_desc_set_layout_t single_texture_set_layout; vulkan_desc_set_layout_t input_attachment_set_layout; - VkDescriptorSet screen_effects_desc_set; + VkDescriptorSet screen_effects_desc_set[2]; vulkan_desc_set_layout_t screen_effects_set_layout; vulkan_desc_set_layout_t single_texture_cs_write_set_layout; vulkan_desc_set_layout_t lightmap_compute_set_layout; @@ -368,6 +368,7 @@ extern qboolean render_warp; extern qboolean in_update_screen; extern qboolean use_simd; extern int render_scale; +extern int simple_scale; // // view origin @@ -399,6 +400,7 @@ extern cvar_t r_slimealpha; extern cvar_t r_dynamic; extern cvar_t r_novis; extern cvar_t r_scale; +extern cvar_t r_simplescale; extern cvar_t gl_polyblend; extern cvar_t gl_nocolors; diff --git a/Shaders/screen_effects.inc b/Shaders/screen_effects.inc index 6aeb93395..bd1c86927 100644 --- a/Shaders/screen_effects.inc +++ b/Shaders/screen_effects.inc @@ -20,6 +20,7 @@ layout (push_constant) uniform PushConsts { uvec2 clamp_size; vec2 screen_size_rcp; + vec2 scale_rcp; float aspect_ratio; float time; uint flags; @@ -142,7 +143,7 @@ void main () const float tex_x = (pos_x_norm + (sin (pos_y_norm * cycle_x + push_constants.time) * amp_x)) * (1.0f - amp_x * 2.0f) + amp_x; const float tex_y = (pos_y_norm + (sin (pos_x_norm * cycle_y + push_constants.time) * amp_y)) * (1.0f - amp_y * 2.0f) + amp_y; - color = texture (input_tex, vec2 (tex_x, tex_y)); + color = texture (input_tex, vec2 (tex_x, tex_y) * push_constants.scale_rcp); } else color = texelFetch (input_tex, ivec2 (min (push_constants.clamp_size.x, pos_x), min (push_constants.clamp_size.y, pos_y)), 0);