mirror of https://github.com/bjornbytes/lovr.git
Tally;
This commit is contained in:
parent
9e7bd34ab1
commit
c327eb103f
|
@ -10,6 +10,7 @@ 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_tally gpu_tally;
|
||||
typedef struct gpu_stream gpu_stream;
|
||||
|
||||
size_t gpu_sizeof_buffer(void);
|
||||
|
@ -20,6 +21,7 @@ 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);
|
||||
size_t gpu_sizeof_tally(void);
|
||||
|
||||
// Buffer
|
||||
|
||||
|
@ -447,6 +449,22 @@ bool gpu_pipeline_init_graphics(gpu_pipeline* pipeline, gpu_pipeline_info* info)
|
|||
bool gpu_pipeline_init_compute(gpu_pipeline* pipeline, gpu_compute_pipeline_info* info);
|
||||
void gpu_pipeline_destroy(gpu_pipeline* pipeline);
|
||||
|
||||
// Tally
|
||||
|
||||
typedef enum {
|
||||
GPU_TALLY_TIMER,
|
||||
GPU_TALLY_PIXEL,
|
||||
GPU_TALLY_PIPELINE
|
||||
} gpu_tally_type;
|
||||
|
||||
typedef struct {
|
||||
gpu_tally_type type;
|
||||
uint32_t count;
|
||||
} gpu_tally_info;
|
||||
|
||||
bool gpu_tally_init(gpu_tally* tally, gpu_tally_info* info);
|
||||
void gpu_tally_destroy(gpu_tally* tally);
|
||||
|
||||
// Stream
|
||||
|
||||
typedef enum {
|
||||
|
@ -547,10 +565,15 @@ void gpu_copy_buffers(gpu_stream* stream, gpu_buffer* src, gpu_buffer* dst, uint
|
|||
void gpu_copy_textures(gpu_stream* stream, gpu_texture* src, gpu_texture* dst, uint32_t srcOffset[4], uint32_t dstOffset[4], uint32_t size[3]);
|
||||
void gpu_copy_buffer_texture(gpu_stream* stream, gpu_buffer* src, gpu_texture* dst, uint32_t srcOffset, uint32_t dstOffset[4], uint32_t extent[3]);
|
||||
void gpu_copy_texture_buffer(gpu_stream* stream, gpu_texture* src, gpu_buffer* dst, uint32_t srcOffset[4], uint32_t dstOffset, uint32_t extent[3]);
|
||||
void gpu_copy_tally_buffer(gpu_stream* stream, gpu_tally* src, gpu_buffer* dst, uint32_t srcIndex, uint32_t dstOffset, uint32_t count, uint32_t stride);
|
||||
void gpu_clear_buffer(gpu_stream* stream, gpu_buffer* buffer, uint32_t offset, uint32_t size);
|
||||
void gpu_clear_texture(gpu_stream* stream, gpu_texture* texture, float value[4], uint32_t layer, uint32_t layerCount, uint32_t level, uint32_t levelCount);
|
||||
void gpu_clear_tally(gpu_stream* stream, gpu_tally* tally, uint32_t index, uint32_t count);
|
||||
void gpu_blit(gpu_stream* stream, gpu_texture* src, gpu_texture* dst, uint32_t srcOffset[4], uint32_t dstOffset[4], uint32_t srcExtent[3], uint32_t dstExtent[3], gpu_filter filter);
|
||||
void gpu_sync(gpu_stream* stream, gpu_barrier* barriers, uint32_t count);
|
||||
void gpu_tally_begin(gpu_stream* stream, gpu_tally* tally, uint32_t index);
|
||||
void gpu_tally_end(gpu_stream* stream, gpu_tally* tally, uint32_t index);
|
||||
void gpu_tally_mark(gpu_stream* stream, gpu_tally* tally, uint32_t index);
|
||||
|
||||
// Entry
|
||||
|
||||
|
|
|
@ -55,6 +55,10 @@ struct gpu_pipeline {
|
|||
VkPipeline handle;
|
||||
};
|
||||
|
||||
struct gpu_tally {
|
||||
VkQueryPool handle;
|
||||
};
|
||||
|
||||
struct gpu_stream {
|
||||
VkCommandBuffer commands;
|
||||
};
|
||||
|
@ -67,6 +71,7 @@ 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); }
|
||||
size_t gpu_sizeof_tally() { return sizeof(gpu_tally); }
|
||||
|
||||
// Internals
|
||||
|
||||
|
@ -262,6 +267,8 @@ static bool check(bool condition, const char* message);
|
|||
X(vkCreateQueryPool)\
|
||||
X(vkDestroyQueryPool)\
|
||||
X(vkCmdResetQueryPool)\
|
||||
X(vkCmdBeginQuery)\
|
||||
X(vkCmdEndQuery)\
|
||||
X(vkCmdWriteTimestamp)\
|
||||
X(vkCmdCopyQueryPoolResults)\
|
||||
X(vkCreateBuffer)\
|
||||
|
@ -1350,6 +1357,40 @@ void gpu_pipeline_destroy(gpu_pipeline* pipeline) {
|
|||
condemn(pipeline->handle, VK_OBJECT_TYPE_PIPELINE);
|
||||
}
|
||||
|
||||
// Tally
|
||||
|
||||
bool gpu_tally_init(gpu_tally* tally, gpu_tally_info* info) {
|
||||
VkQueryType queryTypes[] = {
|
||||
[GPU_TALLY_TIMER] = VK_QUERY_TYPE_TIMESTAMP,
|
||||
[GPU_TALLY_PIXEL] = VK_QUERY_TYPE_OCCLUSION,
|
||||
[GPU_TALLY_PIPELINE] = VK_QUERY_TYPE_PIPELINE_STATISTICS
|
||||
};
|
||||
|
||||
VkQueryPoolCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
|
||||
.queryType = queryTypes[info->type],
|
||||
.queryCount = info->count,
|
||||
.pipelineStatistics = info->type == GPU_TALLY_PIPELINE ? (
|
||||
VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT |
|
||||
VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT |
|
||||
VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT |
|
||||
VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT |
|
||||
VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT |
|
||||
VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
|
||||
) : 0
|
||||
};
|
||||
|
||||
VK(vkCreateQueryPool(state.device, &createInfo, NULL, &tally->handle), "Could not create query pool") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void gpu_tally_destroy(gpu_tally* tally) {
|
||||
condemn(tally->handle, VK_OBJECT_TYPE_QUERY_POOL);
|
||||
}
|
||||
|
||||
// Stream
|
||||
|
||||
gpu_stream* gpu_stream_begin(const char* label) {
|
||||
|
@ -1558,6 +1599,10 @@ void gpu_copy_texture_buffer(gpu_stream* stream, gpu_texture* src, gpu_buffer* d
|
|||
vkCmdCopyImageToBuffer(stream->commands, src->handle, VK_IMAGE_LAYOUT_GENERAL, dst->handle, 1, ®ion);
|
||||
}
|
||||
|
||||
void gpu_copy_tally_buffer(gpu_stream* stream, gpu_tally* src, gpu_buffer* dst, uint32_t srcIndex, uint32_t dstOffset, uint32_t count, uint32_t stride) {
|
||||
vkCmdCopyQueryPoolResults(stream->commands, src->handle, srcIndex, count, dst->handle, dstOffset, stride, 0);
|
||||
}
|
||||
|
||||
void gpu_clear_buffer(gpu_stream* stream, gpu_buffer* buffer, uint32_t offset, uint32_t size) {
|
||||
vkCmdFillBuffer(stream->commands, buffer->handle, buffer->offset + offset, size, 0);
|
||||
}
|
||||
|
@ -1583,6 +1628,10 @@ void gpu_clear_texture(gpu_stream* stream, gpu_texture* texture, float value[4],
|
|||
}
|
||||
}
|
||||
|
||||
void gpu_clear_tally(gpu_stream* stream, gpu_tally* tally, uint32_t index, uint32_t count) {
|
||||
vkCmdResetQueryPool(stream->commands, tally->handle, index, count);
|
||||
}
|
||||
|
||||
void gpu_blit(gpu_stream* stream, gpu_texture* src, gpu_texture* dst, uint32_t srcOffset[4], uint32_t dstOffset[4], uint32_t srcExtent[3], uint32_t dstExtent[3], gpu_filter filter) {
|
||||
VkImageBlit region = {
|
||||
.srcSubresource = {
|
||||
|
@ -1629,6 +1678,18 @@ void gpu_sync(gpu_stream* stream, gpu_barrier* barriers, uint32_t count) {
|
|||
}
|
||||
}
|
||||
|
||||
void gpu_tally_begin(gpu_stream* stream, gpu_tally* tally, uint32_t index) {
|
||||
vkCmdBeginQuery(stream->commands, tally->handle, index, 0);
|
||||
}
|
||||
|
||||
void gpu_tally_end(gpu_stream* stream, gpu_tally* tally, uint32_t index) {
|
||||
vkCmdEndQuery(stream->commands, tally->handle, index);
|
||||
}
|
||||
|
||||
void gpu_tally_mark(gpu_stream* stream, gpu_tally* tally, uint32_t index) {
|
||||
vkCmdWriteTimestamp(stream->commands, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, tally->handle, index);
|
||||
}
|
||||
|
||||
// Entry
|
||||
|
||||
bool gpu_init(gpu_config* config) {
|
||||
|
@ -2352,6 +2413,7 @@ static void expunge() {
|
|||
case VK_OBJECT_TYPE_DESCRIPTOR_POOL: vkDestroyDescriptorPool(state.device, victim->handle, NULL); break;
|
||||
case VK_OBJECT_TYPE_PIPELINE_LAYOUT: vkDestroyPipelineLayout(state.device, victim->handle, NULL); break;
|
||||
case VK_OBJECT_TYPE_PIPELINE: vkDestroyPipeline(state.device, victim->handle, NULL); break;
|
||||
case VK_OBJECT_TYPE_QUERY_POOL: vkDestroyQueryPool(state.device, victim->handle, NULL); break;
|
||||
case VK_OBJECT_TYPE_RENDER_PASS: vkDestroyRenderPass(state.device, victim->handle, NULL); break;
|
||||
case VK_OBJECT_TYPE_FRAMEBUFFER: vkDestroyFramebuffer(state.device, victim->handle, NULL); break;
|
||||
case VK_OBJECT_TYPE_DEVICE_MEMORY: vkFreeMemory(state.device, victim->handle, NULL); break;
|
||||
|
|
|
@ -150,6 +150,14 @@ struct Font {
|
|||
uint32_t atlasY;
|
||||
};
|
||||
|
||||
struct Tally {
|
||||
uint32_t ref;
|
||||
uint32_t tick;
|
||||
TallyInfo info;
|
||||
gpu_tally* gpu;
|
||||
uint64_t* masks;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
float view[16];
|
||||
float projection[16];
|
||||
|
@ -2111,6 +2119,37 @@ void lovrFontGetLines(Font* font, ColoredString* strings, uint32_t count, float
|
|||
tempPop(stack);
|
||||
}
|
||||
|
||||
// Tally
|
||||
|
||||
Tally* lovrTallyCreate(TallyInfo* info) {
|
||||
lovrCheck(info->count > 0, "Tally count must be greater than zero");
|
||||
lovrCheck(info->views <= state.limits.renderSize[2], "Tally view count can not exceed the maximum view count");
|
||||
Tally* tally = calloc(1, sizeof(Tally) + gpu_sizeof_tally());
|
||||
lovrAssert(tally, "Out of memory");
|
||||
tally->ref = 1;
|
||||
tally->tick = state.tick;
|
||||
tally->info = *info;
|
||||
tally->gpu = (gpu_tally*) (tally + 1);
|
||||
tally->masks = calloc((info->count + 63) / 64, sizeof(uint64_t));
|
||||
lovrAssert(tally->masks, "Out of memory");
|
||||
|
||||
uint32_t total = info->count * (info->type == TALLY_TIMER ? 2 * info->views : 1);
|
||||
|
||||
gpu_tally_init(tally->gpu, &(gpu_tally_info) {
|
||||
.type = (gpu_tally_type) info->type,
|
||||
.count = total
|
||||
});
|
||||
|
||||
return tally;
|
||||
}
|
||||
|
||||
void lovrTallyDestroy(void* ref) {
|
||||
Tally* tally = ref;
|
||||
gpu_tally_destroy(tally->gpu);
|
||||
free(tally->masks);
|
||||
free(tally);
|
||||
}
|
||||
|
||||
// Pass
|
||||
|
||||
Pass* lovrGraphicsGetPass(PassInfo* info) {
|
||||
|
@ -3875,6 +3914,34 @@ void lovrPassMipmap(Pass* pass, Texture* texture, uint32_t base, uint32_t count)
|
|||
trackTexture(pass, texture, GPU_PHASE_TRANSFER, GPU_CACHE_TRANSFER_READ | GPU_CACHE_TRANSFER_WRITE);
|
||||
}
|
||||
|
||||
void lovrPassTick(Pass* pass, Tally* tally, uint32_t index) {
|
||||
lovrCheck(index < tally->info.count, "Trying to use tally slot #%d, but the tally only has %d slots", index + 1, tally->info.count);
|
||||
lovrCheck(~tally->masks[index / 64] & (1 << (index % 64)), "Tally slot #%d has already been used", index + 1);
|
||||
|
||||
if (tally->tick != state.tick) {
|
||||
gpu_clear_tally(state.stream, tally->gpu, 0, tally->info.count * 2 * tally->info.views);
|
||||
memset(tally->masks, 0, (tally->info.count + 63) / 64 * sizeof(uint64_t));
|
||||
tally->tick = state.tick;
|
||||
}
|
||||
|
||||
if (tally->info.type == TALLY_TIMER) {
|
||||
gpu_tally_mark(pass->stream, tally->gpu, index * 2 * tally->info.views);
|
||||
} else {
|
||||
gpu_tally_begin(pass->stream, tally->gpu, index);
|
||||
}
|
||||
}
|
||||
|
||||
void lovrPassTock(Pass* pass, Tally* tally, uint32_t index) {
|
||||
lovrCheck(index < tally->info.count, "Trying to use tally slot #%d, but the tally only has %d slots", index + 1, tally->info.count);
|
||||
lovrCheck(tally->masks[index / 64] & (1 << (index % 64)), "Tally slot #%d has not been started yet", index + 1);
|
||||
|
||||
if (tally->info.type == TALLY_TIMER) {
|
||||
gpu_tally_mark(pass->stream, tally->gpu, index * 2 * tally->info.views + tally->info.views);
|
||||
} else {
|
||||
gpu_tally_end(pass->stream, tally->gpu, index);
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
static void* tempAlloc(size_t size) {
|
||||
|
|
|
@ -14,6 +14,7 @@ typedef struct Sampler Sampler;
|
|||
typedef struct Shader Shader;
|
||||
typedef struct Material Material;
|
||||
typedef struct Font Font;
|
||||
typedef struct Tally Tally;
|
||||
typedef struct Pass Pass;
|
||||
|
||||
typedef struct {
|
||||
|
@ -357,6 +358,24 @@ float lovrFontGetKerning(Font* font, uint32_t left, uint32_t right);
|
|||
float lovrFontGetWidth(Font* font, ColoredString* strings, uint32_t count);
|
||||
void lovrFontGetLines(Font* font, ColoredString* strings, uint32_t count, float wrap, void (*callback)(void* context, const char* string, size_t length), void* context);
|
||||
|
||||
// Tally
|
||||
|
||||
typedef enum {
|
||||
TALLY_TIMER,
|
||||
TALLY_PIXEL,
|
||||
TALLY_PIPELINE
|
||||
} TallyType;
|
||||
|
||||
typedef struct {
|
||||
TallyType type;
|
||||
uint32_t count;
|
||||
uint32_t views;
|
||||
} TallyInfo;
|
||||
|
||||
Tally* lovrTallyCreate(TallyInfo* info);
|
||||
void lovrTallyDestroy(void* ref);
|
||||
const TallyInfo* lovrTallyGetInfo(Tally* tally);
|
||||
|
||||
// Pass
|
||||
|
||||
typedef enum {
|
||||
|
@ -506,3 +525,5 @@ void lovrPassCopyImageToTexture(Pass* pass, struct Image* src, Texture* dst, uin
|
|||
void lovrPassCopyTextureToTexture(Pass* pass, Texture* src, Texture* dst, uint32_t srcOffset[4], uint32_t dstOffset[4], uint32_t extent[3]);
|
||||
void lovrPassBlit(Pass* pass, Texture* src, Texture* dst, uint32_t srcOffset[4], uint32_t dstOffset[4], uint32_t srcExtent[3], uint32_t dstExtent[3], FilterMode filter);
|
||||
void lovrPassMipmap(Pass* pass, Texture* texture, uint32_t base, uint32_t count);
|
||||
void lovrPassTick(Pass* pass, Tally* tally, uint32_t index);
|
||||
void lovrPassTock(Pass* pass, Tally* tally, uint32_t index);
|
||||
|
|
Loading…
Reference in New Issue