mojoshader_vulkan.c
changeset 1276 89c389e4112f
parent 1275 7fc13cff18ff
child 1277 da61410edbc9
equal deleted inserted replaced
1275:7fc13cff18ff 1276:89c389e4112f
    18     typedef ret (VKAPI_CALL *vkfntype_MOJOSHADER_##func) params;
    18     typedef ret (VKAPI_CALL *vkfntype_MOJOSHADER_##func) params;
    19 #define VULKAN_DEVICE_FUNCTION(ret, func, params) \
    19 #define VULKAN_DEVICE_FUNCTION(ret, func, params) \
    20 	typedef ret (VKAPI_CALL *vkfntype_MOJOSHADER_##func) params;
    20 	typedef ret (VKAPI_CALL *vkfntype_MOJOSHADER_##func) params;
    21 #include "mojoshader_vulkan_vkfuncs.h"
    21 #include "mojoshader_vulkan_vkfuncs.h"
    22 
    22 
    23 #define UBO_BUFFER_COUNT 8
    23 #define UBO_BUFFER_SIZE 8000000 // 8MB
    24 #define UBO_BUFFER_SIZE 1048576 /* ~1MB */
       
    25 
    24 
    26 // Internal struct defs...
    25 // Internal struct defs...
    27 
    26 
    28 typedef struct MOJOSHADER_vkShader
    27 typedef struct MOJOSHADER_vkShader
    29 {
    28 {
    33 } MOJOSHADER_vkShader;
    32 } MOJOSHADER_vkShader;
    34 
    33 
    35 typedef struct MOJOSHADER_vkUniformBuffer
    34 typedef struct MOJOSHADER_vkUniformBuffer
    36 {
    35 {
    37     VkBuffer buffer;
    36     VkBuffer buffer;
       
    37     VkDeviceMemory deviceMemory;
    38     VkDeviceSize bufferSize;
    38     VkDeviceSize bufferSize;
    39     VkDeviceSize memoryOffset;
       
    40     VkDeviceSize dynamicOffset;
    39     VkDeviceSize dynamicOffset;
    41     VkDeviceSize currentBlockSize;
    40     VkDeviceSize currentBlockSize;
    42     int32_t full; // Records frame on which it became full, -1 if not full
    41     uint8_t *mapPointer;
    43 } MOJOSHADER_vkUniformBuffer;
    42 } MOJOSHADER_vkUniformBuffer;
    44 
    43 
    45 // Error state...
    44 // Error state...
    46 static char error_buffer[1024] = { '\0' };
    45 static char error_buffer[1024] = { '\0' };
    47 
    46 
    53 static inline void out_of_memory(void)
    52 static inline void out_of_memory(void)
    54 {
    53 {
    55     set_error("out of memory");
    54     set_error("out of memory");
    56 } // out_of_memory
    55 } // out_of_memory
    57 
    56 
    58 /* Max entries for each register file type */
    57 // Max entries for each register file type
    59 #define MAX_REG_FILE_F 8192
    58 #define MAX_REG_FILE_F 8192
    60 #define MAX_REG_FILE_I 2047
    59 #define MAX_REG_FILE_I 2047
    61 #define MAX_REG_FILE_B 2047
    60 #define MAX_REG_FILE_B 2047
    62 
    61 
    63 typedef struct MOJOSHADER_vkContext
    62 typedef struct MOJOSHADER_vkContext
    85     uint8_t vs_reg_file_b[MAX_REG_FILE_B * 4];
    84     uint8_t vs_reg_file_b[MAX_REG_FILE_B * 4];
    86     float ps_reg_file_f[MAX_REG_FILE_F * 4];
    85     float ps_reg_file_f[MAX_REG_FILE_F * 4];
    87     int32_t ps_reg_file_i[MAX_REG_FILE_I * 4];
    86     int32_t ps_reg_file_i[MAX_REG_FILE_I * 4];
    88     uint8_t ps_reg_file_b[MAX_REG_FILE_B * 4];
    87     uint8_t ps_reg_file_b[MAX_REG_FILE_B * 4];
    89 
    88 
    90     VkDeviceMemory vertUboMemory;
    89     MOJOSHADER_vkUniformBuffer *vertUboBuffer;
    91     MOJOSHADER_vkUniformBuffer **vertUboBuffers;
    90     MOJOSHADER_vkUniformBuffer *fragUboBuffer;
    92     uint32_t vertUboCurrentIndex;
       
    93 
       
    94     VkDeviceMemory fragUboMemory;
       
    95     MOJOSHADER_vkUniformBuffer **fragUboBuffers;
       
    96     uint32_t fragUboCurrentIndex;
       
    97 
       
    98     uint32_t uboBufferCount;
       
    99 
    91 
   100     MOJOSHADER_vkShader *vertexShader;
    92     MOJOSHADER_vkShader *vertexShader;
   101     MOJOSHADER_vkShader *pixelShader;
    93     MOJOSHADER_vkShader *pixelShader;
   102 
       
   103     uint32_t currentFrame;
       
   104 
    94 
   105     #define VULKAN_INSTANCE_FUNCTION(ret, func, params) \
    95     #define VULKAN_INSTANCE_FUNCTION(ret, func, params) \
   106         vkfntype_MOJOSHADER_##func func;
    96         vkfntype_MOJOSHADER_##func func;
   107     #define VULKAN_DEVICE_FUNCTION(ret, func, params) \
    97     #define VULKAN_DEVICE_FUNCTION(ret, func, params) \
   108         vkfntype_MOJOSHADER_##func func;
    98         vkfntype_MOJOSHADER_##func func;
   141         ctx->minUniformBufferOffsetAlignment *
   131         ctx->minUniformBufferOffsetAlignment *
   142         ctx->minUniformBufferOffsetAlignment
   132         ctx->minUniformBufferOffsetAlignment
   143     );
   133     );
   144 } // next_highest_offset_alignment
   134 } // next_highest_offset_alignment
   145 
   135 
   146 static MOJOSHADER_vkUniformBuffer *create_ubo(MOJOSHADER_vkContext *ctx,
   136 static MOJOSHADER_vkUniformBuffer *create_ubo(MOJOSHADER_vkContext *ctx)
   147                                               MOJOSHADER_malloc m,
   137 {
   148                                               void *d
   138     MOJOSHADER_vkUniformBuffer *result = (MOJOSHADER_vkUniformBuffer *) ctx->malloc_fn(
   149 ) {
       
   150     MOJOSHADER_vkUniformBuffer *result = (MOJOSHADER_vkUniformBuffer *) m(
       
   151         sizeof(MOJOSHADER_vkUniformBuffer),
   139         sizeof(MOJOSHADER_vkUniformBuffer),
   152         d
   140         ctx->malloc_data
   153     );
   141     );
   154     VkBufferCreateInfo bufferCreateInfo =
   142     VkBufferCreateInfo bufferCreateInfo =
   155     {
   143     {
   156         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
   144         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
       
   145     };
       
   146     VkMemoryRequirements memoryRequirements;
       
   147     VkMemoryAllocateInfo allocateInfo =
       
   148     {
       
   149         VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
   157     };
   150     };
   158 
   151 
   159     bufferCreateInfo.flags = 0;
   152     bufferCreateInfo.flags = 0;
   160     bufferCreateInfo.size = UBO_BUFFER_SIZE;
   153     bufferCreateInfo.size = UBO_BUFFER_SIZE;
   161     bufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
   154     bufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
   168         &bufferCreateInfo,
   161         &bufferCreateInfo,
   169         NULL,
   162         NULL,
   170         &result->buffer
   163         &result->buffer
   171     );
   164     );
   172 
   165 
       
   166     ctx->vkGetBufferMemoryRequirements(
       
   167         *ctx->logical_device,
       
   168         result->buffer,
       
   169         &memoryRequirements
       
   170     );
       
   171 
       
   172     allocateInfo.allocationSize = UBO_BUFFER_SIZE;
       
   173 
       
   174     if (!find_memory_type(ctx,
       
   175                           memoryRequirements.memoryTypeBits,
       
   176                           VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
       
   177                           &allocateInfo.memoryTypeIndex))
       
   178     {
       
   179         set_error("failed to find suitable memory type for UBO memory");
       
   180         return NULL;
       
   181     } // if
       
   182 
       
   183     ctx->vkAllocateMemory(*ctx->logical_device,
       
   184                           &allocateInfo,
       
   185                           NULL,
       
   186                           &result->deviceMemory
       
   187     );
       
   188 
       
   189     ctx->vkBindBufferMemory(*ctx->logical_device,
       
   190                             result->buffer,
       
   191                             result->deviceMemory,
       
   192                             0
       
   193     );
       
   194 
       
   195     ctx->vkMapMemory(*ctx->logical_device,
       
   196                      result->deviceMemory,
       
   197                      0,
       
   198                      UBO_BUFFER_SIZE,
       
   199                      0,
       
   200                      (void**) &result->mapPointer
       
   201     );
       
   202 
   173     result->bufferSize = UBO_BUFFER_SIZE;
   203     result->bufferSize = UBO_BUFFER_SIZE;
   174     result->currentBlockSize = 0;
   204     result->currentBlockSize = 0;
   175     result->dynamicOffset = 0;
   205     result->dynamicOffset = 0;
   176     result->full = -1;
       
   177 
   206 
   178     return result;
   207     return result;
   179 } // create_ubo
   208 } // create_ubo
   180 
   209 
   181 static uint32_t uniform_data_size(MOJOSHADER_vkShader *shader)
   210 static uint32_t uniform_data_size(MOJOSHADER_vkShader *shader)
   196 {
   225 {
   197     if (shader == NULL || shader->parseData->uniform_count == 0)
   226     if (shader == NULL || shader->parseData->uniform_count == 0)
   198         return VK_NULL_HANDLE;
   227         return VK_NULL_HANDLE;
   199 
   228 
   200     if (shader->parseData->shader_type == MOJOSHADER_TYPE_VERTEX)
   229     if (shader->parseData->shader_type == MOJOSHADER_TYPE_VERTEX)
   201         return ctx->vertUboBuffers[ctx->vertUboCurrentIndex]->buffer;
   230         return ctx->vertUboBuffer->buffer;
   202     else
   231     else
   203         return ctx->fragUboBuffers[ctx->fragUboCurrentIndex]->buffer;
   232         return ctx->fragUboBuffer->buffer;
   204 } // get_uniform_buffer
   233 } // get_uniform_buffer
   205 
   234 
   206 static VkDeviceSize get_uniform_offset(MOJOSHADER_vkShader *shader)
   235 static VkDeviceSize get_uniform_offset(MOJOSHADER_vkShader *shader)
   207 {
   236 {
   208     if (shader == NULL || shader->parseData->uniform_count == 0)
   237     if (shader == NULL || shader->parseData->uniform_count == 0)
   209         return 0;
   238         return 0;
   210 
   239 
   211     if (shader->parseData->shader_type == MOJOSHADER_TYPE_VERTEX)
   240     if (shader->parseData->shader_type == MOJOSHADER_TYPE_VERTEX)
   212         return ctx->vertUboBuffers[ctx->vertUboCurrentIndex]->dynamicOffset;
   241         return ctx->vertUboBuffer->dynamicOffset;
   213     else
   242     else
   214         return ctx->fragUboBuffers[ctx->fragUboCurrentIndex]->dynamicOffset;
   243         return ctx->fragUboBuffer->dynamicOffset;
   215 } // get_uniform_offset
   244 } // get_uniform_offset
   216 
   245 
   217 static VkDeviceSize get_uniform_size(MOJOSHADER_vkShader *shader)
   246 static VkDeviceSize get_uniform_size(MOJOSHADER_vkShader *shader)
   218 {
   247 {
   219     if (shader == NULL || shader->parseData->uniform_count == 0)
   248     if (shader == NULL || shader->parseData->uniform_count == 0)
   220         return 0;
   249         return 0;
   221 
   250 
   222     if (shader->parseData->shader_type == MOJOSHADER_TYPE_VERTEX)
   251     if (shader->parseData->shader_type == MOJOSHADER_TYPE_VERTEX)
   223         return ctx->vertUboBuffers[ctx->vertUboCurrentIndex]->currentBlockSize;
   252         return ctx->vertUboBuffer->currentBlockSize;
   224     else
   253     else
   225         return ctx->fragUboBuffers[ctx->fragUboCurrentIndex]->currentBlockSize;
   254         return ctx->fragUboBuffer->currentBlockSize;
   226 } // get_uniform_size
   255 } // get_uniform_size
   227 
   256 
   228 static void update_uniform_buffer(MOJOSHADER_vkShader *shader)
   257 static void update_uniform_buffer(MOJOSHADER_vkShader *shader)
   229 {
   258 {
   230     int32_t i, j;
   259     int32_t i, j;
   231     void *map;
       
   232     int32_t offset;
   260     int32_t offset;
   233     uint8_t *contents;
   261     uint8_t *contents;
   234     uint32_t *contentsI;
   262     uint32_t *contentsI;
   235     float *regF; int *regI; uint8_t *regB;
   263     float *regF; int *regI; uint8_t *regB;
   236     MOJOSHADER_vkUniformBuffer *ubo;
   264     MOJOSHADER_vkUniformBuffer *ubo;
   237     VkDeviceMemory uboMemory;
       
   238 
   265 
   239     if (shader == NULL || shader->parseData->uniform_count == 0)
   266     if (shader == NULL || shader->parseData->uniform_count == 0)
   240         return;
   267         return;
   241 
   268 
   242     if (shader->parseData->shader_type == MOJOSHADER_TYPE_VERTEX)
   269     if (shader->parseData->shader_type == MOJOSHADER_TYPE_VERTEX)
   243     {
   270     {
   244         regF = ctx->vs_reg_file_f;
   271         regF = ctx->vs_reg_file_f;
   245         regI = ctx->vs_reg_file_i;
   272         regI = ctx->vs_reg_file_i;
   246         regB = ctx->vs_reg_file_b;
   273         regB = ctx->vs_reg_file_b;
   247 
   274 
   248         ubo = ctx->vertUboBuffers[ctx->vertUboCurrentIndex];
   275         ubo = ctx->vertUboBuffer;
   249         uboMemory = ctx->vertUboMemory;
       
   250     } // if
   276     } // if
   251     else
   277     else
   252     {
   278     {
   253         regF = ctx->ps_reg_file_f;
   279         regF = ctx->ps_reg_file_f;
   254         regI = ctx->ps_reg_file_i;
   280         regI = ctx->ps_reg_file_i;
   255         regB = ctx->ps_reg_file_b;
   281         regB = ctx->ps_reg_file_b;
   256 
   282 
   257         ubo = ctx->fragUboBuffers[ctx->fragUboCurrentIndex];
   283         ubo = ctx->fragUboBuffer;
   258         uboMemory = ctx->fragUboMemory;
       
   259     } // else
   284     } // else
   260 
   285 
   261     ubo->dynamicOffset += ubo->currentBlockSize;
   286     ubo->dynamicOffset += ubo->currentBlockSize;
   262 
   287 
   263     ubo->currentBlockSize = next_highest_offset_alignment(uniform_data_size(shader));
   288     ubo->currentBlockSize = next_highest_offset_alignment(uniform_data_size(shader));
   264 
   289 
   265     // Rotate buffer if it would overrun
       
   266     if (ubo->dynamicOffset + ubo->currentBlockSize >= ubo->bufferSize)
   290     if (ubo->dynamicOffset + ubo->currentBlockSize >= ubo->bufferSize)
   267     {
   291     {
   268         ubo->full = ctx->currentFrame;
   292         set_error("UBO overflow!!");
   269 
   293     } // if
   270         if (shader->parseData->shader_type == MOJOSHADER_TYPE_VERTEX)
   294 
   271         {
   295     contents = ubo->mapPointer + ubo->dynamicOffset;
   272             for (i = 0; i < ctx->uboBufferCount; i++)
       
   273             {
       
   274                 ctx->vertUboCurrentIndex = (ctx->vertUboCurrentIndex + 1) % ctx->uboBufferCount;
       
   275                 if (ctx->vertUboBuffers[ctx->vertUboCurrentIndex]->full == -1)
       
   276                     break;
       
   277             } // for
       
   278 
       
   279             ubo = ctx->vertUboBuffers[ctx->vertUboCurrentIndex];
       
   280         }
       
   281         else
       
   282         {
       
   283             for (int i = 0; i < ctx->uboBufferCount; i++)
       
   284             {
       
   285                 ctx->fragUboCurrentIndex = (ctx->fragUboCurrentIndex + 1) % ctx->uboBufferCount;
       
   286                 if (ctx->fragUboBuffers[ctx->fragUboCurrentIndex]->full == -1)
       
   287                     break;
       
   288             } // for
       
   289 
       
   290             ubo = ctx->fragUboBuffers[ctx->fragUboCurrentIndex];
       
   291         } // else
       
   292 
       
   293         ubo->dynamicOffset = 0;
       
   294         ubo->currentBlockSize = next_highest_offset_alignment(uniform_data_size(shader));
       
   295 
       
   296         if (ubo->full >= 0)
       
   297             set_error("all UBO buffers are full");
       
   298     } // if
       
   299 
       
   300     ctx->vkMapMemory(
       
   301         *ctx->logical_device,
       
   302         uboMemory,
       
   303         ubo->memoryOffset,
       
   304         ubo->bufferSize,
       
   305         0,
       
   306         &map
       
   307     );
       
   308 
       
   309     contents = ((uint8_t *) map) + ubo->dynamicOffset;
       
   310 
   296 
   311     offset = 0;
   297     offset = 0;
   312     for (i = 0; i < shader->parseData->uniform_count; i++)
   298     for (i = 0; i < shader->parseData->uniform_count; i++)
   313     {
   299     {
   314         const int32_t index = shader->parseData->uniforms[i].index;
   300         const int32_t index = shader->parseData->uniforms[i].index;
   348         } // switch
   334         } // switch
   349 
   335 
   350         offset += size * 16;
   336         offset += size * 16;
   351     } // for
   337     } // for
   352 
   338 
   353     ctx->vkUnmapMemory(
       
   354         *ctx->logical_device,
       
   355         uboMemory
       
   356     );
       
   357 } // update_uniform_buffer
   339 } // update_uniform_buffer
   358 
   340 
   359 static void lookup_entry_points(MOJOSHADER_vkContext *ctx)
   341 static void lookup_entry_points(MOJOSHADER_vkContext *ctx)
   360 {
   342 {
   361     #define VULKAN_INSTANCE_FUNCTION(ret, func, params) \
   343     #define VULKAN_INSTANCE_FUNCTION(ret, func, params) \
   393     unsigned int max_uniform_buffer_range,
   375     unsigned int max_uniform_buffer_range,
   394     unsigned int min_uniform_buffer_offset_alignment,
   376     unsigned int min_uniform_buffer_offset_alignment,
   395     MOJOSHADER_malloc m, MOJOSHADER_free f,
   377     MOJOSHADER_malloc m, MOJOSHADER_free f,
   396     void *malloc_d
   378     void *malloc_d
   397 ) {
   379 ) {
   398     int32_t i;
       
   399     int32_t uboMemoryOffset;
       
   400     VkMemoryAllocateInfo allocate_info =
       
   401     {
       
   402         VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
       
   403     };
       
   404     VkMemoryRequirements memoryRequirements;
       
   405     MOJOSHADER_vkContext* resultCtx;
   380     MOJOSHADER_vkContext* resultCtx;
   406 
   381 
   407     if (m == NULL) m = MOJOSHADER_internal_malloc;
   382     if (m == NULL) m = MOJOSHADER_internal_malloc;
   408     if (f == NULL) f = MOJOSHADER_internal_free;
   383     if (f == NULL) f = MOJOSHADER_internal_free;
   409 
   384 
   410     resultCtx = (MOJOSHADER_vkContext *) m(sizeof(MOJOSHADER_vkContext), malloc_d);
   385     resultCtx = (MOJOSHADER_vkContext *) m(sizeof(MOJOSHADER_vkContext), malloc_d);
   411     if (resultCtx == NULL)
   386     if (resultCtx == NULL)
   412     {
   387     {
   413         out_of_memory();
   388         out_of_memory();
   414         goto init_fail;
   389         goto init_fail;
   415     }
   390     } // if
   416 
   391 
   417     memset(resultCtx, '\0', sizeof(MOJOSHADER_vkContext));
   392     memset(resultCtx, '\0', sizeof(MOJOSHADER_vkContext));
   418     resultCtx->malloc_fn = m;
   393     resultCtx->malloc_fn = m;
   419     resultCtx->free_fn = f;
   394     resultCtx->free_fn = f;
   420     resultCtx->malloc_data = malloc_d;
   395     resultCtx->malloc_data = malloc_d;
   426     resultCtx->device_proc_lookup = (PFN_vkGetDeviceProcAddr) device_lookup;
   401     resultCtx->device_proc_lookup = (PFN_vkGetDeviceProcAddr) device_lookup;
   427     resultCtx->frames_in_flight = frames_in_flight;
   402     resultCtx->frames_in_flight = frames_in_flight;
   428     resultCtx->graphics_queue_family_index = graphics_queue_family_index;
   403     resultCtx->graphics_queue_family_index = graphics_queue_family_index;
   429     resultCtx->maxUniformBufferRange = max_uniform_buffer_range;
   404     resultCtx->maxUniformBufferRange = max_uniform_buffer_range;
   430     resultCtx->minUniformBufferOffsetAlignment = min_uniform_buffer_offset_alignment;
   405     resultCtx->minUniformBufferOffsetAlignment = min_uniform_buffer_offset_alignment;
   431     resultCtx->currentFrame = 0;
       
   432 
   406 
   433     lookup_entry_points(resultCtx);
   407     lookup_entry_points(resultCtx);
   434 
   408 
   435     resultCtx->uboBufferCount = UBO_BUFFER_COUNT;
   409     resultCtx->vertUboBuffer = create_ubo(resultCtx);
   436 
   410     resultCtx->fragUboBuffer = create_ubo(resultCtx);
   437     // Allocate vert UBO
       
   438 
       
   439     resultCtx->vertUboCurrentIndex = 0;
       
   440     resultCtx->vertUboBuffers = (MOJOSHADER_vkUniformBuffer**) m(
       
   441         sizeof(MOJOSHADER_vkUniformBuffer*) * resultCtx->uboBufferCount,
       
   442         malloc_d
       
   443     );
       
   444 
       
   445     for (i = 0; i < resultCtx->uboBufferCount; i++)
       
   446         resultCtx->vertUboBuffers[i] = create_ubo(resultCtx, m, malloc_d);
       
   447 
       
   448     resultCtx->vkGetBufferMemoryRequirements(
       
   449         *resultCtx->logical_device,
       
   450         resultCtx->vertUboBuffers[0]->buffer,
       
   451         &memoryRequirements
       
   452     );
       
   453 
       
   454     allocate_info.allocationSize = UBO_BUFFER_SIZE * resultCtx->uboBufferCount;
       
   455 
       
   456     if (!find_memory_type(resultCtx,
       
   457                           memoryRequirements.memoryTypeBits,
       
   458                           VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
       
   459                           &allocate_info.memoryTypeIndex))
       
   460     {
       
   461         set_error("failed to find suitable memory type for UBO memory");
       
   462         return NULL;
       
   463     } // if
       
   464 
       
   465     resultCtx->vkAllocateMemory(
       
   466         *resultCtx->logical_device,
       
   467         &allocate_info,
       
   468         NULL,
       
   469         &resultCtx->vertUboMemory
       
   470     );
       
   471 
       
   472     uboMemoryOffset = 0;
       
   473     for (i = 0; i < resultCtx->uboBufferCount; i++)
       
   474     {
       
   475         resultCtx->vertUboBuffers[i]->memoryOffset = uboMemoryOffset;
       
   476 
       
   477         resultCtx->vkBindBufferMemory(
       
   478             *resultCtx->logical_device,
       
   479             resultCtx->vertUboBuffers[i]->buffer,
       
   480             resultCtx->vertUboMemory,
       
   481             uboMemoryOffset
       
   482         );
       
   483 
       
   484         uboMemoryOffset += UBO_BUFFER_SIZE;
       
   485     } // for
       
   486 
       
   487     // Allocate frag UBO
       
   488 
       
   489     resultCtx->fragUboCurrentIndex = 0;
       
   490     resultCtx->fragUboBuffers = (MOJOSHADER_vkUniformBuffer**) m(
       
   491         sizeof(MOJOSHADER_vkUniformBuffer*) * resultCtx->uboBufferCount,
       
   492         malloc_d
       
   493     );
       
   494 
       
   495     for (i = 0; i < resultCtx->uboBufferCount; i++)
       
   496         resultCtx->fragUboBuffers[i] = create_ubo(resultCtx, m, malloc_d);
       
   497 
       
   498     resultCtx->vkGetBufferMemoryRequirements(
       
   499         *resultCtx->logical_device,
       
   500         resultCtx->fragUboBuffers[0]->buffer,
       
   501         &memoryRequirements
       
   502     );
       
   503 
       
   504     allocate_info.allocationSize = UBO_BUFFER_SIZE * resultCtx->uboBufferCount;
       
   505 
       
   506     if (!find_memory_type(resultCtx,
       
   507                           memoryRequirements.memoryTypeBits,
       
   508                           VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
       
   509                           &allocate_info.memoryTypeIndex))
       
   510     {
       
   511         set_error("failed to find suitable memory type for UBO memory");
       
   512         return NULL;
       
   513     } // if
       
   514 
       
   515     resultCtx->vkAllocateMemory(
       
   516         *resultCtx->logical_device,
       
   517         &allocate_info,
       
   518         NULL,
       
   519         &resultCtx->fragUboMemory
       
   520     );
       
   521 
       
   522     uboMemoryOffset = 0;
       
   523     for (i = 0; i < resultCtx->uboBufferCount; i++)
       
   524     {
       
   525         resultCtx->fragUboBuffers[i]->memoryOffset = uboMemoryOffset;
       
   526 
       
   527         resultCtx->vkBindBufferMemory(
       
   528             *resultCtx->logical_device,
       
   529             resultCtx->fragUboBuffers[i]->buffer,
       
   530             resultCtx->fragUboMemory,
       
   531             uboMemoryOffset
       
   532         );
       
   533 
       
   534         uboMemoryOffset += UBO_BUFFER_SIZE;
       
   535     } // for
       
   536 
   411 
   537     return resultCtx;
   412     return resultCtx;
   538 
   413 
   539 init_fail:
   414 init_fail:
   540     if (resultCtx != NULL)
   415     if (resultCtx != NULL)
   547     ctx = _ctx;
   422     ctx = _ctx;
   548 } // MOJOSHADER_vkMakeContextCurrent
   423 } // MOJOSHADER_vkMakeContextCurrent
   549 
   424 
   550 void MOJOSHADER_vkDestroyContext()
   425 void MOJOSHADER_vkDestroyContext()
   551 {
   426 {
   552     int32_t i;
   427     ctx->vkDestroyBuffer(*ctx->logical_device,
   553     for (i = 0; i < ctx->uboBufferCount; i++)
   428                          ctx->vertUboBuffer->buffer,
   554     {
   429                          NULL);
   555         ctx->vkDestroyBuffer(
   430 
   556             *ctx->logical_device,
   431     ctx->vkDestroyBuffer(*ctx->logical_device,
   557             ctx->vertUboBuffers[i]->buffer,
   432                          ctx->fragUboBuffer->buffer,
   558             NULL
   433                          NULL);
   559         );
   434 
   560 
   435     ctx->vkFreeMemory(*ctx->logical_device,
   561         ctx->free_fn(ctx->vertUboBuffers[i], ctx->malloc_data);
   436                       ctx->vertUboBuffer->deviceMemory,
   562 
   437                       NULL);
   563         ctx->vkDestroyBuffer(
   438 
   564             *ctx->logical_device,
   439     ctx->vkFreeMemory(*ctx->logical_device,
   565             ctx->fragUboBuffers[i]->buffer,
   440                       ctx->fragUboBuffer->deviceMemory,
   566             NULL
   441                       NULL);
   567         );
   442 
   568 
   443     ctx->free_fn(ctx->vertUboBuffer, ctx->malloc_data);
   569         ctx->free_fn(ctx->fragUboBuffers[i], ctx->malloc_data);
   444     ctx->free_fn(ctx->fragUboBuffer, ctx->malloc_data);
   570     } // for
       
   571 
       
   572     ctx->free_fn(ctx->vertUboBuffers, ctx->malloc_data);
       
   573     ctx->free_fn(ctx->fragUboBuffers, ctx->malloc_data);
       
   574 
       
   575     ctx->vkFreeMemory(
       
   576         *ctx->logical_device,
       
   577         ctx->vertUboMemory,
       
   578         NULL
       
   579     );
       
   580 
       
   581     ctx->vkFreeMemory(
       
   582         *ctx->logical_device,
       
   583         ctx->fragUboMemory,
       
   584         NULL
       
   585     );
       
   586 
   445 
   587     ctx->free_fn(ctx, ctx->malloc_data);
   446     ctx->free_fn(ctx, ctx->malloc_data);
   588 } // MOJOSHADER_vkDestroyContext
   447 } // MOJOSHADER_vkDestroyContext
   589 
   448 
   590 MOJOSHADER_vkShader *MOJOSHADER_vkCompileShader(
   449 MOJOSHADER_vkShader *MOJOSHADER_vkCompileShader(
   595     const unsigned int swizcount,
   454     const unsigned int swizcount,
   596     const MOJOSHADER_samplerMap *smap,
   455     const MOJOSHADER_samplerMap *smap,
   597     const unsigned int smapcount
   456     const unsigned int smapcount
   598 ) {
   457 ) {
   599     VkResult result;
   458     VkResult result;
   600     VkShaderModule shaderModule;
       
   601     VkShaderModuleCreateInfo shaderModuleCreateInfo =
   459     VkShaderModuleCreateInfo shaderModuleCreateInfo =
   602     {
   460     {
   603         VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO
   461         VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO
   604     };
   462     };
   605     MOJOSHADER_vkShader *shader;
   463     MOJOSHADER_vkShader *shader;
   689 } // MOJOSHADER_vkGetShaderParseData
   547 } // MOJOSHADER_vkGetShaderParseData
   690 
   548 
   691 void MOJOSHADER_vkBindShaders(MOJOSHADER_vkShader *vshader,
   549 void MOJOSHADER_vkBindShaders(MOJOSHADER_vkShader *vshader,
   692                               MOJOSHADER_vkShader *pshader)
   550                               MOJOSHADER_vkShader *pshader)
   693 {
   551 {
   694     /* NOOP if shader is null */
   552     // NOOP if shader is null
   695 
   553 
   696     if (vshader != NULL)
   554     if (vshader != NULL)
   697         ctx->vertexShader = vshader;
   555         ctx->vertexShader = vshader;
   698     if (pshader != NULL)
   556     if (pshader != NULL)
   699         ctx->pixelShader = pshader;
   557         ctx->pixelShader = pshader;
   738     *psize = get_uniform_size(ctx->pixelShader);
   596     *psize = get_uniform_size(ctx->pixelShader);
   739 } // MOJOSHADER_vkGetUniformBuffers
   597 } // MOJOSHADER_vkGetUniformBuffers
   740 
   598 
   741 void MOJOSHADER_vkEndFrame()
   599 void MOJOSHADER_vkEndFrame()
   742 {
   600 {
   743     int32_t i;
   601     ctx->vertUboBuffer->dynamicOffset = 0;
   744     ctx->currentFrame = (ctx->currentFrame + 1) % ctx->frames_in_flight;
   602     ctx->vertUboBuffer->currentBlockSize = 0;
   745     for (i = 0; i < ctx->uboBufferCount; i++)
   603     ctx->fragUboBuffer->dynamicOffset = 0;
   746     {
   604     ctx->fragUboBuffer->currentBlockSize = 0;
   747         if (ctx->vertUboBuffers[i]->full == ctx->currentFrame)
       
   748         {
       
   749             ctx->vertUboBuffers[i]->dynamicOffset = 0;
       
   750             ctx->vertUboBuffers[i]->currentBlockSize = 0;
       
   751             ctx->vertUboBuffers[i]->full = -1;
       
   752         } // if
       
   753 
       
   754         if (ctx->fragUboBuffers[i]->full == ctx->currentFrame)
       
   755         {
       
   756             ctx->fragUboBuffers[i]->dynamicOffset = 0;
       
   757             ctx->fragUboBuffers[i]->currentBlockSize = 0;
       
   758             ctx->fragUboBuffers[i]->full = -1;
       
   759         } // if
       
   760     } // for
       
   761 } // MOJOSHADER_VkEndFrame
   605 } // MOJOSHADER_VkEndFrame
   762 
   606 
   763 int MOJOSHADER_vkGetVertexAttribLocation(MOJOSHADER_vkShader *vert,
   607 int MOJOSHADER_vkGetVertexAttribLocation(MOJOSHADER_vkShader *vert,
   764                                          MOJOSHADER_usage usage, int index)
   608                                          MOJOSHADER_usage usage, int index)
   765 {
   609 {