mirror of https://github.com/bjornbytes/lovr.git
gpu_bundle; gpu_bundle_pool; layouts;
This commit is contained in:
parent
a0db01959d
commit
e054218713
|
@ -7,6 +7,8 @@ typedef struct gpu_texture gpu_texture;
|
|||
typedef struct gpu_sampler gpu_sampler;
|
||||
typedef struct gpu_layout gpu_layout;
|
||||
typedef struct gpu_shader gpu_shader;
|
||||
typedef struct gpu_bundle_pool gpu_bundle_pool;
|
||||
typedef struct gpu_bundle gpu_bundle;
|
||||
typedef struct gpu_pipeline gpu_pipeline;
|
||||
typedef struct gpu_stream gpu_stream;
|
||||
|
||||
|
@ -15,6 +17,8 @@ size_t gpu_sizeof_texture(void);
|
|||
size_t gpu_sizeof_sampler(void);
|
||||
size_t gpu_sizeof_layout(void);
|
||||
size_t gpu_sizeof_shader(void);
|
||||
size_t gpu_sizeof_bundle_pool(void);
|
||||
size_t gpu_sizeof_bundle(void);
|
||||
size_t gpu_sizeof_pipeline(void);
|
||||
|
||||
// Buffer
|
||||
|
@ -192,10 +196,9 @@ enum {
|
|||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t number;
|
||||
uint8_t type;
|
||||
uint8_t stage;
|
||||
uint8_t count;
|
||||
uint32_t number;
|
||||
gpu_slot_type type;
|
||||
uint32_t stages;
|
||||
} gpu_slot;
|
||||
|
||||
typedef struct {
|
||||
|
@ -223,6 +226,41 @@ typedef struct {
|
|||
bool gpu_shader_init(gpu_shader* shader, gpu_shader_info* info);
|
||||
void gpu_shader_destroy(gpu_shader* shader);
|
||||
|
||||
// Bundles
|
||||
|
||||
typedef struct {
|
||||
gpu_buffer* object;
|
||||
uint32_t offset;
|
||||
uint32_t extent;
|
||||
} gpu_buffer_binding;
|
||||
|
||||
typedef struct {
|
||||
uint32_t number;
|
||||
gpu_slot_type type;
|
||||
union {
|
||||
gpu_buffer_binding buffer;
|
||||
gpu_texture* texture;
|
||||
gpu_sampler* sampler;
|
||||
};
|
||||
} gpu_binding;
|
||||
|
||||
typedef struct {
|
||||
gpu_layout* layout;
|
||||
gpu_binding* bindings;
|
||||
uint32_t count;
|
||||
} gpu_bundle_info;
|
||||
|
||||
typedef struct {
|
||||
gpu_bundle* bundles;
|
||||
gpu_bundle_info* contents;
|
||||
gpu_layout* layout;
|
||||
uint32_t count;
|
||||
} gpu_bundle_pool_info;
|
||||
|
||||
bool gpu_bundle_pool_init(gpu_bundle_pool* pool, gpu_bundle_pool_info* info);
|
||||
void gpu_bundle_pool_destroy(gpu_bundle_pool* pool);
|
||||
void gpu_bundle_write(gpu_bundle** bundles, gpu_bundle_info* info, uint32_t count);
|
||||
|
||||
// Pipeline
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -43,6 +43,14 @@ struct gpu_shader {
|
|||
VkPipelineLayout pipelineLayout;
|
||||
};
|
||||
|
||||
struct gpu_bundle_pool {
|
||||
VkDescriptorPool handle;
|
||||
};
|
||||
|
||||
struct gpu_bundle {
|
||||
VkDescriptorSet handle;
|
||||
};
|
||||
|
||||
struct gpu_pipeline {
|
||||
VkPipeline handle;
|
||||
VkPipelineLayout layout;
|
||||
|
@ -57,6 +65,8 @@ size_t gpu_sizeof_texture() { return sizeof(gpu_texture); }
|
|||
size_t gpu_sizeof_sampler() { return sizeof(gpu_sampler); }
|
||||
size_t gpu_sizeof_layout() { return sizeof(gpu_layout); }
|
||||
size_t gpu_sizeof_shader() { return sizeof(gpu_shader); }
|
||||
size_t gpu_sizeof_bundle_pool() { return sizeof(gpu_bundle_pool); }
|
||||
size_t gpu_sizeof_bundle() { return sizeof(gpu_bundle); }
|
||||
size_t gpu_sizeof_pipeline() { return sizeof(gpu_pipeline); }
|
||||
|
||||
// Internals
|
||||
|
@ -763,11 +773,11 @@ bool gpu_layout_init(gpu_layout* layout, gpu_layout_info* info) {
|
|||
bindings[i] = (VkDescriptorSetLayoutBinding) {
|
||||
.binding = info->slots[i].number,
|
||||
.descriptorType = types[info->slots[i].type],
|
||||
.descriptorCount = info->slots[i].count,
|
||||
.stageFlags = info->slots[i].stage == GPU_STAGE_ALL ? VK_SHADER_STAGE_ALL :
|
||||
(((info->slots[i].stage & GPU_STAGE_VERTEX) ? VK_SHADER_STAGE_VERTEX_BIT : 0) |
|
||||
((info->slots[i].stage & GPU_STAGE_FRAGMENT) ? VK_SHADER_STAGE_FRAGMENT_BIT : 0) |
|
||||
((info->slots[i].stage & GPU_STAGE_COMPUTE) ? VK_SHADER_STAGE_COMPUTE_BIT : 0))
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = info->slots[i].stages == GPU_STAGE_ALL ? VK_SHADER_STAGE_ALL :
|
||||
(((info->slots[i].stages & GPU_STAGE_VERTEX) ? VK_SHADER_STAGE_VERTEX_BIT : 0) |
|
||||
((info->slots[i].stages & GPU_STAGE_FRAGMENT) ? VK_SHADER_STAGE_FRAGMENT_BIT : 0) |
|
||||
((info->slots[i].stages & GPU_STAGE_COMPUTE) ? VK_SHADER_STAGE_COMPUTE_BIT : 0))
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -784,7 +794,7 @@ bool gpu_layout_init(gpu_layout* layout, gpu_layout_info* info) {
|
|||
memset(layout->descriptorCounts, 0, sizeof(layout->descriptorCounts));
|
||||
|
||||
for (uint32_t i = 0; i < info->count; i++) {
|
||||
layout->descriptorCounts[info->slots[i].type] += MAX(info->slots[i].count, 1);
|
||||
layout->descriptorCounts[info->slots[i].type]++;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -843,6 +853,149 @@ void gpu_shader_destroy(gpu_shader* shader) {
|
|||
condemn(shader->pipelineLayout, VK_OBJECT_TYPE_PIPELINE_LAYOUT);
|
||||
}
|
||||
|
||||
// Bundles
|
||||
|
||||
bool gpu_bundle_pool_init(gpu_bundle_pool* pool, gpu_bundle_pool_info* info) {
|
||||
VkDescriptorPoolSize sizes[7] = {
|
||||
[GPU_SLOT_UNIFORM_BUFFER] = { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0 },
|
||||
[GPU_SLOT_STORAGE_BUFFER] = { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0 },
|
||||
[GPU_SLOT_UNIFORM_BUFFER_DYNAMIC] = { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 0 },
|
||||
[GPU_SLOT_STORAGE_BUFFER_DYNAMIC] = { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 0 },
|
||||
[GPU_SLOT_SAMPLED_TEXTURE] = { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 0 },
|
||||
[GPU_SLOT_STORAGE_TEXTURE] = { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 0 },
|
||||
[GPU_SLOT_SAMPLER] = { VK_DESCRIPTOR_TYPE_SAMPLER, 0 }
|
||||
};
|
||||
|
||||
if (info->layout) {
|
||||
for (uint32_t i = 0; i < COUNTOF(sizes); i++) {
|
||||
sizes[i].descriptorCount = info->layout->descriptorCounts[i] * info->count;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < info->count; i++) {
|
||||
for (uint32_t j = 0; j < COUNTOF(sizes); j++) {
|
||||
sizes[j].descriptorCount += info->contents[i].layout->descriptorCounts[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Descriptor counts of zero are forbidden, so swap any zero-sized sizes with the last entry
|
||||
uint32_t poolSizeCount = COUNTOF(sizes);
|
||||
for (uint32_t i = 0; i < poolSizeCount; i++) {
|
||||
if (sizes[i].descriptorCount == 0) {
|
||||
VkDescriptorPoolSize last = sizes[poolSizeCount - 1];
|
||||
sizes[poolSizeCount - 1] = sizes[i];
|
||||
sizes[i] = last;
|
||||
poolSizeCount--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
VkDescriptorPoolCreateInfo poolInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.maxSets = info->count,
|
||||
.poolSizeCount = poolSizeCount,
|
||||
.pPoolSizes = sizes
|
||||
};
|
||||
|
||||
VK(vkCreateDescriptorPool(state.device, &poolInfo, NULL, &pool->handle), "Could not create bundle pool") {
|
||||
return false;
|
||||
}
|
||||
|
||||
VkDescriptorSetLayout layouts[256];
|
||||
for (uint32_t i = 0; i < info->count; i+= COUNTOF(layouts)) {
|
||||
uint32_t chunk = MIN(info->count - i, COUNTOF(layouts));
|
||||
|
||||
for (uint32_t j = 0; j < chunk; j++) {
|
||||
layouts[j] = info->layout ? info->layout->handle : info->contents[i + j].layout->handle;
|
||||
}
|
||||
|
||||
VkDescriptorSetAllocateInfo allocateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorPool = pool->handle,
|
||||
.descriptorSetCount = chunk,
|
||||
.pSetLayouts = layouts
|
||||
};
|
||||
|
||||
VK(vkAllocateDescriptorSets(state.device, &allocateInfo, &info->bundles[i].handle), "Could not allocate descriptor sets") {
|
||||
gpu_bundle_pool_destroy(pool);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void gpu_bundle_pool_destroy(gpu_bundle_pool* pool) {
|
||||
condemn(pool->handle, VK_OBJECT_TYPE_DESCRIPTOR_POOL);
|
||||
}
|
||||
|
||||
void gpu_bundle_write(gpu_bundle** bundles, gpu_bundle_info* infos, uint32_t count) {
|
||||
VkDescriptorBufferInfo buffers[256];
|
||||
VkDescriptorImageInfo images[256];
|
||||
VkWriteDescriptorSet writes[256];
|
||||
uint32_t bufferCount = 0;
|
||||
uint32_t imageCount = 0;
|
||||
uint32_t writeCount = 0;
|
||||
|
||||
static const VkDescriptorType types[] = {
|
||||
[GPU_SLOT_UNIFORM_BUFFER] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
[GPU_SLOT_STORAGE_BUFFER] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
[GPU_SLOT_UNIFORM_BUFFER_DYNAMIC] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
||||
[GPU_SLOT_STORAGE_BUFFER_DYNAMIC] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
|
||||
[GPU_SLOT_SAMPLED_TEXTURE] = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
||||
[GPU_SLOT_STORAGE_TEXTURE] = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
[GPU_SLOT_SAMPLER] = VK_DESCRIPTOR_TYPE_SAMPLER
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
gpu_bundle_info* info = &infos[i];
|
||||
for (uint32_t j = 0; j < info->count; j++) {
|
||||
gpu_binding* binding = &info->bindings[j];
|
||||
VkDescriptorType type = types[binding->type];
|
||||
bool texture = type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
bool sampler = type == VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||
bool image = texture || sampler;
|
||||
|
||||
writes[writeCount++] = (VkWriteDescriptorSet) {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = bundles[i]->handle,
|
||||
.dstBinding = binding->number,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = type,
|
||||
.pBufferInfo = &buffers[bufferCount],
|
||||
.pImageInfo = &images[imageCount]
|
||||
};
|
||||
|
||||
if (sampler) {
|
||||
images[imageCount++] = (VkDescriptorImageInfo) {
|
||||
.sampler = binding->sampler->handle
|
||||
};
|
||||
} else if (texture) {
|
||||
images[imageCount++] = (VkDescriptorImageInfo) {
|
||||
.imageView = binding->texture->view,
|
||||
.imageLayout = binding->texture->layout
|
||||
};
|
||||
} else {
|
||||
buffers[bufferCount++] = (VkDescriptorBufferInfo) {
|
||||
.buffer = binding->buffer.object->handle,
|
||||
.offset = binding->buffer.offset,
|
||||
.range = binding->buffer.extent
|
||||
};
|
||||
}
|
||||
|
||||
if ((image ? imageCount >= COUNTOF(images) : bufferCount >= COUNTOF(buffers)) || writeCount >= COUNTOF(writes)) {
|
||||
vkUpdateDescriptorSets(state.device, writeCount, writes, 0, NULL);
|
||||
bufferCount = imageCount = writeCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (writeCount > 0) {
|
||||
vkUpdateDescriptorSets(state.device, writeCount, writes, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// Pipeline
|
||||
|
||||
bool gpu_pipeline_init_graphics(gpu_pipeline* pipeline, gpu_pipeline_info* info) {
|
||||
|
|
|
@ -92,6 +92,21 @@ struct Pass {
|
|||
uint32_t pipelineIndex;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
void* next;
|
||||
gpu_bundle_pool* gpu;
|
||||
gpu_bundle* bundles;
|
||||
uint32_t cursor;
|
||||
uint32_t tick;
|
||||
} BundlePool;
|
||||
|
||||
typedef struct {
|
||||
uint64_t hash;
|
||||
gpu_layout* gpu;
|
||||
BundlePool* head;
|
||||
BundlePool* tail;
|
||||
} Layout;
|
||||
|
||||
typedef struct {
|
||||
gpu_texture* texture;
|
||||
uint32_t hash;
|
||||
|
@ -115,6 +130,8 @@ static struct {
|
|||
float background[4];
|
||||
Texture* window;
|
||||
Attachment attachments[16];
|
||||
arr_t(Layout) layouts;
|
||||
uint32_t builtinLayout;
|
||||
Allocator allocator;
|
||||
} state;
|
||||
|
||||
|
@ -123,6 +140,7 @@ static struct {
|
|||
static void* tempAlloc(size_t size);
|
||||
static void beginFrame(void);
|
||||
static gpu_stream* getTransfers(void);
|
||||
static uint32_t getLayout(gpu_slot* slots, uint32_t count);
|
||||
static gpu_texture* getAttachment(uint32_t size[2], uint32_t layers, TextureFormat format, bool srgb, uint32_t samples);
|
||||
static size_t measureTexture(TextureFormat format, uint16_t w, uint16_t h, uint16_t d);
|
||||
static void checkShaderFeatures(uint32_t* features, uint32_t count);
|
||||
|
@ -159,6 +177,16 @@ bool lovrGraphicsInit(bool debug, bool vsync) {
|
|||
lovrThrow("Failed to initialize GPU");
|
||||
}
|
||||
|
||||
arr_init(&state.layouts, realloc);
|
||||
|
||||
gpu_slot builtins[] = {
|
||||
{ 0, GPU_SLOT_UNIFORM_BUFFER_DYNAMIC, GPU_STAGE_ALL },
|
||||
{ 1, GPU_SLOT_UNIFORM_BUFFER_DYNAMIC, GPU_STAGE_ALL },
|
||||
{ 2, GPU_SLOT_SAMPLER, GPU_STAGE_ALL }
|
||||
};
|
||||
|
||||
state.builtinLayout = getLayout(builtins, COUNTOF(builtins));
|
||||
|
||||
// Temporary frame memory uses a large 1GB virtual memory allocation, committing pages as needed
|
||||
state.allocator.length = 1 << 14;
|
||||
state.allocator.memory = os_vm_init(MAX_FRAME_MEMORY);
|
||||
|
@ -176,6 +204,11 @@ void lovrGraphicsDestroy() {
|
|||
free(state.attachments[i].texture);
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < state.layouts.length; i++) {
|
||||
gpu_layout_destroy(state.layouts.data[i].gpu);
|
||||
free(state.layouts.data[i].gpu);
|
||||
}
|
||||
arr_free(&state.layouts);
|
||||
lovrRelease(state.window, lovrTextureDestroy);
|
||||
gpu_destroy();
|
||||
glslang_finalize_process();
|
||||
|
@ -850,8 +883,7 @@ Shader* lovrShaderCreate(ShaderInfo* info) {
|
|||
slots[index] = (gpu_slot) {
|
||||
.number = resource->binding,
|
||||
.type = resourceTypes[resource->type],
|
||||
.stage = stage,
|
||||
.count = resource->arraySize
|
||||
.stages = stage
|
||||
};
|
||||
|
||||
shader->resources[index] = (ShaderResource) {
|
||||
|
@ -905,6 +937,7 @@ Shader* lovrShaderCreate(ShaderInfo* info) {
|
|||
shader->ref = 1;
|
||||
shader->gpu = (gpu_shader*) (shader + 1);
|
||||
shader->info = *info;
|
||||
shader->layout = getLayout(slots, shader->resourceCount);
|
||||
|
||||
gpu_shader_info gpu = {
|
||||
.stages[0] = { info->stages[0]->data, info->stages[0]->size },
|
||||
|
@ -913,6 +946,12 @@ Shader* lovrShaderCreate(ShaderInfo* info) {
|
|||
.label = info->label
|
||||
};
|
||||
|
||||
if (info->type == SHADER_GRAPHICS) {
|
||||
gpu.layouts[0] = state.layouts.data[state.builtinLayout].gpu;
|
||||
}
|
||||
|
||||
gpu.layouts[userSet] = shader->resourceCount > 0 ? state.layouts.data[shader->layout].gpu : NULL;
|
||||
|
||||
gpu_shader_init(shader->gpu, &gpu);
|
||||
lovrShaderInit(shader);
|
||||
return shader;
|
||||
|
@ -1295,6 +1334,35 @@ static gpu_stream* getTransfers(void) {
|
|||
return state.transfers->stream;
|
||||
}
|
||||
|
||||
static uint32_t getLayout(gpu_slot* slots, uint32_t count) {
|
||||
uint64_t hash = hash64(slots, count * sizeof(gpu_slot));
|
||||
|
||||
uint32_t index;
|
||||
for (uint32_t index = 0; index < state.layouts.length; index++) {
|
||||
if (state.layouts.data[index].hash == hash) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
gpu_layout_info info = {
|
||||
.slots = slots,
|
||||
.count = count
|
||||
};
|
||||
|
||||
gpu_layout* handle = malloc(gpu_sizeof_layout());
|
||||
lovrAssert(handle, "Out of memory");
|
||||
gpu_layout_init(handle, &info);
|
||||
|
||||
Layout layout = {
|
||||
.hash = hash,
|
||||
.gpu = handle
|
||||
};
|
||||
|
||||
index = state.layouts.length;
|
||||
arr_push(&state.layouts, layout);
|
||||
return index;
|
||||
}
|
||||
|
||||
static gpu_texture* getAttachment(uint32_t size[2], uint32_t layers, TextureFormat format, bool srgb, uint32_t samples) {
|
||||
uint16_t key[] = { size[0], size[1], layers, format, srgb, samples };
|
||||
uint32_t hash = hash64(key, sizeof(key));
|
||||
|
|
Loading…
Reference in New Issue