diff --git a/assets/npc_00.png b/assets/npc_00.png new file mode 100644 index 0000000..2ec78e1 Binary files /dev/null and b/assets/npc_00.png differ diff --git a/assets/oath_corner_inner.png b/assets/oath_corner_inner.png new file mode 100644 index 0000000..3ee040d Binary files /dev/null and b/assets/oath_corner_inner.png differ diff --git a/assets/path_corner.png b/assets/path_corner.png new file mode 100644 index 0000000..679e87a Binary files /dev/null and b/assets/path_corner.png differ diff --git a/assets/path_middle.png b/assets/path_middle.png new file mode 100644 index 0000000..53d815c Binary files /dev/null and b/assets/path_middle.png differ diff --git a/assets/path_middle_edge.png b/assets/path_middle_edge.png new file mode 100644 index 0000000..dff3b8c Binary files /dev/null and b/assets/path_middle_edge.png differ diff --git a/assets/saloon_ext.png b/assets/saloon_ext.png new file mode 100644 index 0000000..3705ef2 Binary files /dev/null and b/assets/saloon_ext.png differ diff --git a/assets/tile_detail_0.png b/assets/tile_detail_0.png new file mode 100644 index 0000000..9d2d4e2 Binary files /dev/null and b/assets/tile_detail_0.png differ diff --git a/assets/tile_detail_1.png b/assets/tile_detail_1.png new file mode 100644 index 0000000..5b8c8e3 Binary files /dev/null and b/assets/tile_detail_1.png differ diff --git a/assets/tile_detail_2.png b/assets/tile_detail_2.png new file mode 100644 index 0000000..d2dadd1 Binary files /dev/null and b/assets/tile_detail_2.png differ diff --git a/assets/tile_detail_3.png b/assets/tile_detail_3.png new file mode 100644 index 0000000..892b79f Binary files /dev/null and b/assets/tile_detail_3.png differ diff --git a/assets/tile_detail_4.png b/assets/tile_detail_4.png new file mode 100644 index 0000000..96dc324 Binary files /dev/null and b/assets/tile_detail_4.png differ diff --git a/assets/tile_detail_5.png b/assets/tile_detail_5.png new file mode 100644 index 0000000..12ca6b8 Binary files /dev/null and b/assets/tile_detail_5.png differ diff --git a/assets/tile_detail_6.png b/assets/tile_detail_6.png new file mode 100644 index 0000000..0ea1098 Binary files /dev/null and b/assets/tile_detail_6.png differ diff --git a/assets/tile_dirt_0.png b/assets/tile_dirt_0.png new file mode 100644 index 0000000..cc5209a Binary files /dev/null and b/assets/tile_dirt_0.png differ diff --git a/assets/tile_dirt_1.png b/assets/tile_dirt_1.png new file mode 100644 index 0000000..51431e6 Binary files /dev/null and b/assets/tile_dirt_1.png differ diff --git a/code/first.c b/code/first.c index 4f5b271..6b8cd35 100644 --- a/code/first.c +++ b/code/first.c @@ -29,9 +29,33 @@ int main(int argc, char **argv) { 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)); - G_ImagesLoad(garena); + game->arena = arena; + + 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; while (running) { @@ -69,6 +93,59 @@ int main(int argc, char **argv) { 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_FrameEnd(); diff --git a/code/game/core.c b/code/game/core.c index 3a63d7a..7caf30e 100644 --- a/code/game/core.c +++ b/code/game/core.c @@ -1,9 +1,14 @@ -void G_ImagesLoad(M_Arena *arena) { - M_TempScope(1, &arena) { +void G_ImagesLoad(G_State *game) { + M_TempScope(0, 0) { 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; U64 offset = 0; @@ -14,12 +19,16 @@ void G_ImagesLoad(M_Arena *arena) { for (FS_Entry *it = assets.first; it != 0; it = it->next) { 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; } } 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; // 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); if (data) { - G_Image *image = &images[n_images]; + G_Image *image = &game->images[n_images]; U64 image_sz = 4 * w * h; @@ -56,7 +65,7 @@ void G_ImagesLoad(M_Arena *arena) { 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.height = h; @@ -117,3 +126,70 @@ void G_ImagesLoad(M_Arena *arena) { 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); +} diff --git a/code/game/core.h b/code/game/core.h index 63d9c47..37df55b 100644 --- a/code/game/core.h +++ b/code/game/core.h @@ -1,16 +1,34 @@ #if !defined(LD_GAME_CORE_H_) #define LD_GAME_CORE_H_ -typedef struct G_Image G_Image; -struct G_Image { - Vk_Image image; - - Str8 name; - - U32 width; - U32 height; +typedef struct G_Vertex G_Vertex; +struct G_Vertex { + F32 x, y, z, w; + F32 u, v; + U32 c; + U32 pad; }; -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_ diff --git a/code/os/core.c b/code/os/core.c index e442952..15ce626 100644 --- a/code/os/core.c +++ b/code/os/core.c @@ -1,3 +1,19 @@ #if OS_WINDOWS #include "impl/windows/core.c" #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; +} diff --git a/code/os/filesystem.h b/code/os/filesystem.h index 180966e..23694f4 100644 --- a/code/os/filesystem.h +++ b/code/os/filesystem.h @@ -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_FileWrite(OS_Handle file, void *ptr, U64 size, U64 offset); +function U64 FS_FileSize(OS_Handle file); + typedef U32 FS_EntryType; enum { FS_ENTRY_TYPE_FILE = 0, @@ -42,4 +44,6 @@ struct FS_List { function FS_List FS_PathList(M_Arena *arena, Str8 path); +function Str8 FS_ReadEntireFile(M_Arena *arena, Str8 path); + #endif // LD_OS_FILESYSTEM_H_ diff --git a/code/os/impl/windows/filesystem.c b/code/os/impl/windows/filesystem.c index 5b960ff..3f6575f 100644 --- a/code/os/impl/windows/filesystem.c +++ b/code/os/impl/windows/filesystem.c @@ -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 result = { 0 }; diff --git a/code/vulkan/core.c b/code/vulkan/core.c index fa27a51..01201e2 100644 --- a/code/vulkan/core.c +++ b/code/vulkan/core.c @@ -354,6 +354,23 @@ bool Vk_Setup(SDL_Window *window) { 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 }; semaphore.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; @@ -364,6 +381,16 @@ bool Vk_Setup(SDL_Window *window) { 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); return result; } @@ -376,6 +403,7 @@ Vk_Frame *Vk_FrameBegin(SDL_Window *window) { vk.ResetFences(vk.device, 1, &frame->fence); 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); (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); - if (wait) { - vk.DeviceWaitIdle(vk.device); - } + if (wait) { vk.DeviceWaitIdle(vk.device); } } #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; } -Vk_Buffer Vk_BufferCreate(U64 size, B32 host_visible) { - Vk_Buffer result = { 0 }; - +void Vk_BufferCreate(Vk_Buffer *buffer) { VkBufferCreateInfo create_info = { 0 }; create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - create_info.size = size; + create_info.usage = buffer->usage; + 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; - 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; - result.memory = Vk_Allocate(&req, usage); + buffer->size = req.size; + 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) { - vk.MapMemory(vk.device, result.memory, 0, result.size, 0, &result.data); + if (buffer->host_visible) { + vk.MapMemory(vk.device, buffer->memory, 0, buffer->size, 0, &buffer->data); } - - return result; } 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); } + +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); +} diff --git a/code/vulkan/core.h b/code/vulkan/core.h index 8c5cc9e..b6849bf 100644 --- a/code/vulkan/core.h +++ b/code/vulkan/core.h @@ -25,26 +25,6 @@ #define VK_MAX_FRAMES_IN_FLIGHT 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; struct Vk_Image { VkDeviceMemory memory; @@ -60,14 +40,65 @@ struct Vk_Image { typedef struct Vk_Buffer Vk_Buffer; struct Vk_Buffer { + VkBuffer handle; + VkDeviceMemory memory; VkDeviceSize size; - VkBuffer handle; + VkBufferUsageFlags usage; + B32 host_visible; 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; struct Vk_Context { void *lib; @@ -110,6 +141,8 @@ struct Vk_Context { U32 width; U32 height; } swapchain; + + VkSampler sampler; }; extern Vk_Context vk; @@ -122,6 +155,7 @@ function void Vk_FrameEnd(); function Vk_CommandBuffer *Vk_CommandBufferPush(); 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_ diff --git a/code/vulkan/functions.h b/code/vulkan/functions.h index 9103cf9..afd5e41 100644 --- a/code/vulkan/functions.h +++ b/code/vulkan/functions.h @@ -48,6 +48,20 @@ VK_FUNC(GetImageMemoryRequirements); VK_FUNC(BindImageMemory); 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(CmdPipelineBarrier2); diff --git a/code/vulkan/shaders/basic.frag b/code/vulkan/shaders/basic.frag new file mode 100644 index 0000000..8886c82 --- /dev/null +++ b/code/vulkan/shaders/basic.frag @@ -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); +} diff --git a/code/vulkan/shaders/basic.vert b/code/vulkan/shaders/basic.vert new file mode 100644 index 0000000..f0b8dfe --- /dev/null +++ b/code/vulkan/shaders/basic.vert @@ -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; +} diff --git a/windows.bat b/windows.bat index a5a4012..e1b3c00 100644 --- a/windows.bat +++ b/windows.bat @@ -58,6 +58,13 @@ IF %assets% equ 1 ( 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] SET COMPILER_OPTS=-nologo -W4 -I"deps\SDL3\include" -I"deps\stb" -I"%VULKAN_SDK%\Include"