rework descriptors

This commit is contained in:
Matthew 2026-03-07 16:11:16 +11:00
parent 38f7bcf3d6
commit 64673b1bf4

550
vulkan.d
View File

@ -3,6 +3,8 @@ import vulkan_logging;
import vulkan_util; import vulkan_util;
import std.stdio; import std.stdio;
import std.algorithm.comparison; import std.algorithm.comparison;
import std.algorithm.searching : canFind;
import std.traits : isPointer;
import core.stdc.string : strcmp, memcpy; import core.stdc.string : strcmp, memcpy;
import core.stdc.stdio : Printf = printf; import core.stdc.stdio : Printf = printf;
import std.format : sformat; import std.format : sformat;
@ -222,33 +224,27 @@ enum ImageLayout : VkImageLayout
alias IL = ImageLayout; alias IL = ImageLayout;
struct Image
{
VkImage image;
VmaAllocation alloc;
Format format;
VkImageLayout layout;
u32 w;
u32 h;
bool depth_image;
ImageUsage usage;
}
struct BufferView struct BufferView
{ {
Buffer base; Buffer base;
VkBufferView view; VkBufferView view;
Format format;
alias base this; alias base this;
} }
struct ImageView struct ImageView
{ {
Image base; VkImage image;
VkImageView view; VkImageView view;
VmaAllocation alloc;
Format format;
ImageUsage usage;
ImageLayout shader_layout; ImageLayout shader_layout;
ImageLayout layout;
alias base this; u32 w;
u32 h;
u32 ch;
} }
struct Buffer struct Buffer
@ -262,18 +258,46 @@ struct Descriptor
{ {
union union
{ {
Buffer buf; Buffer buffer;
Image image; ImageView image;
ImageView view; BufferView buffer_view;
BufferView buf_view;
VkSampler sampler; VkSampler sampler;
} };
DescType type; DescType type;
u32 binding; u32 binding;
u32 index; u32 index;
bool array_elem;
} }
static assert(Descriptor.buffer.buffer.offsetof == Descriptor.buffer_view.base.buffer.offsetof);
struct DescInfo
{
DescType type;
u32 binding;
u32 index;
Format format;
union
{
struct
{
u32 w, h, ch;
ImageUsage usage;
};
struct
{
u64 size;
BufferType buffer_type;
bool host_visible;
};
struct
{
MipmapMode mipmap_mode;
};
};
}
alias Desc = Descriptor;
enum MipmapMode : VkSamplerMipmapMode enum MipmapMode : VkSamplerMipmapMode
{ {
Nearest = VK_SAMPLER_MIPMAP_MODE_NEAREST, Nearest = VK_SAMPLER_MIPMAP_MODE_NEAREST,
@ -434,7 +458,7 @@ struct Vulkan
VkRenderPass render_pass; VkRenderPass render_pass;
VkFramebuffer framebuffer; VkFramebuffer framebuffer;
ImageView[] present_images; Descriptor[] present_images;
u32 image_index; u32 image_index;
Descriptor draw_image; Descriptor draw_image;
@ -535,7 +559,7 @@ struct Vulkan
return this.submit_sems[this.image_index]; return this.submit_sems[this.image_index];
} }
@property ref ImageView @property ref Descriptor
present_image() present_image()
{ {
return this.present_images[this.image_index]; return this.present_images[this.image_index];
@ -662,15 +686,7 @@ CreatePipelineLayout(T)(T layouts, u32 push_const_size, bool compute = false) if
} }
void void
CreateBuffer(Descriptor* desc, BufferType type, u64 size, bool host_visible, DescType desc_type, u32 binding) CreateBuffer(Buffer* buffer, BufferType type, u64 size, bool host_visible)
{
desc.type = desc_type;
desc.binding = binding;
CreateBuffer(&desc.buf, type, size, host_visible);
}
void
CreateBuffer(Buffer* buf, BufferType type, u64 size, bool host_visible)
{ {
assert(type != BT.None, "CreateBuffer failure: type is None"); assert(type != BT.None, "CreateBuffer failure: type is None");
@ -705,11 +721,11 @@ CreateBuffer(Buffer* buf, BufferType type, u64 size, bool host_visible)
} }
VmaAllocationInfo vma_info; VmaAllocationInfo vma_info;
VkResult result = vmaCreateBuffer(g_vk.vma, &buffer_info, &alloc_info, &buf.buffer, &buf.alloc, &vma_info); VkResult result = vmaCreateBuffer(g_vk.vma, &buffer_info, &alloc_info, &buffer.buffer, &buffer.alloc, &vma_info);
// TODO: handle errors here then reallocate buffer // TODO: handle errors here then reallocate buffer
VkCheck("CreateBuffer failure: vmaCreateBuffer error", result); VkCheck("CreateBuffer failure: vmaCreateBuffer error", result);
buf.size = size; buffer.size = size;
} }
void void
@ -805,7 +821,7 @@ BeginRendering()
Transition(g_vk.cmd, &g_vk.draw_image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); Transition(g_vk.cmd, &g_vk.draw_image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
Transition(g_vk.cmd, &g_vk.depth_image, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); Transition(g_vk.cmd, &g_vk.depth_image, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
VkImage image = g_vk.present_image.image; VkImage image = g_vk.present_image.image.image;
Transition(g_vk.cmd, image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); Transition(g_vk.cmd, image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkClearValue[2] clear_color = [ VkClearValue[2] clear_color = [
@ -846,12 +862,6 @@ GetAspect()
return cast(f32)(g_vk.swapchain_extent.width) / cast(f32)(g_vk.swapchain_extent.height); return cast(f32)(g_vk.swapchain_extent.width) / cast(f32)(g_vk.swapchain_extent.height);
} }
void
PrepAuxImage(ImageView* view)
{
Transition(g_vk.cmd, view, VK_IMAGE_LAYOUT_GENERAL);
}
void void
PrepComputeDrawImage() PrepComputeDrawImage()
{ {
@ -873,7 +883,7 @@ SubmitAndPresent()
g_vk.frame_index = (g_vk.frame_index + 1) % FRAME_OVERLAP; g_vk.frame_index = (g_vk.frame_index + 1) % FRAME_OVERLAP;
} }
VkImage image = g_vk.present_image.image; VkImage image = g_vk.present_image.image.image;
VkSemaphore acquire_sem = g_vk.acquire_sem; VkSemaphore acquire_sem = g_vk.acquire_sem;
VkSemaphore submit_sem = g_vk.submit_sem; VkSemaphore submit_sem = g_vk.submit_sem;
@ -885,7 +895,7 @@ SubmitAndPresent()
}; };
// 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(g_vk.cmd, &g_vk.draw_image.view.base, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, extent, extent); Copy(g_vk.cmd, &g_vk.draw_image, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, extent, extent);
Transition(g_vk.cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); Transition(g_vk.cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
@ -1007,13 +1017,13 @@ ImmSubmitFinish()
} }
bool bool
ImmSubmit(Image* image, VkBufferImageCopy copy, void function(Image*, VkBufferImageCopy) fn) ImmSubmit(Descriptor* desc, VkBufferImageCopy copy, void function(Descriptor*, VkBufferImageCopy) fn)
{ {
bool success = ImmSubmitStart(); bool success = ImmSubmitStart();
if(success) if(success)
{ {
fn(image, copy); fn(desc, copy);
VkResult result = vkEndCommandBuffer(g_vk.imm_cmd); VkResult result = vkEndCommandBuffer(g_vk.imm_cmd);
success = VkCheck("ImmSubmit failure: vkEndCommandBuffer error", result); success = VkCheck("ImmSubmit failure: vkEndCommandBuffer error", result);
@ -1028,13 +1038,13 @@ ImmSubmit(Image* image, VkBufferImageCopy copy, void function(Image*, VkBufferIm
} }
bool bool
ImmSubmit(Buffer* buf, VkBufferCopy copy, void function(Buffer*, VkBufferCopy) fn) ImmSubmit(Descriptor* desc, VkBufferCopy copy, void function(Descriptor*, VkBufferCopy) fn)
{ {
bool success = ImmSubmitStart(); bool success = ImmSubmitStart();
if(success) if(success)
{ {
fn(buf, copy); fn(desc, copy);
VkResult result = vkEndCommandBuffer(g_vk.imm_cmd); VkResult result = vkEndCommandBuffer(g_vk.imm_cmd);
success = VkCheck("ImmSubmit failure: vkEndCommandBuffer error", result); success = VkCheck("ImmSubmit failure: vkEndCommandBuffer error", result);
@ -1061,70 +1071,111 @@ WaitForTransfers()
} }
void void
CreateImageView(Descriptor* view, u32 w, u32 h, u32 ch, u8[] data, DescType type = DT.Image, u32 binding, u32 index) CreateDescriptor(T = u8[])(Descriptor* desc, DescInfo info, T data = null) if(is(T: u8[]) || isPointer!(T))
{ {
view.array_elem = true; enum DescType[] image_types = [DT.CombinedSampler, DT.Image, DT.StorageImage, DT.InputAttach];
view.index = index; enum DescType[] texel_types = [DT.UniformTexelBuf, DT.StorageTexelBuf];
CreateImageView(view, w, h, ch, data, type, binding); enum DescType[] buffer_types = [DT.Uniform, DT.DynamicUniform, DT.Storage, DT.DynamicStorage];
desc.type = info.type;
desc.binding = info.binding;
desc.index = info.index;
if(canFind(image_types, info.type))
{
desc.image.usage = info.usage;
desc.image.format = info.format;
desc.image.layout = IL.Undefined;
desc.image.w = info.w;
desc.image.h = info.h;
desc.image.ch = info.ch;
static if(is(T: u8[]))
{
if(data.length)
{
CreateImageView(desc, data);
}
else
{
CreateImageView(desc);
}
}
else
{
CreateImageView(desc);
}
}
else if(canFind(texel_types, info.type))
{
desc.buffer_view.size = info.size;
desc.buffer_view.format = info.format;
CreateBufferView(desc);
if(data)
{
Transfer(desc, data);
}
}
else if(canFind(buffer_types, info.type))
{
CreateBuffer(&desc.buffer, info.buffer_type, info.size, info.host_visible);
if(data)
{
Transfer(desc, data);
}
}
else if(info.type == DT.Sampler)
{
CreateSampler(desc, info.mipmap_mode);
}
else assert(false, "Unknown descriptor type in CreateDescriptor");
} }
void void
CreateImageView(Descriptor* view, u32 w, u32 h, u32 ch, u8[] data, DescType type = DT.Image, u32 binding) CreateImageView(Descriptor* desc, u8[] data)
{ {
ImageDescCheck(type); CreateImageView(desc);
view.type = type;
view.binding = binding;
CreateImageView(&view.view, w, h, ch, data);
}
void if(desc.image.ch == 4)
CreateImageViewTex(Descriptor* desc, u32 w, u32 h, DescType type = DT.Image, u32 binding, u32 index)
{ {
desc.array_elem = true; bool result = Transfer!(true)(desc, data);
desc.index = index;
CreateImageViewTex(desc, w, h, type, binding);
}
void
CreateImageViewTex(Descriptor* desc, u32 w, u32 h, DescType type = DT.Image, u32 binding)
{
ImageDescCheck(type);
desc.type = type;
desc.binding = binding;
CreateImageView(&desc.view, w, h, FMT.RGBA_UNORM, IU.Texture);
}
void
CreateImageView(ImageView* view, u32 w, u32 h, u32 ch, u8[] data)
{
CreateImageView(view, w, h, FMT.RGBA_UNORM, IU.Texture);
if(ch == 4)
{
bool result = Transfer(view, data, w, h);
assert(result); assert(result);
} }
else else
{ {
Descriptor buf; Descriptor buf;
CreateBuffer(&buf, BT.Storage, w * h * ch, false, DT.Storage, 1); CreateDescriptor(&buf, DescInfo(
bool result = Transfer(&buf.buf, data); type: DT.Storage,
buffer_type: BT.Storage,
size: desc.image.w * desc.image.h * desc.image.ch,
binding: 1,
));
bool result = Transfer(&buf.buffer, data);
assert(result, "CreateImageView failure: Buffer Transfer error"); assert(result, "CreateImageView failure: Buffer Transfer error");
Descriptor conv_view; Descriptor conv_view;
CreateImageView(&conv_view, w, h, FMT.RGBA_F32, IU.Convert, DT.StorageImage, 0); CreateDescriptor(&conv_view, DescInfo(
type: DT.StorageImage,
w: desc.image.w,
h: desc.image.h,
format: FMT.RGBA_F32,
usage: IU.Convert,
));
Write(g_vk.conv_desc_set, [conv_view, buf]); Write(g_vk.conv_desc_set, [conv_view, buf]);
BeginComputePass(); BeginComputePass();
Pipeline pipeline = ch == 1 ? g_vk.r_to_rgba_pipeline : Pipeline pipeline = desc.image.ch == 1 ? g_vk.r_to_rgba_pipeline :
ch == 2 ? g_vk.rg_to_rgba_pipeline : desc.image.ch == 2 ? g_vk.rg_to_rgba_pipeline :
g_vk.rgb_to_rgba_pipeline; g_vk.rgb_to_rgba_pipeline;
Bind(pipeline, g_vk.conv_desc_set, true); Bind(pipeline, g_vk.conv_desc_set, true);
ConvPushConst pc = { x: w, y: h }; ConvPushConst pc = { x: desc.image.w, y: desc.image.h };
vkCmdPushConstants( vkCmdPushConstants(
g_vk.comp_cmd, g_vk.comp_cmd,
@ -1139,12 +1190,12 @@ CreateImageView(ImageView* view, u32 w, u32 h, u32 ch, u8[] data)
Dispatch(g_vk.comp_cmd); Dispatch(g_vk.comp_cmd);
Transition(g_vk.comp_cmd, view, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); Transition(g_vk.comp_cmd, desc, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkExtent2D extent = { width: w, height: h }; VkExtent2D extent = { width: desc.image.w, height: desc.image.h };
Copy(g_vk.comp_cmd, &conv_view.view.base, &view.base, extent, extent); Copy(g_vk.comp_cmd, &conv_view, desc, extent, extent);
Transition(g_vk.comp_cmd, view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); Transition(g_vk.comp_cmd, desc, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
FinishComputePass(); FinishComputePass();
@ -1157,26 +1208,8 @@ CreateImageView(ImageView* view, u32 w, u32 h, u32 ch, u8[] data)
} }
} }
void void
CreateImageView(Descriptor* desc, u32 w, u32 h, Format format, ImageUsage usage, DescType type, u32 binding, u32 index) CreateImageView(Descriptor* desc)
{
desc.array_elem = true;
desc.index = index;
CreateImageView(desc, w, h, format, usage, type, binding);
}
void
CreateImageView(Descriptor* desc, u32 w, u32 h, Format format, ImageUsage usage, DescType type, u32 binding)
{
ImageDescCheck(type);
desc.type = type;
desc.binding = binding;
CreateImageView(&desc.view, w, h, format, usage);
}
void
CreateImageView(ImageView* view, u32 w, u32 h, Format format, ImageUsage usage)
{ {
VmaAllocationCreateInfo alloc_info = { VmaAllocationCreateInfo alloc_info = {
usage: VMA_MEMORY_USAGE_GPU_ONLY, usage: VMA_MEMORY_USAGE_GPU_ONLY,
@ -1188,14 +1221,14 @@ CreateImageView(ImageView* view, u32 w, u32 h, Format format, ImageUsage usage)
imageType: VK_IMAGE_TYPE_2D, imageType: VK_IMAGE_TYPE_2D,
mipLevels: 1, mipLevels: 1,
arrayLayers: 1, arrayLayers: 1,
format: format, format: desc.image.format,
tiling: VK_IMAGE_TILING_OPTIMAL, tiling: VK_IMAGE_TILING_OPTIMAL,
initialLayout: VK_IMAGE_LAYOUT_UNDEFINED, initialLayout: VK_IMAGE_LAYOUT_UNDEFINED,
usage: usage, usage: desc.image.usage,
samples: VK_SAMPLE_COUNT_1_BIT, samples: VK_SAMPLE_COUNT_1_BIT,
extent: { extent: {
width: w, width: desc.image.w,
height: h, height: desc.image.h,
depth: 1, depth: 1,
}, },
}; };
@ -1208,42 +1241,37 @@ CreateImageView(ImageView* view, u32 w, u32 h, Format format, ImageUsage usage)
image_info.pQueueFamilyIndices = indices.ptr; image_info.pQueueFamilyIndices = indices.ptr;
} }
VkResult result = vmaCreateImage(g_vk.vma, &image_info, &alloc_info, &view.image, &view.alloc, null); VkResult result = vmaCreateImage(g_vk.vma, &image_info, &alloc_info, &desc.image.image, &desc.image.alloc, null);
// TODO: handle errors and realloc // TODO: handle errors and realloc
VkCheck("CreateImageView failure: vmaCreateImage error", result); VkCheck("CreateImageView failure: vmaCreateImage error", result);
VkImageViewCreateInfo view_info = { VkImageViewCreateInfo view_info = {
sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
image: view.image, image: desc.image.image,
viewType: VK_IMAGE_VIEW_TYPE_2D, viewType: VK_IMAGE_VIEW_TYPE_2D,
format: format, format: desc.image.format,
subresourceRange: { subresourceRange: {
aspectMask: (usage == IU.Depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT), aspectMask: (desc.image.usage == IU.Depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT),
levelCount: 1, levelCount: 1,
layerCount: 1, layerCount: 1,
}, },
}; };
result = vkCreateImageView(g_vk.device, &view_info, null, &view.view); result = vkCreateImageView(g_vk.device, &view_info, null, &desc.image.view);
// TODO: also handle here // TODO: also handle here
VkCheck("CreateImageView failure: vkCreateImageView error", result); VkCheck("CreateImageView failure: vkCreateImageView error", result);
view.layout = VK_IMAGE_LAYOUT_UNDEFINED; if(desc.image.usage == IU.Draw || desc.image.usage == IU.Depth || desc.image.usage == IU.Convert)
view.format = format;
view.w = w;
view.h = h;
view.depth_image = usage == IU.Depth;
view.usage = usage;
if(usage == IU.Draw || usage == IU.Depth || usage == IU.Convert)
{ {
view.shader_layout = IL.General; desc.image.shader_layout = IL.General;
} }
else if(usage == IU.Texture) else if(desc.image.usage == IU.Texture)
{ {
view.shader_layout = IL.ReadOnly; desc.image.shader_layout = IL.ReadOnly;
} }
else assert(false, "Unimplemented usage"); else assert(false, "Unimplemented usage");
desc.image.layout = IL.Undefined;
} }
void void
@ -1290,22 +1318,19 @@ FinishComputePass()
} }
void void
CreateBufferView(Descriptor* desc, u64 size, Format format, DescType type, u32 binding) CreateBufferView(Descriptor* desc)
{ {
CreateBuffer(&desc.buf_view.base, BT.BufferView, size, false); CreateBuffer(&desc.buffer_view.base, BT.BufferView, desc.buffer_view.size, false);
VkBufferViewCreateInfo info = { VkBufferViewCreateInfo info = {
sType: VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, sType: VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
buffer: desc.buf_view.buffer, buffer: desc.buffer_view.buffer,
format: format, format: desc.buffer_view.format,
range: size, range: desc.buffer_view.size,
}; };
VkResult result = vkCreateBufferView(g_vk.device, &info, null, &desc.buf_view.view); VkResult result = vkCreateBufferView(g_vk.device, &info, null, &desc.buffer_view.view);
VkCheckA("CreateBufferView failure: vkCreateBufferView failed", result); VkCheckA("CreateBufferView failure: vkCreateBufferView failed", result);
desc.binding = binding;
desc.buf_view.size = size;
} }
void void
@ -1349,54 +1374,20 @@ ImageBarrier()
} }
bool bool
Transfer(T)(Buffer* buf, T[] data) Transfer(T, U)(T* dst, U[] data)
{ {
static if(is(T: Descriptor))
{
Buffer* buffer = &dst.buffer;
}
else static if(is(T: Buffer))
{
Buffer* buffer = dst;
}
else static assert(false, "Invalid type for transfer target");
u8[] u8_data = (cast(u8*)(data.ptr))[0 .. T.sizeof * data.length]; u8[] u8_data = (cast(u8*)(data.ptr))[0 .. T.sizeof * data.length];
return Transfer(buf, u8_data); return Transfer(buffer, u8_data);
}
bool
Transfer(Buffer* buf, u8[] data)
{
bool success = TransferReady();
u64 copied = 0;
while(copied != data.length && success)
{
if(copied != 0)
{
success = TransferReady();
if(!success)
{
break;
}
}
u64 transfer_length = cast(u64)g_vk.transfer_buf.data.length;
u64 data_length = cast(u64)data.length - copied;
u64 copy_length = transfer_length > data_length ? data_length : transfer_length;
g_vk.transfer_buf.data[0 .. copy_length] = data[copied .. copy_length];
auto fn = function(Buffer* buf, VkBufferCopy copy)
{
vkCmdCopyBuffer(g_vk.imm_cmd, g_vk.transfer_buf.buffer, buf.buffer, 1, &copy);
};
VkBufferCopy copy = {
srcOffset: 0,
dstOffset: copied,
size: copy_length,
};
success = ImmSubmit(buf, copy, fn);
copied += copy_length;
}
WaitForTransfers();
return success;
} }
bool bool
@ -1437,13 +1428,7 @@ TransferReady()
} }
bool bool
Transfer(ImageView* view, u8[] data, u32 w, u32 h) Transfer(bool image)(Descriptor* desc, u8[] data)
{
return Transfer(&view.base, data, w, h);
}
bool
Transfer(Image* image, u8[] data, u32 w, u32 h)
{ {
bool success = true; bool success = true;
@ -1456,32 +1441,47 @@ Transfer(Image* image, u8[] data, u32 w, u32 h)
g_vk.transfer_buf.data[0 .. copy_length] = data[copied .. copy_length]; g_vk.transfer_buf.data[0 .. copy_length] = data[copied .. copy_length];
auto fn = function(Image* image, VkBufferImageCopy copy) static if(image)
{ {
Transition(g_vk.imm_cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); auto fn = function(Descriptor* desc, VkBufferImageCopy copy)
{
Transition(g_vk.imm_cmd, desc, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
vkCmdCopyBufferToImage(g_vk.imm_cmd, g_vk.transfer_buf.buffer, image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy); vkCmdCopyBufferToImage(g_vk.imm_cmd, g_vk.transfer_buf.buffer, desc.image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy);
Transition(g_vk.imm_cmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); Transition(g_vk.imm_cmd, desc, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}; };
VkBufferImageCopy copy = { VkBufferImageCopy copy = {
bufferRowLength: w, bufferRowLength: desc.image.w,
bufferImageHeight: h, bufferImageHeight: desc.image.h,
imageSubresource: { imageSubresource: {
aspectMask: VK_IMAGE_ASPECT_COLOR_BIT, aspectMask: VK_IMAGE_ASPECT_COLOR_BIT,
layerCount: 1, layerCount: 1,
}, },
imageExtent: { imageExtent: {
width: w, width: desc.image.w,
height: h, height: desc.image.h,
depth: 1, depth: 1,
}, },
bufferOffset: copied, bufferOffset: copied,
}; };
}
else
{
auto fn = function(Descriptor* desc, VkBufferCopy copy)
{
vkCmdCopyBuffer(g_vk.imm_cmd, g_vk.transfer_buf.buffer, desc.buffer.buffer, 1, &copy);
};
success = ImmSubmit(image, copy, fn); VkBufferCopy copy = {
srcOffset: 0,
dstOffset: copied,
size: copy_length,
};
}
success = ImmSubmit(desc, copy, fn);
copied += copy_length; copied += copy_length;
} }
@ -1491,15 +1491,15 @@ Transfer(Image* image, u8[] data, u32 w, u32 h)
} }
void void
Copy(VkCommandBuffer cmd, Image* src, Image* dst, VkExtent2D src_ext, VkExtent2D dst_ext) Copy(VkCommandBuffer cmd, Descriptor* src, Descriptor* dst, VkExtent2D src_ext, VkExtent2D dst_ext)
{ {
Copy(cmd, src.image, dst.image, src.layout, dst.layout, src_ext, dst_ext); Copy(cmd, src.image.image, dst.image.image, src.image.layout, dst.image.layout, src_ext, dst_ext);
} }
void void
Copy(VkCommandBuffer cmd, Image* src, VkImage dst, VkImageLayout dst_layout, VkExtent2D src_ext, VkExtent2D dst_ext) Copy(VkCommandBuffer cmd, Descriptor* src, VkImage dst, VkImageLayout dst_layout, VkExtent2D src_ext, VkExtent2D dst_ext)
{ {
Copy(cmd, src.image, dst, src.layout, dst_layout, src_ext, dst_ext); Copy(cmd, src.image.image, dst, src.image.layout, dst_layout, src_ext, dst_ext);
} }
void void
@ -1696,6 +1696,12 @@ ResetScissor(VkCommandBuffer cmd = cast(VkCommandBuffer)VK_NULL_HANDLE)
vkCmdSetScissor(cmd, 0, 1, &scissor); vkCmdSetScissor(cmd, 0, 1, &scissor);
} }
void
Transition(VkCommandBuffer cmd, Descriptor* desc, VkImageLayout new_layout)
{
ImageDescCheck(desc);
Transition(cmd, desc.image.image, desc.image.layout, new_layout);
}
void void
Transition(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkImageLayout new_layout) Transition(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkImageLayout new_layout)
@ -1727,16 +1733,14 @@ Transition(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkI
vkCmdPipelineBarrier2(cmd, &dep_info); vkCmdPipelineBarrier2(cmd, &dep_info);
} }
void bool
ImageDescCheck(Descriptor* desc) ImageDescCheck(Descriptor* desc)
{ {
ImageDescCheck(desc.type); return ImageDescCheck(desc.type);
} }
void bool
ImageDescCheck(DescType desc_type) ImageDescCheck(DescType desc_type)
{
debug
{ {
bool match; bool match;
enum types = [DT.CombinedSampler, DT.Image, DT.StorageImage, DT.InputAttach]; enum types = [DT.CombinedSampler, DT.Image, DT.StorageImage, DT.InputAttach];
@ -1745,29 +1749,7 @@ ImageDescCheck(DescType desc_type)
match |= desc_type == type; match |= desc_type == type;
} }
assert(match, "Unable to transition non image"); return match;
}
}
void
Transition(VkCommandBuffer cmd, Descriptor* desc, VkImageLayout new_layout)
{
ImageDescCheck(desc);
Transition(cmd, &desc.view, new_layout);
}
void
Transition(VkCommandBuffer cmd, ImageView* view, VkImageLayout new_layout)
{
Transition(cmd, view.image, view.layout, new_layout);
view.layout = new_layout;
}
void
Transition(VkCommandBuffer cmd, Image* image, VkImageLayout new_layout)
{
Transition(cmd, image.image, image.layout, new_layout);
image.layout = new_layout;
} }
bool bool
@ -1787,6 +1769,7 @@ bool
CreateGraphicsPipeline(Pipeline* pipeline_handle, GfxPipelineInfo* build_info) CreateGraphicsPipeline(Pipeline* pipeline_handle, GfxPipelineInfo* build_info)
{ {
PipelineHandles* pipeline = NewPipeline(); PipelineHandles* pipeline = NewPipeline();
pipeline.type = VK_PIPELINE_BIND_POINT_GRAPHICS; pipeline.type = VK_PIPELINE_BIND_POINT_GRAPHICS;
pipeline.layout = build_info.layout; pipeline.layout = build_info.layout;
@ -1839,8 +1822,8 @@ CreateGraphicsPipeline(Pipeline* pipeline_handle, 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: cast(VkFormat*)&g_vk.draw_image.view.format, pColorAttachmentFormats: cast(VkFormat*)&g_vk.draw_image.image.format,
depthAttachmentFormat: g_vk.depth_image.view.format, depthAttachmentFormat: g_vk.depth_image.image.format,
}; };
VkPipelineColorBlendAttachmentState blend_state = { VkPipelineColorBlendAttachmentState blend_state = {
@ -2043,24 +2026,17 @@ ClearColor(f32[4] color)
void void
ClearColor(Descriptor* desc, f32[4] color) ClearColor(Descriptor* desc, f32[4] color)
{
ImageDescCheck(desc);
ClearColor(&desc.view, color);
}
void
ClearColor(ImageView* view, f32[4] color)
{ {
VkImageSubresourceRange clear_range = { VkImageSubresourceRange clear_range = {
aspectMask: (view.depth_image ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT), aspectMask: (desc.image.usage == IU.Depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT),
levelCount: 1, levelCount: 1,
layerCount: 1, layerCount: 1,
}; };
vkCmdClearColorImage( vkCmdClearColorImage(
g_vk.cmd, g_vk.cmd,
view.image, desc.image.image,
view.layout, desc.image.layout,
cast(VkClearColorValue*)color, cast(VkClearColorValue*)color,
1, 1,
&clear_range &clear_range
@ -2150,11 +2126,7 @@ PrepareWrite(VkWriteDescriptorSet* write, DescSet set, Descriptor* desc)
write.dstSet = set.handle; write.dstSet = set.handle;
write.dstBinding = desc.binding; write.dstBinding = desc.binding;
write.descriptorCount = 1; write.descriptorCount = 1;
if(desc.array_elem)
{
write.dstArrayElement = desc.index; write.dstArrayElement = desc.index;
}
switch(desc.type) with(DescType) switch(desc.type) with(DescType)
{ {
@ -2162,22 +2134,22 @@ PrepareWrite(VkWriteDescriptorSet* write, DescSet set, Descriptor* desc)
{ {
VkDescriptorImageInfo* info = Alloc!(VkDescriptorImageInfo)(arena); VkDescriptorImageInfo* info = Alloc!(VkDescriptorImageInfo)(arena);
info.imageView = desc.view.view; info.imageView = desc.image.view;
info.imageLayout = desc.view.shader_layout; info.imageLayout = desc.image.shader_layout;
write.pImageInfo = info; write.pImageInfo = info;
} break; } break;
case Uniform, Storage: case Uniform, Storage:
{ {
VkDescriptorBufferInfo* info = Alloc!(VkDescriptorBufferInfo)(arena); VkDescriptorBufferInfo* info = Alloc!(VkDescriptorBufferInfo)(arena);
info.buffer = desc.buf.buffer; info.buffer = desc.buffer.buffer;
info.offset = cast(VkDeviceSize)0; info.offset = cast(VkDeviceSize)0;
info.range = cast(VkDeviceSize)desc.buf.size; info.range = cast(VkDeviceSize)desc.buffer.size;
write.pBufferInfo = info; write.pBufferInfo = info;
} break; } break;
case UniformTexelBuf, StorageTexelBuf: case UniformTexelBuf, StorageTexelBuf:
{ {
write.pTexelBufferView = &desc.buf_view.view; write.pTexelBufferView = &desc.buffer_view.view;
} break; } break;
case Sampler: case Sampler:
{ {
@ -2371,8 +2343,8 @@ SelectSwapchainFormats()
g_vk.present_mode = present_mode; g_vk.present_mode = present_mode;
} }
Descriptor void
CreateSampler(MipmapMode mode, u32 binding) CreateSampler(Descriptor* desc, MipmapMode mode)
{ {
VkPhysicalDeviceProperties props; VkPhysicalDeviceProperties props;
vkGetPhysicalDeviceProperties(g_vk.physical_device, &props); vkGetPhysicalDeviceProperties(g_vk.physical_device, &props);
@ -2391,15 +2363,8 @@ CreateSampler(MipmapMode mode, u32 binding)
mipmapMode: mode, mipmapMode: mode,
}; };
Descriptor sampler = { VkResult result = vkCreateSampler(g_vk.device, &sampler_info, null, &desc.sampler);
type: DT.Sampler,
binding: binding,
};
VkResult result = vkCreateSampler(g_vk.device, &sampler_info, null, &sampler.sampler);
VkCheckA("vkCreateSampler failure", result); VkCheckA("vkCreateSampler failure", result);
return sampler;
} }
bool bool
@ -2413,8 +2378,8 @@ CreateDrawImages()
u32 w = g_vk.swapchain_extent.width; u32 w = g_vk.swapchain_extent.width;
u32 h = g_vk.swapchain_extent.height; u32 h = g_vk.swapchain_extent.height;
CreateImageView(&g_vk.draw_image, w, h, draw_format, IU.Draw, DT.StorageImage, 0); CreateDescriptor(&g_vk.draw_image, DescInfo(type: DT.StorageImage, format: draw_format, usage: IU.Draw, w: w, h: h, binding: 0));
CreateImageView(&g_vk.depth_image, w, h, depth_format, IU.Depth, DT.Image, 0); CreateDescriptor(&g_vk.depth_image, DescInfo(type: DT.Image, format: depth_format, usage: IU.Depth, w: w, h: h, binding: 0));
return success; return success;
} }
@ -2448,12 +2413,12 @@ CreateSwapchain()
surface: g_vk.surface, surface: g_vk.surface,
imageFormat: g_vk.surface_format.format, imageFormat: g_vk.surface_format.format,
imageColorSpace: g_vk.surface_format.colorSpace, imageColorSpace: g_vk.surface_format.colorSpace,
preTransform: cap.currentTransform,
presentMode: g_vk.present_mode,
imageExtent: { imageExtent: {
width: w, width: w,
height: h, height: h,
}, },
preTransform: cap.currentTransform,
presentMode: g_vk.present_mode,
}; };
VkResult result = vkCreateSwapchainKHR(g_vk.device, &info, null, &g_vk.swapchain); VkResult result = vkCreateSwapchainKHR(g_vk.device, &info, null, &g_vk.swapchain);
@ -2465,7 +2430,7 @@ CreateSwapchain()
vkGetSwapchainImagesKHR(g_vk.device, g_vk.swapchain, &count, images.ptr); vkGetSwapchainImagesKHR(g_vk.device, g_vk.swapchain, &count, images.ptr);
VkImageView[] views = Alloc!(VkImageView)(arena, count); VkImageView[] views = Alloc!(VkImageView)(arena, count);
g_vk.present_images = Alloc!(ImageView)(&g_vk.arena, count); g_vk.present_images = Alloc!(Descriptor)(&g_vk.arena, count);
VkImageViewCreateInfo view_info = { VkImageViewCreateInfo view_info = {
sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
@ -2485,18 +2450,17 @@ CreateSwapchain()
}, },
}; };
VkFramebufferCreateInfo framebuffer_info = { VkFramebufferCreateInfo framebuffer_info = { sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
};
foreach(i, image; g_vk.present_images) foreach(i; 0 .. g_vk.present_images.length)
{ {
g_vk.present_images[i].image = images[i]; g_vk.present_images[i].image.image = images[i];
g_vk.present_images[i].format = cast(Format)g_vk.surface_format.format; g_vk.present_images[i].image.format = cast(Format)g_vk.surface_format.format;
view_info.image = images[i]; view_info.image = images[i];
view_info.format = g_vk.surface_format.format; view_info.format = g_vk.surface_format.format;
result = vkCreateImageView(g_vk.device, &view_info, null, &g_vk.present_images[i].view); result = vkCreateImageView(g_vk.device, &view_info, null, &g_vk.present_images[i].image.view);
success = VkCheck("vkCreateImageView failure", result); success = VkCheck("vkCreateImageView failure", result);
} }
@ -2537,7 +2501,7 @@ CreateFramebuffer()
sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
renderPass: g_vk.render_pass, renderPass: g_vk.render_pass,
attachmentCount: 2, attachmentCount: 2,
pAttachments: [g_vk.draw_image.view.view, g_vk.depth_image.view.view], pAttachments: [g_vk.draw_image.image.view, g_vk.depth_image.image.view],
width: g_vk.swapchain_extent.width, width: g_vk.swapchain_extent.width,
height: g_vk.swapchain_extent.height, height: g_vk.swapchain_extent.height,
layers: 1, layers: 1,
@ -2571,33 +2535,33 @@ Destroy(Descriptor* desc)
} break; } break;
case DT.CombinedSampler, DT.Image, DT.StorageImage, DT.InputAttach: case DT.CombinedSampler, DT.Image, DT.StorageImage, DT.InputAttach:
{ {
if(desc.view.view) if(desc.image.view)
{ {
vkDestroyImageView(g_vk.device, desc.view.view, null); vkDestroyImageView(g_vk.device, desc.image.view, null);
} }
if(desc.view.image) if(desc.image.image)
{ {
vmaDestroyImage(g_vk.vma, desc.view.image, desc.view.alloc); vmaDestroyImage(g_vk.vma, desc.image.image, desc.image.alloc);
} }
} break; } break;
case DT.UniformTexelBuf, DT.StorageTexelBuf: case DT.UniformTexelBuf, DT.StorageTexelBuf:
{ {
if(desc.buf_view.view) if(desc.buffer_view.view)
{ {
vkDestroyBufferView(g_vk.device, desc.buf_view.view, null); vkDestroyBufferView(g_vk.device, desc.buffer_view.view, null);
} }
if(desc.buf_view.buffer) if(desc.buffer_view.buffer)
{ {
vmaDestroyBuffer(g_vk.vma, desc.buf_view.buffer, desc.buf_view.alloc); vmaDestroyBuffer(g_vk.vma, desc.buffer_view.buffer, desc.buffer_view.alloc);
} }
} break; } break;
case DT.Uniform, DT.DynamicUniform, DT.Storage, DT.DynamicStorage: case DT.Uniform, DT.DynamicUniform, DT.Storage, DT.DynamicStorage:
{ {
if(desc.buf.buffer) if(desc.buffer.buffer)
{ {
vmaDestroyBuffer(g_vk.vma, desc.buf.buffer, desc.buf.alloc); vmaDestroyBuffer(g_vk.vma, desc.buffer.buffer, desc.buffer.alloc);
} }
} break; } break;
default: assert(false, "Unsupported descriptor Destroy call"); default: assert(false, "Unsupported descriptor Destroy call");
@ -2643,13 +2607,13 @@ Destroy(VkSurfaceKHR surface, VkInstance instance)
} }
void void
Destroy(VkSwapchainKHR swapchain, ImageView[] views, VkDevice device) Destroy(VkSwapchainKHR swapchain, Descriptor[] images, VkDevice device)
{ {
foreach(view; views) foreach(ref image; images)
{ {
if(view.view) if(image.image.view)
{ {
vkDestroyImageView(device, view.view, null); vkDestroyImageView(device, image.image.view, null);
} }
} }
@ -3341,7 +3305,7 @@ Init(PlatformHandles platform_handles, u64 permanent_mem, u64 frame_mem)
VkAttachmentDescription[2] attach_descriptions = [ VkAttachmentDescription[2] attach_descriptions = [
{ {
format: g_vk.draw_image.view.format, format: g_vk.draw_image.image.format,
samples: VK_SAMPLE_COUNT_1_BIT, samples: VK_SAMPLE_COUNT_1_BIT,
loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR,
storeOp: VK_ATTACHMENT_STORE_OP_STORE, storeOp: VK_ATTACHMENT_STORE_OP_STORE,
@ -3351,7 +3315,7 @@ Init(PlatformHandles platform_handles, u64 permanent_mem, u64 frame_mem)
finalLayout: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, finalLayout: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
}, },
{ {
format: g_vk.depth_image.view.format, format: g_vk.depth_image.image.format,
samples: VK_SAMPLE_COUNT_1_BIT, samples: VK_SAMPLE_COUNT_1_BIT,
loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR,
storeOp: VK_ATTACHMENT_STORE_OP_STORE, storeOp: VK_ATTACHMENT_STORE_OP_STORE,