Drawing a textured quad
Added new assets Loaded all texture assets into game state Loaded the basic pipeline Setup a hard-coded quad to test drawing Created a very jank vertex struct Added ReadEntireFile for filesystem Added getting file size from file handle Added a descriptor pool to each in flight frame Changed Vk_BufferCreate to handle multiple uses Added shader building to the windows.bat build script
BIN
assets/npc_00.png
Normal file
|
After Width: | Height: | Size: 801 B |
BIN
assets/oath_corner_inner.png
Normal file
|
After Width: | Height: | Size: 409 B |
BIN
assets/path_corner.png
Normal file
|
After Width: | Height: | Size: 520 B |
BIN
assets/path_middle.png
Normal file
|
After Width: | Height: | Size: 483 B |
BIN
assets/path_middle_edge.png
Normal file
|
After Width: | Height: | Size: 453 B |
BIN
assets/saloon_ext.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
assets/tile_detail_0.png
Normal file
|
After Width: | Height: | Size: 208 B |
BIN
assets/tile_detail_1.png
Normal file
|
After Width: | Height: | Size: 329 B |
BIN
assets/tile_detail_2.png
Normal file
|
After Width: | Height: | Size: 358 B |
BIN
assets/tile_detail_3.png
Normal file
|
After Width: | Height: | Size: 351 B |
BIN
assets/tile_detail_4.png
Normal file
|
After Width: | Height: | Size: 223 B |
BIN
assets/tile_detail_5.png
Normal file
|
After Width: | Height: | Size: 368 B |
BIN
assets/tile_detail_6.png
Normal file
|
After Width: | Height: | Size: 317 B |
BIN
assets/tile_dirt_0.png
Normal file
|
After Width: | Height: | Size: 462 B |
BIN
assets/tile_dirt_1.png
Normal file
|
After Width: | Height: | Size: 494 B |
81
code/first.c
@@ -29,9 +29,33 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
Vk_Setup(window);
|
Vk_Setup(window);
|
||||||
|
|
||||||
|
G_State *game = 0;
|
||||||
|
{
|
||||||
|
M_Arena *arena = M_ArenaAlloc(GB(64), .initial = MB(4));
|
||||||
|
game = M_ArenaPush(arena, G_State);
|
||||||
|
|
||||||
M_Arena *garena = M_ArenaAlloc(GB(64), .initial = MB(4));
|
game->arena = arena;
|
||||||
G_ImagesLoad(garena);
|
|
||||||
|
G_ImagesLoad(game);
|
||||||
|
G_PipelinesLoad(game);
|
||||||
|
|
||||||
|
Vk_Buffer *vbo = &game->vbo;
|
||||||
|
vbo->size = KB(4096);
|
||||||
|
vbo->usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||||
|
vbo->host_visible = true;
|
||||||
|
|
||||||
|
Vk_BufferCreate(vbo);
|
||||||
|
|
||||||
|
G_Vertex *vertices = cast(G_Vertex *) vbo->data;
|
||||||
|
|
||||||
|
vertices[0] = (G_Vertex) { -0.25f, -0.25f, 1.0f, 1.0f, 0.0f, 0.0f, 0xFFFFFFFF, 0};
|
||||||
|
vertices[1] = (G_Vertex) { 0.25f, -0.25f, 1.0f, 1.0f, 1.0f, 0.0f, 0xFFFFFFFF, 0};
|
||||||
|
vertices[2] = (G_Vertex) { -0.25f, 0.25f, 1.0f, 1.0f, 0.0f, 1.0f, 0xFFFFFFFF, 0};
|
||||||
|
|
||||||
|
vertices[3] = (G_Vertex) { 0.25f, -0.25f, 1.0f, 1.0f, 1.0f, 0.0f, 0xFFFFFFFF, 0};
|
||||||
|
vertices[4] = (G_Vertex) { 0.25f, 0.25f, 1.0f, 1.0f, 1.0f, 1.0f, 0xFFFFFFFF, 0};
|
||||||
|
vertices[5] = (G_Vertex) { -0.25f, 0.25f, 1.0f, 1.0f, 0.0f, 1.0f, 0xFFFFFFFF, 0};
|
||||||
|
}
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
while (running) {
|
while (running) {
|
||||||
@@ -69,6 +93,59 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
vk.CmdBeginRendering(cmd, &rendering_info);
|
vk.CmdBeginRendering(cmd, &rendering_info);
|
||||||
|
|
||||||
|
Vk_Pipeline *basic = &game->pipelines[0];
|
||||||
|
|
||||||
|
VkDescriptorSet set;
|
||||||
|
VkDescriptorSetAllocateInfo alloc_info = { 0 };
|
||||||
|
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
alloc_info.descriptorPool = frame->descriptors;
|
||||||
|
alloc_info.descriptorSetCount = 1;
|
||||||
|
alloc_info.pSetLayouts = &basic->layout.set;
|
||||||
|
|
||||||
|
vk.AllocateDescriptorSets(vk.device, &alloc_info, &set);
|
||||||
|
|
||||||
|
// 'update' the descriptor sets for binding
|
||||||
|
{
|
||||||
|
VkWriteDescriptorSet writes[2] = { 0 };
|
||||||
|
|
||||||
|
VkDescriptorBufferInfo vbo_info = { 0 };
|
||||||
|
vbo_info.buffer = game->vbo.handle;
|
||||||
|
vbo_info.offset = 0;
|
||||||
|
vbo_info.range = 256;
|
||||||
|
|
||||||
|
VkDescriptorImageInfo image_info = { 0 };
|
||||||
|
image_info.imageView = game->images[6].image.view;
|
||||||
|
image_info.sampler = vk.sampler;
|
||||||
|
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
|
||||||
|
writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
writes[0].dstSet = set;
|
||||||
|
writes[0].dstBinding = 0;
|
||||||
|
writes[0].descriptorCount = 1;
|
||||||
|
writes[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||||
|
writes[0].pBufferInfo = &vbo_info;
|
||||||
|
|
||||||
|
writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
writes[1].dstSet = set;
|
||||||
|
writes[1].dstBinding = 1;
|
||||||
|
writes[1].descriptorCount = 1;
|
||||||
|
writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
writes[1].pImageInfo = &image_info;
|
||||||
|
|
||||||
|
vk.UpdateDescriptorSets(vk.device, ArraySize(writes), writes, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vk.CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, basic->handle);
|
||||||
|
vk.CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, basic->layout.pipeline, 0, 1, &set, 0, 0);
|
||||||
|
|
||||||
|
VkViewport viewport = { 0, 0, (F32) w, (F32) h, 0.0f, 1.0f };
|
||||||
|
VkRect2D scissor = { 0, 0, w, h };
|
||||||
|
|
||||||
|
vk.CmdSetViewport(cmd, 0, 1, &viewport);
|
||||||
|
vk.CmdSetScissor(cmd, 0, 1, &scissor);
|
||||||
|
|
||||||
|
vk.CmdDraw(cmd, 6, 1, 0, 0);
|
||||||
|
|
||||||
vk.CmdEndRendering(cmd);
|
vk.CmdEndRendering(cmd);
|
||||||
|
|
||||||
Vk_FrameEnd();
|
Vk_FrameEnd();
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
|
||||||
void G_ImagesLoad(M_Arena *arena) {
|
void G_ImagesLoad(G_State *game) {
|
||||||
M_TempScope(1, &arena) {
|
M_TempScope(0, 0) {
|
||||||
FS_List assets = FS_PathList(temp.arena, S("assets"));
|
FS_List assets = FS_PathList(temp.arena, S("assets"));
|
||||||
|
|
||||||
Vk_Buffer staging = Vk_BufferCreate(MB(256), true /* host_visible */);
|
Vk_Buffer staging = { 0 };
|
||||||
|
staging.size = MB(256);
|
||||||
|
staging.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
staging.host_visible = true;
|
||||||
|
|
||||||
|
Vk_BufferCreate(&staging);
|
||||||
|
|
||||||
U8 *base = staging.data;
|
U8 *base = staging.data;
|
||||||
U64 offset = 0;
|
U64 offset = 0;
|
||||||
@@ -14,12 +19,16 @@ void G_ImagesLoad(M_Arena *arena) {
|
|||||||
|
|
||||||
for (FS_Entry *it = assets.first; it != 0; it = it->next) {
|
for (FS_Entry *it = assets.first; it != 0; it = it->next) {
|
||||||
if (Str8_EndsWith(it->basename, S("png"))) {
|
if (Str8_EndsWith(it->basename, S("png"))) {
|
||||||
|
if (Str8_Equal(it->basename, S("saloon_ext.png"), 0)) {
|
||||||
|
printf("IMAGE SALOON == %d\n", n_images);
|
||||||
|
}
|
||||||
|
|
||||||
n_images += 1;
|
n_images += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkBufferImageCopy copy = { 0 };
|
VkBufferImageCopy copy = { 0 };
|
||||||
G_Image *images = M_ArenaPush(arena, G_Image, .count = n_images);
|
game->images = M_ArenaPush(game->arena, G_Image, .count = n_images);
|
||||||
n_images = 0;
|
n_images = 0;
|
||||||
|
|
||||||
// Image upload is sbi_load -> copy to staging -> upload to gpu texture
|
// Image upload is sbi_load -> copy to staging -> upload to gpu texture
|
||||||
@@ -30,7 +39,7 @@ void G_ImagesLoad(M_Arena *arena) {
|
|||||||
stbi_uc *data = stbi_load((const char *) it->path.data, &w, &h, &c, 4);
|
stbi_uc *data = stbi_load((const char *) it->path.data, &w, &h, &c, 4);
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
G_Image *image = &images[n_images];
|
G_Image *image = &game->images[n_images];
|
||||||
|
|
||||||
U64 image_sz = 4 * w * h;
|
U64 image_sz = 4 * w * h;
|
||||||
|
|
||||||
@@ -56,7 +65,7 @@ void G_ImagesLoad(M_Arena *arena) {
|
|||||||
|
|
||||||
n_images += 1;
|
n_images += 1;
|
||||||
|
|
||||||
image->name = Str8_Copy(arena, Str8_RemoveAfterLast(it->basename, '.'));
|
image->name = Str8_Copy(game->arena, Str8_RemoveAfterLast(it->basename, '.'));
|
||||||
|
|
||||||
image->image.width = w;
|
image->image.width = w;
|
||||||
image->image.height = h;
|
image->image.height = h;
|
||||||
@@ -117,3 +126,70 @@ void G_ImagesLoad(M_Arena *arena) {
|
|||||||
Vk_CommandBufferSubmit(cmds, true /* wait */);
|
Vk_CommandBufferSubmit(cmds, true /* wait */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void G_PipelinesLoad(G_State *game) {
|
||||||
|
game->pipelines = M_ArenaPush(game->arena, Vk_Pipeline, .count = 1);
|
||||||
|
|
||||||
|
Vk_Pipeline *basic = &game->pipelines[0];
|
||||||
|
|
||||||
|
VkShaderModule vshader = 0, fshader = 0;
|
||||||
|
M_TempScope(0, 0) {
|
||||||
|
Str8 vshader_code = FS_ReadEntireFile(temp.arena, S("assets/shaders/basic.vert.spv"));
|
||||||
|
Str8 fshader_code = FS_ReadEntireFile(temp.arena, S("assets/shaders/basic.frag.spv"));
|
||||||
|
|
||||||
|
VkShaderModuleCreateInfo create_info = { 0 };
|
||||||
|
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
create_info.pCode = (U32 *) vshader_code.data;
|
||||||
|
create_info.codeSize = vshader_code.count;
|
||||||
|
|
||||||
|
vk.CreateShaderModule(vk.device, &create_info, 0, &vshader);
|
||||||
|
|
||||||
|
create_info.pCode = (U32 *) fshader_code.data;
|
||||||
|
create_info.codeSize = fshader_code.count;
|
||||||
|
|
||||||
|
vk.CreateShaderModule(vk.device, &create_info, 0, &fshader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create pipeline layout, its insane what you have to do for this because the ALREADY KNOW
|
||||||
|
// all of this information
|
||||||
|
{
|
||||||
|
VkDescriptorSetLayoutBinding bindings[2] = { 0 };
|
||||||
|
|
||||||
|
bindings[0].binding = 0;
|
||||||
|
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||||
|
bindings[0].descriptorCount = 1;
|
||||||
|
bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
|
||||||
|
bindings[1].binding = 1;
|
||||||
|
bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
bindings[1].descriptorCount = 1;
|
||||||
|
bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo set_info = { 0 };
|
||||||
|
set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
set_info.bindingCount = 2;
|
||||||
|
set_info.pBindings = bindings;
|
||||||
|
|
||||||
|
vk.CreateDescriptorSetLayout(vk.device, &set_info, 0, &basic->layout.set);
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo layout_create = { 0 };
|
||||||
|
layout_create.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
layout_create.setLayoutCount = 1;
|
||||||
|
layout_create.pSetLayouts = &basic->layout.set;
|
||||||
|
|
||||||
|
vk.CreatePipelineLayout(vk.device, &layout_create, 0, &basic->layout.pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
basic->targets.items[0] = vk.swapchain.format.format;
|
||||||
|
basic->targets.count = 1;
|
||||||
|
|
||||||
|
basic->shaders.count = 2;
|
||||||
|
|
||||||
|
basic->shaders.items[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
basic->shaders.items[0].handle = vshader;
|
||||||
|
|
||||||
|
basic->shaders.items[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
basic->shaders.items[1].handle = fshader;
|
||||||
|
|
||||||
|
Vk_PipelineCreate(basic);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,34 @@
|
|||||||
#if !defined(LD_GAME_CORE_H_)
|
#if !defined(LD_GAME_CORE_H_)
|
||||||
#define LD_GAME_CORE_H_
|
#define LD_GAME_CORE_H_
|
||||||
|
|
||||||
typedef struct G_Image G_Image;
|
typedef struct G_Vertex G_Vertex;
|
||||||
struct G_Image {
|
struct G_Vertex {
|
||||||
Vk_Image image;
|
F32 x, y, z, w;
|
||||||
|
F32 u, v;
|
||||||
Str8 name;
|
U32 c;
|
||||||
|
U32 pad;
|
||||||
U32 width;
|
|
||||||
U32 height;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function void G_ImagesLoad(M_Arena *arena);
|
typedef struct G_Image G_Image;
|
||||||
|
struct G_Image {
|
||||||
|
Str8 name;
|
||||||
|
Vk_Image image;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct G_State G_State;
|
||||||
|
struct G_State {
|
||||||
|
M_Arena *arena;
|
||||||
|
|
||||||
|
U32 n_images;
|
||||||
|
G_Image *images;
|
||||||
|
|
||||||
|
U32 n_pipelines;
|
||||||
|
Vk_Pipeline *pipelines;
|
||||||
|
|
||||||
|
Vk_Buffer vbo;
|
||||||
|
};
|
||||||
|
|
||||||
|
function void G_ImagesLoad(G_State *game);
|
||||||
|
function void G_PipelinesLoad(G_State *game);
|
||||||
|
|
||||||
#endif // LD_GAME_CORE_H_
|
#endif // LD_GAME_CORE_H_
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
#include "impl/windows/core.c"
|
#include "impl/windows/core.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Str8 FS_ReadEntireFile(M_Arena *arena, Str8 path) {
|
||||||
|
Str8 result = { 0 };
|
||||||
|
|
||||||
|
OS_Handle file = FS_FileOpen(path, FS_ACCESS_READ);
|
||||||
|
if (file.v[0]) {
|
||||||
|
result.count = FS_FileSize(file);
|
||||||
|
result.data = M_ArenaPush(arena, U8, .count = result.count);
|
||||||
|
|
||||||
|
FS_FileRead(file, result.data, result.count, 0);
|
||||||
|
FS_FileClose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ function void FS_FileClose(OS_Handle file);
|
|||||||
function void FS_FileRead(OS_Handle file, void *ptr, U64 size, U64 offset);
|
function void FS_FileRead(OS_Handle file, void *ptr, U64 size, U64 offset);
|
||||||
function void FS_FileWrite(OS_Handle file, void *ptr, U64 size, U64 offset);
|
function void FS_FileWrite(OS_Handle file, void *ptr, U64 size, U64 offset);
|
||||||
|
|
||||||
|
function U64 FS_FileSize(OS_Handle file);
|
||||||
|
|
||||||
typedef U32 FS_EntryType;
|
typedef U32 FS_EntryType;
|
||||||
enum {
|
enum {
|
||||||
FS_ENTRY_TYPE_FILE = 0,
|
FS_ENTRY_TYPE_FILE = 0,
|
||||||
@@ -42,4 +44,6 @@ struct FS_List {
|
|||||||
|
|
||||||
function FS_List FS_PathList(M_Arena *arena, Str8 path);
|
function FS_List FS_PathList(M_Arena *arena, Str8 path);
|
||||||
|
|
||||||
|
function Str8 FS_ReadEntireFile(M_Arena *arena, Str8 path);
|
||||||
|
|
||||||
#endif // LD_OS_FILESYSTEM_H_
|
#endif // LD_OS_FILESYSTEM_H_
|
||||||
|
|||||||
@@ -83,6 +83,19 @@ void FS_FileWrite(OS_Handle file, void *ptr, U64 size, U64 offset) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U64 FS_FileSize(OS_Handle file) {
|
||||||
|
U64 result = 0;
|
||||||
|
HANDLE hFile = cast(HANDLE) file.v[0];
|
||||||
|
if (hFile) {
|
||||||
|
DWORD dwLow, dwHigh;
|
||||||
|
dwLow = GetFileSize(hFile, &dwHigh);
|
||||||
|
|
||||||
|
result = ((U64) dwHigh << 32) | ((U64) dwLow);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
FS_List FS_PathList(M_Arena *arena, Str8 path) {
|
FS_List FS_PathList(M_Arena *arena, Str8 path) {
|
||||||
FS_List result = { 0 };
|
FS_List result = { 0 };
|
||||||
|
|
||||||
|
|||||||
@@ -354,6 +354,23 @@ bool Vk_Setup(SDL_Window *window) {
|
|||||||
err = Min(vk.CreateFence(vk.device, &fence, 0, &frame->scratch[s].fence), err);
|
err = Min(vk.CreateFence(vk.device, &fence, 0, &frame->scratch[s].fence), err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Descriptor pool
|
||||||
|
VkDescriptorPoolSize pool_sizes[2] = { 0 };
|
||||||
|
|
||||||
|
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
pool_sizes[0].descriptorCount = 2048;
|
||||||
|
|
||||||
|
pool_sizes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||||
|
pool_sizes[1].descriptorCount = 2048;
|
||||||
|
|
||||||
|
VkDescriptorPoolCreateInfo descriptor_pool = { 0 };
|
||||||
|
descriptor_pool.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
descriptor_pool.maxSets = 1024;
|
||||||
|
descriptor_pool.poolSizeCount = 2;
|
||||||
|
descriptor_pool.pPoolSizes = pool_sizes;
|
||||||
|
|
||||||
|
vk.CreateDescriptorPool(vk.device, &descriptor_pool, 0, &frame->descriptors);
|
||||||
|
|
||||||
VkSemaphoreCreateInfo semaphore = { 0 };
|
VkSemaphoreCreateInfo semaphore = { 0 };
|
||||||
semaphore.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
semaphore.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
|
|
||||||
@@ -364,6 +381,16 @@ bool Vk_Setup(SDL_Window *window) {
|
|||||||
vk.err = err;
|
vk.err = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
VkSamplerCreateInfo create_info = { 0 };
|
||||||
|
create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
|
create_info.magFilter = VK_FILTER_NEAREST;
|
||||||
|
create_info.minFilter = VK_FILTER_NEAREST;
|
||||||
|
create_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
|
||||||
|
vk.CreateSampler(vk.device, &create_info, 0, &vk.sampler);
|
||||||
|
}
|
||||||
|
|
||||||
result = (vk.err == VK_SUCCESS);
|
result = (vk.err == VK_SUCCESS);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -376,6 +403,7 @@ Vk_Frame *Vk_FrameBegin(SDL_Window *window) {
|
|||||||
|
|
||||||
vk.ResetFences(vk.device, 1, &frame->fence);
|
vk.ResetFences(vk.device, 1, &frame->fence);
|
||||||
vk.ResetCommandPool(vk.device, frame->pool, 0);
|
vk.ResetCommandPool(vk.device, frame->pool, 0);
|
||||||
|
vk.ResetDescriptorPool(vk.device, frame->descriptors, 0);
|
||||||
|
|
||||||
VkResult res = vk.AcquireNextImageKHR(vk.device, vk.swapchain.handle, UINT64_MAX, frame->acquire, 0, &frame->image);
|
VkResult res = vk.AcquireNextImageKHR(vk.device, vk.swapchain.handle, UINT64_MAX, frame->acquire, 0, &frame->image);
|
||||||
(void) res; // @Todo: check res to see if swapchain is out of date and rebuild
|
(void) res; // @Todo: check res to see if swapchain is out of date and rebuild
|
||||||
@@ -492,9 +520,7 @@ void Vk_CommandBufferSubmit(Vk_CommandBuffer *cmds, B32 wait) {
|
|||||||
|
|
||||||
vk.QueueSubmit(vk.queue.handle, 1, &submit_info, cmds->fence);
|
vk.QueueSubmit(vk.queue.handle, 1, &submit_info, cmds->fence);
|
||||||
|
|
||||||
if (wait) {
|
if (wait) { vk.DeviceWaitIdle(vk.device); }
|
||||||
vk.DeviceWaitIdle(vk.device);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VK_HOST_VISIBLE_FLAGS (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
|
#define VK_HOST_VISIBLE_FLAGS (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
|
||||||
@@ -532,31 +558,27 @@ internal VkDeviceMemory Vk_Allocate(VkMemoryRequirements *mreq, VkMemoryProperty
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vk_Buffer Vk_BufferCreate(U64 size, B32 host_visible) {
|
void Vk_BufferCreate(Vk_Buffer *buffer) {
|
||||||
Vk_Buffer result = { 0 };
|
|
||||||
|
|
||||||
VkBufferCreateInfo create_info = { 0 };
|
VkBufferCreateInfo create_info = { 0 };
|
||||||
create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
create_info.usage = buffer->usage;
|
||||||
create_info.size = size;
|
create_info.size = buffer->size;
|
||||||
|
|
||||||
vk.CreateBuffer(vk.device, &create_info, 0, &result.handle);
|
vk.CreateBuffer(vk.device, &create_info, 0, &buffer->handle);
|
||||||
|
|
||||||
VkMemoryRequirements req;
|
VkMemoryRequirements req;
|
||||||
vk.GetBufferMemoryRequirements(vk.device, result.handle, &req);
|
vk.GetBufferMemoryRequirements(vk.device, buffer->handle, &req);
|
||||||
|
|
||||||
VkMemoryPropertyFlags usage = host_visible ? VK_HOST_VISIBLE_FLAGS : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
VkMemoryPropertyFlags usage = buffer->host_visible ? VK_HOST_VISIBLE_FLAGS : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||||
|
|
||||||
result.size = req.size;
|
buffer->size = req.size;
|
||||||
result.memory = Vk_Allocate(&req, usage);
|
buffer->memory = Vk_Allocate(&req, usage);
|
||||||
|
|
||||||
vk.BindBufferMemory(vk.device, result.handle, result.memory, 0);
|
vk.BindBufferMemory(vk.device, buffer->handle, buffer->memory, 0);
|
||||||
|
|
||||||
if (host_visible) {
|
if (buffer->host_visible) {
|
||||||
vk.MapMemory(vk.device, result.memory, 0, result.size, 0, &result.data);
|
vk.MapMemory(vk.device, buffer->memory, 0, buffer->size, 0, &buffer->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vk_ImageCreate(Vk_Image *image) {
|
void Vk_ImageCreate(Vk_Image *image) {
|
||||||
@@ -595,3 +617,95 @@ void Vk_ImageCreate(Vk_Image *image) {
|
|||||||
|
|
||||||
vk.CreateImageView(vk.device, &view_info, 0, &image->view);
|
vk.CreateImageView(vk.device, &view_info, 0, &image->view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Vk_PipelineCreate(Vk_Pipeline *pipeline) {
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo ia = { 0 };
|
||||||
|
ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo shaders[8] = { 0 };
|
||||||
|
for (U32 it = 0; it < pipeline->shaders.count; ++it) {
|
||||||
|
shaders[it].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
shaders[it].stage = pipeline->shaders.items[it].stage;
|
||||||
|
shaders[it].module = pipeline->shaders.items[it].handle;
|
||||||
|
shaders[it].pName = "main";
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineVertexInputStateCreateInfo vi = { 0 };
|
||||||
|
vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
|
||||||
|
// This will be updated later using dynamic commands but we still need to supply one here for
|
||||||
|
// some reason
|
||||||
|
VkViewport viewport = { 0, 0, 10, 10, 0, 1 };
|
||||||
|
VkRect2D scissor = { 0, 0, 10, 10 };
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo vp = { 0 };
|
||||||
|
vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
vp.viewportCount = 1;
|
||||||
|
vp.pViewports = &viewport;
|
||||||
|
vp.scissorCount = 1;
|
||||||
|
vp.pScissors = &scissor;
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo rs = { 0 };
|
||||||
|
rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
rs.lineWidth = 1.0f;
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo ms = { 0 };
|
||||||
|
ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
|
||||||
|
VkPipelineDepthStencilStateCreateInfo ds = { 0 };
|
||||||
|
ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||||
|
|
||||||
|
VkPipelineColorBlendAttachmentState blend = { 0 };
|
||||||
|
blend.blendEnable = VK_TRUE;
|
||||||
|
blend.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||||
|
blend.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
blend.colorBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
blend.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||||
|
blend.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||||
|
blend.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo om = { 0 };
|
||||||
|
om.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
om.attachmentCount = 1;
|
||||||
|
om.pAttachments = &blend;
|
||||||
|
|
||||||
|
VkDynamicState dynamic_state[] = {
|
||||||
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
|
VK_DYNAMIC_STATE_SCISSOR
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineDynamicStateCreateInfo dyn = { 0 };
|
||||||
|
dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
dyn.dynamicStateCount = ArraySize(dynamic_state);
|
||||||
|
dyn.pDynamicStates = dynamic_state;
|
||||||
|
|
||||||
|
VkFormat formats[8];
|
||||||
|
for (U32 it = 0; it < pipeline->targets.count; ++it) {
|
||||||
|
formats[it] = pipeline->targets.items[it];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineRenderingCreateInfo rendering_info = { 0 };
|
||||||
|
rendering_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
|
||||||
|
rendering_info.colorAttachmentCount = pipeline->targets.count;
|
||||||
|
rendering_info.pColorAttachmentFormats = formats;
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo create_info = { 0 };
|
||||||
|
create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
|
create_info.pNext = &rendering_info;
|
||||||
|
create_info.stageCount = pipeline->shaders.count;
|
||||||
|
create_info.pStages = shaders;
|
||||||
|
create_info.pVertexInputState = &vi;
|
||||||
|
create_info.pInputAssemblyState = &ia;
|
||||||
|
create_info.pViewportState = &vp;
|
||||||
|
create_info.pRasterizationState = &rs;
|
||||||
|
create_info.pMultisampleState = &ms;
|
||||||
|
create_info.pDepthStencilState = &ds;
|
||||||
|
create_info.pColorBlendState = &om;
|
||||||
|
create_info.pDynamicState = &dyn;
|
||||||
|
create_info.layout = pipeline->layout.pipeline;
|
||||||
|
|
||||||
|
vk.CreateGraphicsPipelines(vk.device, 0, 1, &create_info, 0, &pipeline->handle);
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,26 +25,6 @@
|
|||||||
#define VK_MAX_FRAMES_IN_FLIGHT 8
|
#define VK_MAX_FRAMES_IN_FLIGHT 8
|
||||||
#define VK_NUM_SCRATCH 8
|
#define VK_NUM_SCRATCH 8
|
||||||
|
|
||||||
typedef struct Vk_CommandBuffer Vk_CommandBuffer;
|
|
||||||
struct Vk_CommandBuffer {
|
|
||||||
VkCommandBuffer handle;
|
|
||||||
VkFence fence;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Vk_Frame Vk_Frame;
|
|
||||||
struct Vk_Frame {
|
|
||||||
VkCommandPool pool;
|
|
||||||
VkCommandBuffer cmd;
|
|
||||||
|
|
||||||
VkSemaphore acquire, complete;
|
|
||||||
VkFence fence;
|
|
||||||
|
|
||||||
U32 next_scratch;
|
|
||||||
Vk_CommandBuffer scratch[VK_NUM_SCRATCH];
|
|
||||||
|
|
||||||
U32 image; // swapchain image index
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Vk_Image Vk_Image;
|
typedef struct Vk_Image Vk_Image;
|
||||||
struct Vk_Image {
|
struct Vk_Image {
|
||||||
VkDeviceMemory memory;
|
VkDeviceMemory memory;
|
||||||
@@ -60,14 +40,65 @@ struct Vk_Image {
|
|||||||
|
|
||||||
typedef struct Vk_Buffer Vk_Buffer;
|
typedef struct Vk_Buffer Vk_Buffer;
|
||||||
struct Vk_Buffer {
|
struct Vk_Buffer {
|
||||||
|
VkBuffer handle;
|
||||||
|
|
||||||
VkDeviceMemory memory;
|
VkDeviceMemory memory;
|
||||||
VkDeviceSize size;
|
VkDeviceSize size;
|
||||||
|
|
||||||
VkBuffer handle;
|
VkBufferUsageFlags usage;
|
||||||
|
|
||||||
|
B32 host_visible;
|
||||||
void *data; // if mapped host visible memory
|
void *data; // if mapped host visible memory
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct Vk_Shader Vk_Shader;
|
||||||
|
struct Vk_Shader {
|
||||||
|
VkShaderModule handle;
|
||||||
|
VkShaderStageFlags stage;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Vk_Pipeline Vk_Pipeline;
|
||||||
|
struct Vk_Pipeline {
|
||||||
|
VkPipeline handle;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
VkPipelineLayout pipeline;
|
||||||
|
VkDescriptorSetLayout set;
|
||||||
|
} layout;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
VkFormat items[8];
|
||||||
|
U32 count;
|
||||||
|
} targets;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
Vk_Shader items[8];
|
||||||
|
U32 count;
|
||||||
|
} shaders;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Vk_CommandBuffer Vk_CommandBuffer;
|
||||||
|
struct Vk_CommandBuffer {
|
||||||
|
VkCommandBuffer handle;
|
||||||
|
VkFence fence;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Vk_Frame Vk_Frame;
|
||||||
|
struct Vk_Frame {
|
||||||
|
VkCommandPool pool;
|
||||||
|
VkCommandBuffer cmd;
|
||||||
|
|
||||||
|
VkDescriptorPool descriptors;
|
||||||
|
|
||||||
|
VkSemaphore acquire, complete;
|
||||||
|
VkFence fence;
|
||||||
|
|
||||||
|
U32 next_scratch;
|
||||||
|
Vk_CommandBuffer scratch[VK_NUM_SCRATCH];
|
||||||
|
|
||||||
|
U32 image; // swapchain image index
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct Vk_Context Vk_Context;
|
typedef struct Vk_Context Vk_Context;
|
||||||
struct Vk_Context {
|
struct Vk_Context {
|
||||||
void *lib;
|
void *lib;
|
||||||
@@ -110,6 +141,8 @@ struct Vk_Context {
|
|||||||
U32 width;
|
U32 width;
|
||||||
U32 height;
|
U32 height;
|
||||||
} swapchain;
|
} swapchain;
|
||||||
|
|
||||||
|
VkSampler sampler;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Vk_Context vk;
|
extern Vk_Context vk;
|
||||||
@@ -122,6 +155,7 @@ function void Vk_FrameEnd();
|
|||||||
function Vk_CommandBuffer *Vk_CommandBufferPush();
|
function Vk_CommandBuffer *Vk_CommandBufferPush();
|
||||||
function void Vk_CommandBufferSubmit(Vk_CommandBuffer *cmds, B32 wait);
|
function void Vk_CommandBufferSubmit(Vk_CommandBuffer *cmds, B32 wait);
|
||||||
|
|
||||||
function Vk_Buffer Vk_BufferCreate(U64 size, B32 host_visible);
|
function void Vk_BufferCreate(Vk_Buffer *buffer);
|
||||||
|
function void Vk_ImageCreate(Vk_Image *image);
|
||||||
|
|
||||||
#endif // LD_VULKAN_CORE_H_
|
#endif // LD_VULKAN_CORE_H_
|
||||||
|
|||||||
@@ -48,6 +48,20 @@
|
|||||||
VK_FUNC(GetImageMemoryRequirements);
|
VK_FUNC(GetImageMemoryRequirements);
|
||||||
VK_FUNC(BindImageMemory);
|
VK_FUNC(BindImageMemory);
|
||||||
VK_FUNC(MapMemory);
|
VK_FUNC(MapMemory);
|
||||||
|
VK_FUNC(CreateGraphicsPipelines);
|
||||||
|
VK_FUNC(CreateShaderModule);
|
||||||
|
VK_FUNC(CreateDescriptorSetLayout);
|
||||||
|
VK_FUNC(CreatePipelineLayout);
|
||||||
|
VK_FUNC(CmdBindPipeline);
|
||||||
|
VK_FUNC(CreateDescriptorPool);
|
||||||
|
VK_FUNC(ResetDescriptorPool);
|
||||||
|
VK_FUNC(AllocateDescriptorSets);
|
||||||
|
VK_FUNC(CmdBindDescriptorSets);
|
||||||
|
VK_FUNC(UpdateDescriptorSets);
|
||||||
|
VK_FUNC(CreateSampler);
|
||||||
|
VK_FUNC(CmdDraw);
|
||||||
|
VK_FUNC(CmdSetViewport);
|
||||||
|
VK_FUNC(CmdSetScissor);
|
||||||
|
|
||||||
VK_FUNC(CmdCopyBufferToImage);
|
VK_FUNC(CmdCopyBufferToImage);
|
||||||
VK_FUNC(CmdPipelineBarrier2);
|
VK_FUNC(CmdPipelineBarrier2);
|
||||||
|
|||||||
12
code/vulkan/shaders/basic.frag
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#version 460 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 frag_uv;
|
||||||
|
layout(location = 1) in vec4 frag_c;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 framebuffer;
|
||||||
|
|
||||||
|
layout(binding = 1) uniform sampler2D u_image;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
framebuffer = frag_c * texture(u_image, frag_uv);
|
||||||
|
}
|
||||||
28
code/vulkan/shaders/basic.vert
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#version 460 core
|
||||||
|
|
||||||
|
#extension GL_EXT_scalar_block_layout : enable
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
vec4 p;
|
||||||
|
vec2 uv;
|
||||||
|
uint c;
|
||||||
|
uint pad;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(binding = 0, scalar)
|
||||||
|
readonly buffer Vertices {
|
||||||
|
Vertex vtx[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 frag_uv;
|
||||||
|
layout(location = 1) out vec4 frag_c;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
Vertex v = vtx[gl_VertexIndex];
|
||||||
|
|
||||||
|
gl_Position = v.p;
|
||||||
|
|
||||||
|
frag_uv = v.uv;
|
||||||
|
frag_c = vec4((v.c >> 24) & 0xFF, (v.c >> 16) & 0xFF, (v.c >> 8) & 0xFF, (v.c >> 0) & 0xFF) / 255.0f;
|
||||||
|
frag_c = frag_c.abgr;
|
||||||
|
}
|
||||||
@@ -58,6 +58,13 @@ IF %assets% equ 1 (
|
|||||||
xcopy /Y /Q "..\assets" "assets"
|
xcopy /Y /Q "..\assets" "assets"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ECHO [Building shaders]
|
||||||
|
|
||||||
|
IF NOT EXIST "assets\shaders" ( MKDIR "assets\shaders" )
|
||||||
|
|
||||||
|
glslangValidator -o "assets\shaders\basic.vert.spv" --target-env vulkan1.3 "..\code\vulkan\shaders\basic.vert"
|
||||||
|
glslangValidator -o "assets\shaders\basic.frag.spv" --target-env vulkan1.3 "..\code\vulkan\shaders\basic.frag"
|
||||||
|
|
||||||
ECHO [Building source]
|
ECHO [Building source]
|
||||||
|
|
||||||
SET COMPILER_OPTS=-nologo -W4 -I"deps\SDL3\include" -I"deps\stb" -I"%VULKAN_SDK%\Include"
|
SET COMPILER_OPTS=-nologo -W4 -I"deps\SDL3\include" -I"deps\stb" -I"%VULKAN_SDK%\Include"
|
||||||
|
|||||||