diff --git a/doc/040_cvarlist.md b/doc/040_cvarlist.md index a834f2ec..c7cb090f 100644 --- a/doc/040_cvarlist.md +++ b/doc/040_cvarlist.md @@ -405,6 +405,12 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable` * **vk_picmip**: Shrink factor for the textures. (default: `0`) +* **vk_pixel_size**: Pixel size when rendering the world, used to simulate + lower screen resolutions. The value represents the length, in pixels, of the + side of each pixel block. For example, with size 2 pixels are 2x2 squares, + and at 1600x1200 the image is effectively an upscaled 800x600 image. + (default: `1`) + * **vk_dynamic**: Use dynamic lighting. (default: `1`) * **vk_showtris**: Display mesh triangles. (default: `0`) diff --git a/src/client/refresh/vk/header/local.h b/src/client/refresh/vk/header/local.h index 5d27c2cd..26fea02f 100644 --- a/src/client/refresh/vk/header/local.h +++ b/src/client/refresh/vk/header/local.h @@ -145,6 +145,7 @@ extern cvar_t *vk_flashblend; extern cvar_t *vk_finish; extern cvar_t *vk_polyblend; extern cvar_t *vk_shadows; +extern cvar_t *vk_pixel_size; extern cvar_t *vk_particle_size; extern cvar_t *vk_particle_att_a; extern cvar_t *vk_particle_att_b; @@ -294,6 +295,7 @@ typedef struct qboolean stereo_enabled; VkPipeline current_pipeline; + qvkrenderpasstype_t current_renderpass; } vkstate_t; extern vkconfig_t vk_config; diff --git a/src/client/refresh/vk/spirv/world_warp_frag.c b/src/client/refresh/vk/spirv/world_warp_frag.c index ea2ac83c..55f87dc3 100644 --- a/src/client/refresh/vk/spirv/world_warp_frag.c +++ b/src/client/refresh/vk/spirv/world_warp_frag.c @@ -1,42 +1,44 @@ - // 8.13.3559 + // 1011.0.0 #pragma once const uint32_t world_warp_frag_spv[] = { - 0x07230203,0x00010000,0x00080008,0x00000078,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x07230203,0x00010000,0x0008000a,0x0000007e,0x00000000,0x00020011,0x00000001,0x0006000b, 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, - 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x0000000c,0x00000070,0x00030010, + 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x0000000c,0x00000076,0x00030010, 0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00090004,0x415f4c47,0x735f4252, 0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00040005,0x00000004, 0x6e69616d,0x00000000,0x00030005,0x00000009,0x00007675,0x00060005,0x0000000c,0x465f6c67, 0x43676172,0x64726f6f,0x00000000,0x00060005,0x00000012,0x68737550,0x736e6f43,0x746e6174, 0x00000000,0x00050006,0x00000012,0x00000000,0x656d6974,0x00000000,0x00050006,0x00000012, 0x00000001,0x6c616373,0x00000065,0x00060006,0x00000012,0x00000002,0x57726373,0x68746469, - 0x00000000,0x00060006,0x00000012,0x00000003,0x48726373,0x68676965,0x00000074,0x00030005, - 0x00000014,0x00006370,0x00030005,0x0000002c,0x00007873,0x00030005,0x0000003d,0x00007973, - 0x00040005,0x0000004c,0x69685378,0x00007466,0x00040005,0x00000057,0x69685379,0x00007466, - 0x00050005,0x00000060,0x74736964,0x6974726f,0x00006e6f,0x00060005,0x00000070,0x67617266, - 0x746e656d,0x6f6c6f43,0x00000072,0x00050005,0x00000074,0x78655473,0x65727574,0x00000000, - 0x00040047,0x0000000c,0x0000000b,0x0000000f,0x00050048,0x00000012,0x00000000,0x00000023, - 0x00000044,0x00050048,0x00000012,0x00000001,0x00000023,0x00000048,0x00050048,0x00000012, - 0x00000002,0x00000023,0x0000004c,0x00050048,0x00000012,0x00000003,0x00000023,0x00000050, - 0x00030047,0x00000012,0x00000002,0x00040047,0x00000070,0x0000001e,0x00000000,0x00040047, - 0x00000074,0x00000022,0x00000000,0x00040047,0x00000074,0x00000021,0x00000000,0x00020013, - 0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017, - 0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00040017, - 0x0000000a,0x00000006,0x00000004,0x00040020,0x0000000b,0x00000001,0x0000000a,0x0004003b, - 0x0000000b,0x0000000c,0x00000001,0x00040015,0x0000000d,0x00000020,0x00000000,0x0004002b, - 0x0000000d,0x0000000e,0x00000000,0x00040020,0x0000000f,0x00000001,0x00000006,0x0006001e, - 0x00000012,0x00000006,0x00000006,0x00000006,0x00000006,0x00040020,0x00000013,0x00000009, - 0x00000012,0x0004003b,0x00000013,0x00000014,0x00000009,0x00040015,0x00000015,0x00000020, - 0x00000001,0x0004002b,0x00000015,0x00000016,0x00000002,0x00040020,0x00000017,0x00000009, - 0x00000006,0x0004002b,0x0000000d,0x0000001b,0x00000001,0x0004002b,0x00000015,0x0000001e, - 0x00000003,0x0004002b,0x00000015,0x00000023,0x00000000,0x0004002b,0x00000006,0x00000026, - 0x00000000,0x00020014,0x00000027,0x00040020,0x0000002b,0x00000007,0x00000006,0x0004002b, - 0x00000015,0x0000002d,0x00000001,0x0004002b,0x00000006,0x00000032,0x40000000,0x0004002b, - 0x00000006,0x00000052,0x40490e56,0x0004002b,0x00000006,0x00000054,0x41200000,0x0004002b, - 0x00000006,0x0000006a,0x3bda3c21,0x00040020,0x0000006f,0x00000003,0x0000000a,0x0004003b, - 0x0000006f,0x00000070,0x00000003,0x00090019,0x00000071,0x00000006,0x00000001,0x00000000, - 0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,0x00000072,0x00000071,0x00040020, - 0x00000073,0x00000000,0x00000072,0x0004003b,0x00000073,0x00000074,0x00000000,0x00050036, + 0x00000000,0x00060006,0x00000012,0x00000003,0x48726373,0x68676965,0x00000074,0x00060006, + 0x00000012,0x00000004,0x65786970,0x7a69536c,0x00000065,0x00030005,0x00000014,0x00006370, + 0x00030005,0x0000002c,0x00007873,0x00030005,0x0000003d,0x00007973,0x00040005,0x0000004c, + 0x69685378,0x00007466,0x00040005,0x00000057,0x69685379,0x00007466,0x00050005,0x00000060, + 0x74736964,0x6974726f,0x00006e6f,0x00060005,0x00000076,0x67617266,0x746e656d,0x6f6c6f43, + 0x00000072,0x00050005,0x0000007a,0x78655473,0x65727574,0x00000000,0x00040047,0x0000000c, + 0x0000000b,0x0000000f,0x00050048,0x00000012,0x00000000,0x00000023,0x00000044,0x00050048, + 0x00000012,0x00000001,0x00000023,0x00000048,0x00050048,0x00000012,0x00000002,0x00000023, + 0x0000004c,0x00050048,0x00000012,0x00000003,0x00000023,0x00000050,0x00050048,0x00000012, + 0x00000004,0x00000023,0x00000054,0x00030047,0x00000012,0x00000002,0x00040047,0x00000076, + 0x0000001e,0x00000000,0x00040047,0x0000007a,0x00000022,0x00000000,0x00040047,0x0000007a, + 0x00000021,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016, + 0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008, + 0x00000007,0x00000007,0x00040017,0x0000000a,0x00000006,0x00000004,0x00040020,0x0000000b, + 0x00000001,0x0000000a,0x0004003b,0x0000000b,0x0000000c,0x00000001,0x00040015,0x0000000d, + 0x00000020,0x00000000,0x0004002b,0x0000000d,0x0000000e,0x00000000,0x00040020,0x0000000f, + 0x00000001,0x00000006,0x0007001e,0x00000012,0x00000006,0x00000006,0x00000006,0x00000006, + 0x00000006,0x00040020,0x00000013,0x00000009,0x00000012,0x0004003b,0x00000013,0x00000014, + 0x00000009,0x00040015,0x00000015,0x00000020,0x00000001,0x0004002b,0x00000015,0x00000016, + 0x00000002,0x00040020,0x00000017,0x00000009,0x00000006,0x0004002b,0x0000000d,0x0000001b, + 0x00000001,0x0004002b,0x00000015,0x0000001e,0x00000003,0x0004002b,0x00000015,0x00000023, + 0x00000000,0x0004002b,0x00000006,0x00000026,0x00000000,0x00020014,0x00000027,0x00040020, + 0x0000002b,0x00000007,0x00000006,0x0004002b,0x00000015,0x0000002d,0x00000001,0x0004002b, + 0x00000006,0x00000032,0x40000000,0x0004002b,0x00000006,0x00000052,0x40490e56,0x0004002b, + 0x00000006,0x00000054,0x41200000,0x0004002b,0x00000006,0x0000006a,0x3bda3c21,0x0004002b, + 0x00000015,0x0000006f,0x00000004,0x00040020,0x00000075,0x00000003,0x0000000a,0x0004003b, + 0x00000075,0x00000076,0x00000003,0x00090019,0x00000077,0x00000006,0x00000001,0x00000000, + 0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,0x00000078,0x00000077,0x00040020, + 0x00000079,0x00000000,0x00000078,0x0004003b,0x00000079,0x0000007a,0x00000000,0x00050036, 0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008, 0x00000009,0x00000007,0x0004003b,0x0000002b,0x0000002c,0x00000007,0x0004003b,0x0000002b, 0x0000003d,0x00000007,0x0004003b,0x0000002b,0x0000004c,0x00000007,0x0004003b,0x0000002b, @@ -87,7 +89,10 @@ const uint32_t world_warp_frag_spv[] = { 0x0000006a,0x0003003e,0x00000060,0x0000006b,0x0004003d,0x00000007,0x0000006c,0x00000060, 0x0004003d,0x00000007,0x0000006d,0x00000009,0x00050081,0x00000007,0x0000006e,0x0000006d, 0x0000006c,0x0003003e,0x00000009,0x0000006e,0x000200f9,0x0000002a,0x000200f8,0x0000002a, - 0x0004003d,0x00000072,0x00000075,0x00000074,0x0004003d,0x00000007,0x00000076,0x00000009, - 0x00050057,0x0000000a,0x00000077,0x00000075,0x00000076,0x0003003e,0x00000070,0x00000077, - 0x000100fd,0x00010038 + 0x00050041,0x00000017,0x00000070,0x00000014,0x0000006f,0x0004003d,0x00000006,0x00000071, + 0x00000070,0x0004003d,0x00000007,0x00000072,0x00000009,0x00050050,0x00000007,0x00000073, + 0x00000071,0x00000071,0x00050088,0x00000007,0x00000074,0x00000072,0x00000073,0x0003003e, + 0x00000009,0x00000074,0x0004003d,0x00000078,0x0000007b,0x0000007a,0x0004003d,0x00000007, + 0x0000007c,0x00000009,0x00050057,0x0000000a,0x0000007d,0x0000007b,0x0000007c,0x0003003e, + 0x00000076,0x0000007d,0x000100fd,0x00010038 }; \ No newline at end of file diff --git a/src/client/refresh/vk/vk_common.c b/src/client/refresh/vk/vk_common.c index 95ea545e..3874772a 100644 --- a/src/client/refresh/vk/vk_common.c +++ b/src/client/refresh/vk/vk_common.c @@ -1938,6 +1938,7 @@ VkResult QVk_BeginFrame(const VkViewport* viewport, const VkRect2D* scissor) { // reset tracking variables vk_state.current_pipeline = VK_NULL_HANDLE; + vk_state.current_renderpass = RP_COUNT; vk_config.vertex_buffer_usage = 0; // triangle fan index buffer data will not be cleared between frames unless the buffer itself is too small vk_config.index_buffer_usage = vk_triangleFanIboUsage; @@ -2115,6 +2116,7 @@ void QVk_BeginRenderpass(qvkrenderpasstype_t rpType) } vkCmdBeginRenderPass(vk_commandbuffers[vk_activeBufferIdx], &renderBeginInfo[rpType], VK_SUBPASS_CONTENTS_INLINE); + vk_state.current_renderpass = rpType; } #if 0 diff --git a/src/client/refresh/vk/vk_pipeline.c b/src/client/refresh/vk/vk_pipeline.c index 2755048c..d38ca125 100644 --- a/src/client/refresh/vk/vk_pipeline.c +++ b/src/client/refresh/vk/vk_pipeline.c @@ -166,7 +166,7 @@ void QVk_CreatePipeline(const VkDescriptorSetLayout *descriptorLayout, const uin { .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, .offset = 17 * sizeof(float), - .size = 4 * sizeof(float) + .size = 5 * sizeof(float) }}; VkPipelineLayoutCreateInfo plCreateInfo = { diff --git a/src/client/refresh/vk/vk_rmain.c b/src/client/refresh/vk/vk_rmain.c index ae93ae54..adccba0d 100644 --- a/src/client/refresh/vk/vk_rmain.c +++ b/src/client/refresh/vk/vk_rmain.c @@ -104,6 +104,7 @@ cvar_t *r_lockpvs; cvar_t *vk_polyblend; cvar_t *r_modulate; cvar_t *vk_shadows; +cvar_t *vk_pixel_size; cvar_t *vk_particle_size; cvar_t *vk_particle_att_a; cvar_t *vk_particle_att_b; @@ -540,7 +541,9 @@ void R_DrawParticles (void) float att_c; } particleUbo; - particleUbo.particleSize = vk_particle_size->value; + // Particle size needs to be scaled down proportionally to vk_pixel_size. + const float divisor = (vk_pixel_size->value < 1.0f ? 1.0f : vk_pixel_size->value); + particleUbo.particleSize = vk_particle_size->value / divisor; particleUbo.particleScale = vid.width * ri.Cvar_Get("viewsize", "100", CVAR_ARCHIVE)->value / 102400; particleUbo.minPointSize = vk_particle_min_size->value; particleUbo.maxPointSize = vk_particle_max_size->value; @@ -871,6 +874,17 @@ R_SetupVulkan (void) .minDepth = 0.f, .maxDepth = 1.f, }; + + // When rendering the world, reduce viewport size proportionally to vk_pixel_size. + if (vk_state.current_renderpass == RP_WORLD) + { + const float divisor = (vk_pixel_size->value < 1.0f ? 1.0f : vk_pixel_size->value); + viewport.x /= divisor; + viewport.y /= divisor; + viewport.width /= divisor; + viewport.height /= divisor; + } + vkCmdSetViewport(vk_activeCmdbuffer, 0, 1, &viewport); // set up projection matrix @@ -930,6 +944,16 @@ static void RE_RenderView (refdef_t *fd) .extent = { r_newrefdef.width, r_newrefdef.height } }; + // When rendering the world, scale down scissor proportionally to vk_pixel_size. + if (vk_state.current_renderpass == RP_WORLD) + { + const float divisor = (vk_pixel_size->value < 1.0f ? 1.0f : vk_pixel_size->value); + scissor.offset.x /= divisor; + scissor.offset.y /= divisor; + scissor.extent.width /= divisor; + scissor.extent.height /= divisor; + } + vkCmdSetScissor(vk_activeCmdbuffer, 0, 1, &scissor); R_PushDlights(); @@ -986,13 +1010,25 @@ qboolean RE_EndWorldRenderpass(void) // finish rendering world view to offsceen buffer vkCmdEndRenderPass(vk_activeCmdbuffer); - // apply postprocessing effects (underwater view warp if the player is submerged in liquid) to offscreen buffer + // apply postprocessing effects to offscreen buffer: + // * underwater view warp if the player is submerged in liquid + // * restore world view to the full screen size when vk_pixel_size is >1.0 QVk_BeginRenderpass(RP_WORLD_WARP); - float pushConsts[] = { (r_newrefdef.rdflags & RDF_UNDERWATER) ? r_newrefdef.time : 0.f, viewsize->value / 100, vid.width, vid.height }; + float pushConsts[] = + { + (r_newrefdef.rdflags & RDF_UNDERWATER) ? r_newrefdef.time : 0.f, + viewsize->value / 100.0f, + vid.width, + vid.height, + (vk_pixel_size->value < 1.0f ? 1.0f : vk_pixel_size->value), + }; vkCmdPushConstants(vk_activeCmdbuffer, vk_worldWarpPipeline.layout, VK_SHADER_STAGE_FRAGMENT_BIT, 17 * sizeof(float), sizeof(pushConsts), pushConsts); vkCmdBindDescriptorSets(vk_activeCmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_worldWarpPipeline.layout, 0, 1, &vk_colorbuffer.descriptorSet, 0, NULL); QVk_BindPipeline(&vk_worldWarpPipeline); + // Restore full viewport for future steps. + vkCmdSetViewport(vk_activeCmdbuffer, 0u, 1u, &vk_viewport); + vkCmdSetScissor(vk_activeCmdbuffer, 0u, 1u, &vk_scissor); vkCmdDraw(vk_activeCmdbuffer, 3, 1, 0, 0); vkCmdEndRenderPass(vk_activeCmdbuffer); @@ -1159,6 +1195,7 @@ R_Register( void ) vk_polyblend = ri.Cvar_Get("vk_polyblend", "1", 0); r_modulate = ri.Cvar_Get("r_modulate", "1", CVAR_ARCHIVE); vk_shadows = ri.Cvar_Get("vk_shadows", "0", CVAR_ARCHIVE); + vk_pixel_size = ri.Cvar_Get("vk_pixel_size", "1", CVAR_ARCHIVE); vk_particle_size = ri.Cvar_Get("vk_particle_size", "40", CVAR_ARCHIVE); vk_particle_att_a = ri.Cvar_Get("vk_particle_att_a", "0.01", CVAR_ARCHIVE); vk_particle_att_b = ri.Cvar_Get("vk_particle_att_b", "0.0", CVAR_ARCHIVE); diff --git a/stuff/shaders/world_warp.frag b/stuff/shaders/world_warp.frag index 5fa6f483..3921a8b2 100644 --- a/stuff/shaders/world_warp.frag +++ b/stuff/shaders/world_warp.frag @@ -1,7 +1,8 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable -// Underwater screen warp effect similar to what software renderer provides +// Underwater screen warp effect similar to what software renderer provides. +// Pixel size to simulate lower screen resolutions is used to restore world to full screen size. layout(push_constant) uniform PushConstant { @@ -9,6 +10,7 @@ layout(push_constant) uniform PushConstant layout(offset = 72) float scale; layout(offset = 76) float scrWidth; layout(offset = 80) float scrHeight; + layout(offset = 84) float pixelSize; } pc; layout(set = 0, binding = 0) uniform sampler2D sTexture; @@ -32,5 +34,7 @@ void main() uv += distortion; } + uv /= pc.pixelSize; + fragmentColor = texture(sTexture, uv); }