added better transparency to the pbr shader

This commit is contained in:
matthew 2025-08-04 19:06:32 +10:00
parent 0081887f19
commit e324e47896
18 changed files with 382 additions and 36 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/shaders/oit.frag.spv Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -3,15 +3,18 @@ import includes;
import renderer : Destroy; import renderer : Destroy;
import renderer; import renderer;
import util; import util;
import alloc;
import platform; import platform;
import math; import math;
import core.stdc.math : cosf, sinf; import core.stdc.math : cosf, sinf;
import std.algorithm.sorting;
f32 g_DELTA; f32 g_DELTA;
struct Game struct Game
{ {
Renderer rd; Renderer rd;
Arena frame_arena;
PlatformWindow* window; PlatformWindow* window;
@ -19,6 +22,7 @@ struct Game
Pipeline triangle_pipeline; Pipeline triangle_pipeline;
Pipeline compute_pipeline; Pipeline compute_pipeline;
Pipeline ui_pipeline; Pipeline ui_pipeline;
Pipeline oit_pipeline;
GlobalUniforms globals; GlobalUniforms globals;
PushConst pc; PushConst pc;
@ -36,6 +40,7 @@ InitGame(PlatformWindow* window)
{ {
Game g = { Game g = {
rd: InitRenderer(window), rd: InitRenderer(window),
frame_arena: CreateArena(MB(16)),
window: window, window: window,
timer: CreateTimer(), timer: CreateTimer(),
globals: { globals: {
@ -76,13 +81,23 @@ InitGame(PlatformWindow* window)
] ]
}; };
GfxPipelineInfo oit_info = {
vertex_shader: "shaders/full_screen_triangle.vert.spv",
frag_shader: "shaders/oit.frag.spv",
};
CompPipelineInfo gradient_info = { CompPipelineInfo gradient_info = {
shader: "shaders/gradient.comp.spv", shader: "shaders/gradient.comp.spv",
}; };
Logf("pbr");
g.pbr_pipeline = BuildGfxPipeline(&g.rd, &pbr_info); g.pbr_pipeline = BuildGfxPipeline(&g.rd, &pbr_info);
Logf("triangle");
g.triangle_pipeline = BuildGfxPipeline(&g.rd, &triangle_info); g.triangle_pipeline = BuildGfxPipeline(&g.rd, &triangle_info);
Logf("ui");
g.ui_pipeline = BuildGfxPipeline(&g.rd, &ui_info); g.ui_pipeline = BuildGfxPipeline(&g.rd, &ui_info);
Logf("oit");
g.oit_pipeline = BuildGfxPipeline(&g.rd, &oit_info);
g.compute_pipeline = BuildCompPipeline(&g.rd, &gradient_info); g.compute_pipeline = BuildCompPipeline(&g.rd, &gradient_info);
PrintShader(&g.rd, &g.pbr_pipeline, VK_SHADER_STAGE_VERTEX_BIT); PrintShader(&g.rd, &g.pbr_pipeline, VK_SHADER_STAGE_VERTEX_BIT);
@ -107,8 +122,12 @@ Cycle(Game* g)
{ {
g_DELTA = DeltaTime(&g.timer); g_DELTA = DeltaTime(&g.timer);
Reset(&g.frame_arena);
ProcessInputs(g, &g.camera); ProcessInputs(g, &g.camera);
//Sort(g, g.camera.pos, &g.model);
//Update(g, &g.camera); //Update(g, &g.camera);
Update(&g.camera); Update(&g.camera);
@ -234,3 +253,28 @@ Update(Camera* cam)
Vec4 pos = rotation * Vec4(cam.velocity * 0.5 * g_DELTA, 0.0); Vec4 pos = rotation * Vec4(cam.velocity * 0.5 * g_DELTA, 0.0);
cam.pos += pos.xyz; cam.pos += pos.xyz;
} }
void
Sort(Game* g, Vec3 pos, Model* model)
{
f32[] lengths = AllocArray!(f32)(&g.frame_arena, model.positions.length);
foreach(i; 0 .. lengths.length)
{
model.pos_indices[i] = cast(u32)i;
lengths.ptr[i] = fabs(Norm(&pos) - Norm(model.positions.ptr + i));
}
makeIndex!("a < b")(lengths, model.pos_indices);
Logf("%s", model.positions.length);
foreach(i, v; model.pos_indices)
{
model.indices[i+0] = cast(u32)((3*v)+0);
model.indices[i+1] = cast(u32)((3*v)+1);
model.indices[i+2] = cast(u32)((3*v)+2);
}
UpdateIndexBuffer(&g.rd, model);
}

View File

@ -14,6 +14,7 @@ import core.stdc.string : memcpy;
// 2. Set up VK_AMD_shader_info // 2. Set up VK_AMD_shader_info
// 3. Determine how to better handle inputs // 3. Determine how to better handle inputs
// 4. Make assets loaded from the disk in debug mode // 4. Make assets loaded from the disk in debug mode
// 5. Set up multisampling
void main(string[] argv) void main(string[] argv)
{ {

View File

@ -4,7 +4,7 @@ import assets;
import util; import util;
import alloc; import alloc;
import vulkan; import vulkan;
import vulkan : Destroy, Init, Draw, DrawIndexed, Bind, BindUIBuffers, BeginRender, SetUniform, PrepComputeDrawImage, Dispatch, FinishFrame, BeginFrame, WaitIdle, PushConstants, BindBuffers, SetClearColor; import vulkan : Destroy, Init, Draw, DrawIndexed, Bind, BindUIBuffers, BeginRender, SetUniform, PrepComputeDrawImage, Dispatch, FinishFrame, BeginFrame, WaitIdle, PushConstants, BindBuffers, SetClearColor, ImageBarrier;
import assets; import assets;
import std.math.traits : isNaN; import std.math.traits : isNaN;
import util : Logf; import util : Logf;
@ -33,6 +33,8 @@ enum Format : VkFormat
RGB_F32 = VK_FORMAT_R32G32B32_SFLOAT, RGB_F32 = VK_FORMAT_R32G32B32_SFLOAT,
RGBA_F32 = VK_FORMAT_R32G32B32A32_SFLOAT, RGBA_F32 = VK_FORMAT_R32G32B32A32_SFLOAT,
RGBA_UINT = VK_FORMAT_B8G8R8A8_UINT, RGBA_UINT = VK_FORMAT_B8G8R8A8_UINT,
R_U32 = VK_FORMAT_R32_UINT,
RG_U32 = VK_FORMAT_R32G32_UINT,
RGBA_UNORM = VK_FORMAT_R8G8B8A8_UNORM, RGBA_UNORM = VK_FORMAT_R8G8B8A8_UNORM,
RGBA_SRGB = VK_FORMAT_R8G8B8A8_SRGB, RGBA_SRGB = VK_FORMAT_R8G8B8A8_SRGB,
} }
@ -47,6 +49,7 @@ enum BufferType : int
Uniform = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, Uniform = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
Storage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, Storage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
Staging = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, Staging = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
BufferView = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
} }
alias BT = BufferType; alias BT = BufferType;
@ -161,6 +164,10 @@ struct Model
Buffer[] materials; Buffer[] materials;
ImageView[] textures; ImageView[] textures;
Vec3[] positions;
u32[] pos_indices;
u32[] indices;
} }
Renderer Renderer
@ -260,6 +267,12 @@ Bind(Renderer* rd, Pipeline* pipeline)
Bind(&rd.vk, pipeline); Bind(&rd.vk, pipeline);
} }
void
UpdateIndexBuffer(Renderer* rd, Model* model)
{
assert(Transfer(&rd.vk, &model.index_buffer, model.indices), "UpdateIndexBuffer failure");
}
void void
DrawRect(Renderer* rd, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col) DrawRect(Renderer* rd, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col)
{ {
@ -345,7 +358,6 @@ LoadModel(Renderer* rd, string name)
u32[] tex_lookup = AllocArray!(u32)(&rd.temp_arena, m3d.numtexture); u32[] tex_lookup = AllocArray!(u32)(&rd.temp_arena, m3d.numtexture);
model.textures = AllocArray!(ImageView)(&rd.arena, m3d.numtexture); model.textures = AllocArray!(ImageView)(&rd.arena, m3d.numtexture);
Logf("numtexture %s", m3d.numtexture);
foreach(i; 0 .. m3d.numtexture) foreach(i; 0 .. m3d.numtexture)
{ {
u32 w = m3d.texture[i].w; u32 h = m3d.texture[i].h; u32 ch = m3d.texture[i].f; u32 w = m3d.texture[i].w; u32 h = m3d.texture[i].h; u32 ch = m3d.texture[i].f;
@ -360,7 +372,6 @@ LoadModel(Renderer* rd, string name)
Material[] mats = AllocArray!(Material)(&rd.temp_arena, m3d.nummaterial); Material[] mats = AllocArray!(Material)(&rd.temp_arena, m3d.nummaterial);
u32[] mat_lookup = AllocArray!(u32)(&rd.temp_arena, m3d.nummaterial); u32[] mat_lookup = AllocArray!(u32)(&rd.temp_arena, m3d.nummaterial);
model.materials = AllocArray!(Buffer)(&rd.arena, m3d.nummaterial); model.materials = AllocArray!(Buffer)(&rd.arena, m3d.nummaterial);
Logf("nummaterial %s", m3d.nummaterial);
foreach(i; 0 .. m3d.nummaterial) foreach(i; 0 .. m3d.nummaterial)
{ {
const(char)[] mat_name = m3d.material[i].name[0 .. strlen(m3d.material[i].name)]; const(char)[] mat_name = m3d.material[i].name[0 .. strlen(m3d.material[i].name)];
@ -391,7 +402,6 @@ LoadModel(Renderer* rd, string name)
} break; } break;
case m3dp_map_D: case m3dp_map_D:
{ {
Logf("alpha %s", i);
mats[i].alpha_texture = tex_lookup[m3d.material[i].prop[j].value.textureid]; mats[i].alpha_texture = tex_lookup[m3d.material[i].prop[j].value.textureid];
mats[i].alpha_has_texture = true; mats[i].alpha_has_texture = true;
} break; } break;
@ -447,8 +457,10 @@ LoadModel(Renderer* rd, string name)
m3dv_t* vertex; m3dv_t* vertex;
u32[] indices = AllocArray!(u32)(&rd.temp_arena, m3d.numface * 3); u32[] indices = AllocArray!(u32)(&rd.arena, m3d.numface * 3);
Vertex[] vertices = AllocArray!(Vertex)(&rd.temp_arena, m3d.numface * 3); Vertex[] vertices = AllocArray!(Vertex)(&rd.temp_arena, m3d.numface * 3);
Vec3[] positions = AllocArray!(Vec3)(&rd.arena, m3d.numface);
u32[] pos_indices = AllocArray!(u32)(&rd.arena, m3d.numface);
foreach(i; 0 .. m3d.numface) foreach(i; 0 .. m3d.numface)
{ {
@ -484,6 +496,11 @@ LoadModel(Renderer* rd, string name)
indices[i0] = i0; indices[i0] = i0;
indices[i1] = i1; indices[i1] = i1;
indices[i2] = i2; indices[i2] = i2;
Vec3 center = (vertices[i0].pos + vertices[i1].pos + vertices[i2].pos) / 3.0;
positions[i] = center;
pos_indices[i] = i;
} }
for(u64 i = 0; i < indices.length; i += 3) for(u64 i = 0; i < indices.length; i += 3)
@ -529,6 +546,10 @@ LoadModel(Renderer* rd, string name)
WriteDescriptors(&rd.vk, DT.Material, model.materials, mat_lookup); WriteDescriptors(&rd.vk, DT.Material, model.materials, mat_lookup);
WriteDescriptors(&rd.vk, DT.SampledImage, model.textures, tex_lookup); WriteDescriptors(&rd.vk, DT.SampledImage, model.textures, tex_lookup);
model.positions = positions;
model.indices = indices;
model.pos_indices = pos_indices;
Reset(&rd.temp_arena); Reset(&rd.temp_arena);
return model; return model;
@ -618,6 +639,12 @@ ClearColorEnabled(Renderer* rd, bool enabled)
rd.vk.enable_clear_color = enabled; rd.vk.enable_clear_color = enabled;
} }
void
ImageBarrier(Renderer* rd)
{
ImageBarrier(&rd.vk);
}
void void
Destroy(Renderer* rd, Model* model) Destroy(Renderer* rd, Model* model)
{ {

View File

@ -80,6 +80,10 @@ const VkImageUsageFlags VK_DRAW_IMAGE_USAGE_FLAGS = VK_IMAGE_USAGE_TRANSFER_SRC_
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
const VkImageUsageFlags TEXTURE_IMAGE_USAGE = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
const VkImageUsageFlags CONVERT_IMAGE_USAGE = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
const VkImageUsageFlags OIT_IMAGE_USAGE = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
enum StepInitialized : u32 enum StepInitialized : u32
{ {
Renderer = 1, Renderer = 1,
@ -117,6 +121,14 @@ struct Image
VkImageLayout layout; VkImageLayout layout;
} }
struct BufferView
{
Buffer base;
VkBufferView view;
alias base this;
}
struct ImageView struct ImageView
{ {
Image base; Image base;
@ -199,6 +211,7 @@ struct Vulkan
DescBindings[DT.max] desc_bindings; DescBindings[DT.max] desc_bindings;
VkSampler nearest_sampler; VkSampler nearest_sampler;
VkSampler oit_sampler;
VkPipeline[FRAME_OVERLAP] last_pipeline; VkPipeline[FRAME_OVERLAP] last_pipeline;
VkPipelineLayout pipeline_layout; VkPipelineLayout pipeline_layout;
@ -224,6 +237,9 @@ struct Vulkan
bool enable_clear_color; bool enable_clear_color;
VkClearColorValue clear_color; VkClearColorValue clear_color;
BufferView a_buffer_view;
ImageView aux_image;
alias queues this; alias queues this;
} }
@ -755,7 +771,7 @@ TransferAssets(Vulkan* vk)
pragma(inline): void pragma(inline): void
CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, u32 ch, u8[] data) CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, u32 ch, u8[] data)
{ {
CreateImageView(vk, view, w, h); CreateImageView(vk, view, w, h, FMT.RGBA_UNORM, TEXTURE_IMAGE_USAGE);
if (ch == 4) if (ch == 4)
{ {
@ -768,7 +784,7 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, u32 ch, u8[] data)
assert(Transfer(vk, &buf, data), "CreateImageView failure: Buffer Transfer error"); assert(Transfer(vk, &buf, data), "CreateImageView failure: Buffer Transfer error");
ImageView conv_view; ImageView conv_view;
CreateImageView(vk, &conv_view, w, h, FMT.RGBA_F32); CreateImageView(vk, &conv_view, w, h, FMT.RGBA_F32, CONVERT_IMAGE_USAGE);
WriteConvDescriptor(vk, &buf); WriteConvDescriptor(vk, &buf);
WriteConvDescriptor(vk, &conv_view); WriteConvDescriptor(vk, &conv_view);
@ -872,7 +888,25 @@ FinishComputePass(Vulkan* vk)
} }
pragma(inline): void pragma(inline): void
CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.RGBA_UNORM) CreateBufferView(Vulkan* vk, BufferView* view, u64 size, Format format)
{
CreateBuffer(vk, &view.base, BT.BufferView, size, false);
VkBufferViewCreateInfo info = {
sType: VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
buffer: view.buffer,
format: format,
range: size,
};
VkResult result = vkCreateBufferView(vk.device, &info, null, &view.view);
VkCheckA("CreateBufferView failure: vkCreateBufferView failed", result);
view.size = size;
}
pragma(inline): void
CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.RGBA_UNORM, VkImageUsageFlags usage)
{ {
VmaAllocationCreateInfo alloc_info = { VmaAllocationCreateInfo alloc_info = {
usage: VMA_MEMORY_USAGE_GPU_ONLY, usage: VMA_MEMORY_USAGE_GPU_ONLY,
@ -887,7 +921,7 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.R
format: format, format: format,
tiling: VK_IMAGE_TILING_OPTIMAL, tiling: VK_IMAGE_TILING_OPTIMAL,
initialLayout: VK_IMAGE_LAYOUT_UNDEFINED, initialLayout: VK_IMAGE_LAYOUT_UNDEFINED,
usage: format == FMT.RGBA_F32 ? (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) : (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), usage: usage,
samples: VK_SAMPLE_COUNT_1_BIT, samples: VK_SAMPLE_COUNT_1_BIT,
extent: { extent: {
width: w, width: w,
@ -996,6 +1030,27 @@ PushConstants(Vulkan* vk, PushConst* pc)
); );
} }
void
ImageBarrier(Vulkan* vk)
{
VkMemoryBarrier2 barrier = {
sType: VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
srcStageMask: VK_PIPELINE_STAGE_2_TRANSFER_BIT,
srcAccessMask: VK_ACCESS_2_TRANSFER_WRITE_BIT,
dstStageMask: VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
dstAccessMask: VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT,
};
VkDependencyInfo dependency = {
sType: VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
dependencyFlags: VK_DEPENDENCY_BY_REGION_BIT,
memoryBarrierCount: 1,
pMemoryBarriers: &barrier,
};
vkCmdPipelineBarrier2(vk.cmds[vk.frame_index], &dependency);
}
bool bool
Transfer(T)(Vulkan* vk, Buffer* buf, T[] data) Transfer(T)(Vulkan* vk, Buffer* buf, T[] data)
{ {
@ -1323,7 +1378,7 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info)
VkPipelineDepthStencilStateCreateInfo depth_info = { VkPipelineDepthStencilStateCreateInfo depth_info = {
sType: VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, sType: VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
depthTestEnable: VK_TRUE, depthTestEnable: VK_TRUE,
depthWriteEnable: VK_TRUE, depthWriteEnable: VK_FALSE,
depthCompareOp: VK_COMPARE_OP_GREATER_OR_EQUAL, depthCompareOp: VK_COMPARE_OP_GREATER_OR_EQUAL,
depthBoundsTestEnable: VK_FALSE, depthBoundsTestEnable: VK_FALSE,
stencilTestEnable: VK_FALSE, stencilTestEnable: VK_FALSE,
@ -1380,36 +1435,36 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info)
VkPipelineShaderStageCreateInfo[] shader_info = [ VkPipelineShaderStageCreateInfo[] shader_info = [
{ {
sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
stage: VK_SHADER_STAGE_VERTEX_BIT, stage: VK_SHADER_STAGE_FRAGMENT_BIT,
pName: "main", pName: "main",
}, },
{ {
sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
stage: VK_SHADER_STAGE_FRAGMENT_BIT, stage: VK_SHADER_STAGE_VERTEX_BIT,
pName: "main", pName: "main",
}, },
]; ];
Arena* arena = &vk.frame_arenas[0]; Arena* arena = &vk.frame_arenas[0];
u8[] vert_bytes = LoadAssetData(arena, build_info.vertex_shader);
u8[] frag_bytes = LoadAssetData(arena, build_info.frag_shader); u8[] frag_bytes = LoadAssetData(arena, build_info.frag_shader);
u8[] vert_bytes = LoadAssetData(arena, build_info.vertex_shader);
assert(vert_bytes && frag_bytes, "Unable to load shaders"); assert(vert_bytes && frag_bytes, "Unable to load shaders");
Result!(Shader) vert_module = BuildShader(vk, vert_bytes);
Result!(Shader) frag_module = BuildShader(vk, frag_bytes); Result!(Shader) frag_module = BuildShader(vk, frag_bytes);
Result!(Shader) vert_module = BuildShader(vk, vert_bytes);
assert(vert_module.ok && frag_module.ok, "Unable to build vulkan shaders"); assert(vert_module.ok && frag_module.ok, "Unable to build vulkan shaders");
scope(exit) scope(exit)
{ {
Destroy(vk, vert_module.value);
Destroy(vk, frag_module.value); Destroy(vk, frag_module.value);
Destroy(vk, vert_module.value);
} }
__traits(getMember, shader_info.ptr + 0, "module") = vert_module.value; __traits(getMember, shader_info.ptr + 0, "module") = frag_module.value;
__traits(getMember, shader_info.ptr + 1, "module") = frag_module.value; __traits(getMember, shader_info.ptr + 1, "module") = vert_module.value;
VkSpecializationInfo vert_spec_info = { VkSpecializationInfo vert_spec_info = {
dataSize: build_info.vert_spec.size, dataSize: build_info.vert_spec.size,
@ -1652,6 +1707,7 @@ InitDescriptors(Vulkan* vk)
{ type: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, descriptorCount: 4096 }, { type: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, descriptorCount: 4096 },
{ type: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 4096 }, { type: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 4096 },
{ type: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 4096 }, { type: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 4096 },
{ type: VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, descriptorCount: 4096 },
]; ];
VkDescriptorPoolCreateInfo pool_info = { VkDescriptorPoolCreateInfo pool_info = {
@ -1667,7 +1723,17 @@ InitDescriptors(Vulkan* vk)
if (success) if (success)
{ {
VkDescriptorBindingFlags[4] shared_binding_flags; VkDescriptorSetLayoutBinding[] shared_bindings = [
{ binding: 0, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL },
{ binding: 1, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL },
{ binding: 2, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL },
{ binding: 3, descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL },
{ binding: 4, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL },
{ binding: 5, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL },
{ binding: 6, descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL },
];
VkDescriptorBindingFlags[] shared_binding_flags = AllocArray!(VkDescriptorBindingFlags)(&vk.frame_arenas[0], shared_bindings.length);
shared_binding_flags[] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; shared_binding_flags[] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT;
VkDescriptorSetLayoutBindingFlagsCreateInfo shared_flag_info = { VkDescriptorSetLayoutBindingFlagsCreateInfo shared_flag_info = {
@ -1676,13 +1742,6 @@ InitDescriptors(Vulkan* vk)
pBindingFlags: shared_binding_flags.ptr, pBindingFlags: shared_binding_flags.ptr,
}; };
VkDescriptorSetLayoutBinding[] shared_bindings = [
{ binding: 0, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL },
{ binding: 1, descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL },
{ binding: 2, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL },
{ binding: 3, descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_ALL },
];
VkDescriptorSetLayoutCreateInfo shared_set_info = { VkDescriptorSetLayoutCreateInfo shared_set_info = {
sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
pNext: &shared_flag_info, pNext: &shared_flag_info,
@ -1814,20 +1873,89 @@ InitDescriptors(Vulkan* vk)
if (success) if (success)
{ {
VkSamplerCreateInfo sampler_info = {
sType: VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
magFilter: VK_FILTER_LINEAR,
minFilter: VK_FILTER_LINEAR,
addressModeU: VK_SAMPLER_ADDRESS_MODE_REPEAT,
addressModeV: VK_SAMPLER_ADDRESS_MODE_REPEAT,
addressModeW: VK_SAMPLER_ADDRESS_MODE_REPEAT,
anisotropyEnable: VK_FALSE,
compareEnable: VK_FALSE,
borderColor: VK_BORDER_COLOR_INT_OPAQUE_BLACK,
mipmapMode: VK_SAMPLER_MIPMAP_MODE_NEAREST,
unnormalizedCoordinates: VK_FALSE,
};
result = vkCreateSampler(vk.device, &sampler_info, null, &vk.oit_sampler);
success = VkCheck("vkCreateSampler failure", result);
}
if (success)
{
// TODO: move this elsewhere later
// Also add samples/supersampling scaling
CreateBufferView(vk, &vk.a_buffer_view, (u32.sizeof * 2) * vk.swapchain_extent.width * vk.swapchain_extent.height, FMT.RG_U32);
CreateImageView(vk, &vk.aux_image, vk.swapchain_extent.width, vk.swapchain_extent.height, FMT.R_U32, OIT_IMAGE_USAGE);
VkDescriptorBufferInfo a_buffer_info = {
buffer: vk.a_buffer_view.buffer,
offset: 0,
range: VK_WHOLE_SIZE,
};
VkDescriptorImageInfo aux_info = {
sampler: vk.oit_sampler,
imageView: vk.aux_image.view,
imageLayout: VK_IMAGE_LAYOUT_GENERAL,
};
VkDescriptorImageInfo sampler_info = { VkDescriptorImageInfo sampler_info = {
sampler: vk.nearest_sampler, sampler: vk.nearest_sampler,
}; };
VkWriteDescriptorSet write = { VkDescriptorImageInfo oit_sample_info = {
sampler: vk.oit_sampler,
};
VkWriteDescriptorSet[] writes = [
{
sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
dstSet: vk.desc_sets[DT.Shared], dstSet: vk.desc_sets[DT.Shared],
dstBinding: 3, dstBinding: 3,
descriptorCount: 1, descriptorCount: 1,
descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER,
pImageInfo: &sampler_info, pImageInfo: &sampler_info,
}; },
{
sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
dstSet: vk.desc_sets[DT.Shared],
dstBinding: 4,
descriptorCount: 1,
descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
pBufferInfo: &a_buffer_info,
pTexelBufferView: &vk.a_buffer_view.view,
},
{
sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
dstSet: vk.desc_sets[DT.Shared],
dstBinding: 5,
descriptorCount: 1,
descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
pImageInfo: &aux_info,
},
{
sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
dstSet: vk.desc_sets[DT.Shared],
dstBinding: 6,
descriptorCount: 1,
descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER,
pImageInfo: &oit_sample_info,
},
];
vkUpdateDescriptorSets(vk.device, 1, &write, 0, null); vkUpdateDescriptorSets(vk.device, cast(u32)writes.length, writes.ptr, 0, null);
WriteDrawImageDesc(vk); WriteDrawImageDesc(vk);
} }
@ -2467,6 +2595,7 @@ InitDevice(Vulkan* vk)
descriptorBindingSampledImageUpdateAfterBind: VK_TRUE, descriptorBindingSampledImageUpdateAfterBind: VK_TRUE,
descriptorBindingStorageImageUpdateAfterBind: VK_TRUE, descriptorBindingStorageImageUpdateAfterBind: VK_TRUE,
descriptorBindingStorageBufferUpdateAfterBind: VK_TRUE, descriptorBindingStorageBufferUpdateAfterBind: VK_TRUE,
descriptorBindingStorageTexelBufferUpdateAfterBind: VK_TRUE,
descriptorBindingPartiallyBound: VK_TRUE, descriptorBindingPartiallyBound: VK_TRUE,
shaderSampledImageArrayNonUniformIndexing: VK_TRUE, shaderSampledImageArrayNonUniformIndexing: VK_TRUE,
shaderUniformBufferArrayNonUniformIndexing: VK_TRUE, shaderUniformBufferArrayNonUniformIndexing: VK_TRUE,
@ -2488,6 +2617,7 @@ InitDevice(Vulkan* vk)
shaderStorageBufferArrayDynamicIndexing: VK_TRUE, shaderStorageBufferArrayDynamicIndexing: VK_TRUE,
shaderStorageImageArrayDynamicIndexing: VK_TRUE, shaderStorageImageArrayDynamicIndexing: VK_TRUE,
samplerAnisotropy: VK_TRUE, samplerAnisotropy: VK_TRUE,
fragmentStoresAndAtomics: VK_TRUE,
}, },
}; };
@ -2557,6 +2687,7 @@ CheckDeviceFeatures(VkPhysicalDevice device)
VkPhysicalDeviceFeatures features = features2.features; VkPhysicalDeviceFeatures features = features2.features;
bool result = true; bool result = true;
result &= cast(bool)features.fragmentStoresAndAtomics;
result &= cast(bool)features.shaderUniformBufferArrayDynamicIndexing; result &= cast(bool)features.shaderUniformBufferArrayDynamicIndexing;
result &= cast(bool)features.shaderSampledImageArrayDynamicIndexing; result &= cast(bool)features.shaderSampledImageArrayDynamicIndexing;
result &= cast(bool)features.shaderStorageBufferArrayDynamicIndexing; result &= cast(bool)features.shaderStorageBufferArrayDynamicIndexing;
@ -2566,6 +2697,7 @@ CheckDeviceFeatures(VkPhysicalDevice device)
result &= cast(bool)features_12.descriptorIndexing; result &= cast(bool)features_12.descriptorIndexing;
result &= cast(bool)features_12.bufferDeviceAddress; result &= cast(bool)features_12.bufferDeviceAddress;
result &= cast(bool)features_12.descriptorBindingUniformBufferUpdateAfterBind; result &= cast(bool)features_12.descriptorBindingUniformBufferUpdateAfterBind;
result &= cast(bool)features_12.descriptorBindingStorageTexelBufferUpdateAfterBind;
result &= cast(bool)features_12.descriptorBindingSampledImageUpdateAfterBind; result &= cast(bool)features_12.descriptorBindingSampledImageUpdateAfterBind;
result &= cast(bool)features_12.descriptorBindingStorageImageUpdateAfterBind; result &= cast(bool)features_12.descriptorBindingStorageImageUpdateAfterBind;
result &= cast(bool)features_12.descriptorBindingStorageBufferUpdateAfterBind; result &= cast(bool)features_12.descriptorBindingStorageBufferUpdateAfterBind;

View File

@ -58,6 +58,7 @@ version(AMD_GPU)
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = null; PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = null;
PFN_vkCreateImage vkCreateImage = null; PFN_vkCreateImage vkCreateImage = null;
PFN_vkCreateImageView vkCreateImageView = null; PFN_vkCreateImageView vkCreateImageView = null;
PFN_vkCreateBufferView vkCreateBufferView = null;
PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR = null; PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR = null;
PFN_vkGetDeviceQueue vkGetDeviceQueue = null; PFN_vkGetDeviceQueue vkGetDeviceQueue = null;
PFN_vkCreateSemaphore vkCreateSemaphore = null; PFN_vkCreateSemaphore vkCreateSemaphore = null;
@ -154,6 +155,7 @@ LoadDeviceFunctions(Vulkan* vk)
vkCreateSwapchainKHR = cast(PFN_vkCreateSwapchainKHR)vkGetDeviceProcAddr(vk.device, "vkCreateSwapchainKHR"); vkCreateSwapchainKHR = cast(PFN_vkCreateSwapchainKHR)vkGetDeviceProcAddr(vk.device, "vkCreateSwapchainKHR");
vkCreateImage = cast(PFN_vkCreateImage)vkGetDeviceProcAddr(vk.device, "vkCreateImage"); vkCreateImage = cast(PFN_vkCreateImage)vkGetDeviceProcAddr(vk.device, "vkCreateImage");
vkCreateImageView = cast(PFN_vkCreateImageView)vkGetDeviceProcAddr(vk.device, "vkCreateImageView"); vkCreateImageView = cast(PFN_vkCreateImageView)vkGetDeviceProcAddr(vk.device, "vkCreateImageView");
vkCreateBufferView = cast(PFN_vkCreateBufferView)vkGetDeviceProcAddr(vk.device, "vkCreateBufferView");
vkGetSwapchainImagesKHR = cast(PFN_vkGetSwapchainImagesKHR)vkGetDeviceProcAddr(vk.device, "vkGetSwapchainImagesKHR"); vkGetSwapchainImagesKHR = cast(PFN_vkGetSwapchainImagesKHR)vkGetDeviceProcAddr(vk.device, "vkGetSwapchainImagesKHR");
vkGetDeviceQueue = cast(PFN_vkGetDeviceQueue)vkGetDeviceProcAddr(vk.device, "vkGetDeviceQueue"); vkGetDeviceQueue = cast(PFN_vkGetDeviceQueue)vkGetDeviceProcAddr(vk.device, "vkGetDeviceQueue");
vkCreateSemaphore = cast(PFN_vkCreateSemaphore)vkGetDeviceProcAddr(vk.device, "vkCreateSemaphore"); vkCreateSemaphore = cast(PFN_vkCreateSemaphore)vkGetDeviceProcAddr(vk.device, "vkCreateSemaphore");

View File

@ -0,0 +1,7 @@
#version 460
void main()
{
vec4 pos = vec4((float((gl_VertexIndex >> 1U) & 1U)) * 4.0 - 1.0, (float(gl_VertexIndex & 1U)) * 4.0 - 1.0, 0, 1.0);
gl_Position = pos;
}

84
src/shaders/oit.frag.glsl Normal file
View File

@ -0,0 +1,84 @@
#version 460
#extension GL_GOOGLE_include_directive : require
#extension GL_EXT_nonuniform_qualifier : require
#define COMPOSITE_PASS
#include "structures.layout"
layout (location = 0) out vec4 FragColor;
void BubbleSort(inout uvec2 array[OIT_LAYERS], int n)
{
for(int i = (n - 2); i >= 0; --i)
{
for(int j = 0; j <= i; ++j)
{
if(uintBitsToFloat(array[j].g) >= uintBitsToFloat(array[j+1].g))
{
uvec2 temp = array[j+1];
array[j+1] = array[j];
array[j] = temp;
}
}
}
}
float UnPreMultSRGBToLinear(float col)
{
return col < 0.04045f ? col / 12.92f : pow((col + 0.055f) / 1.055f, 2.4f);
}
vec4 UnPreMultSRGBToLinear(vec4 col)
{
col.r = UnPreMultSRGBToLinear(col.r);
col.g = UnPreMultSRGBToLinear(col.g);
col.b = UnPreMultSRGBToLinear(col.b);
return col;
}
void DoBlend(inout vec4 color, vec4 base_color)
{
color.rgb += (1 - color.a) * base_color.rgb;
color.a += (1 - color.a) * base_color.a;
}
void DoBlendPacked(inout vec4 color, uint fragment)
{
vec4 unpacked_color = unpackUnorm4x8(fragment);
unpacked_color = UnPreMultSRGBToLinear(unpacked_color);
unpacked_color.rgb *= unpacked_color.a;
DoBlend(color, unpacked_color);
}
void main()
{
ivec2 coord = ivec2(gl_FragCoord.xy);
int store_mask = 0;
int view_size = int(G.res.x) * int(G.res.y);
int sample_id = 0;
int list_pos = view_size * OIT_LAYERS * sample_id + coord.y * int(G.res.x) + coord.x;
uvec2 array[OIT_LAYERS];
vec4 color = vec4(0.0);
int fragments = int(imageLoad(ImageAux, coord).r);
fragments = min(OIT_LAYERS, fragments);
for (int i = 0; i < fragments; i++)
{
array[i] = imageLoad(ImageABuffer, list_pos + i * view_size).rg;
}
BubbleSort(array, fragments);
vec4 color_sum = vec4(0.0);
for(int i = 0; i < fragments; i++)
{
DoBlendPacked(color_sum, array[i].x);
}
FragColor = color_sum;
}

View File

@ -10,7 +10,7 @@ layout (location = 0) in struct FragDataIn {
vec2 uv; vec2 uv;
} FragData; } FragData;
layout (location = 0) out vec4 FragColor; layout (location = 0, index = 0) out vec4 FragColor;
vec4 CalculateDirectionalLight(vec4 diff_col, vec4 diff_samp, vec4 light_col, vec3 dir, vec3 normal) vec4 CalculateDirectionalLight(vec4 diff_col, vec4 diff_samp, vec4 light_col, vec3 dir, vec3 normal)
{ {
@ -25,8 +25,27 @@ vec4 CalculateDirectionalLight(vec4 diff_col, vec4 diff_samp, vec4 light_col, ve
return (ambient + diffuse); return (ambient + diffuse);
} }
float UnPreMultLinearToSRGB(float col)
{
return col < 0.0031308f ? col * 12.92f : (pow(col, 1.0f / 2.4f) * 1.055f) - 0.055f;
}
vec4 UnPreMultLinearToSRGB(vec4 col)
{
col.r = UnPreMultLinearToSRGB(col.x);
col.g = UnPreMultLinearToSRGB(col.x);
col.b = UnPreMultLinearToSRGB(col.x);
return col;
}
void main() void main()
{ {
ivec2 coord = ivec2(gl_FragCoord.xy);
int store_mask = 0;
int view_size = int(G.res.x) * int(G.res.y);
int sample_id = 0;
int list_pos = view_size * OIT_LAYERS * sample_id + coord.y * int(G.res.x) + coord.x;
vec4 col = Materials[nonuniformEXT(PC.mat_id)].diffuse; vec4 col = Materials[nonuniformEXT(PC.mat_id)].diffuse;
vec4 tex_col = texture(sampler2D(Textures[nonuniformEXT(Materials[nonuniformEXT(PC.mat_id)].albedo_texture)], SamplerNearest), FragData.uv); vec4 tex_col = texture(sampler2D(Textures[nonuniformEXT(Materials[nonuniformEXT(PC.mat_id)].albedo_texture)], SamplerNearest), FragData.uv);
@ -39,5 +58,19 @@ void main()
out_col.a = alpha_col.a; out_col.a = alpha_col.a;
} }
FragColor = out_col; vec4 srgb_col = UnPreMultLinearToSRGB(out_col);
uvec4 store_value = uvec4(packUnorm4x8(srgb_col), floatBitsToUint(gl_FragCoord.z), store_mask, 0);
uint old_counter = imageAtomicAdd(ImageAux, coord, 1u);
if (old_counter < OIT_LAYERS)
{
imageStore(ImageABuffer, list_pos + int(old_counter) * view_size, store_value);
FragColor = vec4(0.0);
}
else
{
FragColor = vec4(out_col.rgb * out_col.a, out_col.a); // Change to vec4(0.0) to disable tail blending
}
} }

View File

@ -2,6 +2,8 @@
// **** STRUCTS MUST BE PACKED IN OPTIMAL PACKING ORDER TO MATCH D STRUCTS **** // **** STRUCTS MUST BE PACKED IN OPTIMAL PACKING ORDER TO MATCH D STRUCTS ****
// **************************************************************************** // ****************************************************************************
#define OIT_LAYERS 64
layout (set = 0, binding = 0) uniform GlobalUniforms { layout (set = 0, binding = 0) uniform GlobalUniforms {
mat4 view_matrix; mat4 view_matrix;
mat4 projection_matrix; mat4 projection_matrix;
@ -20,6 +22,20 @@ layout (rgba16f, set = 0, binding = 2) uniform image2D DrawImage;
layout (set = 0, binding = 3) uniform sampler SamplerNearest; layout (set = 0, binding = 3) uniform sampler SamplerNearest;
#ifdef COMPOSITE_PASS
layout (set = 0, binding = 4, rg32ui) uniform restrict readonly uimageBuffer ImageABuffer;
layout (set = 0, binding = 5, r32ui) uniform restrict readonly uimage2D ImageAux;
#else
layout (set = 0, binding = 4, rg32ui) uniform coherent uimageBuffer ImageABuffer;
layout (set = 0, binding = 5, r32ui) uniform coherent uimage2D ImageAux;
#endif
layout (set = 1, binding = 0) uniform texture2D Textures[]; layout (set = 1, binding = 0) uniform texture2D Textures[];
layout (set = 2, binding = 0) uniform Material { layout (set = 2, binding = 0) uniform Material {