Compare commits

..

3 Commits

21 changed files with 901 additions and 220 deletions

Binary file not shown.

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

@ -2,16 +2,20 @@ import aliases;
import includes; import includes;
import renderer : Destroy; import renderer : Destroy;
import renderer; import renderer;
import vulkan;
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 +23,10 @@ struct Game
Pipeline triangle_pipeline; Pipeline triangle_pipeline;
Pipeline compute_pipeline; Pipeline compute_pipeline;
Pipeline ui_pipeline; Pipeline ui_pipeline;
Pipeline oit_pipeline;
ImageView draw_image, depth_image;
ImageView aux_image;
GlobalUniforms globals; GlobalUniforms globals;
PushConst pc; PushConst pc;
@ -27,15 +35,21 @@ struct Game
Camera camera; Camera camera;
Model model; Model tree;
} Model rock;
Model magic_rock;
Model log;
Model stump;
SLList!(Model) models;
}
Game Game
InitGame(PlatformWindow* window) 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: {
@ -45,14 +59,24 @@ InitGame(PlatformWindow* window)
}, },
}; };
Extent ext = GetExtent(&g.rd);
CreateImageView(&g.rd, &g.draw_image, ext.w, ext.h, GetDrawImageFormat(&g.rd), IU.Draw, false);
CreateImageView(&g.rd, &g.depth_image, ext.w, ext.h, FMT.D_SF32, IU.Depth, true);
CreateImageView(&g.rd, &g.aux_image, ext.w, ext.h, FMT.R_U32, IU.Storage);
GfxPipelineInfo triangle_info = { GfxPipelineInfo triangle_info = {
vertex_shader: "shaders/triangle.vert.spv", vertex_shader: "shaders/triangle.vert.spv",
frag_shader: "shaders/triangle.frag.spv", frag_shader: "shaders/triangle.frag.spv",
draw_image: &g.draw_image,
depth_image: &g.depth_image,
}; };
GfxPipelineInfo ui_info = { GfxPipelineInfo ui_info = {
vertex_shader: "shaders/gui.vert.spv", vertex_shader: "shaders/gui.vert.spv",
frag_shader: "shaders/gui.frag.spv", frag_shader: "shaders/gui.frag.spv",
draw_image: &g.draw_image,
depth_image: &g.depth_image,
input_rate: IR.Instance, input_rate: IR.Instance,
input_rate_stride: UIVertex.sizeof, input_rate_stride: UIVertex.sizeof,
vertex_attributes: [ vertex_attributes: [
@ -66,6 +90,8 @@ InitGame(PlatformWindow* window)
GfxPipelineInfo pbr_info = { GfxPipelineInfo pbr_info = {
vertex_shader: "shaders/pbr.vert.spv", vertex_shader: "shaders/pbr.vert.spv",
frag_shader: "shaders/pbr.frag.spv", frag_shader: "shaders/pbr.frag.spv",
draw_image: &g.draw_image,
depth_image: &g.depth_image,
input_rate_stride: Vertex.sizeof, input_rate_stride: Vertex.sizeof,
vertex_attributes: [ vertex_attributes: [
{ binding: 0, location: 0, format: FMT.RGBA_F32, offset: 0 }, { binding: 0, location: 0, format: FMT.RGBA_F32, offset: 0 },
@ -76,6 +102,13 @@ InitGame(PlatformWindow* window)
] ]
}; };
GfxPipelineInfo oit_info = {
vertex_shader: "shaders/full_screen_triangle.vert.spv",
frag_shader: "shaders/oit.frag.spv",
draw_image: &g.draw_image,
depth_image: &g.depth_image,
};
CompPipelineInfo gradient_info = { CompPipelineInfo gradient_info = {
shader: "shaders/gradient.comp.spv", shader: "shaders/gradient.comp.spv",
}; };
@ -83,18 +116,85 @@ InitGame(PlatformWindow* window)
g.pbr_pipeline = BuildGfxPipeline(&g.rd, &pbr_info); g.pbr_pipeline = BuildGfxPipeline(&g.rd, &pbr_info);
g.triangle_pipeline = BuildGfxPipeline(&g.rd, &triangle_info); g.triangle_pipeline = BuildGfxPipeline(&g.rd, &triangle_info);
g.ui_pipeline = BuildGfxPipeline(&g.rd, &ui_info); g.ui_pipeline = BuildGfxPipeline(&g.rd, &ui_info);
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);
g.model = LoadModel(&g.rd, "models/Tree01.m3d"); g.rock = LoadModel(&g.rd, "models/BigRock01.m3d");
g.tree = LoadModel(&g.rd, "models/Tree01.m3d");
g.magic_rock = LoadModel(&g.rd, "models/MagicRock01.m3d");
g.log = LoadModel(&g.rd, "models/Log01.m3d");
g.stump = LoadModel(&g.rd, "models/Stump01.m3d");
SetClearColor(&g.rd, Vec4(0.3, 0.5, 0.9, 1.0));
ClearColorEnabled(&g.rd, true);
assert(g.aux_image.view != null);
UpdateAuxImage(&g.rd, &g.aux_image);
return g; return g;
} }
void
Copy(Model* dst, Model* src)
{
dst.vertex_buffer = src.vertex_buffer;
dst.index_buffer = src.index_buffer;
dst.parts = src.parts;
dst.materials = src.materials;
dst.textures = src.textures;
}
void void
ProcessInputs(Game* g, Camera* cam) ProcessInputs(Game* g, Camera* cam)
{ {
foreach(i; 0 .. g.window.inputs.count)
{
InputEvent event = g.window.inputs.events[i];
switch(event.key)
{
case Input.One:
{
Node!(Model)* node = Alloc!(Node!(Model));
Copy(&node.value, &g.tree);
node.value.pos = cam.pos;
PushFront(&g.models, node, null);
} break;
case Input.Two:
{
Node!(Model)* node = Alloc!(Node!(Model));
Copy(&node.value, &g.rock);
node.value.pos = cam.pos;
PushFront(&g.models, node, null);
} break;
case Input.Three:
{
Node!(Model)* node = Alloc!(Node!(Model));
Copy(&node.value, &g.magic_rock);
node.value.pos = cam.pos;
PushFront(&g.models, node, null);
} break;
case Input.Four:
{
Node!(Model)* node = Alloc!(Node!(Model));
Copy(&node.value, &g.log);
node.value.pos = cam.pos;
PushFront(&g.models, node, null);
} break;
case Input.Five:
{
Node!(Model)* node = Alloc!(Node!(Model));
Copy(&node.value, &g.stump);
node.value.pos = cam.pos;
PushFront(&g.models, node, null);
} break;
default: break;
}
}
HandleInputs(cam, &g.window.inputs); HandleInputs(cam, &g.window.inputs);
} }
@ -103,16 +203,32 @@ 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);
ResizeDrawImageIfNeeded(&g.rd, &g.draw_image);
ResizeDrawImageIfNeeded(&g.rd, &g.depth_image);
ResizeDrawImageIfNeeded(&g.rd, &g.aux_image);
UpdateAuxImage(&g.rd, &g.aux_image);
//Sort(g, g.camera.pos, &g.model);
//Update(g, &g.camera); //Update(g, &g.camera);
Update(&g.camera); Update(&g.camera);
BeginFrame(&g.rd); BeginFrame(&g.rd);
PrepAuxImage(&g.rd.vk, &g.aux_image);
Bind(&g.rd, &g.compute_pipeline); Bind(&g.rd, &g.compute_pipeline);
ClearColor(&g.rd, &g.aux_image, Vec4(0.0));
ImageBarrier(&g.rd);
Extent ext = GetExtent(&g.rd); Extent ext = GetExtent(&g.rd);
f32 aspect = (cast(f32)ext.x) / (cast(f32)ext.y); f32 aspect = (cast(f32)ext.x) / (cast(f32)ext.y);
Mat4 projection = Perspective(90.0, aspect, 10000.0, 0.1); Mat4 projection = Perspective(90.0, aspect, 10000.0, 0.1);
@ -123,36 +239,56 @@ Cycle(Game* g)
g.globals.res.y = ext.y; g.globals.res.y = ext.y;
SetUniform(&g.rd, &g.globals); SetUniform(&g.rd, &g.globals);
//DrawRect(&g.rd, 150.0, 300.0, 500.0, 700.0, Vec4(0.0, 0.0, 1.0, 1.0)); BeginRendering(&g.rd, &g.draw_image, &g.depth_image);
//PrepComputeDrawImage(&g.rd);
//Dispatch(&g.rd);
BeginRender(&g.rd);
Bind(&g.rd, &g.ui_pipeline); Bind(&g.rd, &g.ui_pipeline);
BindUIBuffers(&g.rd); BindUIBuffers(&g.rd);
//DrawUI(&g.rd);
Bind(&g.rd, &g.triangle_pipeline); Bind(&g.rd, &g.triangle_pipeline);
//Draw(&g.rd, 3, 1);
Bind(&g.rd, &g.pbr_pipeline); Bind(&g.rd, &g.pbr_pipeline);
g.pc.model_matrix = Mat4Identity(); g.pc.model_matrix = Mat4Identity();
DrawModel(g, &g.model);
FinishFrame(&g.rd); Node!(Model)* model = g.models.first;
for(;;)
{
if (model == null)
{
break;
}
DrawModel(g, &model.value);
model = model.next;
}
/*
ImageBarrier(&g.rd);
Bind(&g.rd, &g.oit_pipeline);
Draw(&g.rd, 3, 1);
*/
FinishRendering(&g.rd);
//ImageBarrier(&g.rd);
//BeginRendering(&g.rd, &g.draw_image, &g.depth_image);
//FinishRendering(&g.rd);
Submit(&g.rd, &g.draw_image);
} }
pragma(inline): void pragma(inline): void
DrawModel(Game* g, Model* model) DrawModel(Game* g, Model* model)
{ {
BindBuffers(&g.rd, &model.index_buffer, &model.vertex_buffer); BindBuffers(&g.rd, &model.index_buffer, &model.vertex_buffer);
g.pc.model_matrix = Mat4Identity();
Translate(&g.pc.model_matrix, model.pos);
foreach(i, part; model.parts) foreach(i, part; model.parts)
{ {
g.pc.mat_id = part.mat; g.pc.mat_id = part.mat;
@ -169,13 +305,25 @@ Destroy(Game* g)
Destroy(&g.rd, &g.triangle_pipeline); Destroy(&g.rd, &g.triangle_pipeline);
Destroy(&g.rd, &g.ui_pipeline); Destroy(&g.rd, &g.ui_pipeline);
Destroy(&g.rd, &g.compute_pipeline); Destroy(&g.rd, &g.compute_pipeline);
Node!(Model)* model = g.models.first;
for(;;)
{
if (model == null)
{
break;
}
Destroy(&g.rd, &model.value);
model = model.next;
}
Destroy(&g.rd); Destroy(&g.rd);
} }
struct Camera struct Camera
{ {
Vec3 velocity = Vec3(0.0); Vec3 velocity = Vec3(0.0);
Vec3 pos = Vec3(0.0, 0.0, 5.0); Vec3 pos = Vec3(0.0, 0.0, 2.0);
f32 pitch = 0.0; f32 pitch = 0.0;
f32 yaw = 0.0; f32 yaw = 0.0;
} }
@ -183,8 +331,6 @@ struct Camera
pragma(inline): void pragma(inline): void
HandleInputs(Camera* cam, Inputs* inputs) HandleInputs(Camera* cam, Inputs* inputs)
{ {
Logf("%.04f %.04f", cam.pitch, cam.yaw);
foreach(i; 0 .. inputs.count) foreach(i; 0 .. inputs.count)
{ {
InputEvent event = inputs.events[i]; InputEvent event = inputs.events[i];
@ -231,3 +377,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,9 @@ 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
// 6. Remove renderer.d and just move the interface into vulkan.d
// 7. Remove dynamic rendering
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; import vulkan : Destroy, Init, Draw, DrawIndexed, Bind, BindUIBuffers, BeginRendering, SetUniform, PrepComputeDrawImage, Dispatch, SubmitAndPresent, BeginFrame, WaitIdle, PushConstants, BindBuffers, SetClearColor, ImageBarrier, CreateImageView, GetDrawImageFormat, FinishRendering, UpdateAuxImage, ClearColor, SubmitAndPresent;
import assets; import assets;
import std.math.traits : isNaN; import std.math.traits : isNaN;
import util : Logf; import util : Logf;
@ -25,6 +25,20 @@ enum InputRate : int
alias IR = InputRate; alias IR = InputRate;
enum ImageUsage : VkImageUsageFlagBits
{
None = cast(VkImageUsageFlagBits)0,
Draw = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
Depth = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
Texture = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
Convert = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
Storage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
Swapchain = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
}
alias IU = ImageUsage;
enum Format : VkFormat enum Format : VkFormat
{ {
UINT = VK_FORMAT_R32_UINT, UINT = VK_FORMAT_R32_UINT,
@ -33,24 +47,35 @@ 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,
D_SF32 = VK_FORMAT_D32_SFLOAT,
} }
alias FMT = Format; alias FMT = Format;
enum BufferType : int enum BufferType : VkBufferUsageFlagBits
{ {
None = 0, None = cast(VkBufferUsageFlagBits)0,
Vertex = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, Vertex = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
Index = VK_BUFFER_USAGE_INDEX_BUFFER_BIT, Index = VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
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;
enum ImageLayout : VkImageLayout
{
Undefined = VK_IMAGE_LAYOUT_UNDEFINED,
General = VK_IMAGE_LAYOUT_GENERAL,
ColorAttach = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
}
struct GlobalUniforms struct GlobalUniforms
{ {
Mat4 view_matrix = Mat4Identity(); Mat4 view_matrix = Mat4Identity();
@ -92,6 +117,8 @@ struct GfxPipelineInfo
Attribute[] vertex_attributes; Attribute[] vertex_attributes;
Specialization vert_spec; Specialization vert_spec;
Specialization frag_spec; Specialization frag_spec;
ImageView* draw_image;
ImageView* depth_image;
} }
struct CompPipelineInfo struct CompPipelineInfo
@ -101,19 +128,6 @@ struct CompPipelineInfo
VkPipelineLayout *layout; VkPipelineLayout *layout;
} }
struct Renderer
{
Arena arena;
Arena temp_arena;
Vulkan vk;
PlatformWindow* window;
UIVertex[] ui_vertex_buf;
u32[] ui_index_buf;
u32 ui_count;
}
struct PushConst struct PushConst
{ {
Mat4 model_matrix; Mat4 model_matrix;
@ -124,6 +138,8 @@ struct Extent
{ {
u32 x; u32 x;
u32 y; u32 y;
alias x w;
alias y h;
} }
struct UIVertex struct UIVertex
@ -161,6 +177,58 @@ struct Model
Buffer[] materials; Buffer[] materials;
ImageView[] textures; ImageView[] textures;
Vec3[] positions;
u32[] pos_indices;
u32[] indices;
}
struct Image
{
VkImage image;
VmaAllocation alloc;
Format format;
VkImageLayout layout;
u32 w;
u32 h;
bool depth_image;
ImageUsage usage;
}
struct BufferView
{
Buffer base;
VkBufferView view;
alias base this;
}
struct ImageView
{
Image base;
VkImageView view;
alias base this;
}
struct Buffer
{
VkBuffer buffer;
VmaAllocation alloc;
u64 size;
}
struct Renderer
{
Arena arena;
Arena temp_arena;
Vulkan vk;
PlatformWindow* window;
UIVertex[] ui_vertex_buf;
u32[] ui_index_buf;
u32 ui_count;
} }
Renderer Renderer
@ -206,12 +274,6 @@ DrawUI(Renderer* rd)
DrawIndexed(rd, 6, rd.ui_count, 0); DrawIndexed(rd, 6, rd.ui_count, 0);
} }
pragma(inline): void
FinishFrame(Renderer* rd)
{
FinishFrame(&rd.vk);
}
pragma(inline): void pragma(inline): void
Dispatch(Renderer* rd) Dispatch(Renderer* rd)
{ {
@ -231,9 +293,9 @@ SetUniform(Renderer* rd, GlobalUniforms* uniforms)
} }
pragma(inline): void pragma(inline): void
BeginRender(Renderer* rd) BeginRendering(Renderer* rd, ImageView* draw_image, ImageView* depth_image)
{ {
BeginRender(&rd.vk); BeginRendering(&rd.vk, draw_image, depth_image);
} }
pragma(inline): void pragma(inline): void
@ -260,6 +322,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)
{ {
@ -371,6 +439,7 @@ LoadModel(Renderer* rd, string name)
case m3dp_Ka: ConvertColor(&mats[i].ambient, m3d.material[i].prop[j].value.color); break; case m3dp_Ka: ConvertColor(&mats[i].ambient, m3d.material[i].prop[j].value.color); break;
case m3dp_Ks: ConvertColor(&mats[i].specular, m3d.material[i].prop[j].value.color); break; case m3dp_Ks: ConvertColor(&mats[i].specular, m3d.material[i].prop[j].value.color); break;
case m3dp_Ns: mats[i].shininess = m3d.material[i].prop[j].value.fnum; break; case m3dp_Ns: mats[i].shininess = m3d.material[i].prop[j].value.fnum; break;
case m3dp_d: mats[i].alpha = m3d.material[i].prop[j].value.fnum; break;
case m3dp_map_Kd: case m3dp_map_Kd:
{ {
mats[i].albedo_texture = tex_lookup[m3d.material[i].prop[j].value.textureid]; mats[i].albedo_texture = tex_lookup[m3d.material[i].prop[j].value.textureid];
@ -386,7 +455,12 @@ LoadModel(Renderer* rd, string name)
mats[i].specular_texture = tex_lookup[m3d.material[i].prop[j].value.textureid]; mats[i].specular_texture = tex_lookup[m3d.material[i].prop[j].value.textureid];
mats[i].specular_has_texture = true; mats[i].specular_has_texture = true;
} break; } break;
default: break; case m3dp_map_D:
{
mats[i].alpha_texture = tex_lookup[m3d.material[i].prop[j].value.textureid];
mats[i].alpha_has_texture = true;
} break;
default: Logf("Unsupported property: %s", M3DPropToStr(m3d.material[i].prop[j].type)); break;
} }
} }
@ -438,8 +512,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)
{ {
@ -475,6 +551,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)
@ -520,11 +601,55 @@ 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;
} }
string
M3DPropToStr(u8 type)
{
string result = "Unknown";
switch(type)
{
case m3dp_Kd: result = "Diffuse"; break;
case m3dp_Ka: result = "Ambient"; break;
case m3dp_Ks: result = "Specular Color"; break;
case m3dp_Ns: result = "Specular Exponent"; break;
case m3dp_Ke: result = "Emissive"; break;
case m3dp_Tf: result = "Transmission"; break;
case m3dp_Km: result = "Bump Strength"; break;
case m3dp_d: result = "Alpha"; break;
case m3dp_il: result = "Illumination"; break;
case m3dp_Pr: result = "Roughness"; break;
case m3dp_Pm: result = "Metallic"; break;
case m3dp_Ps: result = "Sheen"; break;
case m3dp_Ni: result = "Refraction"; break;
case m3dp_Nt: result = "Face Thickness"; break;
case m3dp_map_Kd: result = "Diffuse Texture"; break;
case m3dp_map_Ka: result = "Ambient Texture"; break;
case m3dp_map_Ks: result = "Specular Texture"; break;
case m3dp_map_Ns: result = "Specular Exponent Texture"; break;
case m3dp_map_Ke: result = "Emissive Texture"; break;
case m3dp_map_Tf: result = "Transmission Texture"; break;
case m3dp_map_Km: result = "Bump Map"; break;
case m3dp_map_D: result = "Alpha Map"; break;
case m3dp_map_N: result = "Normal Map"; break;
case m3dp_map_Pr: result = "Roughness Map"; break;
case m3dp_map_Pm: result = "Metallic Map"; break;
case m3dp_map_Ps: result = "Sheen Map"; break;
case m3dp_map_Ni: result = "Refraction Map"; break;
case m3dp_map_Nt: result = "Thickness Map"; break;
default: break;
}
return result;
}
pragma(inline): void pragma(inline): void
CopyVertex(Vec3* dst, m3dv_t* src) CopyVertex(Vec3* dst, m3dv_t* src)
{ {
@ -557,3 +682,85 @@ PrintShader(Renderer* rd, Pipeline* pipeline, VkShaderStageFlagBits stage)
PrintShaderDisassembly(&rd.vk, pipeline, stage); PrintShaderDisassembly(&rd.vk, pipeline, stage);
} }
void
SetClearColor(Renderer* rd, Vec4 color)
{
SetClearColor(&rd.vk, color);
}
void
ClearColorEnabled(Renderer* rd, bool enabled)
{
rd.vk.enable_clear_color = enabled;
}
void
ImageBarrier(Renderer* rd)
{
ImageBarrier(&rd.vk);
}
void
CreateImageView(Renderer* rd, ImageView* view, u32 w, u32 h, Format format, ImageUsage usage, bool depth_image = false)
{
CreateImageView(&rd.vk, view, w, h, format, usage, depth_image);
}
Format
GetDrawImageFormat(Renderer* rd)
{
return cast(Format)GetDrawImageFormat(&rd.vk);
}
pragma(inline): void
ResizeDrawImageIfNeeded(Renderer* rd, ImageView* view)
{
Extent ext = GetExtent(rd);
if (view.w != ext.w || view.h != ext.h)
{
Destroy(view, rd.vk.device, rd.vk.vma);
CreateImageView(&rd.vk, view, ext.w, ext.h, view.format, view.usage, view.depth_image);
}
}
void
FinishRendering(Renderer* rd)
{
FinishRendering(&rd.vk);
}
void
Submit(Renderer* rd, ImageView* view)
{
SubmitAndPresent(&rd.vk, view);
}
void
UpdateAuxImage(Renderer* rd, ImageView* view)
{
UpdateAuxImage(&rd.vk, view);
}
void
ClearColor(Renderer* rd, ImageView* view, Vec4 color)
{
ClearColor(&rd.vk, view, color);
}
void
Destroy(Renderer* rd, Model* model)
{
Destroy(&rd.vk, &model.vertex_buffer);
Destroy(&rd.vk, &model.index_buffer);
foreach(i, mat; model.materials)
{
Destroy(&rd.vk, model.materials.ptr + i);
}
foreach(i, view; model.textures)
{
Destroy(model.textures.ptr + i, rd.vk.device, rd.vk.vma);
}
}

View File

@ -4,6 +4,7 @@ import aliases;
import std.stdio; import std.stdio;
import std.algorithm.comparison; import std.algorithm.comparison;
import core.stdc.string : strcmp, memcpy; import core.stdc.string : strcmp, memcpy;
import core.stdc.stdio : Printf = printf;
import std.format : sformat; import std.format : sformat;
import util; import util;
import alloc; import alloc;
@ -52,6 +53,7 @@ const char*[] VK_BASE_DEVICE_EXTENSIONS = [
cast(char*)VK_KHR_SWAPCHAIN_EXTENSION_NAME, cast(char*)VK_KHR_SWAPCHAIN_EXTENSION_NAME,
cast(char*)VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, cast(char*)VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME,
cast(char*)VK_KHR_8BIT_STORAGE_EXTENSION_NAME, cast(char*)VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
cast(char*)"VK_KHR_dynamic_rendering_local_read",
]; ];
const char*[] VK_AMD_DEVICE_EXTENSIONS = [ const char*[] VK_AMD_DEVICE_EXTENSIONS = [
@ -75,11 +77,6 @@ const VkFormat[] VK_IMAGE_FORMATS = [
VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM,
]; ];
const VkImageUsageFlags VK_DRAW_IMAGE_USAGE_FLAGS = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
enum StepInitialized : u32 enum StepInitialized : u32
{ {
Renderer = 1, Renderer = 1,
@ -93,6 +90,7 @@ enum StepInitialized : u32
Swapchain, Swapchain,
DrawImages, DrawImages,
Descriptors, Descriptors,
Pipelines,
} }
alias SI = StepInitialized; alias SI = StepInitialized;
@ -108,22 +106,6 @@ enum DescType : u32
alias DT = DescType; alias DT = DescType;
struct Image
{
VkImage image;
VmaAllocation alloc;
VkFormat format;
VkImageLayout layout;
}
struct ImageView
{
Image base;
VkImageView view;
alias base this;
}
struct MappedBuffer(T) struct MappedBuffer(T)
{ {
Buffer base; Buffer base;
@ -133,13 +115,6 @@ struct MappedBuffer(T)
alias base this; alias base this;
} }
struct Buffer
{
VkBuffer buffer;
VmaAllocation alloc;
u64 size;
}
struct DescBindings struct DescBindings
{ {
u32[] free; u32[] free;
@ -198,6 +173,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;
@ -220,6 +196,12 @@ struct Vulkan
VkPipeline last_comp_pipeline; VkPipeline last_comp_pipeline;
bool compute_pass_started; bool compute_pass_started;
bool enable_clear_color;
VkClearColorValue clear_color;
BufferView a_buffer_view;
ImageView aux_image;
alias queues this; alias queues this;
} }
@ -294,6 +276,8 @@ Init(PlatformWindow* window, u64 permanent_mem, u64 frame_mem)
bool bool
InitConversionPipeline(Vulkan* vk) InitConversionPipeline(Vulkan* vk)
{ {
Push(vk, SI.Pipelines);
VkDescriptorBindingFlags[] binding_flags; VkDescriptorBindingFlags[] binding_flags;
binding_flags[] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; binding_flags[] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT;
@ -432,6 +416,7 @@ InitBuffers(Vulkan* vk)
Push(vk, SI.Buffers); Push(vk, SI.Buffers);
vk.global_buf = CreateMappedBuffer!(GlobalUniforms)(vk, BT.Uniform, 1); vk.global_buf = CreateMappedBuffer!(GlobalUniforms)(vk, BT.Uniform, 1);
vk.shader_buf = CreateMappedBuffer!(ShaderUniforms)(vk, BT.Uniform, 1);
u64 transfer_size = MB(64); u64 transfer_size = MB(64);
vk.transfer_buf = CreateMappedBuffer!(u8)(vk, BT.Staging, transfer_size); vk.transfer_buf = CreateMappedBuffer!(u8)(vk, BT.Staging, transfer_size);
@ -527,27 +512,30 @@ BeginFrame(Vulkan* vk)
} }
void void
BeginRender(Vulkan* vk) BeginRendering(Vulkan* vk, ImageView* draw_image, ImageView* depth_image)
{ {
// TODO: probably get rid of these // TODO: probably get rid of these
Transition(vk.cmds[vk.frame_index], &vk.draw_image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); Transition(vk.cmds[vk.frame_index], draw_image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
Transition(vk.cmds[vk.frame_index], &vk.depth_image, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); Transition(vk.cmds[vk.frame_index], depth_image, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
VkImage image = CurrentImage(vk); VkImage image = CurrentImage(vk);
Transition(vk.cmds[vk.frame_index], image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); Transition(vk.cmds[vk.frame_index], image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkRenderingAttachmentInfo col_attach = { VkRenderingAttachmentInfo col_attach = {
sType: VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, sType: VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
imageView: vk.draw_image.view, imageView: draw_image.view,
imageLayout: vk.draw_image.layout, imageLayout: draw_image.layout,
loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, // CLEAR instead of LOAD if wanting to clear colors, also clearColor value (or whatever) loadOp: (vk.enable_clear_color ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD), // CLEAR instead of LOAD if wanting to clear colors, also clearColor value (or whatever)
storeOp: VK_ATTACHMENT_STORE_OP_STORE, storeOp: VK_ATTACHMENT_STORE_OP_STORE,
clearValue: {
color: vk.clear_color,
},
}; };
VkRenderingAttachmentInfo depth_attach = { VkRenderingAttachmentInfo depth_attach = {
sType: VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, sType: VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
imageView: vk.depth_image.view, imageView: depth_image.view,
imageLayout: vk.depth_image.layout, imageLayout: depth_image.layout,
loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR,
storeOp: VK_ATTACHMENT_STORE_OP_STORE, storeOp: VK_ATTACHMENT_STORE_OP_STORE,
}; };
@ -569,6 +557,21 @@ BeginRender(Vulkan* vk)
vkCmdBeginRendering(vk.cmds[vk.frame_index], &render_info); vkCmdBeginRendering(vk.cmds[vk.frame_index], &render_info);
} }
void
SetClearColor(Vulkan* vk, Vec4 color)
{
vk.clear_color.float32[0] = color.r;
vk.clear_color.float32[1] = color.g;
vk.clear_color.float32[2] = color.b;
vk.clear_color.float32[3] = color.a;
}
void
PrepAuxImage(Vulkan* vk, ImageView* view)
{
Transition(vk.cmds[vk.frame_index], view, VK_IMAGE_LAYOUT_GENERAL);
}
void void
PrepComputeDrawImage(Vulkan* vk) PrepComputeDrawImage(Vulkan* vk)
{ {
@ -576,7 +579,13 @@ PrepComputeDrawImage(Vulkan* vk)
} }
void void
FinishFrame(Vulkan* vk) FinishRendering(Vulkan* vk)
{
vkCmdEndRendering(vk.cmds[vk.frame_index]);
}
void
SubmitAndPresent(Vulkan* vk, ImageView* draw_image)
{ {
scope(exit) scope(exit)
{ {
@ -588,9 +597,7 @@ FinishFrame(Vulkan* vk)
VkSemaphore acquire_sem = vk.acquire_sems[vk.frame_index]; VkSemaphore acquire_sem = vk.acquire_sems[vk.frame_index];
VkSemaphore submit_sem = vk.submit_sems[vk.image_index]; VkSemaphore submit_sem = vk.submit_sems[vk.image_index];
vkCmdEndRendering(vk.cmds[vk.frame_index]); Transition(vk.cmds[vk.frame_index], draw_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
Transition(vk.cmds[vk.frame_index], &vk.draw_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
VkExtent2D extent = { VkExtent2D extent = {
width: vk.swapchain_extent.width, width: vk.swapchain_extent.width,
@ -598,7 +605,7 @@ FinishFrame(Vulkan* vk)
}; };
// TODO: Find out how to copy from same dimension images (pretty sure its not blitting) // TODO: Find out how to copy from same dimension images (pretty sure its not blitting)
Copy(vk.cmds[vk.frame_index], &vk.draw_image.base, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, extent, extent); Copy(vk.cmds[vk.frame_index], &draw_image.base, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, extent, extent);
Transition(vk.cmds[vk.frame_index], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); Transition(vk.cmds[vk.frame_index], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
@ -736,7 +743,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, IU.Texture);
if (ch == 4) if (ch == 4)
{ {
@ -749,7 +756,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, IU.Convert);
WriteConvDescriptor(vk, &buf); WriteConvDescriptor(vk, &buf);
WriteConvDescriptor(vk, &conv_view); WriteConvDescriptor(vk, &conv_view);
@ -853,7 +860,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, ImageUsage usage, bool depth_image = false)
{ {
VmaAllocationCreateInfo alloc_info = { VmaAllocationCreateInfo alloc_info = {
usage: VMA_MEMORY_USAGE_GPU_ONLY, usage: VMA_MEMORY_USAGE_GPU_ONLY,
@ -868,7 +893,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,
@ -884,9 +909,6 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.R
image_info.pQueueFamilyIndices = cast(const u32*)[vk.gfx_index, vk.tfer_index]; image_info.pQueueFamilyIndices = cast(const u32*)[vk.gfx_index, vk.tfer_index];
} }
view.layout = VK_IMAGE_LAYOUT_UNDEFINED;
view.format = VK_FORMAT_R8G8B8A8_SRGB;
VkResult result = vmaCreateImage(vk.vma, &image_info, &alloc_info, &view.image, &view.alloc, null); VkResult result = vmaCreateImage(vk.vma, &image_info, &alloc_info, &view.image, &view.alloc, null);
// TODO: handle errors and realloc // TODO: handle errors and realloc
assert(VkCheck("CreateImageView failure: vmaCreateImage error", result), "CreateImageView failure"); assert(VkCheck("CreateImageView failure: vmaCreateImage error", result), "CreateImageView failure");
@ -897,7 +919,7 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.R
viewType: VK_IMAGE_VIEW_TYPE_2D, viewType: VK_IMAGE_VIEW_TYPE_2D,
format: format, format: format,
subresourceRange: { subresourceRange: {
aspectMask: VK_IMAGE_ASPECT_COLOR_BIT, aspectMask: (depth_image ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT),
levelCount: 1, levelCount: 1,
layerCount: 1, layerCount: 1,
}, },
@ -906,6 +928,13 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, Format format = FMT.R
result = vkCreateImageView(vk.device, &view_info, null, &view.view); result = vkCreateImageView(vk.device, &view_info, null, &view.view);
// TODO: also handle here // TODO: also handle here
assert(VkCheck("CreateImageView failure: vkCreateImageView error", result), "CreateImageView failure"); assert(VkCheck("CreateImageView failure: vkCreateImageView error", result), "CreateImageView failure");
view.layout = VK_IMAGE_LAYOUT_UNDEFINED;
view.format = format;
view.w = w;
view.h = h;
view.depth_image = depth_image;
view.usage = usage;
} }
u32 u32
@ -977,6 +1006,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)
{ {
@ -1315,13 +1365,19 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info)
VkPipelineRenderingCreateInfo rendering_info = { VkPipelineRenderingCreateInfo rendering_info = {
sType: VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, sType: VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
colorAttachmentCount: 1, colorAttachmentCount: 1,
pColorAttachmentFormats: &vk.draw_image.format, pColorAttachmentFormats: cast(VkFormat*)&build_info.draw_image.format,
depthAttachmentFormat: vk.depth_image.format, depthAttachmentFormat: build_info.depth_image.format,
}; };
VkPipelineColorBlendAttachmentState blend_state = { VkPipelineColorBlendAttachmentState blend_state = {
colorWriteMask: VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, colorWriteMask: VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
blendEnable: VK_FALSE, blendEnable: VK_TRUE,
srcColorBlendFactor: VK_BLEND_FACTOR_SRC_ALPHA,
dstColorBlendFactor: VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
colorBlendOp: VK_BLEND_OP_ADD,
srcAlphaBlendFactor: VK_BLEND_FACTOR_SRC_ALPHA,
dstAlphaBlendFactor: VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
alphaBlendOp: VK_BLEND_OP_ADD,
}; };
VkPipelineColorBlendStateCreateInfo blend_info = { VkPipelineColorBlendStateCreateInfo blend_info = {
@ -1355,36 +1411,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,
@ -1475,6 +1531,25 @@ CreateComputePipeline(Vulkan* vk, CompPipelineInfo* comp_info)
return pipeline; return pipeline;
} }
void
ClearColor(Vulkan* vk, ImageView* view, Vec4 color)
{
VkImageSubresourceRange clear_range = {
aspectMask: (view.depth_image ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT),
levelCount: 1,
layerCount: 1,
};
vkCmdClearColorImage(
vk.cmds[vk.frame_index],
view.image,
view.layout,
cast(VkClearColorValue*)color.v,
1,
&clear_range
);
}
void void
SetUniform(Vulkan* vk, GlobalUniforms* globals) SetUniform(Vulkan* vk, GlobalUniforms* globals)
{ {
@ -1558,6 +1633,13 @@ Destroy(Vulkan* vk)
break; break;
case SI.Buffers: case SI.Buffers:
Destroy(vk, &vk.transfer_buf); Destroy(vk, &vk.transfer_buf);
Destroy(vk, &vk.ui_vert_buf);
Destroy(vk, &vk.ui_index_buf);
Destroy(vk, &vk.global_buf);
Destroy(vk, &vk.shader_buf);
break;
case SI.Pipelines:
DestroyPipelines(vk);
break; break;
default: default:
break; break;
@ -1565,6 +1647,35 @@ Destroy(Vulkan* vk)
} }
} }
void
DestroyPipelines(Vulkan* vk)
{
if (vk.conv_pipeline_layout)
{
vkDestroyPipelineLayout(vk.device, vk.conv_pipeline_layout, null);
}
if (vk.conv_desc_layout)
{
vkDestroyDescriptorSetLayout(vk.device, vk.conv_desc_layout, null);
}
if (vk.r_to_rgba_pipeline.handle)
{
vkDestroyPipeline(vk.device, vk.r_to_rgba_pipeline.handle, null);
}
if (vk.rg_to_rgba_pipeline.handle)
{
vkDestroyPipeline(vk.device, vk.rg_to_rgba_pipeline.handle, null);
}
if (vk.rgb_to_rgba_pipeline.handle)
{
vkDestroyPipeline(vk.device, vk.rgb_to_rgba_pipeline.handle, null);
}
}
void void
Destroy(T)(Vulkan* vk, MappedBuffer!(T)* buf) Destroy(T)(Vulkan* vk, MappedBuffer!(T)* buf)
{ {
@ -1591,6 +1702,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 = {
@ -1606,7 +1718,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 = {
@ -1615,13 +1737,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,
@ -1753,20 +1868,80 @@ 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);
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: 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);
} }
@ -1774,6 +1949,31 @@ InitDescriptors(Vulkan* vk)
return success; return success;
} }
// TODO: better descriptor updating
void
UpdateAuxImage(Vulkan* vk, ImageView* view)
{
VkDescriptorImageInfo aux_info = {
sampler: vk.oit_sampler,
imageView: view.view,
imageLayout: VK_IMAGE_LAYOUT_GENERAL,
};
assert(view.view != VK_NULL_HANDLE);
VkWriteDescriptorSet write = {
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,
};
vkUpdateDescriptorSets(vk.device, 1, &write, 0, null);
}
void void
WriteDrawImageDesc(Vulkan* vk) WriteDrawImageDesc(Vulkan* vk)
{ {
@ -2054,7 +2254,7 @@ GetDrawImageFormat(Vulkan* vk)
format, format,
VK_IMAGE_TYPE_2D, VK_IMAGE_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_OPTIMAL,
VK_DRAW_IMAGE_USAGE_FLAGS, IU.Draw,
0, 0,
&props &props
); );
@ -2080,91 +2280,14 @@ CreateDrawImages(Vulkan* vk)
bool success = true; bool success = true;
VkFormat draw_format = GetDrawImageFormat(vk); Format draw_format = cast(Format)GetDrawImageFormat(vk);
VkFormat depth_format = VK_FORMAT_D32_SFLOAT; Format depth_format = cast(Format)VK_FORMAT_D32_SFLOAT;
VmaAllocationCreateInfo alloc_info = { u32 w = vk.swapchain_extent.width;
usage: VMA_MEMORY_USAGE_GPU_ONLY, u32 h = vk.swapchain_extent.height;
requiredFlags: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
};
VkImageCreateInfo image_info = { CreateImageView(vk, &vk.draw_image, w, h, draw_format, IU.Draw, false);
sType: VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, CreateImageView(vk, &vk.depth_image, w, h, depth_format, IU.Depth, true);
imageType: VK_IMAGE_TYPE_2D,
mipLevels: 1,
arrayLayers: 1,
samples: VK_SAMPLE_COUNT_1_BIT,
tiling: VK_IMAGE_TILING_OPTIMAL,
usage: VK_DRAW_IMAGE_USAGE_FLAGS,
extent: vk.swapchain_extent,
format: draw_format,
};
VkResult result = vmaCreateImage(vk.vma, &image_info, &alloc_info, &vk.draw_image.image, &vk.draw_image.alloc, null);
success = VkCheck("vmaCreateImage failure", result);
if (success)
{
VkImageViewCreateInfo view_info = {
sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
image: vk.draw_image.image,
format: draw_format,
viewType: VK_IMAGE_VIEW_TYPE_2D,
subresourceRange: {
aspectMask: VK_IMAGE_ASPECT_COLOR_BIT,
baseMipLevel: 0,
levelCount: 1,
baseArrayLayer: 0,
layerCount: 1,
},
};
result = vkCreateImageView(vk.device, &view_info, null, &vk.draw_image.view);
success = VkCheck("vkCreateImageView failure", result);
}
if (success)
{
VkImageCreateInfo depth_image_info = {
sType: VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
imageType: VK_IMAGE_TYPE_2D,
mipLevels: 1,
arrayLayers: 1,
samples: VK_SAMPLE_COUNT_1_BIT,
tiling: VK_IMAGE_TILING_OPTIMAL,
format: depth_format,
usage: VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
extent: vk.swapchain_extent,
};
result = vmaCreateImage(vk.vma, &depth_image_info, &alloc_info, &vk.depth_image.image, &vk.depth_image.alloc, null);
success = VkCheck("vmaCreateImage failure", result);
}
if (success)
{
VkImageViewCreateInfo depth_view_info = {
sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
image: vk.depth_image.image,
viewType: VK_IMAGE_VIEW_TYPE_2D,
format: depth_format,
subresourceRange: {
aspectMask: VK_IMAGE_ASPECT_DEPTH_BIT,
baseMipLevel: 0,
levelCount: 1,
baseArrayLayer: 0,
layerCount: 1,
},
};
result = vkCreateImageView(vk.device, &depth_view_info, null, &vk.depth_image.view);
success = VkCheck("vmaCreateImageView failure", result);
}
vk.draw_image.format = draw_format;
vk.draw_image.layout = VK_IMAGE_LAYOUT_UNDEFINED;
vk.depth_image.format = depth_format;
vk.depth_image.layout = VK_IMAGE_LAYOUT_UNDEFINED;
return success; return success;
} }
@ -2218,7 +2341,7 @@ CreateSwapchain(Vulkan* vk)
VkSwapchainCreateInfoKHR info = { VkSwapchainCreateInfoKHR info = {
sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
imageArrayLayers: 1, imageArrayLayers: 1,
imageUsage: VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, imageUsage: IU.Swapchain,
compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
clipped: VK_TRUE, clipped: VK_TRUE,
imageSharingMode: VK_SHARING_MODE_EXCLUSIVE, imageSharingMode: VK_SHARING_MODE_EXCLUSIVE,
@ -2406,6 +2529,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,
@ -2427,6 +2551,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,
}, },
}; };
@ -2496,6 +2621,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;
@ -2505,6 +2631,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;
@ -2789,6 +2916,21 @@ DestroyFS(Vulkan* vk)
vkDestroyCommandPool(vk.device, vk.imm_pool, null); vkDestroyCommandPool(vk.device, vk.imm_pool, null);
} }
if (vk.comp_cmd)
{
vkFreeCommandBuffers(vk.device, vk.comp_cmd_pool, 1, &vk.comp_cmd);
}
if (vk.comp_cmd_pool)
{
vkDestroyCommandPool(vk.device, vk.comp_cmd_pool, null);
}
if (vk.comp_fence)
{
vkDestroyFence(vk.device, vk.comp_fence, null);
}
foreach(sem; vk.submit_sems) foreach(sem; vk.submit_sems)
{ {
if (sem) if (sem)

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

@ -1,7 +1,6 @@
#version 460 #version 460
#extension GL_EXT_shader_8bit_storage : require #extension GL_EXT_shader_8bit_storage : require
#extension GL_EXT_debug_printf : require
layout (constant_id = 0) const int CHANNELS = 3; layout (constant_id = 0) const int CHANNELS = 3;
@ -35,7 +34,6 @@ void main()
uint index = x + y * PC.x; uint index = x + y * PC.x;
vec4 col = vec4(vec3(uint(src[index]) / 255.0), 1.0); vec4 col = vec4(vec3(uint(src[index]) / 255.0), 1.0);
debugPrintfEXT("col = %v4f", col);
imageStore(dst, ivec2(x, y), col); imageStore(dst, ivec2(x, y), col);
} }
else if (CHANNELS == 2) else if (CHANNELS == 2)
@ -45,7 +43,6 @@ void main()
float f = uint(src[index]) / 255.0; float f = uint(src[index]) / 255.0;
float a = uint(src[index+1]) / 255.0; float a = uint(src[index+1]) / 255.0;
vec4 col = vec4(f, f, f, a); vec4 col = vec4(f, f, f, a);
debugPrintfEXT("col = %v4f", col);
imageStore(dst, ivec2(x, y), col); imageStore(dst, ivec2(x, y), col);
} }
else if (CHANNELS == 3) else if (CHANNELS == 3)
@ -53,7 +50,6 @@ void main()
uint index = (x + y * PC.x) * 3; uint index = (x + y * PC.x) * 3;
vec4 col = vec4(uint(src[index]) / 255.0, uint(src[index+1]) / 255.0, uint(src[index+2]) / 255.0, 1.0); vec4 col = vec4(uint(src[index]) / 255.0, uint(src[index+1]) / 255.0, uint(src[index+2]) / 255.0, 1.0);
debugPrintfEXT("col = %v4f", col);
imageStore(dst, ivec2(x, y), col); imageStore(dst, ivec2(x, y), col);
} }
} }

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,10 +25,57 @@ 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);
FragColor = CalculateDirectionalLight(col, tex_col, G.light_color, G.light_direction, FragData.normal); vec4 out_col = CalculateDirectionalLight(col, tex_col, G.light_color, G.light_direction, FragData.normal);
out_col.a = 1.0;// Materials[nonuniformEXT(PC.mat_id)].alpha;
if (Materials[nonuniformEXT(PC.mat_id)].alpha_has_texture)
{
vec4 alpha_col = texture(sampler2D(Textures[nonuniformEXT(Materials[nonuniformEXT(PC.mat_id)].alpha_texture)], SamplerNearest), FragData.uv);
out_col.a = alpha_col.a;
}
FragColor = out_col;
/*
TODO: set up OIT again
vec4 srgb_col = out_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 8
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 {
@ -29,10 +45,13 @@ layout (set = 2, binding = 0) uniform Material {
uint albedo_texture; uint albedo_texture;
uint ambient_texture; uint ambient_texture;
uint specular_texture; uint specular_texture;
uint alpha_texture;
bool albedo_has_texture; bool albedo_has_texture;
bool ambient_has_texture; bool ambient_has_texture;
bool specular_has_texture; bool specular_has_texture;
bool alpha_has_texture;
float shininess; float shininess;
float alpha;
} Materials[]; } Materials[];
layout (push_constant) uniform Constants { layout (push_constant) uniform Constants {

View File

@ -73,10 +73,13 @@ struct Material
u32 albedo_texture; u32 albedo_texture;
u32 ambient_texture; u32 ambient_texture;
u32 specular_texture; u32 specular_texture;
u32 alpha_texture;
b32 albedo_has_texture; b32 albedo_has_texture;
b32 ambient_has_texture; b32 ambient_has_texture;
b32 specular_has_texture; b32 specular_has_texture;
b32 alpha_has_texture;
f32 shininess = 0.0; f32 shininess = 0.0;
f32 alpha = 0.0;
} }
struct TextureInfo struct TextureInfo