mirror of https://github.com/bjornbytes/lovr.git
rm core/gpu;
This is far from done and will probably be structured a bit differently.
This commit is contained in:
parent
9777306b70
commit
96337bf8cc
337
src/core/gpu.h
337
src/core/gpu.h
|
@ -1,337 +0,0 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct gpu_buffer gpu_buffer;
|
||||
typedef struct gpu_texture gpu_texture;
|
||||
typedef struct gpu_canvas gpu_canvas;
|
||||
typedef struct gpu_shader gpu_shader;
|
||||
typedef struct gpu_pipeline gpu_pipeline;
|
||||
|
||||
// Buffer
|
||||
|
||||
typedef enum {
|
||||
GPU_BUFFER_USAGE_VERTEX = (1 << 0),
|
||||
GPU_BUFFER_USAGE_INDEX = (1 << 1),
|
||||
GPU_BUFFER_USAGE_UNIFORM = (1 << 2),
|
||||
GPU_BUFFER_USAGE_COMPUTE = (1 << 3),
|
||||
GPU_BUFFER_USAGE_COPY = (1 << 4),
|
||||
GPU_BUFFER_USAGE_PASTE = (1 << 5)
|
||||
} gpu_buffer_usage;
|
||||
|
||||
typedef struct {
|
||||
uint64_t size;
|
||||
uint32_t usage;
|
||||
void* data;
|
||||
const char* label;
|
||||
} gpu_buffer_info;
|
||||
|
||||
size_t gpu_sizeof_buffer(void);
|
||||
bool gpu_buffer_init(gpu_buffer* buffer, gpu_buffer_info* info);
|
||||
void gpu_buffer_destroy(gpu_buffer* buffer);
|
||||
uint8_t* gpu_buffer_map(gpu_buffer* buffer, uint64_t offset, uint64_t size);
|
||||
void gpu_buffer_discard(gpu_buffer* buffer);
|
||||
|
||||
// Texture
|
||||
|
||||
typedef enum {
|
||||
GPU_TEXTURE_USAGE_SAMPLE = (1 << 0),
|
||||
GPU_TEXTURE_USAGE_CANVAS = (1 << 1),
|
||||
GPU_TEXTURE_USAGE_COMPUTE = (1 << 2),
|
||||
GPU_TEXTURE_USAGE_COPY = (1 << 3),
|
||||
GPU_TEXTURE_USAGE_PASTE = (1 << 4)
|
||||
} gpu_texture_usage;
|
||||
|
||||
typedef enum {
|
||||
GPU_TEXTURE_TYPE_2D,
|
||||
GPU_TEXTURE_TYPE_3D,
|
||||
GPU_TEXTURE_TYPE_CUBE,
|
||||
GPU_TEXTURE_TYPE_ARRAY
|
||||
} gpu_texture_type;
|
||||
|
||||
typedef enum {
|
||||
GPU_TEXTURE_FORMAT_RGBA8,
|
||||
GPU_TEXTURE_FORMAT_RGBA4,
|
||||
GPU_TEXTURE_FORMAT_R16F,
|
||||
GPU_TEXTURE_FORMAT_RG16F,
|
||||
GPU_TEXTURE_FORMAT_RGBA16F,
|
||||
GPU_TEXTURE_FORMAT_R32F,
|
||||
GPU_TEXTURE_FORMAT_RG32F,
|
||||
GPU_TEXTURE_FORMAT_RGBA32F,
|
||||
GPU_TEXTURE_FORMAT_RGB10A2,
|
||||
GPU_TEXTURE_FORMAT_RG11B10F,
|
||||
GPU_TEXTURE_FORMAT_D16,
|
||||
GPU_TEXTURE_FORMAT_D32F,
|
||||
GPU_TEXTURE_FORMAT_D24S8
|
||||
} gpu_texture_format;
|
||||
|
||||
typedef struct {
|
||||
gpu_texture* source;
|
||||
gpu_texture_type type;
|
||||
gpu_texture_format format;
|
||||
uint32_t baseMipmap;
|
||||
uint32_t mipmapCount;
|
||||
uint32_t baseLayer;
|
||||
uint32_t layerCount;
|
||||
} gpu_texture_view_info;
|
||||
|
||||
typedef struct {
|
||||
gpu_texture_type type;
|
||||
gpu_texture_format format;
|
||||
uint32_t size[3];
|
||||
uint32_t layers;
|
||||
uint32_t mipmaps;
|
||||
uint32_t usage;
|
||||
const char* label;
|
||||
} gpu_texture_info;
|
||||
|
||||
size_t gpu_sizeof_texture(void);
|
||||
bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info);
|
||||
bool gpu_texture_init_view(gpu_texture* texture, gpu_texture_view_info* info);
|
||||
void gpu_texture_destroy(gpu_texture* texture);
|
||||
void gpu_texture_write(gpu_texture* texture, uint8_t* data, uint16_t offset[4], uint16_t extent[4], uint16_t mip);
|
||||
|
||||
// Canvas
|
||||
|
||||
typedef enum {
|
||||
GPU_LOAD_OP_LOAD,
|
||||
GPU_LOAD_OP_CLEAR,
|
||||
GPU_LOAD_OP_DISCARD
|
||||
} gpu_load_op;
|
||||
|
||||
typedef struct {
|
||||
gpu_texture* texture;
|
||||
uint32_t layer;
|
||||
uint32_t level;
|
||||
gpu_load_op load;
|
||||
float clear[4];
|
||||
} gpu_color_attachment;
|
||||
|
||||
typedef struct {
|
||||
gpu_texture* texture;
|
||||
gpu_load_op load;
|
||||
float clear;
|
||||
struct {
|
||||
gpu_load_op load;
|
||||
uint8_t clear;
|
||||
} stencil;
|
||||
} gpu_depth_attachment;
|
||||
|
||||
typedef struct {
|
||||
gpu_color_attachment color[4];
|
||||
gpu_depth_attachment depth;
|
||||
uint32_t size[2];
|
||||
uint32_t views;
|
||||
uint32_t msaa;
|
||||
const char* label;
|
||||
} gpu_canvas_info;
|
||||
|
||||
size_t gpu_sizeof_canvas(void);
|
||||
bool gpu_canvas_init(gpu_canvas* canvas, gpu_canvas_info* info);
|
||||
void gpu_canvas_destroy(gpu_canvas* canvas);
|
||||
|
||||
// Shader
|
||||
|
||||
typedef struct {
|
||||
const void* code;
|
||||
size_t size;
|
||||
const char* entry;
|
||||
} gpu_shader_source;
|
||||
|
||||
typedef struct {
|
||||
gpu_shader_source vertex;
|
||||
gpu_shader_source fragment;
|
||||
gpu_shader_source compute;
|
||||
const char* label;
|
||||
} gpu_shader_info;
|
||||
|
||||
size_t gpu_sizeof_shader(void);
|
||||
bool gpu_shader_init(gpu_shader* shader, gpu_shader_info* info);
|
||||
void gpu_shader_destroy(gpu_shader* shader);
|
||||
|
||||
// Pipeline
|
||||
|
||||
typedef enum {
|
||||
GPU_FLOAT_F32,
|
||||
GPU_VEC2_F32,
|
||||
GPU_VEC2_F16,
|
||||
GPU_VEC2_U16N,
|
||||
GPU_VEC2_I16N,
|
||||
GPU_VEC3_F32,
|
||||
GPU_VEC4_F32,
|
||||
GPU_VEC4_F16,
|
||||
GPU_VEC4_U16N,
|
||||
GPU_VEC4_I16N,
|
||||
GPU_VEC4_U8N,
|
||||
GPU_VEC4_I8N,
|
||||
GPU_UINT_U32,
|
||||
GPU_UVEC2_U32,
|
||||
GPU_UVEC3_U32,
|
||||
GPU_UVEC4_U32,
|
||||
GPU_INT_I32,
|
||||
GPU_IVEC2_I32,
|
||||
GPU_IVEC3_I32,
|
||||
GPU_IVEC4_I32
|
||||
} gpu_attribute_format;
|
||||
|
||||
typedef struct {
|
||||
uint8_t location;
|
||||
uint8_t buffer;
|
||||
uint8_t format;
|
||||
uint8_t offset;
|
||||
} gpu_attribute;
|
||||
|
||||
typedef struct {
|
||||
uint16_t stride;
|
||||
uint16_t divisor;
|
||||
} gpu_buffer_layout;
|
||||
|
||||
typedef enum {
|
||||
GPU_DRAW_POINTS,
|
||||
GPU_DRAW_LINES,
|
||||
GPU_DRAW_LINE_STRIP,
|
||||
GPU_DRAW_TRIANGLES,
|
||||
GPU_DRAW_TRIANGLE_STRIP
|
||||
} gpu_draw_mode;
|
||||
|
||||
typedef enum {
|
||||
GPU_INDEX_U16,
|
||||
GPU_INDEX_U32
|
||||
} gpu_index_stride;
|
||||
|
||||
typedef enum {
|
||||
GPU_CULL_NONE,
|
||||
GPU_CULL_FRONT,
|
||||
GPU_CULL_BACK
|
||||
} gpu_cull_mode;
|
||||
|
||||
typedef enum {
|
||||
GPU_WINDING_CCW,
|
||||
GPU_WINDING_CW
|
||||
} gpu_winding;
|
||||
|
||||
typedef enum {
|
||||
GPU_COMPARE_NONE,
|
||||
GPU_COMPARE_EQUAL,
|
||||
GPU_COMPARE_NEQUAL,
|
||||
GPU_COMPARE_LESS,
|
||||
GPU_COMPARE_LEQUAL,
|
||||
GPU_COMPARE_GREATER,
|
||||
GPU_COMPARE_GEQUAL
|
||||
} gpu_compare_mode;
|
||||
|
||||
typedef enum {
|
||||
GPU_STENCIL_KEEP,
|
||||
GPU_STENCIL_ZERO,
|
||||
GPU_STENCIL_REPLACE,
|
||||
GPU_STENCIL_INCREMENT,
|
||||
GPU_STENCIL_DECREMENT,
|
||||
GPU_STENCIL_INCREMENT_WRAP,
|
||||
GPU_STENCIL_DECREMENT_WRAP,
|
||||
GPU_STENCIL_INVERT
|
||||
} gpu_stencil_action;
|
||||
|
||||
typedef struct {
|
||||
gpu_stencil_action fail;
|
||||
gpu_stencil_action depthFail;
|
||||
gpu_stencil_action pass;
|
||||
gpu_compare_mode test;
|
||||
uint8_t readMask;
|
||||
uint8_t writeMask;
|
||||
uint8_t reference;
|
||||
} gpu_stencil_state;
|
||||
|
||||
typedef enum {
|
||||
GPU_BLEND_ZERO,
|
||||
GPU_BLEND_ONE,
|
||||
GPU_BLEND_SRC_COLOR,
|
||||
GPU_BLEND_ONE_MINUS_SRC_COLOR,
|
||||
GPU_BLEND_SRC_ALPHA,
|
||||
GPU_BLEND_ONE_MINUS_SRC_ALPHA,
|
||||
GPU_BLEND_DST_COLOR,
|
||||
GPU_BLEND_ONE_MINUS_DST_COLOR,
|
||||
GPU_BLEND_DST_ALPHA,
|
||||
GPU_BLEND_ONE_MINUS_DST_ALPHA
|
||||
} gpu_blend_factor;
|
||||
|
||||
typedef enum {
|
||||
GPU_BLEND_ADD,
|
||||
GPU_BLEND_SUB,
|
||||
GPU_BLEND_RSUB,
|
||||
GPU_BLEND_MIN,
|
||||
GPU_BLEND_MAX
|
||||
} gpu_blend_op;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
gpu_blend_factor src;
|
||||
gpu_blend_factor dst;
|
||||
gpu_blend_op op;
|
||||
} color, alpha;
|
||||
bool enabled;
|
||||
} gpu_blend_state;
|
||||
|
||||
typedef struct {
|
||||
gpu_shader* shader;
|
||||
gpu_canvas* canvas;
|
||||
gpu_buffer_layout buffers[16];
|
||||
gpu_attribute attributes[16];
|
||||
gpu_index_stride indexStride;
|
||||
gpu_draw_mode drawMode;
|
||||
gpu_cull_mode cullMode;
|
||||
gpu_winding winding;
|
||||
float depthOffset;
|
||||
float depthOffsetSloped;
|
||||
bool depthWrite;
|
||||
gpu_compare_mode depthTest;
|
||||
gpu_stencil_state stencilFront;
|
||||
gpu_stencil_state stencilBack;
|
||||
bool alphaToCoverage;
|
||||
uint8_t colorMask;
|
||||
gpu_blend_state blend;
|
||||
const char* label;
|
||||
} gpu_pipeline_info;
|
||||
|
||||
size_t gpu_sizeof_pipeline(void);
|
||||
bool gpu_pipeline_init(gpu_pipeline* pipeline, gpu_pipeline_info* info);
|
||||
void gpu_pipeline_destroy(gpu_pipeline* pipeline);
|
||||
|
||||
// Entry
|
||||
|
||||
typedef struct {
|
||||
bool debug;
|
||||
void* (*getProcAddress)(const char*);
|
||||
void (*callback)(void* context, const char* message, int level);
|
||||
void* context;
|
||||
} gpu_config;
|
||||
|
||||
typedef struct {
|
||||
bool anisotropy;
|
||||
bool astc;
|
||||
bool dxt;
|
||||
} gpu_features;
|
||||
|
||||
typedef struct {
|
||||
uint32_t textureSize;
|
||||
uint32_t framebufferSize[2];
|
||||
uint32_t framebufferSamples;
|
||||
} gpu_limits;
|
||||
|
||||
bool gpu_init(gpu_config* config);
|
||||
void gpu_destroy(void);
|
||||
void gpu_frame_wait(void);
|
||||
void gpu_frame_finish(void);
|
||||
void gpu_render_begin(gpu_canvas* canvas);
|
||||
void gpu_render_finish(void);
|
||||
void gpu_set_pipeline(gpu_pipeline* pipeline);
|
||||
void gpu_set_vertex_buffers(gpu_buffer** buffers, uint64_t* offsets, uint32_t count);
|
||||
void gpu_set_index_buffer(gpu_buffer* buffer, uint64_t offset);
|
||||
void gpu_draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex);
|
||||
void gpu_draw_indexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t baseVertex);
|
||||
void gpu_draw_indirect(gpu_buffer* buffer, uint64_t offset, uint32_t drawCount);
|
||||
void gpu_draw_indirect_indexed(gpu_buffer* buffer, uint64_t offset, uint32_t drawCount);
|
||||
void gpu_compute(gpu_shader* shader, uint32_t x, uint32_t y, uint32_t z);
|
||||
void gpu_get_features(gpu_features* features);
|
||||
void gpu_get_limits(gpu_limits* limits);
|
|
@ -1,517 +0,0 @@
|
|||
#include "gpu.h"
|
||||
#include <string.h>
|
||||
#include <GL/glcorearb.h>
|
||||
|
||||
// Loader
|
||||
|
||||
#define GL_FOREACH(X)\
|
||||
X(glGetIntegerv, GLGETINTEGERV)\
|
||||
X(glEnable, GLENABLE)\
|
||||
X(glDisable, GLDISABLE)\
|
||||
X(glVertexBindingDivisor, GLVERTEXBINDINGDIVISOR)\
|
||||
X(glVertexAttribBinding, GLVERTEXATTRIBBINDING)\
|
||||
X(glVertexAttribFormat, GLVERTEXATTRIBFORMAT)\
|
||||
X(glVertexAttribIFormat, GLVERTEXATTRIBIFORMAT)\
|
||||
X(glBindVertexBuffer, GLBINDVERTEXBUFFER)\
|
||||
X(glCullFace, GLCULLFACE)\
|
||||
X(glFrontFace, GLFRONTFACE)\
|
||||
X(glPolygonOffset, GLPOLYGONOFFSET)\
|
||||
X(glDepthMask, GLDEPTHMASK)\
|
||||
X(glDepthFunc, GLDEPTHFUNC)\
|
||||
X(glColorMask, GLCOLORMASK)\
|
||||
X(glBlendFuncSeparate, GLBLENDFUNCSEPARATE)\
|
||||
X(glBlendEquationSeparate, GLBLENDEQUATIONSEPARATE)\
|
||||
X(glDrawArraysInstanced, GLDRAWARRAYSINSTANCED)\
|
||||
X(glDrawElementsInstancedBaseVertex, GLDRAWELEMENTSINSTANCEDBASEVERTEX)\
|
||||
X(glMultiDrawArraysIndirect, GLMULTIDRAWARRAYSINDIRECT)\
|
||||
X(glMultiDrawElementsIndirect, GLMULTIDRAWELEMENTSINDIRECT)\
|
||||
X(glDispatchCompute, GLDISPATCHCOMPUTE)\
|
||||
X(glGenVertexArrays, GLGENVERTEXARRAYS)\
|
||||
X(glDeleteVertexArrays, GLDELETEVERTEXARRAYS)\
|
||||
X(glBindVertexArray, GLBINDVERTEXARRAY)\
|
||||
X(glGenBuffers, GLGENBUFFERS)\
|
||||
X(glDeleteBuffers, GLDELETEBUFFERS)\
|
||||
X(glBindBuffer, GLBINDBUFFER)\
|
||||
X(glBufferStorage, GLBUFFERSTORAGE)\
|
||||
X(glMapBufferRange, GLMAPBUFFERRANGE)\
|
||||
X(glFlushMappedBufferRange, GLFLUSHMAPPEDBUFFERRANGE)\
|
||||
X(glUnmapBuffer, GLUNMAPBUFFER)\
|
||||
X(glInvalidateBufferData, GLINVALIDATEBUFFERDATA)\
|
||||
X(glGenTextures, GLGENTEXTURES)\
|
||||
X(glDeleteTextures, GLDELETETEXTURES)\
|
||||
X(glBindTexture, GLBINDTEXTURE)\
|
||||
X(glTexStorage2D, GLTEXSTORAGE2D)\
|
||||
X(glTexStorage3D, GLTEXSTORAGE3D)\
|
||||
X(glTexSubImage2D, GLTEXSUBIMAGE2D)\
|
||||
X(glTexSubImage3D, GLTEXSUBIMAGE3D)\
|
||||
X(glGenFramebuffers, GLGENFRAMEBUFFERS)\
|
||||
X(glDeleteFramebuffers, GLDELETEFRAMEBUFFERS)\
|
||||
X(glBindFramebuffer, GLBINDFRAMEBUFFER)\
|
||||
X(glFramebufferTexture2D, GLFRAMEBUFFERTEXTURE2D)\
|
||||
X(glFramebufferTextureLayer, GLFRAMEBUFFERTEXTURELAYER)\
|
||||
X(glCheckFramebufferStatus, GLCHECKFRAMEBUFFERSTATUS)\
|
||||
X(glDrawBuffers, GLDRAWBUFFERS)\
|
||||
X(glCreateProgram, GLCREATEPROGRAM)\
|
||||
X(glDeleteProgram, GLDELETEPROGRAM)\
|
||||
X(glUseProgram, GLUSEPROGRAM)\
|
||||
|
||||
#define GL_DECLARE(fn, upper) static PFN##upper##PROC fn;
|
||||
#define GL_LOAD(fn, upper) fn = (PFN##upper##PROC) config->getProcAddress(#fn);
|
||||
|
||||
// Types
|
||||
|
||||
struct gpu_buffer {
|
||||
GLuint id;
|
||||
GLenum target;
|
||||
uint8_t* data;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
struct gpu_texture {
|
||||
GLuint id;
|
||||
GLenum target;
|
||||
GLenum format;
|
||||
GLenum pixelFormat;
|
||||
GLenum pixelType;
|
||||
};
|
||||
|
||||
struct gpu_canvas {
|
||||
GLuint id;
|
||||
};
|
||||
|
||||
struct gpu_shader {
|
||||
GLuint id;
|
||||
};
|
||||
|
||||
struct gpu_pipeline {
|
||||
gpu_pipeline_info info;
|
||||
};
|
||||
|
||||
static struct {
|
||||
GLuint vertexArray;
|
||||
GLsizei bufferStrides[16];
|
||||
gpu_pipeline_info cache;
|
||||
gpu_pipeline* pipeline;
|
||||
gpu_canvas* canvas;
|
||||
} state;
|
||||
|
||||
// Setup
|
||||
|
||||
GL_FOREACH(GL_DECLARE)
|
||||
|
||||
bool gpu_init(gpu_config* config) {
|
||||
GL_FOREACH(GL_LOAD);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
|
||||
glGenVertexArrays(1, &state.vertexArray);
|
||||
glBindVertexArray(state.vertexArray);
|
||||
return true;
|
||||
}
|
||||
|
||||
void gpu_destroy(void) {
|
||||
glDeleteVertexArrays(1, &state.vertexArray);
|
||||
}
|
||||
|
||||
void gpu_frame_wait(void) {
|
||||
//
|
||||
}
|
||||
|
||||
void gpu_frame_finish(void) {
|
||||
//
|
||||
}
|
||||
|
||||
void gpu_render_begin(gpu_canvas* canvas) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, canvas->id);
|
||||
state.canvas = canvas;
|
||||
}
|
||||
|
||||
void gpu_render_finish(void) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
state.canvas = NULL;
|
||||
}
|
||||
|
||||
void gpu_set_pipeline(gpu_pipeline* pipeline) {
|
||||
if (state.pipeline == pipeline) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpu_pipeline_info* my = &state.cache;
|
||||
gpu_pipeline_info* new = &pipeline->info;
|
||||
|
||||
if (my->shader != new->shader) {
|
||||
glUseProgram(new->shader->id);
|
||||
my->shader = new->shader;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 16; i++) {
|
||||
if (my->buffers[i].divisor != new->buffers[i].divisor) {
|
||||
glVertexBindingDivisor(i, new->buffers[i].divisor);
|
||||
my->buffers[i].divisor = new->buffers[i].divisor;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 16; i++) {
|
||||
static const struct { GLint count; GLenum type; GLboolean normalized; } formats[] = {
|
||||
[GPU_FLOAT_F32] = { 1, GL_FLOAT, GL_FALSE },
|
||||
[GPU_VEC2_F32] = { 2, GL_FLOAT, GL_FALSE },
|
||||
[GPU_VEC2_U16N] = { 2, GL_UNSIGNED_SHORT, GL_TRUE },
|
||||
[GPU_VEC2_I16N] = { 2, GL_SHORT, GL_TRUE },
|
||||
[GPU_VEC3_F32] = { 3, GL_FLOAT, GL_FALSE },
|
||||
[GPU_VEC4_F32] = { 4, GL_FLOAT, GL_FALSE },
|
||||
[GPU_VEC4_F16] = { 4, GL_HALF_FLOAT, GL_FALSE },
|
||||
[GPU_VEC4_U16N] = { 4, GL_UNSIGNED_SHORT, GL_TRUE },
|
||||
[GPU_VEC4_I16N] = { 4, GL_SHORT, GL_TRUE },
|
||||
[GPU_VEC4_U8N] = { 4, GL_UNSIGNED_BYTE, GL_TRUE },
|
||||
[GPU_VEC4_I8N] = { 4, GL_BYTE, GL_TRUE },
|
||||
[GPU_UINT_U32] = { 1, GL_UNSIGNED_INT },
|
||||
[GPU_UVEC2_U32] = { 2, GL_UNSIGNED_INT },
|
||||
[GPU_UVEC3_U32] = { 3, GL_UNSIGNED_INT },
|
||||
[GPU_UVEC4_U32] = { 4, GL_UNSIGNED_INT },
|
||||
[GPU_INT_I32] = { 1, GL_INT },
|
||||
[GPU_IVEC2_I32] = { 2, GL_INT },
|
||||
[GPU_IVEC3_I32] = { 3, GL_INT },
|
||||
[GPU_IVEC4_I32] = { 4, GL_INT }
|
||||
};
|
||||
if (memcmp(&my->attributes[i], &new->attributes[i], sizeof(gpu_attribute))) {
|
||||
GLuint location = new->attributes[i].location;
|
||||
GLint size = formats[new->attributes[i].format].count;
|
||||
GLenum type = formats[new->attributes[i].format].type;
|
||||
GLboolean normalized = formats[new->attributes[i].format].normalized;
|
||||
GLuint offset = new->attributes[i].offset;
|
||||
glVertexAttribBinding(location, new->attributes[i].buffer);
|
||||
if (new->attributes[i].format >= GPU_UINT_U32) {
|
||||
glVertexAttribIFormat(location, size, type, offset);
|
||||
} else {
|
||||
glVertexAttribFormat(location, size, type, normalized, offset);
|
||||
}
|
||||
memcpy(&my->attributes[i], &new->attributes[i], sizeof(gpu_attribute));
|
||||
}
|
||||
}
|
||||
|
||||
my->drawMode = new->drawMode;
|
||||
|
||||
if (my->cullMode != new->cullMode) {
|
||||
if (new->cullMode == GPU_CULL_NONE) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
} else {
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(new->cullMode == GPU_CULL_FRONT ? GL_FRONT : GL_BACK);
|
||||
}
|
||||
my->cullMode = new->cullMode;
|
||||
}
|
||||
|
||||
if (my->winding != new->winding) {
|
||||
glFrontFace(new->winding == GPU_WINDING_CCW ? GL_CCW : GL_CW);
|
||||
my->winding = new->winding;
|
||||
}
|
||||
|
||||
if (my->depthOffset != new->depthOffset || my->depthOffsetSloped != new->depthOffsetSloped) {
|
||||
glPolygonOffset(new->depthOffsetSloped, new->depthOffset);
|
||||
my->depthOffset = new->depthOffset;
|
||||
my->depthOffsetSloped = new->depthOffsetSloped;
|
||||
}
|
||||
|
||||
if (my->depthWrite != new->depthWrite) {
|
||||
glDepthMask(new->depthWrite);
|
||||
my->depthWrite = new->depthWrite;
|
||||
}
|
||||
|
||||
if (my->depthTest != new->depthTest) {
|
||||
static const GLenum funcs[] = {
|
||||
[GPU_COMPARE_EQUAL] = GL_EQUAL,
|
||||
[GPU_COMPARE_NEQUAL] = GL_NOTEQUAL,
|
||||
[GPU_COMPARE_LESS] = GL_LESS,
|
||||
[GPU_COMPARE_LEQUAL] = GL_LEQUAL,
|
||||
[GPU_COMPARE_GREATER] = GL_GREATER,
|
||||
[GPU_COMPARE_GEQUAL] = GL_GEQUAL
|
||||
};
|
||||
if (new->depthTest == GPU_COMPARE_NONE) {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
} else {
|
||||
if (my->depthTest == GPU_COMPARE_NONE) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
glDepthFunc(funcs[new->depthTest]);
|
||||
}
|
||||
my->depthTest = new->depthTest;
|
||||
}
|
||||
|
||||
// stencil
|
||||
|
||||
if (my->alphaToCoverage != new->alphaToCoverage) {
|
||||
if (new->alphaToCoverage) {
|
||||
glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
} else {
|
||||
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
}
|
||||
my->alphaToCoverage = new->alphaToCoverage;
|
||||
}
|
||||
|
||||
if (my->colorMask != new->colorMask) {
|
||||
glColorMask(new->colorMask & 0x8, new->colorMask & 0x4, new->colorMask & 0x2, new->colorMask & 0x1);
|
||||
my->colorMask = new->colorMask;
|
||||
}
|
||||
|
||||
if (my->blend.enabled != new->blend.enabled) {
|
||||
if (new->blend.enabled) {
|
||||
glEnable(GL_BLEND);
|
||||
} else {
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
my->blend.enabled = new->blend.enabled;
|
||||
}
|
||||
|
||||
if (memcmp(&my->blend, &new->blend, sizeof(my->blend))) {
|
||||
static const GLenum factors[] = {
|
||||
[GPU_BLEND_ZERO] = GL_ZERO,
|
||||
[GPU_BLEND_ONE] = GL_ONE,
|
||||
[GPU_BLEND_SRC_COLOR] = GL_SRC_COLOR,
|
||||
[GPU_BLEND_ONE_MINUS_SRC_COLOR] = GL_ONE_MINUS_SRC_COLOR,
|
||||
[GPU_BLEND_SRC_ALPHA] = GL_SRC_ALPHA,
|
||||
[GPU_BLEND_ONE_MINUS_SRC_ALPHA] = GL_ONE_MINUS_SRC_ALPHA,
|
||||
[GPU_BLEND_DST_COLOR] = GL_DST_COLOR,
|
||||
[GPU_BLEND_ONE_MINUS_DST_COLOR] = GL_ONE_MINUS_DST_COLOR,
|
||||
[GPU_BLEND_DST_ALPHA] = GL_DST_ALPHA,
|
||||
[GPU_BLEND_ONE_MINUS_DST_ALPHA] = GL_ONE_MINUS_DST_ALPHA
|
||||
};
|
||||
static const GLenum opps[] = {
|
||||
[GPU_BLEND_ADD] = GL_FUNC_ADD,
|
||||
[GPU_BLEND_SUB] = GL_FUNC_SUBTRACT,
|
||||
[GPU_BLEND_RSUB] = GL_FUNC_REVERSE_SUBTRACT,
|
||||
[GPU_BLEND_MIN] = GL_MIN,
|
||||
[GPU_BLEND_MAX] = GL_MAX
|
||||
};
|
||||
glBlendFuncSeparate(factors[new->blend.color.src], factors[new->blend.color.dst], factors[new->blend.alpha.src], factors[new->blend.alpha.dst]);
|
||||
glBlendEquationSeparate(opps[new->blend.color.op], opps[new->blend.alpha.op]);
|
||||
memcpy(&my->blend, &new->blend, sizeof(my->blend));
|
||||
}
|
||||
|
||||
state.pipeline = pipeline;
|
||||
}
|
||||
|
||||
void gpu_set_vertex_buffers(gpu_buffer** buffers, uint64_t* offsets, uint32_t count) {
|
||||
for (uint32_t i = 0; i < count; i++) { // Not convinced multibind would be any better here
|
||||
glBindVertexBuffer(i, buffers[i] ? buffers[i]->id : 0, offsets[i], state.bufferStrides[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void gpu_set_index_buffer(gpu_buffer* buffer, uint64_t offset) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->id);
|
||||
}
|
||||
|
||||
static const GLenum drawModes[] = {
|
||||
[GPU_DRAW_POINTS] = GL_POINTS,
|
||||
[GPU_DRAW_LINES] = GL_LINES,
|
||||
[GPU_DRAW_LINE_STRIP] = GL_LINE_STRIP,
|
||||
[GPU_DRAW_TRIANGLES] = GL_TRIANGLES,
|
||||
[GPU_DRAW_TRIANGLE_STRIP] = GL_TRIANGLE_STRIP
|
||||
};
|
||||
|
||||
void gpu_draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex) {
|
||||
GLenum mode = drawModes[state.pipeline->info.drawMode];
|
||||
glDrawArraysInstanced(mode, firstVertex, vertexCount, instanceCount);
|
||||
}
|
||||
|
||||
void gpu_draw_indexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t baseVertex) {
|
||||
GLenum mode = drawModes[state.pipeline->info.drawMode];
|
||||
GLenum type = state.pipeline->info.indexStride == GPU_INDEX_U16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
|
||||
GLvoid* offset = (GLvoid*) ((uint64_t) firstIndex * (type == GL_UNSIGNED_SHORT ? 2 : 4));
|
||||
glDrawElementsInstancedBaseVertex(mode, indexCount, type, offset, instanceCount, baseVertex);
|
||||
}
|
||||
|
||||
void gpu_draw_indirect(gpu_buffer* buffer, uint64_t offset, uint32_t drawCount) {
|
||||
GLenum mode = drawModes[state.pipeline->info.drawMode];
|
||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer->id);
|
||||
glMultiDrawArraysIndirect(mode, (GLvoid*) offset, drawCount, 0);
|
||||
}
|
||||
|
||||
void gpu_draw_indirect_indexed(gpu_buffer* buffer, uint64_t offset, uint32_t drawCount) {
|
||||
GLenum mode = drawModes[state.pipeline->info.drawMode];
|
||||
GLenum type = state.pipeline->info.indexStride == GPU_INDEX_U16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
|
||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer->id);
|
||||
glMultiDrawElementsIndirect(mode, type, (GLvoid*) offset, drawCount, 0);
|
||||
}
|
||||
|
||||
void gpu_compute(gpu_shader* shader, uint32_t x, uint32_t y, uint32_t z) {
|
||||
glUseProgram(shader->id);
|
||||
glDispatchCompute(x, y, z);
|
||||
}
|
||||
|
||||
void gpu_get_features(gpu_features* features) {
|
||||
features->anisotropy = true;
|
||||
features->dxt = true;
|
||||
}
|
||||
|
||||
void gpu_get_limits(gpu_limits* limits) {
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &limits->textureSize);
|
||||
glGetIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &limits->framebufferSize[0]);
|
||||
glGetIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &limits->framebufferSize[1]);
|
||||
glGetIntegerv(GL_MAX_FRAMEBUFFER_SAMPLES, &limits->framebufferSamples);
|
||||
}
|
||||
|
||||
// Buffer
|
||||
|
||||
size_t gpu_sizeof_buffer(void) {
|
||||
return sizeof(gpu_buffer);
|
||||
}
|
||||
|
||||
bool gpu_buffer_init(gpu_buffer* buffer, gpu_buffer_info* info) {
|
||||
if (info->usage & GPU_BUFFER_USAGE_VERTEX) buffer->target = GL_ARRAY_BUFFER;
|
||||
else if (info->usage & GPU_BUFFER_USAGE_INDEX) buffer->target = GL_ELEMENT_ARRAY_BUFFER;
|
||||
else if (info->usage & GPU_BUFFER_USAGE_UNIFORM) buffer->target = GL_UNIFORM_BUFFER;
|
||||
else if (info->usage & GPU_BUFFER_USAGE_COMPUTE) buffer->target = GL_SHADER_STORAGE_BUFFER;
|
||||
else if (info->usage & GPU_BUFFER_USAGE_COPY) buffer->target = GL_COPY_READ_BUFFER;
|
||||
else if (info->usage & GPU_BUFFER_USAGE_PASTE) buffer->target = GL_COPY_WRITE_BUFFER;
|
||||
else buffer->target = GL_TRANSFORM_FEEDBACK_BUFFER; // Haha no one uses this r-right
|
||||
glGenBuffers(1, &buffer->id);
|
||||
glBindBuffer(buffer->target, buffer->id);
|
||||
GLbitfield flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
|
||||
glBufferStorage(buffer->target, info->size, info->data, flags);
|
||||
buffer->data = glMapBufferRange(buffer->target, 0, info->size, flags);
|
||||
buffer->size = info->size;
|
||||
return true;
|
||||
}
|
||||
|
||||
void gpu_buffer_destroy(gpu_buffer* buffer) {
|
||||
glDeleteBuffers(1, &buffer->id);
|
||||
}
|
||||
|
||||
uint8_t* gpu_buffer_map(gpu_buffer* buffer, uint64_t offset, uint64_t size) {
|
||||
return buffer->data + offset;
|
||||
}
|
||||
|
||||
void gpu_buffer_discard(gpu_buffer* buffer) {
|
||||
glInvalidateBufferData(buffer->id);
|
||||
}
|
||||
|
||||
// Texture
|
||||
|
||||
static const GLenum textureTargets[] = {
|
||||
[GPU_TEXTURE_TYPE_2D] = GL_TEXTURE_2D,
|
||||
[GPU_TEXTURE_TYPE_3D] = GL_TEXTURE_3D,
|
||||
[GPU_TEXTURE_TYPE_CUBE] = GL_TEXTURE_CUBE_MAP,
|
||||
[GPU_TEXTURE_TYPE_ARRAY] = GL_TEXTURE_2D_ARRAY
|
||||
};
|
||||
|
||||
static const struct { GLenum format, pixelFormat, pixelType; } textureFormats[] = {
|
||||
[GPU_TEXTURE_FORMAT_RGBA8] = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE },
|
||||
[GPU_TEXTURE_FORMAT_RGBA4] = { GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE },
|
||||
[GPU_TEXTURE_FORMAT_R16F] = { GL_R16F, GL_RED, GL_HALF_FLOAT },
|
||||
[GPU_TEXTURE_FORMAT_RG16F] = { GL_RG16F, GL_RG, GL_HALF_FLOAT },
|
||||
[GPU_TEXTURE_FORMAT_RGBA16F] = { GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT },
|
||||
[GPU_TEXTURE_FORMAT_R32F] = { GL_R32F, GL_RED, GL_FLOAT },
|
||||
[GPU_TEXTURE_FORMAT_RG32F] = { GL_RG32F, GL_RG, GL_FLOAT },
|
||||
[GPU_TEXTURE_FORMAT_RGBA32F] = { GL_RGBA32F, GL_RGBA, GL_FLOAT },
|
||||
[GPU_TEXTURE_FORMAT_RGB10A2] = { GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV },
|
||||
[GPU_TEXTURE_FORMAT_RG11B10F] = { GL_R11F_G11F_B10F, GL_RGBA, GL_UNSIGNED_INT_10F_11F_11F_REV },
|
||||
[GPU_TEXTURE_FORMAT_D16] = { GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT },
|
||||
[GPU_TEXTURE_FORMAT_D32F] = { GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT },
|
||||
[GPU_TEXTURE_FORMAT_D24S8] = { GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 }
|
||||
};
|
||||
|
||||
size_t gpu_sizeof_texture(void) {
|
||||
return sizeof(gpu_texture);
|
||||
}
|
||||
|
||||
bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
|
||||
texture->target = textureTargets[info->type];
|
||||
texture->format = textureTormats[info->format].format;
|
||||
texture->pixelFormat = textureTormats[info->format].pixelFormat;
|
||||
texture->pixelType = textureTormats[info->format].pixelType;
|
||||
glGenTextures(1, &texture->id);
|
||||
glBindTexture(texture->target, texture->id);
|
||||
if (info->type == GPU_TEXTURE_TYPE_2D || info->type == GPU_TEXTURE_TYPE_CUBE) {
|
||||
glTexStorage2D(texture->target, info->mipmaps, texture->format, info->size[0], info->size[1]);
|
||||
} else {
|
||||
uint32_t depth = info->type == GPU_TEXTURE_TYPE_ARRAY ? info->layers : info->size[2];
|
||||
glTexStorage3D(texture->target, info->mipmaps, texture->format, info->size[0], info->size[1], depth);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gpu_texture_init_view(gpu_texture* texture, gpu_texture_view_info* info) {
|
||||
texture->target = textureTargets[info->type];
|
||||
texture->format = textureTormats[info->format].format;
|
||||
texture->pixelFormat = textureTormats[info->format].pixelFormat;
|
||||
texture->pixelType = textureTormats[info->format].pixelType;
|
||||
glGenTextures(1, &texture->id);
|
||||
glTextureView(texture->id, texture->target, info->source, texture->format, info->baseMipmap, info->mipmapCount, info->baseLayer, info->layerCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
void gpu_texture_destroy(gpu_texture* texture) {
|
||||
glDeleteTextures(1, &texture->id);
|
||||
}
|
||||
|
||||
void gpu_texture_write(gpu_texture* texture, uint8_t* data, uint16_t offset[4], uint16_t extent[4], uint16_t mip) {
|
||||
glBindTexture(texture->target, texture->id);
|
||||
int x = offset[0], y = offset[1], z = offset[2], i = offset[3];
|
||||
int w = extent[0], h = extent[1], d = extent[2], n = extent[3];
|
||||
GLenum format = texture->pixelFormat;
|
||||
GLenum type = texture->pixelType;
|
||||
switch (texture->target) {
|
||||
case GL_TEXTURE_2D: glTexSubImage2D(GL_TEXTURE_2D, mip, x, y, w, h, format, type, data);
|
||||
case GL_TEXTURE_3D: glTexSubImage3D(GL_TEXTURE_3D, mip, x, y, z, w, h, d, format, type, data);
|
||||
case GL_TEXTURE_CUBE_MAP: glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + z, mip, x, y, w, h, format, type, data);
|
||||
case GL_TEXTURE_2D_ARRAY: glTexSubImage3D(GL_TEXTURE_2D_ARRAY, mip, x, y, i, w, h, n, format, type, data);
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Canvas
|
||||
|
||||
size_t gpu_sizeof_canvas(void) {
|
||||
return sizeof(gpu_canvas);
|
||||
}
|
||||
|
||||
bool gpu_canvas_init(gpu_canvas* canvas, gpu_canvas_info* info) {
|
||||
glGenFramebuffers(1, &canvas->id);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, canvas->id);
|
||||
GLsizei bufferCount = 0;
|
||||
GLenum buffers[4] = { GL_NONE };
|
||||
for (uint32_t i = 0; i < 4 && info->color[i].texture; i++, bufferCount++) {
|
||||
buffers[i] = GL_COLOR_ATTACHMENT0 + i;
|
||||
gpu_color_attachment* attachment = &info->color[i];
|
||||
switch (attachment->texture->target) {
|
||||
case GL_TEXTURE_2D: glFramebufferTexture2D(GL_FRAMEBUFFER, buffers[i], GL_TEXTURE_2D, attachment->texture->id, attachment->level); break;
|
||||
case GL_TEXTURE_3D: glFramebufferTextureLayer(GL_FRAMEBUFFER, buffers[i], attachment->texture->id, attachment->level, attachment->layer); break;
|
||||
case GL_TEXTURE_CUBE_MAP: glFramebufferTexture2D(GL_FRAMEBUFFER, buffers[i], GL_TEXTURE_CUBE_MAP_POSITIVE_X + attachment->layer, attachment->texture->id, attachment->level); break;
|
||||
case GL_TEXTURE_2D_ARRAY: glFramebufferTextureLayer(GL_FRAMEBUFFER, buffers[i], attachment->texture->id, attachment->level, attachment->layer); break;
|
||||
}
|
||||
}
|
||||
glDrawBuffers(bufferCount, buffers);
|
||||
if (info->depth.texture) {
|
||||
GLenum attachment = GL_DEPTH_STENCIL_ATTACHMENT; // Depends on texture format
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, info->depth.texture->id, 0);
|
||||
}
|
||||
return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
|
||||
}
|
||||
|
||||
void gpu_canvas_destroy(gpu_canvas* canvas) {
|
||||
glDeleteFramebuffers(1, &canvas->id);
|
||||
}
|
||||
|
||||
// Shader
|
||||
|
||||
bool gpu_shader_init(gpu_shader* shader, gpu_shader_info* info) {
|
||||
shader->id = glCreateProgram();
|
||||
return true;
|
||||
}
|
||||
|
||||
void gpu_shader_destroy(gpu_shader* shader) {
|
||||
glDeleteProgram(shader->id);
|
||||
}
|
||||
|
||||
// Pipeline
|
||||
|
||||
bool gpu_pipeline_init(gpu_pipeline* pipeline, gpu_pipeline_info* info) {
|
||||
pipeline->info = *info;
|
||||
return true;
|
||||
}
|
||||
|
||||
void gpu_pipeline_destroy(gpu_pipeline* pipeline) {
|
||||
//
|
||||
}
|
1336
src/core/gpu_vk.c
1336
src/core/gpu_vk.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue