Add Pass; Buffer transfers; lovr.graphics.submit; Bugfixes;

This commit is contained in:
bjorn 2022-04-28 22:30:31 -07:00
parent 874c35120b
commit 7aee0a4656
5 changed files with 141 additions and 20 deletions

View File

@ -235,6 +235,11 @@ static int l_lovrGraphicsInit(lua_State* L) {
return 0;
}
static int l_lovrGraphicsSubmit(lua_State* L) {
lovrGraphicsSubmit(NULL, 0);
return 0;
}
static int l_lovrGraphicsGetDevice(lua_State* L) {
GraphicsDevice device;
lovrGraphicsGetDevice(&device);
@ -382,6 +387,7 @@ static int l_lovrGraphicsBuffer(lua_State* L) {
static const luaL_Reg lovrGraphics[] = {
{ "init", l_lovrGraphicsInit },
{ "submit", l_lovrGraphicsSubmit },
{ "getDevice", l_lovrGraphicsGetDevice },
{ "getFeatures", l_lovrGraphicsGetFeatures },
{ "getLimits", l_lovrGraphicsGetLimits },

View File

@ -28,9 +28,10 @@ void* gpu_map(gpu_buffer* buffer, uint32_t size, uint32_t align, gpu_map_mode mo
// Stream
gpu_stream* gpu_stream_begin(void);
gpu_stream* gpu_stream_begin(const char* label);
void gpu_stream_end(gpu_stream* stream);
void gpu_copy_buffers(gpu_stream* stream, gpu_buffer* src, gpu_buffer* dst, uint32_t srcOffset, uint32_t dstOffset, uint32_t size);
void gpu_clear_buffer(gpu_stream* stream, gpu_buffer* buffer, uint32_t offset, uint32_t size);
// Entry

View File

@ -303,8 +303,9 @@ void* gpu_map(gpu_buffer* buffer, uint32_t size, uint32_t align, gpu_map_mode mo
bufferSize = size;
} else {
while (pool->size < size) {
pool->size = bufferSize = pool->size ? (pool->size << 1) : (1 << 22);
pool->size = pool->size ? (pool->size << 1) : (1 << 22);
}
bufferSize = pool->size * COUNTOF(state.ticks);
}
VkBufferCreateInfo info = {
@ -320,7 +321,7 @@ void* gpu_map(gpu_buffer* buffer, uint32_t size, uint32_t align, gpu_map_mode mo
VkBuffer handle;
VK(vkCreateBuffer(state.device, &info, NULL, &handle), "Could not create scratch buffer") return NULL;
nickname(handle, VK_OBJECT_TYPE_BUFFER, mode == GPU_MAP_WRITE ? "Write Scratchpad" : "Read Scratchpad");
nickname(handle, VK_OBJECT_TYPE_BUFFER, "Scratchpad");
VkDeviceSize offset;
VkMemoryRequirements requirements;
@ -346,24 +347,25 @@ void* gpu_map(gpu_buffer* buffer, uint32_t size, uint32_t align, gpu_map_mode mo
pool->memory = memory;
pool->buffer = handle;
pool->cursor = cursor = 0;
pool->pointer = (char*) pool->memory->pointer + pool->size * zone;
pool->pointer = pool->memory->pointer;
}
}
pool->cursor = cursor + size;
buffer->handle = pool->buffer;
buffer->memory = ~0u;
buffer->offset = cursor + pool->size * zone;
buffer->offset = pool->size * zone + cursor;
return pool->pointer + cursor;
return pool->pointer + pool->size * zone + cursor;
}
// Stream
gpu_stream* gpu_stream_begin() {
gpu_stream* gpu_stream_begin(const char* label) {
gpu_tick* tick = &state.ticks[state.tick[CPU] & TICK_MASK];
CHECK(state.streamCount < COUNTOF(tick->streams), "Too many streams") return NULL;
gpu_stream* stream = &tick->streams[state.streamCount];
nickname(stream->commands, VK_OBJECT_TYPE_COMMAND_BUFFER, label);
VkCommandBufferBeginInfo beginfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
@ -387,6 +389,10 @@ void gpu_copy_buffers(gpu_stream* stream, gpu_buffer* src, gpu_buffer* dst, uint
});
}
void gpu_clear_buffer(gpu_stream* stream, gpu_buffer* buffer, uint32_t offset, uint32_t size) {
vkCmdFillBuffer(stream->commands, buffer->handle, offset, size, 0);
}
// Entry
bool gpu_init(gpu_config* config) {
@ -615,20 +621,20 @@ bool gpu_init(gpu_config* config) {
vkGetBufferMemoryRequirements(state.device, buffer, &requirements);
vkDestroyBuffer(state.device, buffer, NULL);
uint32_t fallback = i == GPU_MEMORY_BUFFER_GPU ? VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT : hostVisible;
VkMemoryPropertyFlags fallback = i == GPU_MEMORY_BUFFER_GPU ? VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT : hostVisible;
for (uint32_t j = 0; j < memoryProperties.memoryTypeCount; j++) {
if (~requirements.memoryTypeBits & (1 << i)) {
if (~requirements.memoryTypeBits & (1 << j)) {
continue;
}
if ((memoryTypes[i].propertyFlags & fallback) == fallback) {
if ((memoryTypes[j].propertyFlags & fallback) == fallback) {
allocator->memoryFlags = memoryTypes[j].propertyFlags;
allocator->memoryType = j;
continue;
}
if ((memoryTypes[i].propertyFlags & bufferFlags[i].flags) == bufferFlags[i].flags) {
if ((memoryTypes[j].propertyFlags & bufferFlags[i].flags) == bufferFlags[i].flags) {
allocator->memoryFlags = memoryTypes[j].propertyFlags;
allocator->memoryType = j;
break;
@ -680,6 +686,8 @@ void gpu_destroy(void) {
if (state.device) vkDeviceWaitIdle(state.device);
state.tick[GPU] = state.tick[CPU];
expunge();
if (state.scratchpad[0].buffer) vkDestroyBuffer(state.device, state.scratchpad[0].buffer, NULL);
if (state.scratchpad[1].buffer) vkDestroyBuffer(state.device, state.scratchpad[0].buffer, NULL);
for (uint32_t i = 0; i < COUNTOF(state.ticks); i++) {
gpu_tick* tick = &state.ticks[i];
if (tick->pool) vkDestroyCommandPool(state.device, tick->pool, NULL);
@ -687,6 +695,9 @@ void gpu_destroy(void) {
if (tick->semaphores[1]) vkDestroySemaphore(state.device, tick->semaphores[1], NULL);
if (tick->fence) vkDestroyFence(state.device, tick->fence, NULL);
}
for (uint32_t i = 0; i < COUNTOF(state.memory); i++) {
if (state.memory[i].handle) vkFreeMemory(state.device, state.memory[i].handle, NULL);
}
if (state.device) vkDestroyDevice(state.device, NULL);
if (state.messenger) vkDestroyDebugUtilsMessengerEXT(state.instance, state.messenger, NULL);
if (state.instance) vkDestroyInstance(state.instance, NULL);
@ -789,6 +800,7 @@ static gpu_memory* gpu_allocate(gpu_memory_type type, VkMemoryRequirements info,
static void gpu_release(gpu_memory* memory) {
if (memory && --memory->refs == 0) {
condemn(memory->handle, VK_OBJECT_TYPE_DEVICE_MEMORY);
memory->handle = NULL;
}
}

View File

@ -15,6 +15,12 @@ struct Buffer {
char* pointer;
};
struct Pass {
uint32_t ref;
PassInfo info;
gpu_stream* stream;
};
typedef struct {
char* memory;
uint32_t cursor;
@ -23,6 +29,9 @@ typedef struct {
static struct {
bool initialized;
bool active;
uint32_t tick;
Pass* transfers;
gpu_device_info device;
gpu_features features;
gpu_limits limits;
@ -31,7 +40,9 @@ static struct {
// Helpers
static void* fralloc(size_t size);
static void* tempAlloc(size_t size);
static void beginFrame(void);
static gpu_stream* getTransfers(void);
static void onMessage(void* context, const char* message, bool severe);
// Entry
@ -120,6 +131,34 @@ void lovrGraphicsGetLimits(GraphicsLimits* limits) {
limits->pointSize = state.limits.pointSize;
}
void lovrGraphicsSubmit(Pass** passes, uint32_t count) {
if (!state.active) {
return;
}
// Allocate a few extra stream handles for any internal passes we sneak in
gpu_stream** streams = tempAlloc((count + 3) * sizeof(gpu_stream*));
uint32_t extraPassCount = 0;
if (state.transfers) {
streams[extraPassCount++] = state.transfers->stream;
}
for (uint32_t i = 0; i < count; i++) {
streams[extraPassCount + i] = passes[i]->stream;
}
for (uint32_t i = 0; i < extraPassCount + count; i++) {
gpu_stream_end(streams[i]);
}
gpu_submit(streams, extraPassCount + count);
state.transfers = NULL;
state.active = false;
}
// Buffer
Buffer* lovrGraphicsGetBuffer(BufferInfo* info, void** data) {
@ -127,7 +166,7 @@ Buffer* lovrGraphicsGetBuffer(BufferInfo* info, void** data) {
lovrCheck(size > 0, "Buffer size can not be zero");
lovrCheck(size <= 1 << 30, "Max buffer size is 16GB");
Buffer* buffer = fralloc(sizeof(Buffer) + gpu_sizeof_buffer());
Buffer* buffer = tempAlloc(sizeof(Buffer) + gpu_sizeof_buffer());
buffer->ref = 1;
buffer->size = size;
buffer->gpu = (gpu_buffer*) (buffer + 1);
@ -161,7 +200,7 @@ Buffer* lovrBufferCreate(BufferInfo* info, void** data) {
});
if (data && *data == NULL) {
gpu_buffer* scratchpad = fralloc(gpu_sizeof_buffer());
gpu_buffer* scratchpad = tempAlloc(gpu_sizeof_buffer());
*data = gpu_map(scratchpad, size, 4, GPU_MAP_WRITE);
// TODO copy scratchpad to buffer
}
@ -195,24 +234,47 @@ void* lovrBufferMap(Buffer* buffer, uint32_t offset, uint32_t size) {
return buffer->pointer + offset;
}
// TODO stage copy once commands exist
return NULL;
gpu_stream* transfers = getTransfers();
gpu_buffer* scratchpad = tempAlloc(gpu_sizeof_buffer());
void* data = gpu_map(scratchpad, size, 4, GPU_MAP_WRITE);
gpu_copy_buffers(transfers, scratchpad, buffer->gpu, 0, offset, size);
return data;
}
void lovrBufferClear(Buffer* buffer, uint32_t offset, uint32_t size) {
lovrCheck(size % 4 == 0, "Buffer clear size must be a multiple of 4");
lovrCheck(offset % 4 == 0, "Buffer clear offset must be a multiple of 4");
lovrCheck(offset + size <= buffer->size, "Tried to clear past the end of the Buffer");
if (buffer->pointer) {
memset(buffer->pointer + offset, 0, size);
} else {
lovrCheck(size % 4 == 0, "Buffer clear size must be a multiple of 4");
lovrCheck(offset % 4 == 0, "Buffer clear offset must be a multiple of 4");
// TODO clear once commands exist
gpu_stream* transfers = getTransfers();
gpu_clear_buffer(transfers, buffer->gpu, offset, size);
}
}
// Pass
Pass* lovrGraphicsGetPass(PassInfo* info) {
beginFrame();
Pass* pass = tempAlloc(sizeof(Pass));
pass->ref = 1;
pass->info = *info;
pass->stream = gpu_stream_begin(info->label);
return pass;
}
void lovrPassDestroy(void* ref) {
//
}
const PassInfo* lovrPassGetInfo(Pass* pass) {
return &pass->info;
}
// Helpers
static void* fralloc(size_t size) {
static void* tempAlloc(size_t size) {
while (state.allocator.cursor + size > state.allocator.length) {
lovrAssert(state.allocator.length << 1 <= MAX_FRAME_MEMORY, "Out of memory");
os_vm_commit(state.allocator.memory + state.allocator.length, state.allocator.length);
@ -224,6 +286,26 @@ static void* fralloc(size_t size) {
return state.allocator.memory + cursor;
}
static void beginFrame(void) {
if (state.active) {
return;
}
state.active = true;
state.tick = gpu_begin();
}
static gpu_stream* getTransfers(void) {
if (!state.transfers) {
state.transfers = lovrGraphicsGetPass(&(PassInfo) {
.type = PASS_TRANSFER,
.label = "Internal Transfers"
});
}
return state.transfers->stream;
}
static void onMessage(void* context, const char* message, bool severe) {
if (severe) {
lovrLog(LOG_ERROR, "GPU", message);

View File

@ -4,6 +4,7 @@
#pragma once
typedef struct Buffer Buffer;
typedef struct Pass Pass;
typedef struct {
uint32_t deviceId;
@ -59,6 +60,8 @@ void lovrGraphicsGetDevice(GraphicsDevice* device);
void lovrGraphicsGetFeatures(GraphicsFeatures* features);
void lovrGraphicsGetLimits(GraphicsLimits* limits);
void lovrGraphicsSubmit(Pass** passes, uint32_t count);
// Buffer
typedef enum {
@ -125,3 +128,20 @@ const BufferInfo* lovrBufferGetInfo(Buffer* buffer);
bool lovrBufferIsTemporary(Buffer* buffer);
void* lovrBufferMap(Buffer* buffer, uint32_t offset, uint32_t size);
void lovrBufferClear(Buffer* buffer, uint32_t offset, uint32_t size);
// Pass
typedef enum {
PASS_RENDER,
PASS_COMPUTE,
PASS_TRANSFER
} PassType;
typedef struct {
PassType type;
const char* label;
} PassInfo;
Pass* lovrGraphicsGetPass(PassInfo* info);
void lovrPassDestroy(void* ref);
const PassInfo* lovrPassGetInfo(Pass* pass);