[vulkan] Implement order implement transparency

It's a bit flaky for particles, especially at higher frame rates, but
that's due to supporting only 64 overlapping pixels. A reasonable
solution is probably switching to a priority heap for the "sort" and
upping the limit.
This commit is contained in:
Bill Currie 2022-12-01 03:00:47 +09:00
parent ecd5e1de9f
commit 00cade072c
27 changed files with 694 additions and 50 deletions

View file

@ -21,7 +21,9 @@ typedef struct qfv_bufferbarrier_s {
// image layout transitions
enum {
qfv_LT_Undefined_to_TransferDst,
qfv_LT_Undefined_to_General,
qfv_LT_TransferDst_to_TransferSrc,
qfv_LT_TransferDst_to_General,
qfv_LT_TransferDst_to_ShaderReadOnly,
qfv_LT_TransferSrc_to_ShaderReadOnly,
qfv_LT_ShaderReadOnly_to_TransferDst,
@ -35,6 +37,7 @@ enum {
qfv_BB_TransferWrite_to_VertexAttrRead,
qfv_BB_TransferWrite_to_IndexRead,
qfv_BB_TransferWrite_to_UniformRead,
qfv_BB_TransferWrite_to_ShaderRW,
qfv_BB_ShaderRW_to_ShaderRO,
qfv_BB_ShaderRW_to_ShaderRO_VA,
qfv_BB_ShaderRO_to_ShaderWrite,

View file

@ -1,6 +1,11 @@
#ifndef __QF_Vulkan_renderpass_h
#define __QF_Vulkan_renderpass_h
#ifndef VK_NO_PROTOTYPES
#define VK_NO_PROTOTYPES
#endif
#include <vulkan/vulkan.h>
#include "QF/darray.h"
#include "QF/simd/types.h"

View file

@ -0,0 +1,61 @@
#ifndef __QF_Vulkan_qf_translucent_h
#define __QF_Vulkan_qf_translucent_h
#include "QF/darray.h"
#include "QF/simd/types.h"
#include "QF/Vulkan/command.h"
typedef struct qfv_transfrag_s {
vec4f_t color;
float depth;
int32_t next;
} qfv_transfrag_t;
typedef struct qfv_transtate_s {
int32_t numFragments;
int32_t maxFragments;
} qfv_transtate_t;
typedef enum {
QFV_translucentClear,
QFV_translucentBlend,
QFV_translucentNumPasses
} QFV_TranslucentSubpass;
typedef struct translucentframe_s {
VkDescriptorSet descriptors;
VkImage heads;
VkBuffer state;
qfv_cmdbufferset_t cmdSet;
} translucentframe_t;
typedef struct translucentframeset_s
DARRAY_TYPE (translucentframe_t) translucentframeset_t;
typedef struct translucentctx_s {
translucentframeset_t frames;
struct qfv_resource_s *resources;
VkPipeline pipeline;
VkPipelineLayout layout;
VkDescriptorPool pool;
VkDescriptorSetLayout setLayout;
} translucentctx_t;
struct vulkan_ctx_s;
struct qfv_renderframe_s;
void Vulkan_Translucent_Init (struct vulkan_ctx_s *ctx);
void Vulkan_Translucent_Shutdown (struct vulkan_ctx_s *ctx);
void Vulkan_Translucent_Draw (struct qfv_renderframe_s *rFrame);
VkDescriptorSet Vulkan_Translucent_Descriptors (struct vulkan_ctx_s *ctx,
int frame)__attribute__((pure));
void Vulkan_Translucent_CreateBuffers (struct vulkan_ctx_s *ctx,
VkExtent2D extent);
void Vulkan_Translucent_CreateRenderPasses (struct vulkan_ctx_s *ctx);
#endif//__QF_Vulkan_qf_translucent_h

View file

@ -42,17 +42,19 @@ enum {
QFV_rp_particles,
QFV_rp_shadowmap,
QFV_rp_preoutput,
QFV_rp_translucent,
QFV_rp_main,
QFV_rp_output,
};
//FIXME location
typedef enum {
QFV_passDepth, // geometry
QFV_passTranslucent, // geometry
QFV_passGBuffer, // geometry
QFV_passLighting, // single triangle
QFV_passCompose, // single triangle
QFV_passDepth, // geometry
QFV_passTranslucentFrag, // geometry
QFV_passGBuffer, // geometry
QFV_passLighting, // single triangle
QFV_passTranslucentFinal, // single triangle
QFV_passCompose, // single triangle
QFV_NumPasses
} QFV_Subpass;

View file

@ -47,6 +47,7 @@ typedef struct vulkan_ctx_s {
struct scriptctx_s *script_context;
struct texturectx_s *texture_context;
struct matrixctx_s *matrix_context;
struct translucentctx_s *translucent_context;
struct aliasctx_s *alias_context;
struct bspctx_s *bsp_context;
struct iqmctx_s *iqm_context;

View file

@ -254,6 +254,7 @@ libs_video_renderer_librender_vulkan_la_SOURCES = \
libs/video/renderer/vulkan/vulkan_scene.c \
libs/video/renderer/vulkan/vulkan_sprite.c \
libs/video/renderer/vulkan/vulkan_texture.c \
libs/video/renderer/vulkan/vulkan_translucent.c \
libs/video/renderer/vulkan/vulkan_vid_common.c
libs/video/renderer/vulkan/vkparse.lo: \
@ -339,6 +340,10 @@ lightingf_src = $(vkshaderpath)/lighting.frag
lightingf_c = $(vkshaderpath)/lighting.frag.spvc
composef_src = $(vkshaderpath)/compose.frag
composef_c = $(vkshaderpath)/compose.frag.spvc
oit_store = $(vkshaderpath)/oit_store.finc
oit_h = $(vkshaderpath)/oit.h
oit_blendf_src = $(vkshaderpath)/oit_blend.frag
oit_blendf_c = $(vkshaderpath)/oit_blend.frag.spvc
aliasv_src = $(vkshaderpath)/alias.vert
aliasv_c = $(vkshaderpath)/alias.vert.spvc
aliasf_src = $(vkshaderpath)/alias.frag
@ -378,7 +383,7 @@ $(partphysicsc_c): $(partphysicsc_src)
$(partupdatec_c): $(partupdatec_src)
$(particlev_c): $(particlev_src)
$(particleg_c): $(particleg_src)
$(particlef_c): $(particlef_src)
$(particlef_c): $(particlef_src) $(oit_store) $(oit_h)
$(sprite_gbufv_c): $(sprite_gbufv_src)
@ -408,14 +413,16 @@ $(bsp_gbuff_c): $(bsp_gbuff_src)
$(bsp_shadow_c): $(bsp_shadow_src)
$(bsp_skyf_c): $(bsp_skyf_src)
$(bsp_skyf_c): $(bsp_skyf_src) $(oit_store) $(oit_h)
$(bsp_turbf_c): $(bsp_turbf_src)
$(bsp_turbf_c): $(bsp_turbf_src) $(oit_store) $(oit_h)
$(lightingf_c): $(lightingf_src)
$(composef_c): $(composef_src)
$(oit_blendf_c): $(oit_blendf_src) $(oit_h)
$(aliasv_c): $(aliasv_src)
$(alias_depth_c): $(alias_depth_src)
@ -471,6 +478,7 @@ vkshader_c = \
$(bsp_turbf_c) \
$(lightingf_c) \
$(composef_c) \
$(oit_blendf_c) \
$(aliasv_c) \
$(alias_depth_c) \
$(aliasf_c) \
@ -537,6 +545,7 @@ EXTRA_DIST += \
libs/video/renderer/vulkan/shader/bsp_sky.frag \
libs/video/renderer/vulkan/shader/bsp_turb.frag \
libs/video/renderer/vulkan/shader/compose.frag \
libs/video/renderer/vulkan/shader/oit_blend.frag \
libs/video/renderer/vulkan/shader/iqm.frag \
libs/video/renderer/vulkan/shader/iqm.vert \
libs/video/renderer/vulkan/shader/lighting.frag \

View file

@ -57,6 +57,7 @@
#include "QF/Vulkan/qf_scene.h"
#include "QF/Vulkan/qf_sprite.h"
#include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/qf_translucent.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/capture.h"
#include "QF/Vulkan/command.h"
@ -109,6 +110,7 @@ vulkan_R_Init (void)
Vulkan_Sprite_Init (vulkan_ctx);
Vulkan_Draw_Init (vulkan_ctx);
Vulkan_Lighting_Init (vulkan_ctx);
Vulkan_Translucent_Init (vulkan_ctx);
Vulkan_Compose_Init (vulkan_ctx);
Skin_Init ();
@ -740,6 +742,7 @@ vulkan_vid_render_shutdown (void)
Mod_ClearAll ();
Vulkan_Compose_Shutdown (vulkan_ctx);
Vulkan_Translucent_Shutdown (vulkan_ctx);
Vulkan_Lighting_Shutdown (vulkan_ctx);
Vulkan_Draw_Shutdown (vulkan_ctx);
Vulkan_Sprite_Shutdown (vulkan_ctx);

View file

@ -44,6 +44,19 @@ const qfv_imagebarrier_t imageBarriers[] = {
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
},
},
[qfv_LT_Undefined_to_General] = {
.srcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
.dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT,
.barrier = {
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
},
},
[qfv_LT_TransferDst_to_TransferSrc] = {
.srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT,
.dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT,
@ -57,6 +70,19 @@ const qfv_imagebarrier_t imageBarriers[] = {
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
},
},
[qfv_LT_TransferDst_to_General] = {
.srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT,
.dstStages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
.barrier = {
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_GENERAL,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
},
},
[qfv_LT_TransferDst_to_ShaderReadOnly] = {
.srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT,
.dstStages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
@ -164,6 +190,16 @@ const qfv_bufferbarrier_t bufferBarriers[] = {
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
},
},
[qfv_BB_TransferWrite_to_ShaderRW] = {
.srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT,
.dstStages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
.barrier = {
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
},
},
[qfv_BB_ShaderRW_to_ShaderRO] = {
.srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
.dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,

View file

@ -156,6 +156,7 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions)
VkPhysicalDeviceFeatures features = {
.geometryShader = 1,
.multiViewport = 1,
.fragmentStoresAndAtomics = 1,
};
VkDeviceCreateInfo dCreateInfo = {
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, &multiview_features, 0,

View file

@ -233,6 +233,20 @@
},
);
};
oit_pool = {
flags = 0;
maxSets = $frames.size;
bindings = (
{
type = storage_buffer;
descriptorCount = "2z * $frames.size";
},
{
type = storage_image;
descriptorCount = "1z * $frames.size";
},
);
};
compose_attach_pool = {
flags = 0;
maxSets = $frames.size;
@ -293,6 +307,28 @@
},
);
};
oit_set = {
bindings = (
{
binding = 0;
descriptorType = storage_buffer;
descriptorCount = 1;
stageFlags = fragment;
},
{
binding = 1;
descriptorType = storage_buffer;
descriptorCount = 1;
stageFlags = fragment;
},
{
binding = 2;
descriptorType = storage_image;
descriptorCount = 1;
stageFlags = fragment;
},
);
};
entity_set = {
bindings = (
{
@ -433,7 +469,7 @@
setLayouts = (matrix_set);
};
quakebsp_layout = {
setLayouts = (matrix_set, entity_set, texture_set, texture_set);
setLayouts = (matrix_set, entity_set, oit_set, texture_set, texture_set);
pushConstantRanges = (
{
stageFlags = fragment;
@ -490,6 +526,9 @@
lighting_layout = {
setLayouts = (lighting_attach, lighting_lights, lighting_shadow);
};
oit_layout = {
setLayouts = (oit_set);
};
compose_layout = {
setLayouts = (compose_attach);
};
@ -507,7 +546,7 @@
setLayouts = (particle_set, particle_set, particle_set);
};
partdraw_layout = {
setLayouts = (matrix_set, texture_set);
setLayouts = (matrix_set, texture_set, oit_set);
pushConstantRanges = (
{
stageFlags = vertex;
@ -1225,9 +1264,22 @@
);
layout = lighting_layout;
};
compose = {
oit = {
@inherit = $properties.pipelines.comp_base;
subpass = 4;
stages = (
$properties.fstriangle.vertexStage,
{
stage = fragment;
name = main;
module = $builtin/oit_blend.frag;
},
);
layout = oit_layout;
};
compose = {
@inherit = $properties.pipelines.comp_base;
subpass = 5;
stages = (
$properties.fstriangle.vertexStage,
{

View file

@ -146,6 +146,7 @@
{ name = translucent; color = "[ 0.25, 0.25, 0.6, 1]" },
{ name = g-buffef; color = "[ 0.3, 0.7, 0.3, 1]" },
{ name = lighting; color = "[ 0.8, 0.8, 0.8, 1]" },
{ name = translucent; color = "[ 0.25, 0.6, 0.25, 1]" },
{ name = compose; color = "[ 0.7, 0.3, 0.3, 1]" },
);
};
@ -200,14 +201,8 @@
layout = depth_stencil_attachment_optimal;
};
},
{ // 1 translucent
{ // 1 translucent-frags
pipelineBindPoint = graphics;
colorAttachments = (
{ // translucent
attachment = 6;
layout = color_attachment_optimal;
},
);
depthStencilAttachment = {
attachment = 0;
layout = depth_stencil_read_only_optimal;
@ -272,7 +267,17 @@
);
preserveAttachments = (6);
},
{ // 4 compose
{ // 4 translucent-final
pipelineBindPoint = graphics;
colorAttachments = (
{ // translucent
attachment = 6;
layout = color_attachment_optimal;
},
);
preserveAttachments = (1, 2, 3, 4, 5);
},
{ // 5 compose
pipelineBindPoint = graphics;
inputAttachments = (
{ // opaque
@ -305,11 +310,11 @@
},
/*{
srcSubpass = ~0u; // external
dstSubpass = 1; // translucent
srcStageMask = compute_shader;
dstStageMask = vertex_input|draw_indirect;
srcAccessMask = shader_write;
dstAccessMask = vertex_attribute_read|indirect_command_read;
dstSubpass = 1; // translucent-frags
srcStageMask = transfer;
dstStageMask = fragment_shader|early_fragment_tests;
srcAccessMask = transfer_write;
dstAccessMask = shader_read|shader_write;
},*/
{
srcSubpass = 0; // depth
@ -331,7 +336,7 @@
},
{
srcSubpass = 3; // lighting
dstSubpass = 4; // compose
dstSubpass = 5; // compose
srcStageMask = color_attachment_output;
dstStageMask = fragment_shader;
srcAccessMask = color_attachment_write;
@ -339,8 +344,17 @@
dependencyFlags = by_region;
},
{
srcSubpass = 1; // translucent
dstSubpass = 4; // compose
srcSubpass = 1; // translucent-frags
dstSubpass = 4; // translucent-final
srcStageMask = color_attachment_output;
dstStageMask = fragment_shader;
srcAccessMask = color_attachment_write;
dstAccessMask = input_attachment_read;
dependencyFlags = by_region;
},
{
srcSubpass = 4; // translucent-final
dstSubpass = 5; // compose
srcStageMask = color_attachment_output;
dstStageMask = fragment_shader;
srcAccessMask = color_attachment_write;

View file

@ -95,6 +95,8 @@ static
static
#include "libs/video/renderer/vulkan/shader/compose.frag.spvc"
static
#include "libs/video/renderer/vulkan/shader/oit_blend.frag.spvc"
static
#include "libs/video/renderer/vulkan/shader/alias.vert.spvc"
static
#include "libs/video/renderer/vulkan/shader/alias_depth.vert.spvc"
@ -156,6 +158,7 @@ static shaderdata_t builtin_shaders[] = {
{ "bsp_turb.frag", bsp_turb_frag, sizeof (bsp_turb_frag) },
{ "lighting.frag", lighting_frag, sizeof (lighting_frag) },
{ "compose.frag", compose_frag, sizeof (compose_frag) },
{ "oit_blend.frag", oit_blend_frag, sizeof (oit_blend_frag) },
{ "alias.vert", alias_vert, sizeof (alias_vert) },
{ "alias_depth.vert", alias_depth_vert, sizeof (alias_depth_vert) },
{ "alias.frag", alias_frag, sizeof (alias_frag) },

View file

@ -1,6 +1,6 @@
#version 450
layout (set = 2, binding = 0) uniform sampler2DArray Texture;
layout (set = 3, binding = 0) uniform sampler2DArray Texture;
layout (push_constant) uniform PushConstants {
vec4 fog;

View file

@ -1,10 +1,12 @@
#version 450
#extension GL_GOOGLE_include_directive : enable
#include "oit_store.finc"
layout (constant_id = 0) const bool doSkyBox = false;
layout (constant_id = 1) const bool doSkySheet = false;
layout (set = 2, binding = 0) uniform sampler2DArray SkySheet;
layout (set = 3, binding = 0) uniform samplerCube SkyBox;
layout (set = 3, binding = 0) uniform sampler2DArray SkySheet;
layout (set = 4, binding = 0) uniform samplerCube SkyBox;
layout (push_constant) uniform PushConstants {
vec4 fog;
@ -17,7 +19,8 @@ layout (location = 0) in vec4 tl_st;
layout (location = 1) in vec3 direction;
layout (location = 2) in vec4 color;
layout (location = 0) out vec4 frag_color;
layout(early_fragment_tests) in;
//layout (location = 0) out vec4 frag_color;
const float SCALE = 189.0 / 64.0;
@ -95,5 +98,6 @@ main (void)
} else {
c = vec4 (0, 0, 0, 1);
}
frag_color = c;//fogBlend (c);
//frag_color = c;//fogBlend (c);
StoreFrag (c, gl_FragCoord.z);
}

View file

@ -1,6 +1,8 @@
#version 450
#extension GL_GOOGLE_include_directive : enable
#include "oit_store.finc"
layout (set = 2, binding = 0) uniform sampler2DArray Texture;
layout (set = 3, binding = 0) uniform sampler2DArray Texture;
layout (push_constant) uniform PushConstants {
vec4 fog;
@ -13,7 +15,8 @@ layout (location = 0) in vec4 tl_st;
layout (location = 1) in vec3 direction;
layout (location = 2) in vec4 color;
layout (location = 0) out vec4 frag_color;
layout(early_fragment_tests) in;
//layout (location = 0) out vec4 frag_color;
const float PI = 3.14159265;
const float SPEED = 20.0;
@ -49,5 +52,6 @@ main (void)
float a = c.a * e.a * alpha;
c += e;
c.a = a;
frag_color = c * color;//fogBlend (c);
//frag_color = c * color;//fogBlend (c);
StoreFrag (c * color, gl_FragCoord.z);
}

View file

@ -0,0 +1,20 @@
#ifndef OIT_SET
#define OIT_SET 2
#endif
struct FragData {
vec4 color;
float depth;
int next;
};
layout (set = OIT_SET, binding = 0) coherent buffer FragCount {
int numFragments;
int maxFragments;
};
layout (set = OIT_SET, binding = 1) buffer Fragments {
FragData fragments[];
};
layout (set = OIT_SET, binding = 2, r32i) coherent uniform iimage2D heads;

View file

@ -0,0 +1,40 @@
#version 450
#extension GL_GOOGLE_include_directive : enable
#define OIT_SET 0
#include "oit.h"
layout (location = 0) out vec4 frag_color;
void
main (void)
{
#define MAX_FRAGMENTS 64
FragData frags[MAX_FRAGMENTS];
int numFrags = 0;
ivec2 coord = ivec2(gl_FragCoord.xy);
int index = imageLoad (heads, coord).r;
//FIXME use a heap and prioritize closer fragments
while (index != -1 && numFrags < MAX_FRAGMENTS) {
frags[numFrags] = fragments[index];
numFrags++;
index = fragments[index].next;
}
//insertion sort
for (int i = 1; i < numFrags; i++) {
FragData toInsert = frags[i];
int j = i;
while (j > 0 && toInsert.depth > frags[j - 1].depth) {
frags[j] = frags[j - 1];
j--;
}
frags[j] = toInsert;
}
vec4 color = vec4 (0, 0, 0, 0);
for (int i = 0; i < numFrags; i++) {
color = mix (color, frags[i].color,
clamp (frags[i].color.a, 0.0f, 1.0f));
}
frag_color = color;
}

View file

@ -0,0 +1,14 @@
#include "oit.h"
void
StoreFrag (vec4 color, float depth)
{
int index = atomicAdd (numFragments, 1);
ivec2 coord = ivec2(gl_FragCoord.xy);
if (index < maxFragments) {
int prevIndex = imageAtomicExchange (heads, coord, index);
fragments[index].color = color;
fragments[index].depth = depth;
fragments[index].next = prevIndex;
}
}

View file

@ -1,9 +1,11 @@
#version 450
#extension GL_GOOGLE_include_directive : enable
#include "oit_store.finc"
layout (location = 0) in vec4 uv_tr;
layout (location = 1) in vec4 color;
layout (location = 0) out vec4 frag_color;
layout(early_fragment_tests) in;
void
main (void)
@ -16,5 +18,5 @@ main (void)
discard;
}
c *= (a);
frag_color = c;
StoreFrag (c, gl_FragCoord.z);
}

View file

@ -69,7 +69,7 @@ static const char * __attribute__((used)) alias_pass_names[] = {
static QFV_Subpass subpass_map[] = {
QFV_passDepth, // QFV_aliasDepth
QFV_passGBuffer, // QFV_aliasGBuffer
QFV_passTranslucent, // QFV_aliasTranslucent
QFV_passTranslucentFrag,// QFV_aliasTranslucent
};
static void

View file

@ -60,6 +60,7 @@
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_scene.h"
#include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/qf_translucent.h"
#include "QF/Vulkan/buffer.h"
#include "QF/Vulkan/barrier.h"
#include "QF/Vulkan/command.h"
@ -76,6 +77,9 @@
#include "r_internal.h"
#include "vid_vulkan.h"
#define TEX_SET 3
#define SKYBOX_SET 4
typedef struct bsp_push_constants_s {
quat_t fog;
float time;
@ -93,8 +97,8 @@ static const char * __attribute__((used)) bsp_pass_names[] = {
static QFV_Subpass subpass_map[] = {
[QFV_bspDepth] = QFV_passDepth,
[QFV_bspGBuffer] = QFV_passGBuffer,
[QFV_bspSky] = QFV_passTranslucent,
[QFV_bspTurb] = QFV_passTranslucent,
[QFV_bspSky] = QFV_passTranslucentFrag,
[QFV_bspTurb] = QFV_passTranslucentFrag,
};
static void
@ -828,9 +832,10 @@ bsp_begin_subpass (QFV_BspSubpass subpass, VkPipeline pipeline,
VkDescriptorSet sets[] = {
Vulkan_Matrix_Descriptors (ctx, ctx->curFrame),
Vulkan_Scene_Descriptors (ctx),
Vulkan_Translucent_Descriptors (ctx, ctx->curFrame),
};
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
layout, 0, 2, sets, 0, 0);
layout, 0, 3, sets, 0, 0);
//XXX glsl_Fog_GetColor (fog);
//XXX fog[3] = glsl_Fog_GetDensity () / 64.0;
@ -884,7 +889,7 @@ turb_begin (qfv_renderframe_t *rFrame)
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucent],
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucentFrag],
bframe->cmdSet.a[QFV_bspTurb]);
qfvPushDebug (ctx, "bsp_begin_subpass");
@ -909,7 +914,7 @@ sky_begin (qfv_renderframe_t *rFrame)
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucent],
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucentFrag],
bframe->cmdSet.a[QFV_bspSky]);
qfvPushDebug (ctx, "bsp_begin_subpass");
@ -1020,7 +1025,7 @@ draw_queue (bsp_pass_t *pass, int queue, VkPipelineLayout layout,
__auto_type d = pass->draw_queues[queue].a[i];
if (pass->textures) {
vulktex_t *tex = pass->textures->a[d.tex_id];
bind_texture (tex, 2, layout, dfunc, cmd);
bind_texture (tex, TEX_SET, layout, dfunc, cmd);
}
dfunc->vkCmdDrawIndexed (cmd, d.index_count, d.instance_count,
d.first_index, 0, d.first_instance);
@ -1189,7 +1194,7 @@ Vulkan_DrawSky (qfv_renderframe_t *rFrame)
sky_begin (rFrame);
vulktex_t skybox = { .descriptor = bctx->skybox_descriptor };
bind_texture (&skybox, 3, bctx->layout, dfunc,
bind_texture (&skybox, SKYBOX_SET, bctx->layout, dfunc,
bframe->cmdSet.a[QFV_bspSky]);
bsp_push_constants_t frag_constants = { .time = vr_data.realtime };
push_fragconst (&frag_constants, bctx->layout, device,

View file

@ -70,7 +70,7 @@ static const char * __attribute__((used)) iqm_pass_names[] = {
static QFV_Subpass subpass_map[] = {
QFV_passDepth, // QFV_iqmDepth
QFV_passGBuffer, // QFV_iqmGBuffer
QFV_passTranslucent, // QFV_iqmTranslucent
QFV_passTranslucentFrag,// QFV_iqmTranslucent
};
static void

View file

@ -60,6 +60,7 @@
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_scene.h"
#include "QF/Vulkan/qf_sprite.h"
#include "QF/Vulkan/qf_translucent.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/swapchain.h"
@ -140,6 +141,7 @@ Vulkan_RenderView (qfv_renderframe_t *rFrame)
Vulkan_Bsp_Flush (ctx);
Vulkan_RenderEntities (r_ent_queue, rFrame);
Vulkan_Scene_Flush (ctx);
Vulkan_Translucent_Draw (rFrame);
}
void
@ -187,4 +189,5 @@ Vulkan_Main_CreateRenderPasses (vulkan_ctx_t *ctx)
DARRAY_APPEND (&ctx->renderPasses, rp);
Vulkan_Output_SetInput (ctx, rp->output.view);
Vulkan_Translucent_CreateBuffers (ctx, rp->output.extent);
}

View file

@ -53,6 +53,7 @@
#include "QF/Vulkan/qf_palette.h"
#include "QF/Vulkan/qf_particles.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_translucent.h"
#include "r_internal.h"
#include "vid_vulkan.h"
@ -83,7 +84,7 @@ particle_begin_subpass (VkPipeline pipeline, qfv_renderframe_t *rFrame)
dfunc->vkResetCommandBuffer (cmd, 0);
VkCommandBufferInheritanceInfo inherit = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0,
rFrame->renderpass->renderpass, QFV_passTranslucent,
rFrame->renderpass->renderpass, QFV_passTranslucentFrag,
rFrame->framebuffer,
0, 0, 0,
};
@ -100,9 +101,10 @@ particle_begin_subpass (VkPipeline pipeline, qfv_renderframe_t *rFrame)
VkDescriptorSet sets[] = {
Vulkan_Matrix_Descriptors (ctx, ctx->curFrame),
Vulkan_Palette_Descriptor (ctx),
Vulkan_Translucent_Descriptors (ctx, ctx->curFrame),
};
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
pctx->draw_layout, 0, 2, sets, 0, 0);
pctx->draw_layout, 0, 3, sets, 0, 0);
dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport);
dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor);
}
@ -128,7 +130,7 @@ Vulkan_DrawParticles (qfv_renderframe_t *rFrame)
particleframe_t *pframe = &pctx->frames.a[curFrame];
VkCommandBuffer cmd = pframe->cmdSet.a[0];
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucent],
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucentFrag],
pframe->cmdSet.a[0]);
particle_begin_subpass (pctx->draw, rFrame);

View file

@ -76,7 +76,7 @@ static const char * __attribute__((used)) sprite_pass_names[] = {
static QFV_Subpass subpass_map[] = {
QFV_passDepth, // QFV_spriteDepth
QFV_passGBuffer, // QFV_spriteGBuffer
QFV_passTranslucent, // QFV_spriteTranslucent
QFV_passTranslucentFrag,// QFV_spriteTranslucent
};
static void

View file

@ -0,0 +1,358 @@
/*
vulkan_translucent.c
Vulkan translucent pass pipeline
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2022/11/30
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include "qfalloca.h"
#include "QF/cvar.h"
#include "QF/sys.h"
#include "QF/va.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_translucent.h"
#include "QF/Vulkan/barrier.h"
#include "QF/Vulkan/debug.h"
#include "QF/Vulkan/descriptor.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/image.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/resource.h"
#include "QF/Vulkan/staging.h"
#include "r_internal.h"
#include "vid_vulkan.h"
#define MAX_FRAGMENTS (1<<24)
static const char * __attribute__((used)) translucent_pass_names[] = {
"clear",
"blend",
};
void
Vulkan_Translucent_Draw (qfv_renderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
qfv_renderpass_t *renderpass = rFrame->renderpass;
translucentctx_t *tctx = ctx->translucent_context;
translucentframe_t *tframe = &tctx->frames.a[ctx->curFrame];
VkCommandBuffer cmd = tframe->cmdSet.a[QFV_translucentBlend];
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucentFinal], cmd);
dfunc->vkResetCommandBuffer (cmd, 0);
VkCommandBufferInheritanceInfo inherit = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0,
renderpass->renderpass, QFV_passTranslucentFinal,
rFrame->framebuffer,
0, 0, 0,
};
VkCommandBufferBeginInfo beginInfo = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0,
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
| VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit,
};
dfunc->vkBeginCommandBuffer (cmd, &beginInfo);
QFV_duCmdBeginLabel (device, cmd, "translucent", { 0, 0.2, 0.6, 1});
dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
tctx->pipeline);
VkDescriptorSet set[] = {
tframe->descriptors,
};
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
tctx->layout, 0, 1, set, 0, 0);
dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport);
dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor);
dfunc->vkCmdDraw (cmd, 3, 1, 0, 0);
QFV_duCmdEndLabel (device, cmd);
dfunc->vkEndCommandBuffer (cmd);
}
void
Vulkan_Translucent_Init (vulkan_ctx_t *ctx)
{
if (ctx->translucent_context) {//FIXME
return;
}
qfv_device_t *device = ctx->device;
qfvPushDebug (ctx, "translucent init");
translucentctx_t *tctx = calloc (1, sizeof (translucentctx_t));
ctx->translucent_context = tctx;
size_t frames = ctx->frames.size;
DARRAY_INIT (&tctx->frames, frames);
DARRAY_RESIZE (&tctx->frames, frames);
tctx->frames.grow = 0;
tctx->pipeline = Vulkan_CreateGraphicsPipeline (ctx, "oit");
tctx->layout = Vulkan_CreatePipelineLayout (ctx, "oit_layout");
__auto_type setLayout = QFV_AllocDescriptorSetLayoutSet (frames, alloca);
for (size_t i = 0; i < frames; i++) {
setLayout->a[i] = Vulkan_CreateDescriptorSetLayout (ctx, "oit_set");
}
__auto_type pool = Vulkan_CreateDescriptorPool (ctx, "oit_pool");
__auto_type sets = QFV_AllocateDescriptorSet (device, pool, setLayout);
for (size_t i = 0; i < frames; i++) {
__auto_type tframe = &tctx->frames.a[i];
DARRAY_INIT (&tframe->cmdSet, QFV_translucentNumPasses);
DARRAY_RESIZE (&tframe->cmdSet, QFV_translucentNumPasses);
tframe->cmdSet.grow = 0;
QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, &tframe->cmdSet);
tframe->descriptors = sets->a[i];
for (int j = 0; j < QFV_translucentNumPasses; j++) {
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER,
tframe->cmdSet.a[j],
va (ctx->va_ctx, "cmd:translucent:%zd:%s", i,
translucent_pass_names[j]));
}
}
free (sets);
qfvPopDebug (ctx);
}
void
Vulkan_Translucent_Shutdown (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
translucentctx_t *tctx = ctx->translucent_context;
if (tctx->resources) {
QFV_DestroyResource (device, tctx->resources);
free (tctx->resources);
tctx->resources = 0;
}
dfunc->vkDestroyPipeline (device->dev, tctx->pipeline, 0);
free (tctx->frames.a);
free (tctx);
}
VkDescriptorSet
Vulkan_Translucent_Descriptors (vulkan_ctx_t *ctx, int frame)
{
__auto_type tctx = ctx->translucent_context;
return tctx->frames.a[frame].descriptors;
}
void
Vulkan_Translucent_CreateBuffers (vulkan_ctx_t *ctx, VkExtent2D extent)
{
if (!ctx->translucent_context) {//FIXME
Vulkan_Translucent_Init (ctx);
}
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
__auto_type tctx = ctx->translucent_context;
size_t frames = ctx->frames.size;
if (tctx->resources) {
QFV_DestroyResource (device, tctx->resources);
free (tctx->resources);
tctx->resources = 0;
}
tctx->resources = malloc (sizeof (qfv_resource_t)
// heads image
+ frames * sizeof (qfv_resobj_t)
// heads image view
+ frames * sizeof (qfv_resobj_t)
// fragment buffer
+ frames * sizeof (qfv_resobj_t)
// fragment count
+ frames * sizeof (qfv_resobj_t));
__auto_type heads_objs = (qfv_resobj_t *) &tctx->resources[1];
__auto_type head_views_objs = &heads_objs[frames];
__auto_type buffer_objs = &head_views_objs[frames];
__auto_type count_objs = &buffer_objs[frames];
tctx->resources[0] = (qfv_resource_t) {
.name = "oit",
.va_ctx = ctx->va_ctx,
.memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
.num_objects = 4 * frames,
.objects = heads_objs,
};
for (size_t i = 0; i < frames; i++) {
heads_objs[i] = (qfv_resobj_t) {
.name = va (ctx->va_ctx, "heads:%zd", i),
.type = qfv_res_image,
.image = {
.type = VK_IMAGE_TYPE_2D,
.format = VK_FORMAT_R32_SINT,
.extent = { extent.width, extent.height, 1 },
.num_mipmaps = 1,
.num_layers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.usage = VK_IMAGE_USAGE_STORAGE_BIT
| VK_IMAGE_USAGE_TRANSFER_DST_BIT,
},
};
head_views_objs[i] = (qfv_resobj_t) {
.name = "head view",
.type = qfv_res_image_view,
.image_view = {
.image = i,
.type = VK_IMAGE_VIEW_TYPE_2D,
.format = VK_FORMAT_R32_SINT,
.aspect = VK_IMAGE_ASPECT_COLOR_BIT,
},
};
buffer_objs[i] = (qfv_resobj_t) {
.name = va (ctx->va_ctx, "frags:%zd", i),
.type = qfv_res_buffer,
.buffer = {
.size = sizeof (qfv_transfrag_t) * MAX_FRAGMENTS,
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
},
};
count_objs[i] = (qfv_resobj_t) {
.name = va (ctx->va_ctx, "count:%zd", i),
.type = qfv_res_buffer,
.buffer = {
.size = 2 * sizeof (qfv_transtate_t),
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
},
};
}
QFV_CreateResource (device, tctx->resources);
for (size_t i = 0; i < frames; i++) {
__auto_type tframe = &tctx->frames.a[i];
tframe->heads = heads_objs[i].image.image;
tframe->state = count_objs[i].buffer.buffer;
VkDescriptorImageInfo imageInfo[] = {
{ 0, head_views_objs[i].image_view.view, VK_IMAGE_LAYOUT_GENERAL },
};
VkDescriptorBufferInfo bufferInfo[] = {
{ count_objs[i].buffer.buffer, 0, VK_WHOLE_SIZE },
{ buffer_objs[i].buffer.buffer, 0, VK_WHOLE_SIZE },
};
VkWriteDescriptorSet write[] = {
{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0,
tframe->descriptors, 2, 0, 1,
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.pImageInfo = imageInfo },
{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0,
tframe->descriptors, 0, 0, 2,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = bufferInfo },
};
dfunc->vkUpdateDescriptorSets (device->dev, 2, write, 0, 0);
}
}
static void
translucent_clear (qfv_renderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
translucentctx_t *tctx = ctx->translucent_context;
__auto_type tframe = &tctx->frames.a[ctx->curFrame];
VkCommandBuffer cmd = tframe->cmdSet.a[QFV_translucentClear];
DARRAY_APPEND (&rFrame->subpassCmdSets[0], cmd);
dfunc->vkResetCommandBuffer (cmd, 0);
VkCommandBufferInheritanceInfo inherit = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0,
0, 0, 0,
0, 0, 0,
};
VkCommandBufferBeginInfo beginInfo = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0,
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, &inherit,
};
dfunc->vkBeginCommandBuffer (cmd, &beginInfo);
qfv_imagebarrier_t ib = imageBarriers[qfv_LT_Undefined_to_TransferDst];
ib.barrier.image = tframe->heads;
dfunc->vkCmdPipelineBarrier (cmd, ib.srcStages, ib.dstStages,
0, 0, 0, 0, 0,
1, &ib.barrier);
VkClearColorValue clear_color[] = {
{ .int32 = {-1, -1, -1, -1} },
};
VkImageSubresourceRange ranges[] = {
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 },
};
dfunc->vkCmdClearColorImage (cmd, tframe->heads,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
clear_color, 1, ranges);
ib = imageBarriers[qfv_LT_TransferDst_to_General];
ib.barrier.image = tframe->heads;
dfunc->vkCmdPipelineBarrier (cmd, ib.srcStages, ib.dstStages,
0, 0, 0, 0, 0,
1, &ib.barrier);
dfunc->vkEndCommandBuffer (cmd);
qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging);
qfv_transtate_t *state = QFV_PacketExtend (packet, 2 * sizeof (*state));
*state = (qfv_transtate_t) { 0, MAX_FRAGMENTS };
__auto_type bb = &bufferBarriers[qfv_BB_TransferWrite_to_ShaderRW];
QFV_PacketCopyBuffer (packet, tframe->state, bb);
QFV_PacketSubmit (packet);
}
void
Vulkan_Translucent_CreateRenderPasses (vulkan_ctx_t *ctx)
{
__auto_type rp = QFV_RenderPass_New (ctx, "translucent", translucent_clear);
rp->order = QFV_rp_translucent;
DARRAY_APPEND (&ctx->renderPasses, rp);
}

View file

@ -56,6 +56,7 @@
#include "QF/Vulkan/qf_output.h"
#include "QF/Vulkan/qf_particles.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_translucent.h"
#include "QF/Vulkan/qf_vid.h"
#include "r_internal.h"
@ -169,6 +170,7 @@ Vulkan_CreateRenderPasses (vulkan_ctx_t *ctx)
Vulkan_Main_CreateRenderPasses (ctx);
Vulkan_Particles_CreateRenderPasses (ctx);
Vulkan_Lighting_CreateRenderPasses (ctx);
Vulkan_Translucent_CreateRenderPasses (ctx);
heapsort (ctx->renderPasses.a, ctx->renderPasses.size,
sizeof (qfv_renderpass_t *), renderpass_cmp);