libs/vulkan-compute/test_pipeline.c
1/* test_pipeline.c - Test complete compute pipeline
2 *
3 * Tests shader loading, pipeline creation, buffer binding, and dispatch.
4 */
5
6#include "include/vk_compute.h"
7#include <stdio.h>
8#include <stdlib.h>
9#include <math.h>
10
11#define NUM_ELEMENTS 1024
12
13int main(void) {
14 printf("=== Vulkan Pipeline Test ===\n\n");
15
16 /* Initialize Vulkan */
17 printf("[1] Initializing Vulkan...\n");
18 VkComputeContext* ctx = vkc_init(false);
19 if (!ctx) {
20 fprintf(stderr, "ERROR: Failed to initialize Vulkan\n");
21 return 1;
22 }
23 printf(" [OK] Vulkan initialized\n");
24
25 /* Create test data */
26 printf("\n[2] Creating test data (%d floats)...\n", NUM_ELEMENTS);
27 float* input_data = malloc(NUM_ELEMENTS * sizeof(float));
28 float* output_data = calloc(NUM_ELEMENTS, sizeof(float));
29
30 for (size_t i = 0; i < NUM_ELEMENTS; i++) {
31 input_data[i] = (float)i;
32 }
33 printf(" [OK] Input: [0.0, 1.0, 2.0, ... %d.0]\n", NUM_ELEMENTS - 1);
34
35 /* Create GPU buffers */
36 printf("\n[3] Creating GPU buffers...\n");
37 VkComputeBuffer* input_buffer = vkc_create_buffer(ctx,
38 NUM_ELEMENTS * sizeof(float),
39 VKC_BUFFER_DEVICE_LOCAL);
40 VkComputeBuffer* output_buffer = vkc_create_buffer(ctx,
41 NUM_ELEMENTS * sizeof(float),
42 VKC_BUFFER_DEVICE_LOCAL);
43
44 if (!input_buffer || !output_buffer) {
45 fprintf(stderr, "ERROR: Failed to create buffers\n");
46 vkc_destroy(ctx);
47 return 1;
48 }
49 printf(" [OK] Created input and output buffers\n");
50
51 /* Upload input data */
52 printf("\n[4] Uploading data to GPU...\n");
53 VkComputeResult result = vkc_upload_buffer(ctx, input_buffer, input_data,
54 NUM_ELEMENTS * sizeof(float));
55 if (result != VKC_SUCCESS) {
56 fprintf(stderr, "ERROR: Failed to upload input data\n");
57 vkc_destroy_buffer(ctx, input_buffer);
58 vkc_destroy_buffer(ctx, output_buffer);
59 vkc_destroy(ctx);
60 return 1;
61 }
62 printf(" [OK] Uploaded %zu bytes\n", NUM_ELEMENTS * sizeof(float));
63
64 /* Create compute pipeline */
65 printf("\n[5] Loading shader and creating pipeline...\n");
66 VkComputePipeline* pipeline = vkc_create_pipeline(ctx,
67 "build/test_multiply.spv",
68 sizeof(uint32_t));
69
70 if (!pipeline) {
71 fprintf(stderr, "ERROR: Failed to create pipeline\n");
72 vkc_destroy_buffer(ctx, input_buffer);
73 vkc_destroy_buffer(ctx, output_buffer);
74 vkc_destroy(ctx);
75 return 1;
76 }
77 printf(" [OK] Pipeline created from test_multiply.spv\n");
78
79 /* Bind buffers to pipeline */
80 printf("\n[6] Binding buffers to pipeline...\n");
81 result = vkc_bind_buffer(ctx, pipeline, 0, input_buffer);
82 if (result != VKC_SUCCESS) {
83 fprintf(stderr, "ERROR: Failed to bind input buffer\n");
84 vkc_destroy_pipeline(ctx, pipeline);
85 vkc_destroy_buffer(ctx, input_buffer);
86 vkc_destroy_buffer(ctx, output_buffer);
87 vkc_destroy(ctx);
88 return 1;
89 }
90
91 result = vkc_bind_buffer(ctx, pipeline, 1, output_buffer);
92 if (result != VKC_SUCCESS) {
93 fprintf(stderr, "ERROR: Failed to bind output buffer\n");
94 vkc_destroy_pipeline(ctx, pipeline);
95 vkc_destroy_buffer(ctx, input_buffer);
96 vkc_destroy_buffer(ctx, output_buffer);
97 vkc_destroy(ctx);
98 return 1;
99 }
100 printf(" [OK] Buffers bound to bindings 0 and 1\n");
101
102 /* Dispatch compute shader */
103 printf("\n[7] Dispatching compute shader...\n");
104 uint32_t push_constant = NUM_ELEMENTS;
105 uint32_t workgroup_count = (NUM_ELEMENTS + 255) / 256;
106
107 printf(" Workgroups: %u (256 threads each)\n", workgroup_count);
108 printf(" Push constant: count=%u\n", push_constant);
109
110 result = vkc_dispatch(ctx, pipeline, workgroup_count, 1, 1, &push_constant);
111 if (result != VKC_SUCCESS) {
112 fprintf(stderr, "ERROR: Failed to dispatch shader: %s\n",
113 vkc_get_error_string(result));
114 vkc_destroy_pipeline(ctx, pipeline);
115 vkc_destroy_buffer(ctx, input_buffer);
116 vkc_destroy_buffer(ctx, output_buffer);
117 vkc_destroy(ctx);
118 return 1;
119 }
120 printf(" [OK] Shader executed successfully\n");
121
122 /* Download results */
123 printf("\n[8] Downloading results from GPU...\n");
124 result = vkc_download_buffer(ctx, output_buffer, output_data,
125 NUM_ELEMENTS * sizeof(float));
126 if (result != VKC_SUCCESS) {
127 fprintf(stderr, "ERROR: Failed to download output data\n");
128 vkc_destroy_pipeline(ctx, pipeline);
129 vkc_destroy_buffer(ctx, input_buffer);
130 vkc_destroy_buffer(ctx, output_buffer);
131 vkc_destroy(ctx);
132 return 1;
133 }
134 printf(" [OK] Downloaded %zu bytes\n", NUM_ELEMENTS * sizeof(float));
135
136 /* Verify results */
137 printf("\n[9] Verifying results...\n");
138 bool all_correct = true;
139 int error_count = 0;
140
141 for (size_t i = 0; i < NUM_ELEMENTS; i++) {
142 float expected = input_data[i] * 2.0f;
143 if (fabs(output_data[i] - expected) > 0.0001f) {
144 if (error_count < 5) {
145 fprintf(stderr, " MISMATCH at index %zu: expected %.1f, got %.1f\n",
146 i, expected, output_data[i]);
147 }
148 all_correct = false;
149 error_count++;
150 }
151 }
152
153 if (all_correct) {
154 printf(" [SUCCESS] All %d values correct!\n", NUM_ELEMENTS);
155 printf(" Sample results: [0.0, 2.0, 4.0, ... %d.0]\n",
156 (NUM_ELEMENTS - 1) * 2);
157 } else {
158 fprintf(stderr, " [FAILED] %d errors found\n", error_count);
159 }
160
161 /* Cleanup */
162 printf("\n[10] Cleaning up...\n");
163 free(input_data);
164 free(output_data);
165 vkc_destroy_pipeline(ctx, pipeline);
166 vkc_destroy_buffer(ctx, input_buffer);
167 vkc_destroy_buffer(ctx, output_buffer);
168 vkc_destroy(ctx);
169
170 if (all_correct) {
171 printf("\n[SUCCESS] Pipeline test passed!\n");
172 return 0;
173 } else {
174 printf("\n[FAILED] Pipeline test failed\n");
175 return 1;
176 }
177}
178