Compare commits

..
8 Commits
Author SHA1 Message Date
abdelrahman 136853328a Render texture and fix camera target 2026-11-01 17:38:22 +00:00
abdelrahman 9536dbc550 Copy the temp buffer to the output image 2026-11-01 03:03:30 +00:00
abdelrahman 466e0345b8 Silence some warnings 2026-11-01 01:31:25 +00:00
abdelrahman 4a726321e9 Fix instance indexed shader data 2026-11-01 00:23:29 +00:00
abdelrahman f308900207 Add gpuFlushBuffer 2026-11-01 00:22:59 +00:00
abdelrahman 6c6dd5626c Instance index attempt 2026-10-31 23:58:02 +00:00
abdelrahman 9a168facec Pull latest wapp module 2026-10-29 02:18:17 +00:00
abdelrahman fe61e58a50 Update README 2026-10-29 00:34:30 +00:00
7 changed files with 421 additions and 107 deletions

No files matched your search

+1 -1
View File
@@ -73,7 +73,7 @@ copy-assets:
@cp -r $(ASSETS_DIR) $(BUILDDIR) @cp -r $(ASSETS_DIR) $(BUILDDIR)
run: run:
@cd $(BUILDDIR) && ./$(OUT_NAME) @cd $(BUILDDIR) && VK_LAYER_MESSAGE_ID_FILTER=0x8adbf7e3,0x8b6f2f9a ./$(OUT_NAME)
clean: clean:
@rm -rf $(BUILD_ROOT) @rm -rf $(BUILD_ROOT)
+6
View File
@@ -2,6 +2,12 @@
A window and a custom renderer implementation using wrappers around SDL3 and Vulkan with ability to add support for other APIs. A window and a custom renderer implementation using wrappers around SDL3 and Vulkan with ability to add support for other APIs.
## Cloning the repo
```console
git clone --recursive http://git.thewizardapprentice.com/abdelrahman/window_renderer_test.git
```
## Building ## Building
Run the following commands to build the code Run the following commands to build the code
+24 -6
View File
@@ -354,6 +354,13 @@ typedef struct GpuBufferCreateRequest {
GpuBufferUsage usage; GpuBufferUsage usage;
} GpuBufferCreateRequest; } GpuBufferCreateRequest;
typedef struct GpuBufferFlushRequest {
GpuBuffer buffer;
GpuDevice *device;
u64 offset;
u64 size;
} GpuBufferFlushRequest;
typedef struct GpuFence GpuFence; typedef struct GpuFence GpuFence;
typedef GpuFence **GpuFencePtrArray; typedef GpuFence **GpuFencePtrArray;
@@ -1159,12 +1166,21 @@ typedef struct GpuCmdDispatchBaseRequest {
u32 group_count_z; u32 group_count_z;
} GpuCmdDispatchBaseRequest; } GpuCmdDispatchBaseRequest;
typedef struct GpuQueueSubmitRequest { typedef struct GpuBufferImageCopy {
GpuSemaphorePtrArray wait_semaphores; GpuImageSubresourceLayers image_subresource;
GpuPipelineStageFlagsArray wait_dst_stage_masks; GpuOffset3d image_offset;
GpuCommandBufferPtrArray command_buffers; GpuExtent3d image_extent;
GpuSemaphorePtrArray signal_semaphores; u64 buffer_offset;
} GpuQueueSubmitRequest; } GpuBufferImageCopy;
typedef GpuBufferImageCopy *GpuBufferImageCopyArray;
typedef struct GpuCmdCopyBufferToImageRequest {
GpuCommandBuffer *command_buffer;
GpuBuffer *src_buffer;
GpuImage *dst_image;
GpuImageLayout dst_image_layout;
GpuBufferImageCopyArray copy_regions;
} GpuCmdCopyBufferToImageRequest;
GpuInstance *gpuInit(const WpAllocator *allocator, GpuInitRequest request); GpuInstance *gpuInit(const WpAllocator *allocator, GpuInitRequest request);
GpuPhysicalDevice gpuFindPhysicalDevice(const WpAllocator *allocator, const WpAllocator *temp, GpuPhysicalDevice gpuFindPhysicalDevice(const WpAllocator *allocator, const WpAllocator *temp,
@@ -1192,6 +1208,7 @@ GpuImage *gpuLoadImageFromFile(const WpAllocator *allocator
ivec3s gpuGetImageSize(GpuImage *image); ivec3s gpuGetImageSize(GpuImage *image);
GpuBuffer gpuCreateBuffer(const WpAllocator *allocator, GpuBufferCreateRequest request); GpuBuffer gpuCreateBuffer(const WpAllocator *allocator, GpuBufferCreateRequest request);
void gpuDestroyBuffer(GpuBuffer *buffer); void gpuDestroyBuffer(GpuBuffer *buffer);
void gpuFlushBuffer(GpuBufferFlushRequest request);
GpuFence *gpuCreateFence(const WpAllocator *allocator, GpuDevice *device); GpuFence *gpuCreateFence(const WpAllocator *allocator, GpuDevice *device);
void gpuDestroyFence(GpuFence *fence); void gpuDestroyFence(GpuFence *fence);
void gpuResetFences(const WpAllocator *temp, GpuResetFencesRequest request); void gpuResetFences(const WpAllocator *temp, GpuResetFencesRequest request);
@@ -1244,6 +1261,7 @@ void gpuCmdDraw(GpuCmdDrawRequest request);
void gpuCmdDrawIndexed(GpuCmdDrawIndexedRequest request); void gpuCmdDrawIndexed(GpuCmdDrawIndexedRequest request);
void gpuCmdDispatch(GpuCmdDispatchRequest request); void gpuCmdDispatch(GpuCmdDispatchRequest request);
void gpuCmdDispatchBase(GpuCmdDispatchBaseRequest request); void gpuCmdDispatchBase(GpuCmdDispatchBaseRequest request);
void gpuCmdCopyBufferToImage(const WpAllocator *temp, GpuCmdCopyBufferToImageRequest request);
#ifdef WP_PLATFORM_CPP #ifdef WP_PLATFORM_CPP
END_C_LINKAGE END_C_LINKAGE
+178 -5
View File
@@ -7,9 +7,9 @@
#include "../../window/window_inc.h" #include "../../window/window_inc.h"
#include "../../wapp/wapp.h" #include "../../wapp/wapp.h"
#include "../../cglm/struct.h" #include "../../cglm/struct.h"
#include <stdio.h>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "../../stb_image/stb_image.h" #include "../../stb_image/stb_image.h"
#include <math.h>
#include <stdint.h> #include <stdint.h>
#ifdef USE_SDL_WINDOW_BACKEND #ifdef USE_SDL_WINDOW_BACKEND
@@ -77,6 +77,7 @@ typedef VkRenderingAttachmentInfo *VkRenderingAttachmen
typedef VkSemaphoreSubmitInfo *VkSemaphoreSubmitInfoArray; typedef VkSemaphoreSubmitInfo *VkSemaphoreSubmitInfoArray;
typedef VkCommandBufferSubmitInfo *VkCommandBufferSubmitInfoArray; typedef VkCommandBufferSubmitInfo *VkCommandBufferSubmitInfoArray;
typedef VkImageBlit2 *VkImageBlit2Array; typedef VkImageBlit2 *VkImageBlit2Array;
typedef VkBufferImageCopy *VkBufferImageCopyArray;
struct GpuInstance { struct GpuInstance {
VkInstance vk_instance; VkInstance vk_instance;
@@ -315,10 +316,13 @@ wp_intern VkAttachmentStoreOp vkAttachmentStoreOpFromGpuAttachmentStore
wp_intern GpuAttachmentStoreOp gpuAttachmentStoreOpFromVkAttachmentStoreOp(VkAttachmentStoreOp op); wp_intern GpuAttachmentStoreOp gpuAttachmentStoreOpFromVkAttachmentStoreOp(VkAttachmentStoreOp op);
wp_intern VkResolveModeFlagBits vkResolveModeFlagsFromGpuResolveModeFlags(GpuResolveModeFlags flags); wp_intern VkResolveModeFlagBits vkResolveModeFlagsFromGpuResolveModeFlags(GpuResolveModeFlags flags);
wp_intern GpuResolveModeFlags gpuResolveModeFlagsFromVkResolveModeFlags(VkResolveModeFlags flags); wp_intern GpuResolveModeFlags gpuResolveModeFlagsFromVkResolveModeFlags(VkResolveModeFlags flags);
wp_intern u32 calcMaxMipLevelsForSize(ivec3s size);
GpuInstance *gpuInit(const WpAllocator *allocator, GpuInitRequest request) { GpuInstance *gpuInit(const WpAllocator *allocator, GpuInitRequest request) {
assertWithLogger(volkInitialize() == VK_SUCCESS, &logger, "Failed to initialise volk"); assertWithLogger(volkInitialize() == VK_SUCCESS, &logger, "Failed to initialise volk");
stbi_set_flip_vertically_on_load(true);
VpProfileProperties profile = { VpProfileProperties profile = {
.profileName = VP_TEST_WINDOW_RENDERER_NAME, .profileName = VP_TEST_WINDOW_RENDERER_NAME,
.specVersion = VP_TEST_WINDOW_RENDERER_SPEC_VERSION, .specVersion = VP_TEST_WINDOW_RENDERER_SPEC_VERSION,
@@ -857,6 +861,8 @@ GpuSampler *gpuCreateSampler(const WpAllocator *allocator, GpuSamplerCreateReque
wpLogDebug(&logger, wpStr8Lit("Created Vulkan sampler")); wpLogDebug(&logger, wpStr8Lit("Created Vulkan sampler"));
output->device = request.device;
return output; return output;
} }
@@ -869,6 +875,7 @@ GpuImage *gpuCreateImage(const WpAllocator *allocator, GpuImageCreateRequest req
GpuImage *output = wpMemAllocatorAlloc(allocator, sizeof(GpuImage)); GpuImage *output = wpMemAllocatorAlloc(allocator, sizeof(GpuImage));
assertWithLogger(output != NULL, &logger, "Failed to allocate image"); assertWithLogger(output != NULL, &logger, "Failed to allocate image");
u32 mip_levels = min(calcMaxMipLevelsForSize(request.size), request.subresource.level_count);
VkFormat format = vkFormatFromGpuFormat(request.format); VkFormat format = vkFormatFromGpuFormat(request.format);
VkImageCreateInfo image_create_info = { VkImageCreateInfo image_create_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
@@ -877,7 +884,7 @@ GpuImage *gpuCreateImage(const WpAllocator *allocator, GpuImageCreateRequest req
.extent = (VkExtent3D){ .width = request.size.x, .extent = (VkExtent3D){ .width = request.size.x,
.height = request.size.y, .height = request.size.y,
.depth = request.size.z }, .depth = request.size.z },
.mipLevels = request.subresource.level_count, .mipLevels = mip_levels,
.arrayLayers = request.subresource.layer_count, .arrayLayers = request.subresource.layer_count,
.samples = vkSampleCountFromGpuSampleCount(request.samples), .samples = vkSampleCountFromGpuSampleCount(request.samples),
.tiling = vkImageTilingFromGpuImageTiling(request.tiling), .tiling = vkImageTilingFromGpuImageTiling(request.tiling),
@@ -888,8 +895,24 @@ GpuImage *gpuCreateImage(const WpAllocator *allocator, GpuImageCreateRequest req
.initialLayout = vkImageLayoutFromGpuImageLayout(request.layout), .initialLayout = vkImageLayoutFromGpuImageLayout(request.layout),
}; };
// Check if the image requires a dedicated allocation
VkMemoryDedicatedRequirements dedicated_memory_reqs = {
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
};
VkMemoryRequirements2 memory_reqs = {
.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
.pNext = &dedicated_memory_reqs,
};
VkDeviceImageMemoryRequirements image_memory_reqs = {
.sType = VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS,
.pCreateInfo = &image_create_info,
};
vkGetDeviceImageMemoryRequirements(request.device->vk_device, &image_memory_reqs, &memory_reqs);
b8 requires_dedicated_memory = dedicated_memory_reqs.requiresDedicatedAllocation ||
dedicated_memory_reqs.prefersDedicatedAllocation;
VmaAllocationCreateInfo alloc_create_info = { VmaAllocationCreateInfo alloc_create_info = {
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, .flags = requires_dedicated_memory ? VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT : 0,
.usage = VMA_MEMORY_USAGE_AUTO, .usage = VMA_MEMORY_USAGE_AUTO,
}; };
@@ -932,11 +955,14 @@ GpuImage *gpuLoadImageFromFile(const WpAllocator *allocator, const WpAllocator *
wpStr8CopyToCstr(buf, &request.filename, request.filename.size + 1); wpStr8CopyToCstr(buf, &request.filename, request.filename.size + 1);
i32 width, height, channels; i32 width, height, channels;
const u8 *data = stbi_load(buf, &width, &height, &channels, 4); i32 requested_channels = 4;
const u8 *data = stbi_load(buf, &width, &height, &channels, requested_channels);
assertWithLogger(data != NULL, &logger, "Failed to load image data"); assertWithLogger(data != NULL, &logger, "Failed to load image data");
GpuDevice *device = request.command_pool->device;
GpuImageCreateRequest img_request = { GpuImageCreateRequest img_request = {
.device = request.command_pool->device, .device = device,
.size = { .x = width, .y = height, .z = 1 }, .size = { .x = width, .y = height, .z = 1 },
.type = GPU_IMAGE_TYPE_2D, .type = GPU_IMAGE_TYPE_2D,
.format = GPU_FORMAT_R8G8B8A8_SRGB, .format = GPU_FORMAT_R8G8B8A8_SRGB,
@@ -954,8 +980,114 @@ GpuImage *gpuLoadImageFromFile(const WpAllocator *allocator, const WpAllocator *
}; };
GpuImage *output = gpuCreateImage(allocator, img_request); GpuImage *output = gpuCreateImage(allocator, img_request);
u64 data_size = width * height * requested_channels * sizeof(u8);
GpuBufferCreateRequest temp_buf_request = {
.device = device,
.size = data_size,
.usage = GPU_BUFFER_USAGE_TRANSFER_SRC,
};
GpuBuffer temp_storage = gpuCreateBuffer(allocator, temp_buf_request);
memcpy(temp_storage.cpu_mapping, data, data_size);
gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = temp_storage });
stbi_image_free((void *)data); stbi_image_free((void *)data);
GpuCommandBufferAllocateRequest cb_request = {
.pool = request.command_pool,
.buffer_count = 1,
};
GpuCommandBufferPtrArray cbs = gpuAllocateCommandBuffers(allocator, temp, cb_request);
GpuCommandBuffer *cb = cbs[0];
gpuBeginCommandBuffer((GpuCommandBufferBeginRequest){ .command_buffer = cb, .one_time_submit = true });
GpuImageMemoryBarrier image_barrier = {
.image = output,
.src_stage_mask = GPU_PIPELINE_STAGE_NONE,
.src_access_mask = GPU_ACCESS_NONE,
.dst_stage_mask = GPU_PIPELINE_STAGE_TRANSFER,
.dst_access_mask = GPU_ACCESS_TRANSFER_WRITE,
.old_layout = GPU_IMAGE_LAYOUT_UNDEFINED,
.new_layout = GPU_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.subresource = {
.aspect = GPU_IMAGE_ASPECT_COLOR,
.level_count = 1,
.layer_count = 1,
}
};
GpuCmdPipelineBarrierRequest barrier_req = {
.command_buffer = cb,
.info = (GpuDependencyInfo){
.image_memory_barriers = wpArray(GpuImageMemoryBarrier, image_barrier),
},
};
gpuCmdPipelineBarrier(temp, barrier_req);
GpuCmdCopyBufferToImageRequest copy_req = {
.command_buffer = cb,
.src_buffer = &temp_storage,
.dst_image = output,
.dst_image_layout = GPU_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.copy_regions = wpArray(
GpuBufferImageCopy,
(GpuBufferImageCopy){
.image_subresource = { .layer_count = 1, .aspect_mask = GPU_IMAGE_ASPECT_COLOR },
.image_extent = { .width = width, .height = height, .depth = 1 },
}
),
};
gpuCmdCopyBufferToImage(temp, copy_req);
image_barrier = (GpuImageMemoryBarrier){
.image = output,
.src_stage_mask = GPU_PIPELINE_STAGE_TRANSFER,
.src_access_mask = GPU_ACCESS_TRANSFER_WRITE,
.dst_stage_mask = GPU_PIPELINE_STAGE_FRAGMENT_SHADER,
.dst_access_mask = GPU_ACCESS_SHADER_READ,
.old_layout = GPU_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.new_layout = GPU_IMAGE_LAYOUT_READ_ONLY_OPTIMAL,
.subresource = {
.aspect = GPU_IMAGE_ASPECT_COLOR,
.level_count = 1,
.layer_count = 1,
}
};
barrier_req = (GpuCmdPipelineBarrierRequest){
.command_buffer = cb,
.info = (GpuDependencyInfo){
.image_memory_barriers = wpArray(GpuImageMemoryBarrier, image_barrier),
},
};
gpuCmdPipelineBarrier(temp, barrier_req);
gpuEndCommandBuffer(cb);
GpuFence *fence = gpuCreateFence(allocator, device);
GpuResetFencesRequest reset_req = {
.device = device,
.fences = wpArray(GpuFence *, fence)
};
gpuResetFences(temp, reset_req);
GpuCommandBuffersSubmitRequest submit_req = {
.device = device,
.command_buffers = cbs,
.fence = fence,
};
gpuSubmitCommandBuffers(temp, submit_req);
GpuWaitForFencesRequest wait_req = {
.device = device,
.fences = wpArray(GpuFence *, fence),
.timeout = UINT64_MAX,
};
gpuWaitForFences(temp, wait_req);
gpuDestroyFence(fence);
gpuDestroyBuffer(&temp_storage);
return output; return output;
} }
@@ -1019,6 +1151,13 @@ void gpuDestroyBuffer(GpuBuffer *buffer) {
buffer->size = 0; buffer->size = 0;
} }
void gpuFlushBuffer(GpuBufferFlushRequest request) {
u64 size = request.size > 0 ? request.size : VK_WHOLE_SIZE;
VkResult vk_result = vmaFlushAllocation(request.device->allocator, request.buffer.internal->allocation,
request.offset, size);
assertWithLogger(vk_result == VK_SUCCESS, &logger, "Failed to flush buffer");
}
GpuFence *gpuCreateFence(const WpAllocator *allocator, GpuDevice *device) { GpuFence *gpuCreateFence(const WpAllocator *allocator, GpuDevice *device) {
GpuFence *fence = wpMemAllocatorAlloc(allocator, sizeof(GpuFence)); GpuFence *fence = wpMemAllocatorAlloc(allocator, sizeof(GpuFence));
assertWithLogger(fence != NULL, &logger, "Failed to allocate fence internal"); assertWithLogger(fence != NULL, &logger, "Failed to allocate fence internal");
@@ -2168,6 +2307,35 @@ void gpuCmdDispatchBase(GpuCmdDispatchBaseRequest request) {
request.group_count_z); request.group_count_z);
} }
void gpuCmdCopyBufferToImage(const WpAllocator *temp, GpuCmdCopyBufferToImageRequest request) {
u64 region_count = wpArrayCount(request.copy_regions);
VkBufferImageCopyArray copy_regions = wpArrayAllocCapacity(VkBufferImageCopy, temp, region_count,
WP_ARRAY_INIT_FILLED);
assertWithLogger(copy_regions != NULL, &logger, "Failed to allocate temp copy buffer to image arrays");
for (u64 i = 0; i < region_count; ++i) {
copy_regions[i] = (VkBufferImageCopy){
.bufferOffset = request.copy_regions[i].buffer_offset,
.imageSubresource = (VkImageSubresourceLayers){
.aspectMask = vkImageAspectFromGpuImageAspect(request.copy_regions[i].image_subresource.aspect_mask),
.baseArrayLayer = request.copy_regions[i].image_subresource.base_array_layer,
.layerCount = request.copy_regions[i].image_subresource.layer_count,
.mipLevel = request.copy_regions[i].image_subresource.mip_level,
},
.imageOffset = (VkOffset3D){ .x = request.copy_regions[i].image_offset.x,
.y = request.copy_regions[i].image_offset.y,
.z = request.copy_regions[i].image_offset.z },
.imageExtent = (VkExtent3D){ .width = request.copy_regions[i].image_extent.width,
.height = request.copy_regions[i].image_extent.height,
.depth = request.copy_regions[i].image_extent.depth },
};
}
vkCmdCopyBufferToImage(request.command_buffer->vk_buffer, request.src_buffer->internal->vk_buffer,
request.dst_image->vk_image, vkImageLayoutFromGpuImageLayout(request.dst_image_layout),
wpArrayCount(copy_regions), copy_regions);
}
wp_intern VkExtensions getInstanceExtensions(void) { wp_intern VkExtensions getInstanceExtensions(void) {
Config config = configGet(); Config config = configGet();
VkExtensions output = {0}; VkExtensions output = {0};
@@ -3555,3 +3723,8 @@ wp_intern GpuResolveModeFlags gpuResolveModeFlagsFromVkResolveModeFlags(VkResolv
return output; return output;
} }
wp_intern u32 calcMaxMipLevelsForSize(ivec3s size) {
f32 max_dim = max(max(size.x, size.y), size.z);
return (u32)(floorf(log2f(max_dim)) + 1.0f);
}
+200 -90
View File
@@ -20,16 +20,19 @@ enum Errors {
typedef struct Vertex { typedef struct Vertex {
vec3s position; vec3s position;
vec3s color; vec3s color;
vec2s uv;
} Vertex; } Vertex;
typedef Vertex *VertexArray; typedef Vertex *VertexArray;
typedef vec3s *Vec3sArray;
typedef struct ShaderData { typedef struct ShaderData {
mat4s mvp; mat4s mvp;
} ShaderData; } ShaderData;
typedef ShaderData *ShaderDataArray;
typedef struct Camera { typedef struct Camera {
vec3s position; vec3s position;
vec3s target;
vec3s up; vec3s up;
} Camera; } Camera;
@@ -43,31 +46,33 @@ typedef struct Projection {
wp_intern const VertexArray vertices = wpArray( wp_intern const VertexArray vertices = wpArray(
Vertex, Vertex,
(Vertex){ (Vertex){
.position = (vec3s){ .x = 0.0f, .y = 0.5f, .z = 0.0f }, .position = (vec3s){ .x = -0.5f, .y = -0.5f, .z = 0.0f },
.color = (vec3s){ .r = 1.0f, .g = 0.0f, .b = 0.0f }, .color = (vec3s){ .r = 1.0f, .g = 1.0f, .b = 1.0f },
.uv = (vec2s){ .x = 0.0f, .y = 0.0f },
}, },
(Vertex){ (Vertex){
.position = (vec3s){ .x = -0.5f, .y = -0.5f, .z = 0.0f }, .position = (vec3s){ .x = -0.5f, .y = 0.5f, .z = 0.0f },
.color = (vec3s){ .r = 0.0f, .g = 1.0f, .b = 0.0f }, .color = (vec3s){ .r = 1.0f, .g = 1.0f, .b = 1.0f },
.uv = (vec2s){ .x = 0.0f, .y = 1.0f },
}, },
(Vertex){ (Vertex){
.position = (vec3s){ .x = 0.5f, .y = -0.5f, .z = 0.0f }, .position = (vec3s){ .x = 0.5f, .y = -0.5f, .z = 0.0f },
.color = (vec3s){ .r = 0.0f, .g = 0.0f, .b = 1.0f }, .color = (vec3s){ .r = 1.0f, .g = 1.0f, .b = 1.0f },
.uv = (vec2s){ .x = 1.0f, .y = 0.0f },
}, },
(Vertex){ (Vertex){
.position = (vec3s){ .x = 0.25f, .y = 0.5f, .z = -1.0f }, .position = (vec3s){ .x = 0.5f, .y = 0.5f, .z = 0.0f },
.color = (vec3s){ .r = 1.00f, .g = 0.5f, .b = 0.0f }, .color = (vec3s){ .r = 1.0f, .g = 1.0f, .b = 1.0f },
.uv = (vec2s){ .x = 1.0f, .y = 1.0f },
}, },
(Vertex){ );
.position = (vec3s){ .x = -0.25f, .y = -0.5f, .z = -1.0f }, wp_intern const WpU16Array indices = wpArray(
.color = (vec3s){ .r = 1.00f, .g = 0.5f, .b = 0.0f }, u16,
}, 0, 1, 2,
(Vertex){ 1, 3, 2,
.position = (vec3s){ .x = 0.75f, .y = -0.5f, .z = -1.0f },
.color = (vec3s){ .r = 1.00f, .g = 0.5f, .b = 0.0f },
}
); );
wp_intern mat4s calculateModelViewProjection(vec3s translation, Camera camera, Projection projection);
wp_intern mat4s modelViewProjection(mat4s model, mat4s view, mat4s proj); wp_intern mat4s modelViewProjection(mat4s model, mat4s view, mat4s proj);
i32 main(void) { i32 main(void) {
@@ -129,17 +134,21 @@ i32 main(void) {
wpStr8Format(&msg, "Created swapchain %p with %" PRIu64 " images", swapchain, swapchain_image_count); wpStr8Format(&msg, "Created swapchain %p with %" PRIu64 " images", swapchain, swapchain_image_count);
wpLogInfo(&logger, msg); wpLogInfo(&logger, msg);
u64 vertices_size = sizeof(Vertex) * wpArrayCount(vertices); u64 vertices_size = wpArrayItemSize(vertices) * wpArrayCount(vertices);
u64 indices_size = wpArrayItemSize(indices) * wpArrayCount(indices);
GpuBufferCreateRequest vert_idx_buf_request = { GpuBufferCreateRequest vert_idx_buf_request = {
.device = device, .device = device,
.usage = GPU_BUFFER_USAGE_VERTEX_BUFFER, .usage = GPU_BUFFER_USAGE_VERTEX_BUFFER | GPU_BUFFER_USAGE_INDEX_BUFFER,
.size = vertices_size, .size = vertices_size + indices_size,
}; };
GpuBuffer vertex_buffer = gpuCreateBuffer(&arena, vert_idx_buf_request); GpuBuffer vert_idx_buffer = gpuCreateBuffer(&arena, vert_idx_buf_request);
memcpy(vertex_buffer.cpu_mapping, vertices, vertices_size); void *idx_buf_start = (void *)((uptr)vert_idx_buffer.cpu_mapping + vertices_size);
memcpy(vert_idx_buffer.cpu_mapping, vertices, vertices_size);
memcpy(idx_buf_start, indices, indices_size);
gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = vert_idx_buffer });
wpStr8Format(&msg, "Created buffer with size %" PRIu64 " (CPU: %p, GPU: %" PRIu64 ")", wpStr8Format(&msg, "Created buffer with size %" PRIu64 " (CPU: %p, GPU: %" PRIu64 ")",
vertex_buffer.size, vertex_buffer.cpu_mapping, vertex_buffer.gpu_device_address); vert_idx_buffer.size, vert_idx_buffer.cpu_mapping, vert_idx_buffer.gpu_device_address);
wpLogInfo(&logger, msg); wpLogInfo(&logger, msg);
GpuCommandPool *pool = gpuCreateCommandPool(&arena, device); GpuCommandPool *pool = gpuCreateCommandPool(&arena, device);
@@ -166,6 +175,17 @@ i32 main(void) {
}; };
GpuImage *texture = gpuLoadImageFromFile(&arena, &temp_arena, load_img_req); GpuImage *texture = gpuLoadImageFromFile(&arena, &temp_arena, load_img_req);
GpuSamplerCreateRequest sampler_req = {
.device = device,
.min_filter = GPU_FILTER_LINEAR,
.mag_filter = GPU_FILTER_LINEAR,
.address_mode_u = GPU_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.address_mode_v = GPU_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.address_mode_w = GPU_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.mipmap_mode = GPU_SAMPLER_MIPMAP_MODE_LINEAR,
};
GpuSampler *sampler = gpuCreateSampler(&arena, sampler_req);
GpuShaderCreateRequest shader_request = { GpuShaderCreateRequest shader_request = {
.device = device, .device = device,
.code = (void *)code, .code = (void *)code,
@@ -176,15 +196,19 @@ i32 main(void) {
wpFileClose(spirv); wpFileClose(spirv);
Vec3sArray translations = wpArray(
vec3s,
(vec3s){},
(vec3s){ .x = 1.0f, .z = -3.0f },
);
GpuBufferCreateRequest shader_data_req = { .device = device, GpuBufferCreateRequest shader_data_req = { .device = device,
.size = sizeof(ShaderData), .size = sizeof(ShaderData) * wpArrayCount(translations),
.usage = GPU_BUFFER_USAGE_STORAGE_BUFFER | .usage = GPU_BUFFER_USAGE_STORAGE_BUFFER };
GPU_BUFFER_USAGE_SHADER_DEVICE_ADDRESS };
GpuBuffer shader_data = gpuCreateBuffer(&arena, shader_data_req); GpuBuffer shader_data = gpuCreateBuffer(&arena, shader_data_req);
Camera camera = { Camera camera = {
.position = { .x = 0.0f, .y = 0.0f, .z = 2.0f }, .position = { .x = 0.0f, .y = 0.0f, .z = 2.0f },
.target = { 0 },
.up = { 0.0f, 1.0f, 0.0f }, .up = { 0.0f, 1.0f, 0.0f },
}; };
Projection projection = { Projection projection = {
@@ -193,22 +217,89 @@ i32 main(void) {
.near = 0.1f, .near = 0.1f,
.far = 100.0f, .far = 100.0f,
}; };
ShaderData data = {
.mvp = modelViewProjection( ShaderDataArray data = wpArray(
glms_mat4_identity(), ShaderData,
glms_lookat(camera.position, camera.target, camera.up), (ShaderData){
glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) .mvp = calculateModelViewProjection(translations[0], camera, projection),
},
(ShaderData){
.mvp = calculateModelViewProjection(translations[1], camera, projection),
},
);
memcpy(shader_data.cpu_mapping, data, wpArrayItemSize(data) * wpArrayCount(data));
gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = shader_data });
GpuDescriptorPoolSizeArray pool_sizes = wpArray(
GpuDescriptorPoolSize,
(GpuDescriptorPoolSize){ .type = GPU_DESCRIPTOR_TYPE_STORAGE_BUFFER, .count = 1 },
(GpuDescriptorPoolSize){ .type = GPU_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .count = 1 }
);
GpuDescriptorPoolCreateRequest desc_pool_req = {
.descriptor_pool_sizes = pool_sizes,
.device = device,
.max_sets = 20,
};
GpuDescriptorPool *desc_pool = gpuCreateDescriptorPool(&arena, desc_pool_req);
GpuDescriptorSetBindingArray bindings = wpArray(
GpuDescriptorSetBinding,
(GpuDescriptorSetBinding){
.binding = 0,
.type = GPU_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptor_count = 1,
.stages = GPU_SHADER_STAGE_VERTEX,
},
(GpuDescriptorSetBinding){
.binding = 1,
.type = GPU_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptor_count = 1,
.stages = GPU_SHADER_STAGE_FRAGMENT,
}
);
GpuDescriptorSetLayoutCreateRequest desc_set_layout_req = {
.device = device,
.bindings = bindings,
};
GpuDescriptorSetLayout *desc_set_layout = gpuCreateDescriptorSetLayout(&arena, &temp_arena, desc_set_layout_req);
GpuDescriptorSetAllocateRequest desc_sets_req = {
.pool = desc_pool,
.layouts = wpArray(GpuDescriptorSetLayout *, desc_set_layout),
};
GpuDescriptorSetPtrArray descriptor_sets = gpuAllocateDescriptorSets(&arena, &temp_arena, desc_sets_req);
GpuDescriptorSetWriteInfo shader_data_write_info = {
.set = descriptor_sets[0],
.descriptor_type = GPU_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.dst_binding = 0,
.buffer_infos = wpArray(
GpuDescriptorBufferInfo,
(GpuDescriptorBufferInfo){ .buffer = &shader_data },
), ),
}; };
memcpy(shader_data.cpu_mapping, &data, sizeof(ShaderData)); GpuDescriptorSetWriteInfo texture_write_info = {
.set = descriptor_sets[0],
GpuPushConstantRange push_constants = { .descriptor_type = GPU_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.stages = GPU_SHADER_STAGE_VERTEX, .dst_binding = 1,
.size = sizeof(shader_data.gpu_device_address), .image_infos = wpArray(
GpuDescriptorImageInfo,
(GpuDescriptorImageInfo){
.image = texture,
.image_layout = GPU_IMAGE_LAYOUT_READ_ONLY_OPTIMAL,
.sampler = sampler,
}
),
}; };
GpuDescriptorSetWriteRequest desc_set_req = {
.device = device,
.write_infos = wpArray(GpuDescriptorSetWriteInfo, shader_data_write_info, texture_write_info),
};
gpuWriteDescriptorSets(&temp_arena, desc_set_req);
GpuPipelineLayoutCreateRequest graphics_pipeline_layout_request = { GpuPipelineLayoutCreateRequest graphics_pipeline_layout_request = {
.device = device, .device = device,
.push_constants = wpArray(GpuPushConstantRange, push_constants), .descriptor_set_layouts = wpArray(GpuDescriptorSetLayout *, desc_set_layout),
}; };
GpuPipelineLayout *layout = gpuCreatePipelineLayout(&arena, &temp_arena, graphics_pipeline_layout_request); GpuPipelineLayout *layout = gpuCreatePipelineLayout(&arena, &temp_arena, graphics_pipeline_layout_request);
@@ -231,6 +322,12 @@ i32 main(void) {
.offset = offsetof(Vertex, color), .offset = offsetof(Vertex, color),
.format = GPU_FORMAT_R32G32B32_SFLOAT, .format = GPU_FORMAT_R32G32B32_SFLOAT,
}, },
(GpuVertexInputAttribute){
.location = 2,
.binding = 0,
.offset = offsetof(Vertex, uv),
.format = GPU_FORMAT_R32G32_SFLOAT,
},
); );
GpuPipelineVertexInputStateInfo vert_info = { GpuPipelineVertexInputStateInfo vert_info = {
.bindings = wpArray(GpuVertexInputBinding, vert_binding), .bindings = wpArray(GpuVertexInputBinding, vert_binding),
@@ -304,6 +401,35 @@ i32 main(void) {
.timeout = UINT64_MAX }); .timeout = UINT64_MAX });
gpuResetFences(&temp_arena, (GpuResetFencesRequest){ .device = device, .fences = fences }); gpuResetFences(&temp_arena, (GpuResetFencesRequest){ .device = device, .fences = fences });
if (windowIsKeyPressed(KEYBOARD_KEY_UP)) {
camera.position.z -= 0.01f;
data[0].mvp = calculateModelViewProjection(translations[0], camera, projection);
data[1].mvp = calculateModelViewProjection(translations[1], camera, projection);
memcpy(shader_data.cpu_mapping, data, wpArrayItemSize(data) * wpArrayCount(data));
gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = shader_data });
}
if (windowIsKeyPressed(KEYBOARD_KEY_DOWN)) {
camera.position.z += 0.01f;
data[0].mvp = calculateModelViewProjection(translations[0], camera, projection);
data[1].mvp = calculateModelViewProjection(translations[1], camera, projection);
memcpy(shader_data.cpu_mapping, data, wpArrayItemSize(data) * wpArrayCount(data));
gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = shader_data });
}
if (windowIsKeyPressed(KEYBOARD_KEY_RIGHT)) {
camera.position.x += 0.01f;
data[0].mvp = calculateModelViewProjection(translations[0], camera, projection);
data[1].mvp = calculateModelViewProjection(translations[1], camera, projection);
memcpy(shader_data.cpu_mapping, data, wpArrayItemSize(data) * wpArrayCount(data));
gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = shader_data });
}
if (windowIsKeyPressed(KEYBOARD_KEY_LEFT)) {
camera.position.x -= 0.01f;
data[0].mvp = calculateModelViewProjection(translations[0], camera, projection);
data[1].mvp = calculateModelViewProjection(translations[1], camera, projection);
memcpy(shader_data.cpu_mapping, data, wpArrayItemSize(data) * wpArrayCount(data));
gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = shader_data });
}
GpuSwapchainAcquireImageResult acquire_result = gpuAcquireNextSwapchainImage( GpuSwapchainAcquireImageResult acquire_result = gpuAcquireNextSwapchainImage(
(GpuSwapchainAcquireImageRequest){ (GpuSwapchainAcquireImageRequest){
.swapchain = swapchain, .swapchain = swapchain,
@@ -387,15 +513,6 @@ i32 main(void) {
}; };
gpuCmdBeginRendering(&temp_arena, render_request); gpuCmdBeginRendering(&temp_arena, render_request);
GpuCmdPushConstantsRequest push_const_req = {
.command_buffer = buffers[0],
.layout = layout,
.stage_flags = GPU_SHADER_STAGE_VERTEX,
.values = &shader_data.gpu_device_address,
.total_size_in_bytes = sizeof(shader_data.gpu_device_address),
};
gpuCmdPushConstants(push_const_req);
GpuViewportArray viewports = wpArray( GpuViewportArray viewports = wpArray(
GpuViewport, GpuViewport,
(GpuViewport){ .x = 0, .y = 0, (GpuViewport){ .x = 0, .y = 0,
@@ -416,18 +533,34 @@ i32 main(void) {
GpuCmdBindVertexBuffersRequest vert_bind_req = { GpuCmdBindVertexBuffersRequest vert_bind_req = {
.command_buffer = buffers[0], .command_buffer = buffers[0],
.vertex_buffers = wpArray(GpuBuffer, vertex_buffer), .vertex_buffers = wpArray(GpuBuffer, vert_idx_buffer),
.offsets = wpArray(u64, 0), .offsets = wpArray(u64, 0),
}; };
gpuCmdBindVertexBuffers(&temp_arena, vert_bind_req); gpuCmdBindVertexBuffers(&temp_arena, vert_bind_req);
GpuCmdBindIndexBufferRequest idx_bind_req = {
.index_buffer = vert_idx_buffer,
.command_buffer = buffers[0],
.offset = vertices_size,
.index_type = GPU_INDEX_TYPE_UINT16,
};
gpuCmdBindIndexBuffer(idx_bind_req);
GpuCmdBindDescriptorSetsRequest bind_desc_sets_req = {
.command_buffer = buffers[0],
.layout = layout,
.sets = descriptor_sets,
.bind_point = GPU_PIPELINE_BIND_POINT_GRAPHICS,
};
gpuCmdBindDescriptorSets(&temp_arena, bind_desc_sets_req);
gpuCmdBindPipeline((GpuCmdBindPipelineRequest){ .command_buffer = buffers[0], gpuCmdBindPipeline((GpuCmdBindPipelineRequest){ .command_buffer = buffers[0],
.bind_point = GPU_PIPELINE_BIND_POINT_GRAPHICS, .bind_point = GPU_PIPELINE_BIND_POINT_GRAPHICS,
.pipeline = pipelines[0] }); .pipeline = pipelines[0] });
gpuCmdDraw((GpuCmdDrawRequest){ .command_buffer = buffers[0], gpuCmdDrawIndexed((GpuCmdDrawIndexedRequest){ .command_buffer = buffers[0],
.vertex_count = wpArrayCount(vertices), .instance_count = wpArrayCount(translations),
.instance_count = 1 }); .index_count = wpArrayCount(indices) });
gpuCmdEndRendering(buffers[0]); gpuCmdEndRendering(buffers[0]);
@@ -470,45 +603,6 @@ i32 main(void) {
.swapchain_infos = wpArray(GpuSwpachainPresentInfo, present_info), .swapchain_infos = wpArray(GpuSwpachainPresentInfo, present_info),
}; };
gpuPresentSwapchains(&temp_arena, present_request); gpuPresentSwapchains(&temp_arena, present_request);
if (windowIsKeyPressed(KEYBOARD_KEY_UP)) {
camera.position.z -= 0.01f;
data.mvp = modelViewProjection(
glms_mat4_identity(),
glms_lookat(camera.position, camera.target, camera.up),
glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far)
);
memcpy(shader_data.cpu_mapping, &data, sizeof(ShaderData));
}
if (windowIsKeyPressed(KEYBOARD_KEY_DOWN)) {
camera.position.z += 0.01f;
data.mvp = modelViewProjection(
glms_mat4_identity(),
glms_lookat(camera.position, camera.target, camera.up),
glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far)
);
memcpy(shader_data.cpu_mapping, &data, sizeof(ShaderData));
}
if (windowIsKeyPressed(KEYBOARD_KEY_RIGHT)) {
camera.position.x += 0.01f;
camera.target.x += 0.01f;
data.mvp = modelViewProjection(
glms_mat4_identity(),
glms_lookat(camera.position, camera.target, camera.up),
glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far)
);
memcpy(shader_data.cpu_mapping, &data, sizeof(ShaderData));
}
if (windowIsKeyPressed(KEYBOARD_KEY_LEFT)) {
camera.position.x -= 0.01f;
camera.target.x -= 0.01f;
data.mvp = modelViewProjection(
glms_mat4_identity(),
glms_lookat(camera.position, camera.target, camera.up),
glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far)
);
memcpy(shader_data.cpu_mapping, &data, sizeof(ShaderData));
}
} }
gpuDeviceWaitIdle(device); gpuDeviceWaitIdle(device);
@@ -521,11 +615,14 @@ i32 main(void) {
gpuDestroyPipeline(pipelines[i]); gpuDestroyPipeline(pipelines[i]);
} }
gpuDestroyPipelineLayout(layout); gpuDestroyPipelineLayout(layout);
gpuDestroyDescriptorSetLayout(desc_set_layout);
gpuDestroyDescriptorPool(desc_pool);
gpuDestroyBuffer(&shader_data); gpuDestroyBuffer(&shader_data);
gpuDestroyShader(shader); gpuDestroyShader(shader);
gpuDestroySampler(sampler);
gpuDestroyImage(texture); gpuDestroyImage(texture);
gpuDestroyCommandPool(pool); gpuDestroyCommandPool(pool);
gpuDestroyBuffer(&vertex_buffer); gpuDestroyBuffer(&vert_idx_buffer);
gpuDestroySwapchain(swapchain); gpuDestroySwapchain(swapchain);
gpuDestroySurface(surface); gpuDestroySurface(surface);
gpuDestroyDevice(device); gpuDestroyDevice(device);
@@ -542,6 +639,19 @@ i32 main(void) {
return ERROR_NONE; return ERROR_NONE;
} }
wp_intern mat4s calculateModelViewProjection(vec3s translation, Camera camera, Projection projection) {
vec3s target = {
.x = camera.position.x,
.y = camera.position.y,
.z = camera.position.z - 2.0f
};
return modelViewProjection(
glms_translate(glms_mat4_identity(), translation),
glms_lookat(camera.position, target, camera.up),
glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far)
);
}
wp_intern mat4s modelViewProjection(mat4s model, mat4s view, mat4s proj) { wp_intern mat4s modelViewProjection(mat4s model, mat4s view, mat4s proj) {
// Matrix to flip the Y-axis since in Vulkan Y points down // Matrix to flip the Y-axis since in Vulkan Y points down
mat4s clip = { mat4s clip = {
+11 -4
View File
@@ -1,26 +1,33 @@
struct VSInput { struct VSInput {
float3 Pos; float3 Pos;
float3 Color; float3 Color;
float2 Uv;
}; };
struct ShaderData { struct ShaderData {
float4x4 mvp; float4x4 mvp;
}; };
StructuredBuffer<ShaderData> data;
Sampler2D texture;
struct VertexOutput { struct VertexOutput {
float3 Color;
float4 sv_position : SV_Position; float4 sv_position : SV_Position;
float3 Color;
float2 Uv;
}; };
[shader("vertex")] [shader("vertex")]
VertexOutput vertMain(VSInput input, uniform ShaderData *data, uint vid : SV_VertexID) { VertexOutput vertMain(VSInput input, uint idx: SV_InstanceID) {
VertexOutput output; VertexOutput output;
output.sv_position = mul(data[idx].mvp, float4(input.Pos, 1.0));
output.Color = input.Color; output.Color = input.Color;
output.sv_position = mul(data->mvp, float4(input.Pos, 1.0)); output.Uv = input.Uv;
return output; return output;
} }
[shader("fragment")] [shader("fragment")]
float4 fragMain(VertexOutput inVert) : SV_Target { float4 fragMain(VertexOutput inVert) : SV_Target {
return float4(inVert.Color, 1.0); float4 color = texture.Sample(inVert.Uv) * float4(inVert.Color, 1.0f);
return color;
} }
Vendored
+1 -1
Submodule vendor/wapp updated: 741566fafd...5687cb512c.