|
|
|
|
@ -234,34 +234,380 @@ VkResult create_ui_pipeline(
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Layer structs come from uninitialized malloc, so cleanup is gated on the
|
|
|
|
|
// data.* count fields create_layer always sets, not on pointer NULL checks
|
|
|
|
|
static void destroy_layer(Layer* layer, RenderContext* gpu) {
|
|
|
|
|
// Reassigns glyph scratch slots densely. Scratch contents don't need copying:
|
|
|
|
|
// string.comp rewrites every live glyph each dispatch.
|
|
|
|
|
static VkResult compact_scratch(Container* c, RenderContext* gpu) {
|
|
|
|
|
VkResult result;
|
|
|
|
|
uint32_t bump = 0;
|
|
|
|
|
for(uint32_t s = 0; s < c->num_strings; s++) {
|
|
|
|
|
if(c->string_live[s] == 0 || c->strings_buffer[s].max_length == 0) continue;
|
|
|
|
|
uint32_t scratch = c->cap_drawables + bump;
|
|
|
|
|
bump += c->strings_buffer[s].max_length;
|
|
|
|
|
if(c->strings_buffer[s].scratch != scratch) {
|
|
|
|
|
c->strings_buffer[s].scratch = scratch;
|
|
|
|
|
VK_RESULT(add_transfers(
|
|
|
|
|
&c->strings_buffer[s].scratch,
|
|
|
|
|
c->strings,
|
|
|
|
|
sizeof(GPUString)*s + offsetof(GPUString, scratch),
|
|
|
|
|
sizeof(uint32_t),
|
|
|
|
|
gpu));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
c->scratch_used = bump;
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct ZEntryStruct {
|
|
|
|
|
float z;
|
|
|
|
|
uint32_t string;
|
|
|
|
|
uint32_t slot;
|
|
|
|
|
} ZEntry;
|
|
|
|
|
|
|
|
|
|
// Plain float compare; equal-z draw order is undefined and may change
|
|
|
|
|
// across rebuilds
|
|
|
|
|
static int z_entry_compare(const void* a, const void* b) {
|
|
|
|
|
float za = ((const ZEntry*)a)->z;
|
|
|
|
|
float zb = ((const ZEntry*)b)->z;
|
|
|
|
|
return (za > zb) - (za < zb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rewrites the z-sorted index list and instance count after any structural
|
|
|
|
|
// change (create/destroy/z change). Strings reserve max_length entries at
|
|
|
|
|
// their z, pointing into glyph scratch.
|
|
|
|
|
static VkResult rebuild_indices(Container* c, RenderContext* gpu) {
|
|
|
|
|
VkResult result;
|
|
|
|
|
ZEntry* entries = malloc(sizeof(ZEntry)*(c->num_drawables + c->num_strings));
|
|
|
|
|
uint32_t entry_count = 0;
|
|
|
|
|
|
|
|
|
|
for(uint32_t d = 0; d < c->num_drawables; d++) {
|
|
|
|
|
if(c->drawable_live[d] == 0) continue;
|
|
|
|
|
entries[entry_count].z = c->drawables_buffer[d].z;
|
|
|
|
|
entries[entry_count].string = 0;
|
|
|
|
|
entries[entry_count].slot = d;
|
|
|
|
|
entry_count += 1;
|
|
|
|
|
}
|
|
|
|
|
for(uint32_t s = 0; s < c->num_strings; s++) {
|
|
|
|
|
if(c->string_live[s] == 0 || c->strings_buffer[s].max_length == 0) continue;
|
|
|
|
|
entries[entry_count].z = c->strings_buffer[s].z;
|
|
|
|
|
entries[entry_count].string = 1;
|
|
|
|
|
entries[entry_count].slot = s;
|
|
|
|
|
entry_count += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qsort(entries, entry_count, sizeof(ZEntry), z_entry_compare);
|
|
|
|
|
|
|
|
|
|
uint32_t n = 0;
|
|
|
|
|
for(uint32_t e = 0; e < entry_count; e++) {
|
|
|
|
|
if(entries[e].string == 0) {
|
|
|
|
|
c->indices_buffer[n] = entries[e].slot;
|
|
|
|
|
n += 1;
|
|
|
|
|
} else {
|
|
|
|
|
GPUString* string = &c->strings_buffer[entries[e].slot];
|
|
|
|
|
for(uint32_t i = 0; i < string->max_length; i++) {
|
|
|
|
|
c->indices_buffer[n] = string->scratch + i;
|
|
|
|
|
n += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(entries);
|
|
|
|
|
|
|
|
|
|
if(n > 0) {
|
|
|
|
|
VK_RESULT(add_transfers(c->indices_buffer, c->indices, 0, sizeof(uint32_t)*n, gpu));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c->data.draw.instance_count = n;
|
|
|
|
|
return add_transfers(
|
|
|
|
|
&c->data.draw.instance_count,
|
|
|
|
|
c->container,
|
|
|
|
|
offsetof(GPUContainer, draw) + offsetof(DrawCommand, instance_count),
|
|
|
|
|
sizeof(uint32_t),
|
|
|
|
|
gpu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Recreates the drawable pool (and the index list, whose capacity is tied to
|
|
|
|
|
// it) at a new capacity. Old buffers are retired, addresses re-patched, and
|
|
|
|
|
// scratch bases recomputed since they sit at cap_drawables.
|
|
|
|
|
static VkResult container_realloc_drawable_pool(
|
|
|
|
|
Container* c,
|
|
|
|
|
uint32_t new_cap_drawables,
|
|
|
|
|
uint32_t new_cap_codes,
|
|
|
|
|
RenderContext* gpu) {
|
|
|
|
|
VkResult result;
|
|
|
|
|
uint32_t pool = new_cap_drawables + new_cap_codes;
|
|
|
|
|
|
|
|
|
|
c->drawables_buffer = realloc(c->drawables_buffer, sizeof(GPUDrawable)*new_cap_drawables);
|
|
|
|
|
c->drawable_live = realloc(c->drawable_live, new_cap_drawables);
|
|
|
|
|
memset(c->drawable_live + c->cap_drawables, 0, new_cap_drawables - c->cap_drawables);
|
|
|
|
|
c->free_drawables = realloc(c->free_drawables, sizeof(uint32_t)*new_cap_drawables);
|
|
|
|
|
c->indices_buffer = realloc(c->indices_buffer, sizeof(uint32_t)*pool);
|
|
|
|
|
c->drawable_generation = realloc(c->drawable_generation, sizeof(uint32_t)*new_cap_drawables);
|
|
|
|
|
memset(c->drawable_generation + c->cap_drawables, 0, sizeof(uint32_t)*(new_cap_drawables - c->cap_drawables));
|
|
|
|
|
c->drawable_ref = realloc(c->drawable_ref, sizeof(int)*new_cap_drawables);
|
|
|
|
|
for(uint32_t i = c->cap_drawables; i < new_cap_drawables; i++) {
|
|
|
|
|
c->drawable_ref[i] = LUA_NOREF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
retire_buffer(c->drawables[f], c->drawables_memory[f], gpu);
|
|
|
|
|
retire_buffer(c->indices[f], c->indices_memory[f], gpu);
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, 0, sizeof(GPUDrawable)*pool, &c->drawables[f], &c->drawables_memory[f]));
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, 0, sizeof(uint32_t)*pool, &c->indices[f], &c->indices_memory[f]));
|
|
|
|
|
|
|
|
|
|
VkDeviceAddress drawables_address = buffer_address(gpu->device, c->drawables[f]);
|
|
|
|
|
VkDeviceAddress indices_address = buffer_address(gpu->device, c->indices[f]);
|
|
|
|
|
VK_RESULT(add_transfer(&drawables_address, c->container[f], offsetof(GPUContainer, drawables), sizeof(VkDeviceAddress), f, gpu));
|
|
|
|
|
VK_RESULT(add_transfer(&indices_address, c->container[f], offsetof(GPUContainer, indices), sizeof(VkDeviceAddress), f, gpu));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c->cap_drawables = new_cap_drawables;
|
|
|
|
|
c->cap_codes = new_cap_codes;
|
|
|
|
|
|
|
|
|
|
if(c->num_drawables > 0) {
|
|
|
|
|
VK_RESULT(add_transfers(c->drawables_buffer, c->drawables, 0, sizeof(GPUDrawable)*c->num_drawables, gpu));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return compact_scratch(c, gpu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static VkResult container_realloc_string_pool(
|
|
|
|
|
Container* c,
|
|
|
|
|
uint32_t new_cap,
|
|
|
|
|
RenderContext* gpu) {
|
|
|
|
|
VkResult result;
|
|
|
|
|
|
|
|
|
|
c->strings_buffer = realloc(c->strings_buffer, sizeof(GPUString)*new_cap);
|
|
|
|
|
c->string_resources = realloc(c->string_resources, sizeof(StringResources)*new_cap);
|
|
|
|
|
memset(c->string_resources + c->cap_strings, 0, sizeof(StringResources)*(new_cap - c->cap_strings));
|
|
|
|
|
c->string_live = realloc(c->string_live, new_cap);
|
|
|
|
|
memset(c->string_live + c->cap_strings, 0, new_cap - c->cap_strings);
|
|
|
|
|
c->free_strings = realloc(c->free_strings, sizeof(uint32_t)*new_cap);
|
|
|
|
|
c->string_generation = realloc(c->string_generation, sizeof(uint32_t)*new_cap);
|
|
|
|
|
memset(c->string_generation + c->cap_strings, 0, sizeof(uint32_t)*(new_cap - c->cap_strings));
|
|
|
|
|
c->string_ref = realloc(c->string_ref, sizeof(int)*new_cap);
|
|
|
|
|
for(uint32_t i = c->cap_strings; i < new_cap; i++) {
|
|
|
|
|
c->string_ref[i] = LUA_NOREF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
retire_buffer(layer->layer[f], layer->layer_memory[f], gpu);
|
|
|
|
|
if(layer->data.max_strings > 0) {
|
|
|
|
|
retire_buffer(layer->strings[f], layer->strings_memory[f], gpu);
|
|
|
|
|
retire_buffer(c->strings[f], c->strings_memory[f], gpu);
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, 0, sizeof(GPUString)*new_cap, &c->strings[f], &c->strings_memory[f]));
|
|
|
|
|
VkDeviceAddress address = buffer_address(gpu->device, c->strings[f]);
|
|
|
|
|
VK_RESULT(add_transfer(&address, c->container[f], offsetof(GPUContainer, strings), sizeof(VkDeviceAddress), f, gpu));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c->cap_strings = new_cap;
|
|
|
|
|
|
|
|
|
|
if(c->num_strings > 0) {
|
|
|
|
|
VK_RESULT(add_transfers(c->strings_buffer, c->strings, 0, sizeof(GPUString)*c->num_strings, gpu));
|
|
|
|
|
// The bulk transfer wrote the mirror's zeroed codes fields; restore the
|
|
|
|
|
// per-frame codes buffer addresses
|
|
|
|
|
for(uint32_t s = 0; s < c->num_strings; s++) {
|
|
|
|
|
if(c->string_resources[s].codes_buffer == NULL) continue;
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
VkDeviceAddress address = buffer_address(gpu->device, c->string_resources[s].codes[f]);
|
|
|
|
|
VK_RESULT(add_transfer(&address, c->strings[f], sizeof(GPUString)*s + offsetof(GPUString, codes), sizeof(VkDeviceAddress), f, gpu));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static VkResult container_add_drawable(
|
|
|
|
|
Container* c,
|
|
|
|
|
const GPUDrawable* drawable,
|
|
|
|
|
RenderContext* gpu,
|
|
|
|
|
uint32_t* slot_out) {
|
|
|
|
|
VkResult result;
|
|
|
|
|
uint32_t slot;
|
|
|
|
|
if(c->free_drawable_count > 0) {
|
|
|
|
|
c->free_drawable_count -= 1;
|
|
|
|
|
slot = c->free_drawables[c->free_drawable_count];
|
|
|
|
|
} else {
|
|
|
|
|
if(c->num_drawables == c->cap_drawables) {
|
|
|
|
|
VK_RESULT(container_realloc_drawable_pool(c, c->cap_drawables*2, c->cap_codes, gpu));
|
|
|
|
|
}
|
|
|
|
|
if(layer->data.max_drawables > 0) {
|
|
|
|
|
retire_buffer(layer->drawables[f], layer->drawables_memory[f], gpu);
|
|
|
|
|
slot = c->num_drawables;
|
|
|
|
|
c->num_drawables += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c->drawables_buffer[slot] = *drawable;
|
|
|
|
|
c->drawable_live[slot] = 1;
|
|
|
|
|
VK_RESULT(add_transfers(&c->drawables_buffer[slot], c->drawables, sizeof(GPUDrawable)*slot, sizeof(GPUDrawable), gpu));
|
|
|
|
|
|
|
|
|
|
*slot_out = slot;
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static VkResult container_add_string(
|
|
|
|
|
Container* c,
|
|
|
|
|
const GPUString* string,
|
|
|
|
|
RenderContext* gpu,
|
|
|
|
|
uint32_t* slot_out) {
|
|
|
|
|
VkResult result;
|
|
|
|
|
uint32_t slot;
|
|
|
|
|
if(c->free_string_count > 0) {
|
|
|
|
|
c->free_string_count -= 1;
|
|
|
|
|
slot = c->free_strings[c->free_string_count];
|
|
|
|
|
} else {
|
|
|
|
|
if(c->num_strings == c->cap_strings) {
|
|
|
|
|
VK_RESULT(container_realloc_string_pool(c, c->cap_strings*2, gpu));
|
|
|
|
|
}
|
|
|
|
|
slot = c->num_strings;
|
|
|
|
|
c->num_strings += 1;
|
|
|
|
|
c->data.dispatch_strings.x = c->num_strings;
|
|
|
|
|
VK_RESULT(add_transfers(
|
|
|
|
|
&c->data.dispatch_strings.x,
|
|
|
|
|
c->container,
|
|
|
|
|
offsetof(GPUContainer, dispatch_strings),
|
|
|
|
|
sizeof(uint32_t),
|
|
|
|
|
gpu));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(layer->data.max_strings > 0) {
|
|
|
|
|
for(uint32_t s = 0; s < layer->data.max_strings; s++) {
|
|
|
|
|
if(layer->string_resources[s].codes_buffer == NULL) continue;
|
|
|
|
|
StringResources* sr = &c->string_resources[slot];
|
|
|
|
|
uint32_t max_len = string->max_length;
|
|
|
|
|
|
|
|
|
|
if(max_len > sr->max_codes) {
|
|
|
|
|
// Recycled slot's codes buffers (if any) are too small for this string
|
|
|
|
|
if(sr->codes_buffer != NULL) {
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
retire_buffer(layer->string_resources[s].codes[f], layer->string_resources[s].codes_memory[f], gpu);
|
|
|
|
|
retire_buffer(sr->codes[f], sr->codes_memory[f], gpu);
|
|
|
|
|
}
|
|
|
|
|
free(layer->string_resources[s].codes_buffer);
|
|
|
|
|
free(sr->codes_buffer);
|
|
|
|
|
}
|
|
|
|
|
uint32_t codes_size = ((max_len + 3) / 4) * sizeof(uint32_t);
|
|
|
|
|
sr->codes_buffer = malloc(codes_size);
|
|
|
|
|
memset(sr->codes_buffer, 0, codes_size);
|
|
|
|
|
sr->max_codes = max_len;
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, 0, codes_size, &sr->codes[f], &sr->codes_memory[f]));
|
|
|
|
|
}
|
|
|
|
|
free(layer->string_resources);
|
|
|
|
|
free(layer->strings_buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(layer->data.num_drawables > 0) {
|
|
|
|
|
free(layer->drawables_buffer);
|
|
|
|
|
c->strings_buffer[slot] = *string;
|
|
|
|
|
c->strings_buffer[slot].codes = 0;
|
|
|
|
|
|
|
|
|
|
if(max_len > 0) {
|
|
|
|
|
if(c->scratch_used + max_len > c->cap_codes) {
|
|
|
|
|
VK_RESULT(compact_scratch(c, gpu));
|
|
|
|
|
}
|
|
|
|
|
if(c->scratch_used + max_len > c->cap_codes) {
|
|
|
|
|
uint32_t new_cap = c->cap_codes*2;
|
|
|
|
|
while(c->scratch_used + max_len > new_cap) {
|
|
|
|
|
new_cap *= 2;
|
|
|
|
|
}
|
|
|
|
|
VK_RESULT(container_realloc_drawable_pool(c, c->cap_drawables, new_cap, gpu));
|
|
|
|
|
}
|
|
|
|
|
c->strings_buffer[slot].scratch = c->cap_drawables + c->scratch_used;
|
|
|
|
|
c->scratch_used += max_len;
|
|
|
|
|
} else {
|
|
|
|
|
c->strings_buffer[slot].scratch = STRING_SCRATCH_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c->string_live[slot] = 1;
|
|
|
|
|
|
|
|
|
|
VK_RESULT(add_transfers(&c->strings_buffer[slot], c->strings, sizeof(GPUString)*slot, sizeof(GPUString), gpu));
|
|
|
|
|
if(max_len > 0) {
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
VkDeviceAddress address = buffer_address(gpu->device, sr->codes[f]);
|
|
|
|
|
VK_RESULT(add_transfer(&address, c->strings[f], sizeof(GPUString)*slot + offsetof(GPUString, codes), sizeof(VkDeviceAddress), f, gpu));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*slot_out = slot;
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult ui_create_drawable(
|
|
|
|
|
Container* container,
|
|
|
|
|
const GPUDrawable* drawable,
|
|
|
|
|
RenderContext* gpu,
|
|
|
|
|
uint32_t* slot) {
|
|
|
|
|
VkResult result;
|
|
|
|
|
VK_RESULT(container_add_drawable(container, drawable, gpu, slot));
|
|
|
|
|
return rebuild_indices(container, gpu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult ui_destroy_drawable(
|
|
|
|
|
Container* container,
|
|
|
|
|
uint32_t slot,
|
|
|
|
|
RenderContext* gpu) {
|
|
|
|
|
if(slot >= container->num_drawables || container->drawable_live[slot] == 0) {
|
|
|
|
|
return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
container->drawable_live[slot] = 0;
|
|
|
|
|
container->drawable_generation[slot] += 1;
|
|
|
|
|
container->drawables_buffer[slot].type = DRAWABLE_TYPE_NONE;
|
|
|
|
|
container->drawables_buffer[slot].events = 0;
|
|
|
|
|
container->free_drawables[container->free_drawable_count] = slot;
|
|
|
|
|
container->free_drawable_count += 1;
|
|
|
|
|
|
|
|
|
|
return rebuild_indices(container, gpu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult ui_create_string(
|
|
|
|
|
Container* container,
|
|
|
|
|
const GPUString* string,
|
|
|
|
|
RenderContext* gpu,
|
|
|
|
|
uint32_t* slot) {
|
|
|
|
|
VkResult result;
|
|
|
|
|
VK_RESULT(container_add_string(container, string, gpu, slot));
|
|
|
|
|
return rebuild_indices(container, gpu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult ui_destroy_string(
|
|
|
|
|
Container* container,
|
|
|
|
|
uint32_t slot,
|
|
|
|
|
RenderContext* gpu) {
|
|
|
|
|
VkResult result;
|
|
|
|
|
if(slot >= container->num_strings || container->string_live[slot] == 0) {
|
|
|
|
|
return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
container->string_live[slot] = 0;
|
|
|
|
|
container->string_generation[slot] += 1;
|
|
|
|
|
container->strings_buffer[slot].length = 0;
|
|
|
|
|
container->strings_buffer[slot].scratch = STRING_SCRATCH_NONE;
|
|
|
|
|
// Neutralize on the GPU so the compute pass can't write into scratch slots
|
|
|
|
|
// that later get reassigned
|
|
|
|
|
VK_RESULT(add_transfers(
|
|
|
|
|
&container->strings_buffer[slot].scratch,
|
|
|
|
|
container->strings,
|
|
|
|
|
sizeof(GPUString)*slot + offsetof(GPUString, scratch),
|
|
|
|
|
sizeof(uint32_t),
|
|
|
|
|
gpu));
|
|
|
|
|
container->free_strings[container->free_string_count] = slot;
|
|
|
|
|
container->free_string_count += 1;
|
|
|
|
|
// codes buffers are kept for slot reuse
|
|
|
|
|
|
|
|
|
|
return rebuild_indices(container, gpu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult ui_set_drawable_z(
|
|
|
|
|
Container* container,
|
|
|
|
|
uint32_t slot,
|
|
|
|
|
float z,
|
|
|
|
|
RenderContext* gpu) {
|
|
|
|
|
if(slot >= container->num_drawables || container->drawable_live[slot] == 0) {
|
|
|
|
|
return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
container->drawables_buffer[slot].z = z;
|
|
|
|
|
return rebuild_indices(container, gpu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult ui_set_string_z(
|
|
|
|
|
Container* container,
|
|
|
|
|
uint32_t slot,
|
|
|
|
|
float z,
|
|
|
|
|
RenderContext* gpu) {
|
|
|
|
|
if(slot >= container->num_strings || container->string_live[slot] == 0) {
|
|
|
|
|
return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
container->strings_buffer[slot].z = z;
|
|
|
|
|
return rebuild_indices(container, gpu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult unload_container(
|
|
|
|
|
@ -273,16 +619,57 @@ VkResult unload_container(
|
|
|
|
|
return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(uint32_t l = 0; l < container->layer_count; l++) {
|
|
|
|
|
destroy_layer(&container->layers[l], gpu);
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
retire_buffer(container->container[f], container->container_memory[f], gpu);
|
|
|
|
|
retire_buffer(container->strings[f], container->strings_memory[f], gpu);
|
|
|
|
|
retire_buffer(container->drawables[f], container->drawables_memory[f], gpu);
|
|
|
|
|
retire_buffer(container->indices[f], container->indices_memory[f], gpu);
|
|
|
|
|
}
|
|
|
|
|
free(container->layers);
|
|
|
|
|
container->layers = NULL;
|
|
|
|
|
container->layer_count = 0;
|
|
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
|
|
|
retire_buffer(container->container[i], container->container_memory[i], gpu);
|
|
|
|
|
container->address[i] = 0;
|
|
|
|
|
for(uint32_t s = 0; s < container->cap_strings; s++) {
|
|
|
|
|
if(container->string_resources[s].codes_buffer == NULL) continue;
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
retire_buffer(container->string_resources[s].codes[f], container->string_resources[s].codes_memory[f], gpu);
|
|
|
|
|
}
|
|
|
|
|
free(container->string_resources[s].codes_buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Release the Lua handle refs; the userdata objects themselves die with
|
|
|
|
|
// the script environment
|
|
|
|
|
for(uint32_t d = 0; d < container->cap_drawables; d++) {
|
|
|
|
|
if(container->drawable_ref[d] != LUA_NOREF) {
|
|
|
|
|
luaL_unref(context->lua, LUA_REGISTRYINDEX, container->drawable_ref[d]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(uint32_t s = 0; s < container->cap_strings; s++) {
|
|
|
|
|
if(container->string_ref[s] != LUA_NOREF) {
|
|
|
|
|
luaL_unref(context->lua, LUA_REGISTRYINDEX, container->string_ref[s]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(container->drawables_buffer);
|
|
|
|
|
free(container->strings_buffer);
|
|
|
|
|
free(container->string_resources);
|
|
|
|
|
free(container->indices_buffer);
|
|
|
|
|
free(container->drawable_live);
|
|
|
|
|
free(container->string_live);
|
|
|
|
|
free(container->free_drawables);
|
|
|
|
|
free(container->free_strings);
|
|
|
|
|
free(container->drawable_generation);
|
|
|
|
|
free(container->string_generation);
|
|
|
|
|
free(container->drawable_ref);
|
|
|
|
|
free(container->string_ref);
|
|
|
|
|
|
|
|
|
|
uint32_t index = (uint32_t)(container - context->containers);
|
|
|
|
|
for(uint32_t i = 0; i < context->container_order_count; i++) {
|
|
|
|
|
if(context->container_order[i] == index) {
|
|
|
|
|
memmove(
|
|
|
|
|
&context->container_order[i],
|
|
|
|
|
&context->container_order[i+1],
|
|
|
|
|
(context->container_order_count - i - 1)*sizeof(uint32_t));
|
|
|
|
|
context->container_order_count -= 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Drop focus without dispatching on_deselect: the script is being unloaded
|
|
|
|
|
@ -293,27 +680,25 @@ VkResult unload_container(
|
|
|
|
|
|
|
|
|
|
if(container->script_env != 0) {
|
|
|
|
|
luaL_unref(context->lua, LUA_REGISTRYINDEX, container->script_env);
|
|
|
|
|
container->script_env = 0;
|
|
|
|
|
}
|
|
|
|
|
if(container->script_path != NULL) {
|
|
|
|
|
free(container->script_path);
|
|
|
|
|
container->script_path = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
container->id = 0;
|
|
|
|
|
memset(container, 0, sizeof(Container));
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult load_container(
|
|
|
|
|
ContainerInput* container,
|
|
|
|
|
ContainerInput* input,
|
|
|
|
|
RenderContext* gpu,
|
|
|
|
|
UIContext* context) {
|
|
|
|
|
if(container == NULL) return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
if(container->id == 0) return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
if(input == NULL) return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
if(input->id == 0) return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < context->max_containers; i++) {
|
|
|
|
|
if(context->containers[i].id == container->id) return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
if(context->containers[i].id == input->id) return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t index = 0xFFFFFFFF;
|
|
|
|
|
@ -327,158 +712,89 @@ VkResult load_container(
|
|
|
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult result;
|
|
|
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, 0, sizeof(GPUContainer), &context->containers[index].container[i], &context->containers[index].container_memory[i]));
|
|
|
|
|
context->containers[index].address[i] = buffer_address(gpu->device, context->containers[index].container[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context->containers[index].data.offset[0] = container->offset[0];
|
|
|
|
|
context->containers[index].data.offset[1] = container->offset[1];
|
|
|
|
|
context->containers[index].data.size[0] = container->size[0];
|
|
|
|
|
context->containers[index].data.size[1] = container->size[1];
|
|
|
|
|
context->containers[index].data.anchor = container->anchor;
|
|
|
|
|
context->containers[index].data.context = context->address;
|
|
|
|
|
add_transfers(&context->containers[index].data, context->containers[index].container, 0, sizeof(GPUContainer), gpu);
|
|
|
|
|
|
|
|
|
|
context->containers[index].id = container->id;
|
|
|
|
|
context->containers[index].layers = malloc(sizeof(Layer)*container->layer_count);
|
|
|
|
|
for(uint32_t i = 0; i < container->layer_count; i++) {
|
|
|
|
|
VK_RESULT(create_layer(i, &container->layers[i], gpu, &context->containers[index]));
|
|
|
|
|
Container* c = &context->containers[index];
|
|
|
|
|
memset(c, 0, sizeof(Container));
|
|
|
|
|
|
|
|
|
|
c->cap_drawables = CONTAINER_MIN_DRAWABLES;
|
|
|
|
|
c->cap_strings = CONTAINER_MIN_STRINGS;
|
|
|
|
|
c->cap_codes = CONTAINER_MIN_CODES;
|
|
|
|
|
|
|
|
|
|
uint32_t pool = c->cap_drawables + c->cap_codes;
|
|
|
|
|
|
|
|
|
|
c->drawables_buffer = malloc(sizeof(GPUDrawable)*c->cap_drawables);
|
|
|
|
|
c->strings_buffer = malloc(sizeof(GPUString)*c->cap_strings);
|
|
|
|
|
c->string_resources = malloc(sizeof(StringResources)*c->cap_strings);
|
|
|
|
|
memset(c->string_resources, 0, sizeof(StringResources)*c->cap_strings);
|
|
|
|
|
c->indices_buffer = malloc(sizeof(uint32_t)*pool);
|
|
|
|
|
c->drawable_live = malloc(c->cap_drawables);
|
|
|
|
|
memset(c->drawable_live, 0, c->cap_drawables);
|
|
|
|
|
c->string_live = malloc(c->cap_strings);
|
|
|
|
|
memset(c->string_live, 0, c->cap_strings);
|
|
|
|
|
c->free_drawables = malloc(sizeof(uint32_t)*c->cap_drawables);
|
|
|
|
|
c->free_strings = malloc(sizeof(uint32_t)*c->cap_strings);
|
|
|
|
|
c->drawable_generation = malloc(sizeof(uint32_t)*c->cap_drawables);
|
|
|
|
|
memset(c->drawable_generation, 0, sizeof(uint32_t)*c->cap_drawables);
|
|
|
|
|
c->string_generation = malloc(sizeof(uint32_t)*c->cap_strings);
|
|
|
|
|
memset(c->string_generation, 0, sizeof(uint32_t)*c->cap_strings);
|
|
|
|
|
c->drawable_ref = malloc(sizeof(int)*c->cap_drawables);
|
|
|
|
|
for(uint32_t i = 0; i < c->cap_drawables; i++) {
|
|
|
|
|
c->drawable_ref[i] = LUA_NOREF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context->containers[index].layer_count = container->layer_count;
|
|
|
|
|
|
|
|
|
|
context->containers[index].script_env = 0;
|
|
|
|
|
context->containers[index].script_path = NULL;
|
|
|
|
|
if(container->script_path != NULL) {
|
|
|
|
|
context->containers[index].script_path = strdup(container->script_path);
|
|
|
|
|
VK_RESULT(ui_lua_load_container(
|
|
|
|
|
context->lua,
|
|
|
|
|
&context->containers[index],
|
|
|
|
|
context,
|
|
|
|
|
gpu,
|
|
|
|
|
container->script_path));
|
|
|
|
|
c->string_ref = malloc(sizeof(int)*c->cap_strings);
|
|
|
|
|
for(uint32_t i = 0; i < c->cap_strings; i++) {
|
|
|
|
|
c->string_ref[i] = LUA_NOREF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult create_layer(
|
|
|
|
|
uint32_t index,
|
|
|
|
|
LayerInput* input,
|
|
|
|
|
RenderContext* gpu,
|
|
|
|
|
Container* container) {
|
|
|
|
|
VkResult result;
|
|
|
|
|
|
|
|
|
|
uint32_t max_strings = (input->num_strings > input->max_strings) ? input->num_strings : input->max_strings;
|
|
|
|
|
uint32_t max_drawables = (input->num_drawables > input->max_drawables) ? input->num_drawables : input->max_drawables;
|
|
|
|
|
|
|
|
|
|
uint32_t total_max_codes = 0;
|
|
|
|
|
for(uint32_t s = 0; s < input->num_strings; s++) {
|
|
|
|
|
total_max_codes += input->strings[s].max_length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(max_strings > 0) {
|
|
|
|
|
container->layers[index].strings_buffer = malloc(sizeof(GPUString)*max_strings);
|
|
|
|
|
container->layers[index].string_resources = malloc(sizeof(StringResources)*max_strings);
|
|
|
|
|
memset(container->layers[index].string_resources, 0, sizeof(StringResources)*max_strings);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(max_drawables > 0) {
|
|
|
|
|
container->layers[index].drawables_buffer = malloc(sizeof(GPUDrawable)*max_drawables);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(uint32_t s = 0; s < input->num_strings; s++) {
|
|
|
|
|
uint32_t max_len = input->strings[s].max_length;
|
|
|
|
|
if(max_len == 0) continue;
|
|
|
|
|
uint32_t codes_size = ((max_len + 3) / 4) * sizeof(uint32_t);
|
|
|
|
|
container->layers[index].string_resources[s].codes_buffer = malloc(codes_size);
|
|
|
|
|
memset(container->layers[index].string_resources[s].codes_buffer, 0, codes_size);
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, 0, codes_size,
|
|
|
|
|
&container->layers[index].string_resources[s].codes[f],
|
|
|
|
|
&container->layers[index].string_resources[s].codes_memory[f]));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, sizeof(GPULayer), &container->layers[index].layer[i], &container->layers[index].layer_memory[i]));
|
|
|
|
|
if(max_strings > 0) {
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, 0, sizeof(GPUString)*max_strings, &container->layers[index].strings[i], &container->layers[index].strings_memory[i]));
|
|
|
|
|
VkDeviceAddress address = buffer_address(gpu->device, container->layers[index].strings[i]);
|
|
|
|
|
add_transfer(
|
|
|
|
|
&address,
|
|
|
|
|
container->layers[index].layer[i],
|
|
|
|
|
offsetof(GPULayer, strings),
|
|
|
|
|
sizeof(VkDeviceAddress),
|
|
|
|
|
i,
|
|
|
|
|
gpu);
|
|
|
|
|
}
|
|
|
|
|
if(total_max_codes + max_drawables > 0) {
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, 0, sizeof(GPUDrawable)*(max_drawables + total_max_codes), &container->layers[index].drawables[i], &container->layers[index].drawables_memory[i]));
|
|
|
|
|
VkDeviceAddress address = buffer_address(gpu->device, container->layers[index].drawables[i]);
|
|
|
|
|
add_transfer(
|
|
|
|
|
&address,
|
|
|
|
|
container->layers[index].layer[i],
|
|
|
|
|
offsetof(GPULayer, drawables),
|
|
|
|
|
sizeof(VkDeviceAddress),
|
|
|
|
|
i,
|
|
|
|
|
gpu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
container->layers[index].address[i] = buffer_address(gpu->device, container->layers[index].layer[i]);
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, sizeof(GPUContainer), &c->container[f], &c->container_memory[f]));
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, 0, sizeof(GPUString)*c->cap_strings, &c->strings[f], &c->strings_memory[f]));
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, 0, sizeof(GPUDrawable)*pool, &c->drawables[f], &c->drawables_memory[f]));
|
|
|
|
|
VK_RESULT(create_storage_buffer(gpu->allocator, 0, sizeof(uint32_t)*pool, &c->indices[f], &c->indices_memory[f]));
|
|
|
|
|
c->address[f] = buffer_address(gpu->device, c->container[f]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
|
|
|
add_transfer(
|
|
|
|
|
&container->address[i],
|
|
|
|
|
container->layers[index].layer[i],
|
|
|
|
|
offsetof(GPULayer, container),
|
|
|
|
|
sizeof(VkDeviceAddress),
|
|
|
|
|
i,
|
|
|
|
|
gpu);
|
|
|
|
|
c->data.draw.vertex_count = 6;
|
|
|
|
|
c->data.draw.instance_count = 0;
|
|
|
|
|
c->data.draw.first_vertex = 0;
|
|
|
|
|
c->data.draw.first_instance = 0;
|
|
|
|
|
c->data.dispatch_strings.x = 0;
|
|
|
|
|
c->data.dispatch_strings.y = 1;
|
|
|
|
|
c->data.dispatch_strings.z = 1;
|
|
|
|
|
c->data.anchor = input->anchor;
|
|
|
|
|
c->data.offset[0] = input->offset[0];
|
|
|
|
|
c->data.offset[1] = input->offset[1];
|
|
|
|
|
c->data.size[0] = input->size[0];
|
|
|
|
|
c->data.size[1] = input->size[1];
|
|
|
|
|
c->data.context = context->address;
|
|
|
|
|
|
|
|
|
|
// Buffer addresses differ per frame: transfer the shared prefix once, then
|
|
|
|
|
// patch each frame's copies individually
|
|
|
|
|
VK_RESULT(add_transfers(&c->data, c->container, 0, offsetof(GPUContainer, strings), gpu));
|
|
|
|
|
VK_RESULT(add_transfers(&c->data.context, c->container, offsetof(GPUContainer, context), sizeof(VkDeviceAddress), gpu));
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
VkDeviceAddress strings_address = buffer_address(gpu->device, c->strings[f]);
|
|
|
|
|
VkDeviceAddress drawables_address = buffer_address(gpu->device, c->drawables[f]);
|
|
|
|
|
VkDeviceAddress indices_address = buffer_address(gpu->device, c->indices[f]);
|
|
|
|
|
VK_RESULT(add_transfer(&strings_address, c->container[f], offsetof(GPUContainer, strings), sizeof(VkDeviceAddress), f, gpu));
|
|
|
|
|
VK_RESULT(add_transfer(&drawables_address, c->container[f], offsetof(GPUContainer, drawables), sizeof(VkDeviceAddress), f, gpu));
|
|
|
|
|
VK_RESULT(add_transfer(&indices_address, c->container[f], offsetof(GPUContainer, indices), sizeof(VkDeviceAddress), f, gpu));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
container->layers[index].data.draw.first_vertex = 0;
|
|
|
|
|
container->layers[index].data.draw.vertex_count = 6;
|
|
|
|
|
container->layers[index].data.draw.first_instance = 0;
|
|
|
|
|
container->layers[index].data.draw.instance_count = 0;
|
|
|
|
|
|
|
|
|
|
container->layers[index].data.dispatch_strings.x = max_strings;
|
|
|
|
|
container->layers[index].data.dispatch_strings.y = 1;
|
|
|
|
|
container->layers[index].data.dispatch_strings.z = 1;
|
|
|
|
|
|
|
|
|
|
container->layers[index].data.max_drawables = max_drawables + total_max_codes;
|
|
|
|
|
container->layers[index].data.max_strings = max_strings;
|
|
|
|
|
container->layers[index].data.num_drawables = max_drawables;
|
|
|
|
|
add_transfers(&container->layers[index].data, container->layers[index].layer, 0, sizeof(GPULayer)-3*sizeof(VkDeviceAddress), gpu);
|
|
|
|
|
|
|
|
|
|
if(input->num_strings > 0) {
|
|
|
|
|
memcpy(container->layers[index].strings_buffer, input->strings, sizeof(GPUString)*input->num_strings);
|
|
|
|
|
for(uint32_t s = 0; s < input->num_strings; s++) {
|
|
|
|
|
container->layers[index].strings_buffer[s].codes = 0;
|
|
|
|
|
}
|
|
|
|
|
add_transfers(container->layers[index].strings_buffer, container->layers[index].strings, 0, sizeof(GPUString)*input->num_strings, gpu);
|
|
|
|
|
c->id = input->id;
|
|
|
|
|
context->container_order[context->container_order_count] = index;
|
|
|
|
|
context->container_order_count += 1;
|
|
|
|
|
|
|
|
|
|
for(uint32_t s = 0; s < input->num_strings; s++) {
|
|
|
|
|
if(input->strings[s].max_length == 0) continue;
|
|
|
|
|
for(uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; f++) {
|
|
|
|
|
VkDeviceAddress addr = buffer_address(gpu->device, container->layers[index].string_resources[s].codes[f]);
|
|
|
|
|
add_transfer(
|
|
|
|
|
&addr,
|
|
|
|
|
container->layers[index].strings[f],
|
|
|
|
|
s * sizeof(GPUString) + offsetof(GPUString, codes),
|
|
|
|
|
sizeof(VkDeviceAddress),
|
|
|
|
|
f,
|
|
|
|
|
gpu);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
VK_RESULT(rebuild_indices(c, gpu));
|
|
|
|
|
|
|
|
|
|
if(input->num_drawables > 0) {
|
|
|
|
|
memcpy(container->layers[index].drawables_buffer, input->drawables, sizeof(GPUDrawable)*input->num_drawables);
|
|
|
|
|
add_transfers(container->layers[index].drawables_buffer, container->layers[index].drawables, 0, sizeof(GPUDrawable)*input->num_drawables, gpu);
|
|
|
|
|
if(input->script_path != NULL) {
|
|
|
|
|
c->script_path = strdup(input->script_path);
|
|
|
|
|
VK_RESULT(ui_lua_load_container(
|
|
|
|
|
context->lua,
|
|
|
|
|
c,
|
|
|
|
|
context,
|
|
|
|
|
gpu,
|
|
|
|
|
input->script_path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
@ -1227,6 +1543,8 @@ VkResult create_ui_context(
|
|
|
|
|
memset(context->fonts, 0, max_fonts*sizeof(Font));
|
|
|
|
|
context->containers = malloc(max_containers*sizeof(Container));
|
|
|
|
|
memset(context->containers, 0, max_containers*sizeof(Container));
|
|
|
|
|
context->container_order = malloc(max_containers*sizeof(uint32_t));
|
|
|
|
|
context->container_order_count = 0;
|
|
|
|
|
|
|
|
|
|
context->lua = luaL_newstate();
|
|
|
|
|
if(context->lua == NULL) {
|
|
|
|
|
@ -1279,7 +1597,6 @@ Container* context_container(uint32_t container_id, UIContext* ui) {
|
|
|
|
|
VkResult update_ui_string(
|
|
|
|
|
const char* string,
|
|
|
|
|
Container* container,
|
|
|
|
|
uint32_t layer_index,
|
|
|
|
|
uint32_t string_index,
|
|
|
|
|
UIContext* ui,
|
|
|
|
|
RenderContext* gpu) {
|
|
|
|
|
@ -1288,25 +1605,27 @@ VkResult update_ui_string(
|
|
|
|
|
if(container == NULL) {
|
|
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
if(string_index >= container->num_strings || container->string_live[string_index] == 0) {
|
|
|
|
|
return VK_ERROR_VALIDATION_FAILED_EXT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Layer* layer = &container->layers[layer_index];
|
|
|
|
|
StringResources* sr = &layer->string_resources[string_index];
|
|
|
|
|
StringResources* sr = &container->string_resources[string_index];
|
|
|
|
|
uint32_t len = strlen(string);
|
|
|
|
|
|
|
|
|
|
if(len > layer->strings_buffer[string_index].max_length) {
|
|
|
|
|
len = layer->strings_buffer[string_index].max_length;
|
|
|
|
|
if(len > container->strings_buffer[string_index].max_length) {
|
|
|
|
|
len = container->strings_buffer[string_index].max_length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layer->strings_buffer[string_index].length = len;
|
|
|
|
|
container->strings_buffer[string_index].length = len;
|
|
|
|
|
|
|
|
|
|
if(len > 0) {
|
|
|
|
|
VK_RESULT(map_string(string, sr->codes_buffer, layer->strings_buffer[string_index].font, ui));
|
|
|
|
|
VK_RESULT(map_string(string, sr->codes_buffer, container->strings_buffer[string_index].font, ui));
|
|
|
|
|
VK_RESULT(add_transfers(sr->codes_buffer, sr->codes, 0, ((len + 3) / 4) * sizeof(uint32_t), gpu));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VK_RESULT(add_transfers(
|
|
|
|
|
&layer->strings_buffer[string_index].length,
|
|
|
|
|
layer->strings,
|
|
|
|
|
&container->strings_buffer[string_index].length,
|
|
|
|
|
container->strings,
|
|
|
|
|
sizeof(GPUString)*string_index + offsetof(GPUString, length),
|
|
|
|
|
sizeof(uint32_t),
|
|
|
|
|
gpu));
|
|
|
|
|
@ -1341,31 +1660,33 @@ bool ui_intersect(
|
|
|
|
|
UIContext* ui,
|
|
|
|
|
uint32_t events,
|
|
|
|
|
uint32_t* container,
|
|
|
|
|
uint32_t* layer,
|
|
|
|
|
uint32_t* element,
|
|
|
|
|
vec2 position) {
|
|
|
|
|
for(uint32_t c = 0; c < ui->max_containers; c++) {
|
|
|
|
|
if(ui->containers[c].id == 0x00000000) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vec2 container_offset = {ui->containers[c].data.offset[0], ui->containers[c].data.offset[1]};
|
|
|
|
|
anchor_offset(gpu, &ui->containers[c], container_offset);
|
|
|
|
|
|
|
|
|
|
for(uint32_t l = 0; l < ui->containers[c].layer_count; l++) {
|
|
|
|
|
for(uint32_t d = 0; d < ui->containers[c].layers[l].data.num_drawables; d++) {
|
|
|
|
|
if(ui->containers[c].layers[l].drawables_buffer[d].events & events
|
|
|
|
|
&& ui_contains(
|
|
|
|
|
cursor,
|
|
|
|
|
container_offset,
|
|
|
|
|
ui->containers[c].data.size,
|
|
|
|
|
&ui->containers[c].layers[l].drawables_buffer[d],
|
|
|
|
|
position)) {
|
|
|
|
|
*container = ui->containers[c].id;
|
|
|
|
|
*layer = l;
|
|
|
|
|
*element = d;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// Walk containers and their z-sorted index lists in reverse draw order so
|
|
|
|
|
// the top-most drawn element wins the hit
|
|
|
|
|
for(uint32_t o = ui->container_order_count; o > 0; o--) {
|
|
|
|
|
Container* c = &ui->containers[ui->container_order[o-1]];
|
|
|
|
|
|
|
|
|
|
vec2 container_offset = {c->data.offset[0], c->data.offset[1]};
|
|
|
|
|
anchor_offset(gpu, c, container_offset);
|
|
|
|
|
|
|
|
|
|
uint32_t count = c->data.draw.instance_count;
|
|
|
|
|
for(uint32_t k = count; k > 0; k--) {
|
|
|
|
|
uint32_t slot = c->indices_buffer[k-1];
|
|
|
|
|
if(slot >= c->cap_drawables) {
|
|
|
|
|
continue; // glyph scratch, not hit-testable
|
|
|
|
|
}
|
|
|
|
|
GPUDrawable* drawable = &c->drawables_buffer[slot];
|
|
|
|
|
if(drawable->events & events
|
|
|
|
|
&& ui_contains(
|
|
|
|
|
cursor,
|
|
|
|
|
container_offset,
|
|
|
|
|
c->data.size,
|
|
|
|
|
drawable,
|
|
|
|
|
position)) {
|
|
|
|
|
*container = c->id;
|
|
|
|
|
*element = slot;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1373,22 +1694,40 @@ bool ui_intersect(
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ui_container_to_front(uint32_t id, UIContext* ui) {
|
|
|
|
|
Container* container = context_container(id, ui);
|
|
|
|
|
if(container == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t index = (uint32_t)(container - ui->containers);
|
|
|
|
|
for(uint32_t i = 0; i < ui->container_order_count; i++) {
|
|
|
|
|
if(ui->container_order[i] == index) {
|
|
|
|
|
memmove(
|
|
|
|
|
&ui->container_order[i],
|
|
|
|
|
&ui->container_order[i+1],
|
|
|
|
|
(ui->container_order_count - i - 1)*sizeof(uint32_t));
|
|
|
|
|
ui->container_order[ui->container_order_count - 1] = index;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void clear_active_element(UIContext* ui, RenderContext* gpu) {
|
|
|
|
|
// Clear the active fields before dispatching so a script calling
|
|
|
|
|
// ui.blur() inside on_deselect can't recurse forever
|
|
|
|
|
Container* container = ui->active_container;
|
|
|
|
|
uint32_t layer = ui->active_layer;
|
|
|
|
|
uint32_t element = ui->active_element;
|
|
|
|
|
|
|
|
|
|
ui->active_container = NULL;
|
|
|
|
|
ui->active_element = 0;
|
|
|
|
|
|
|
|
|
|
if(container != NULL) {
|
|
|
|
|
ui_lua_dispatch_deselect(ui, gpu, container, layer, element);
|
|
|
|
|
ui_lua_dispatch_deselect(ui, gpu, container, element);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void set_active_element(uint32_t container, uint32_t layer, uint32_t element, UIContext* ui) {
|
|
|
|
|
void set_active_element(uint32_t container, uint32_t element, UIContext* ui) {
|
|
|
|
|
Container* container_ptr = context_container(container, ui);
|
|
|
|
|
if(container_ptr == NULL) {
|
|
|
|
|
fprintf(stderr, "set_active_element passed invalid container id");
|
|
|
|
|
@ -1396,7 +1735,6 @@ void set_active_element(uint32_t container, uint32_t layer, uint32_t element, UI
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ui->active_element = element;
|
|
|
|
|
ui->active_layer = layer;
|
|
|
|
|
ui->active_container = container_ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|