mirror of https://github.com/bjornbytes/lovr.git
Add Pass; Buffer transfers; lovr.graphics.submit; Bugfixes;
This commit is contained in:
parent
874c35120b
commit
7aee0a4656
|
@ -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 },
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue