mirror of https://github.com/bjornbytes/lovr.git
Shaders; Rework vertex formats;
This commit is contained in:
parent
70e0f5c5cf
commit
7de6bdf242
|
@ -437,7 +437,7 @@ src += config.modules.thread and 'src/lib/tinycthread/*.c' or nil
|
|||
|
||||
-- embed resource files with xxd
|
||||
|
||||
res = { 'etc/*.lua', 'etc/*.ttf' }
|
||||
res = { 'etc/*.lua', 'etc/*.ttf', 'etc/shaders/*.glsl' }
|
||||
tup.foreach_rule(res, '^ XD %b^ xxd -i %f > %o', '%f.h')
|
||||
|
||||
for i, pattern in ipairs(res) do
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
#include "shaders/unlit.vert.h"
|
||||
#include "shaders/unlit.frag.h"
|
||||
|
||||
#include "shaders/lovr.glsl.h"
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
// Resources
|
||||
#ifndef GL_COMPUTE_SHADER
|
||||
struct Camera {
|
||||
mat4 view;
|
||||
mat4 projection;
|
||||
mat4 viewProjection;
|
||||
mat4 inverseProjection;
|
||||
};
|
||||
|
||||
struct Draw {
|
||||
mat4 transform;
|
||||
mat4 normalMatrix;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 0) uniform Cameras { Camera cameras[6]; };
|
||||
layout(set = 0, binding = 1) uniform Draws { Draw draws[256]; };
|
||||
layout(set = 0, binding = 2) uniform sampler Sampler;
|
||||
#endif
|
||||
|
||||
// Attributes
|
||||
#ifdef GL_VERTEX_SHADER
|
||||
layout(location = 10) in vec4 VertexPosition;
|
||||
layout(location = 11) in vec3 VertexNormal;
|
||||
layout(location = 12) in vec2 VertexUV;
|
||||
layout(location = 13) in vec4 VertexColor;
|
||||
layout(location = 14) in vec3 VertexTangent;
|
||||
#endif
|
||||
|
||||
// Framebuffer
|
||||
#ifdef GL_FRAGMENT_SHADER
|
||||
layout(location = 0) out vec4 PixelColors[1];
|
||||
#endif
|
||||
|
||||
// Varyings
|
||||
#ifdef GL_VERTEX_SHADER
|
||||
layout(location = 10) out vec4 FragColor;
|
||||
layout(location = 11) out vec2 FragUV;
|
||||
#else
|
||||
layout(location = 10) in vec4 FragColor;
|
||||
layout(location = 11) in vec2 FragUV;
|
||||
#endif
|
||||
|
||||
// Macros
|
||||
#ifdef GL_COMPUTE_SHADER
|
||||
//
|
||||
#else
|
||||
#define BaseInstance gl_BaseInstance
|
||||
#define BaseVertex gl_BaseVertex
|
||||
#define ClipDistance gl_ClipDistance
|
||||
#define CullDistance gl_CullDistance
|
||||
#define DrawIndex gl_DrawIndex
|
||||
#define InstanceIndex (gl_InstanceIndex - gl_BaseInstance)
|
||||
#define FragCoord gl_FragCoord
|
||||
#define FragDepth gl_FragDepth
|
||||
#define FrontFacing gl_FrontFacing
|
||||
#define PointCoord gl_PointCoord
|
||||
#define PointSize gl_PointSize
|
||||
#define Position gl_Position
|
||||
#define PrimitiveId gl_PrimitiveID
|
||||
#define SampleId gl_SampleID
|
||||
#define SampleMaskIn gl_SampleMaskIn
|
||||
#define SampleMask gl_SampleMask
|
||||
#define SamplePosition gl_SamplePosition
|
||||
#define VertexIndex gl_VertexIndex
|
||||
#define ViewIndex gl_ViewIndex
|
||||
|
||||
#define DrawId gl_BaseInstance
|
||||
#define Projection cameras[ViewIndex].projection
|
||||
#define View cameras[ViewIndex].view
|
||||
#define ViewProjection cameras[ViewIndex].viewProjection
|
||||
#define InverseProjection cameras[ViewIndex].inverseProjection
|
||||
#define Transform draws[DrawId].transform
|
||||
#define NormalMatrix draws[DrawId].normalMatrix
|
||||
#define Color draws[DrawId].color
|
||||
|
||||
#define ClipFromLocal (ViewProjection * Transform)
|
||||
#define ClipFromWorld (ViewProjection)
|
||||
#define ClipFromView (Projection)
|
||||
#define ViewFromLocal (View * Transform)
|
||||
#define ViewFromWorld (View)
|
||||
#define WorldFromLocal (Transform)
|
||||
|
||||
#define DefaultPosition (ClipFromLocal * VertexPosition)
|
||||
#define DefaultColor (FragColor)
|
||||
#endif
|
|
@ -1,11 +1,9 @@
|
|||
#version 460
|
||||
#extension GL_EXT_multiview : require
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
|
||||
layout(location = 0) in vec4 inColor;
|
||||
layout(location = 1) in vec2 inUV;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
#include "lovr.glsl"
|
||||
|
||||
void main() {
|
||||
outColor = inColor;
|
||||
PixelColors[0] = FragColor;
|
||||
}
|
||||
|
|
|
@ -1,40 +1,12 @@
|
|||
#version 460
|
||||
#extension GL_EXT_multiview : require
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
|
||||
struct Camera {
|
||||
mat4 view;
|
||||
mat4 projection;
|
||||
mat4 viewProjection;
|
||||
mat4 inverseProjection;
|
||||
};
|
||||
|
||||
struct PerDraw {
|
||||
mat4 transform;
|
||||
mat4 normalMatrix;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 0) uniform Cameras { Camera cameras[6]; };
|
||||
layout(set = 0, binding = 1) uniform Draws { PerDraw draws[256]; };
|
||||
layout(set = 0, binding = 2) uniform sampler defaultSampler;
|
||||
|
||||
layout(location = 0) in vec4 inPosition;
|
||||
layout(location = 1) in vec4 inNormal;
|
||||
layout(location = 2) in vec4 inUV;
|
||||
layout(location = 3) in vec4 inColor;
|
||||
layout(location = 4) in vec4 inTangent;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
layout(location = 1) out vec4 outUV;
|
||||
#include "lovr.glsl"
|
||||
|
||||
void main() {
|
||||
uint drawId = gl_BaseInstance & 0xff;
|
||||
|
||||
outColor = vec4(1.);
|
||||
outColor *= draws[drawId].color;
|
||||
|
||||
outUV = inUV;
|
||||
|
||||
gl_Position = cameras[gl_ViewIndex].viewProjection * (draws[drawId].transform * vec4(inPosition.xyz, 1.));
|
||||
gl_PointSize = 1.f;
|
||||
FragColor = VertexColor * Color;
|
||||
FragUV = VertexUV;
|
||||
Position = DefaultPosition;
|
||||
PointSize = 1.f;
|
||||
}
|
||||
|
|
|
@ -216,10 +216,19 @@ static struct { uint32_t size, scalarAlign, baseAlign, components; } fieldInfo[]
|
|||
[FIELD_MAT4] = { 64, 4, 16, 16 }
|
||||
};
|
||||
|
||||
static uint32_t luax_checkfieldtype(lua_State* L, int index) {
|
||||
static uint32_t luax_checkfieldtype(lua_State* L, int index, uint32_t* nameHash) {
|
||||
size_t length;
|
||||
const char* string = luaL_checklstring(L, index, &length);
|
||||
|
||||
char* colon = strchr(string, ':');
|
||||
|
||||
if (colon) {
|
||||
*nameHash = (uint32_t) hash64(colon + 1, length - (colon + 1 - string));
|
||||
length = colon - string;
|
||||
} else {
|
||||
*nameHash = 0;
|
||||
}
|
||||
|
||||
if (length < 3) {
|
||||
return luaL_error(L, "invalid FieldType '%s'", string), 0;
|
||||
}
|
||||
|
@ -255,10 +264,6 @@ static uint32_t luax_checkfieldtype(lua_State* L, int index) {
|
|||
return FIELD_UN8x4;
|
||||
}
|
||||
|
||||
if (length == 6 && !memcmp(string, "normal", length)) {
|
||||
return FIELD_UN10x3;
|
||||
}
|
||||
|
||||
for (int i = 0; lovrFieldType[i].length; i++) {
|
||||
if (length == lovrFieldType[i].length && !memcmp(string, lovrFieldType[i].string, length)) {
|
||||
return i;
|
||||
|
@ -276,7 +281,7 @@ static void luax_checkbufferformat(lua_State* L, int index, BufferInfo* info) {
|
|||
break;
|
||||
case LUA_TSTRING:
|
||||
info->fieldCount = 1;
|
||||
info->fields[0].type = luax_checkfieldtype(L, index);
|
||||
info->fields[0].type = luax_checkfieldtype(L, index, &info->fields[0].hash);
|
||||
info->stride = fieldInfo[info->fields[0].type].size;
|
||||
break;
|
||||
case LUA_TTABLE:
|
||||
|
@ -297,7 +302,7 @@ static void luax_checkbufferformat(lua_State* L, int index, BufferInfo* info) {
|
|||
lua_rawgeti(L, index, i + 1);
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_getfield(L, -1, "type");
|
||||
field->type = luax_checkenum(L, -1, FieldType, NULL);
|
||||
field->type = luax_checkfieldtype(L, -1, &field->hash);
|
||||
lua_pop(L, 1);
|
||||
|
||||
uint32_t align = layout == LAYOUT_PACKED ? fieldInfo[field->type].scalarAlign : fieldInfo[field->type].baseAlign;
|
||||
|
@ -313,10 +318,18 @@ static void luax_checkbufferformat(lua_State* L, int index, BufferInfo* info) {
|
|||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, -1, "location");
|
||||
field->location = lua_isnil(L, -1) ? location++ : luaL_checkinteger(L, -1); // TODO names
|
||||
field->location = lua_isnil(L, -1) ? location++ : luaL_checkinteger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, -1, "name");
|
||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||
size_t nameLength;
|
||||
const char* name = lua_tolstring(L, -1, &nameLength);
|
||||
field->hash = (uint32_t) hash64(name, nameLength);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
} else if (lua_isstring(L, -1)) {
|
||||
FieldType type = luax_checkfieldtype(L, -1);
|
||||
FieldType type = luax_checkfieldtype(L, -1, &field->hash);
|
||||
uint32_t align = layout == LAYOUT_PACKED ? fieldInfo[type].scalarAlign : fieldInfo[type].baseAlign;
|
||||
field->offset = ALIGN(offset, align);
|
||||
field->location = location++;
|
||||
|
|
|
@ -16,13 +16,14 @@
|
|||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t location;
|
||||
} input;
|
||||
uint16_t location;
|
||||
uint16_t name;
|
||||
} attribute;
|
||||
struct {
|
||||
uint8_t set;
|
||||
uint8_t binding;
|
||||
uint16_t name;
|
||||
} resource;
|
||||
} variable;
|
||||
struct {
|
||||
uint16_t number;
|
||||
uint16_t name;
|
||||
|
@ -72,19 +73,19 @@ spv_result spv_parse(const void* source, uint32_t size, spv_info* info) {
|
|||
|
||||
spv.bound = spv.words[3];
|
||||
|
||||
if (spv.bound >= 0xffff) {
|
||||
if (spv.bound >= 8192) {
|
||||
return SPV_TOO_BIG;
|
||||
}
|
||||
|
||||
spv_cache cache[65536];
|
||||
spv_cache cache[8192];
|
||||
memset(cache, 0xff, spv.bound * sizeof(spv_cache));
|
||||
spv.cache = cache;
|
||||
|
||||
info->inputLocationMask = 0;
|
||||
info->featureCount = 0;
|
||||
info->specConstantCount = 0;
|
||||
info->pushConstantCount = 0;
|
||||
info->pushConstantSize = 0;
|
||||
info->attributeCount = 0;
|
||||
info->resourceCount = 0;
|
||||
|
||||
const uint32_t* op = spv.words + 5;
|
||||
|
@ -157,7 +158,6 @@ const char* spv_result_to_string(spv_result result) {
|
|||
case SPV_OK: return "OK";
|
||||
case SPV_INVALID: return "Invalid SPIR-V";
|
||||
case SPV_TOO_BIG: return "SPIR-V contains too many types/variables (max ID is 65534)";
|
||||
case SPV_LOCATION_TOO_BIG: return "Max location is 31";
|
||||
case SPV_UNSUPPORTED_IMAGE_TYPE: return "This type of image variable is not supported";
|
||||
case SPV_UNSUPPORTED_SPEC_CONSTANT_TYPE: return "This type of specialization constant is not supported";
|
||||
case SPV_UNSUPPORTED_PUSH_CONSTANT_TYPE: return "Push constants must be square matrices, vectors, 32 bit numbers, or bools";
|
||||
|
@ -199,9 +199,9 @@ static spv_result spv_parse_decoration(spv_context* spv, const uint32_t* op, spv
|
|||
}
|
||||
|
||||
switch (decoration) {
|
||||
case 33: spv->cache[id].resource.binding = op[3]; break; // Binding
|
||||
case 34: spv->cache[id].resource.set = op[3]; break; // Set
|
||||
case 30: spv->cache[id].input.location = op[3]; break; // Location
|
||||
case 33: spv->cache[id].variable.binding = op[3]; break; // Binding
|
||||
case 34: spv->cache[id].variable.set = op[3]; break; // Set
|
||||
case 30: spv->cache[id].attribute.location = op[3]; break; // Location
|
||||
case 1: spv->cache[id].flag.number = op[3]; break; // SpecID
|
||||
default: break;
|
||||
}
|
||||
|
@ -290,14 +290,17 @@ static spv_result spv_parse_variable(spv_context* spv, const uint32_t* op, spv_i
|
|||
uint32_t storageClass = op[3];
|
||||
|
||||
if (storageClass == 1) { // Input
|
||||
uint32_t location = spv->cache[variableId].input.location;
|
||||
if (spv->cache[variableId].attribute.location == 0xffff) {
|
||||
return SPV_OK; // Not all input variables are attributes
|
||||
}
|
||||
|
||||
if (location == 0xff) {
|
||||
if (info->attributes) {
|
||||
spv_attribute* attribute = &info->attributes[info->attributeCount++];
|
||||
attribute->location = spv->cache[variableId].attribute.location;
|
||||
attribute->name = (char*) (spv->words + spv->cache[variableId].attribute.name);
|
||||
return SPV_OK;
|
||||
} else if (location > 31) {
|
||||
return SPV_LOCATION_TOO_BIG;
|
||||
} else {
|
||||
info->inputLocationMask |= (1 << location);
|
||||
info->attributeCount++;
|
||||
return SPV_OK;
|
||||
}
|
||||
}
|
||||
|
@ -306,8 +309,8 @@ static spv_result spv_parse_variable(spv_context* spv, const uint32_t* op, spv_i
|
|||
return spv_parse_push_constants(spv, op, info);
|
||||
}
|
||||
|
||||
uint32_t set = spv->cache[variableId].resource.set;
|
||||
uint32_t binding = spv->cache[variableId].resource.binding;
|
||||
uint32_t set = spv->cache[variableId].variable.set;
|
||||
uint32_t binding = spv->cache[variableId].variable.binding;
|
||||
|
||||
// Ignore output variables (storageClass 3) and anything without a set/binding decoration
|
||||
if (storageClass == 3 || set == 0xff || binding == 0xff) {
|
||||
|
@ -370,8 +373,8 @@ static spv_result spv_parse_variable(spv_context* spv, const uint32_t* op, spv_i
|
|||
}
|
||||
|
||||
// Sampler and texture variables are named directly
|
||||
if (spv->cache[variableId].resource.name != 0xffff) {
|
||||
resource->name = (char*) (spv->words + spv->cache[variableId].resource.name);
|
||||
if (spv->cache[variableId].variable.name != 0xffff) {
|
||||
resource->name = (char*) (spv->words + spv->cache[variableId].variable.name);
|
||||
}
|
||||
|
||||
if (OP_CODE(type) == 26) { // OpTypeSampler
|
||||
|
|
|
@ -33,6 +33,11 @@ typedef struct {
|
|||
spv_type type;
|
||||
} spv_push_constant;
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
uint32_t location;
|
||||
} spv_attribute;
|
||||
|
||||
typedef enum {
|
||||
SPV_UNIFORM_BUFFER,
|
||||
SPV_STORAGE_BUFFER,
|
||||
|
@ -51,15 +56,16 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint32_t inputLocationMask;
|
||||
uint32_t featureCount;
|
||||
uint32_t specConstantCount;
|
||||
uint32_t pushConstantCount;
|
||||
uint32_t pushConstantSize;
|
||||
uint32_t attributeCount;
|
||||
uint32_t resourceCount;
|
||||
uint32_t* features;
|
||||
spv_spec_constant* specConstants;
|
||||
spv_push_constant* pushConstants;
|
||||
spv_attribute* attributes;
|
||||
spv_resource* resources;
|
||||
} spv_info;
|
||||
|
||||
|
@ -67,7 +73,6 @@ typedef enum {
|
|||
SPV_OK,
|
||||
SPV_INVALID,
|
||||
SPV_TOO_BIG,
|
||||
SPV_LOCATION_TOO_BIG,
|
||||
SPV_UNSUPPORTED_IMAGE_TYPE,
|
||||
SPV_UNSUPPORTED_SPEC_CONSTANT_TYPE,
|
||||
SPV_UNSUPPORTED_PUSH_CONSTANT_TYPE
|
||||
|
|
|
@ -23,12 +23,6 @@ const char** os_vk_get_instance_extensions(uint32_t* count);
|
|||
#define MAX_FRAME_MEMORY (1 << 30)
|
||||
#define MAX_SHADER_RESOURCES 32
|
||||
|
||||
typedef struct {
|
||||
gpu_vertex_format gpu;
|
||||
uint64_t hash;
|
||||
uint32_t mask;
|
||||
} VertexFormat;
|
||||
|
||||
typedef struct {
|
||||
gpu_phase readPhase;
|
||||
gpu_phase writePhase;
|
||||
|
@ -43,7 +37,7 @@ struct Buffer {
|
|||
char* pointer;
|
||||
gpu_buffer* gpu;
|
||||
BufferInfo info;
|
||||
VertexFormat format;
|
||||
uint64_t hash;
|
||||
Sync sync;
|
||||
};
|
||||
|
||||
|
@ -74,6 +68,11 @@ typedef struct {
|
|||
gpu_slot_type type;
|
||||
} ShaderResource;
|
||||
|
||||
typedef struct {
|
||||
uint32_t location;
|
||||
uint32_t hash;
|
||||
} ShaderAttribute;
|
||||
|
||||
struct Shader {
|
||||
uint32_t ref;
|
||||
Shader* parent;
|
||||
|
@ -81,7 +80,6 @@ struct Shader {
|
|||
ShaderInfo info;
|
||||
uint32_t layout;
|
||||
uint32_t computePipeline;
|
||||
uint32_t attributeMask;
|
||||
uint32_t bufferMask;
|
||||
uint32_t textureMask;
|
||||
uint32_t samplerMask;
|
||||
|
@ -89,12 +87,15 @@ struct Shader {
|
|||
uint32_t constantSize;
|
||||
uint32_t constantCount;
|
||||
uint32_t resourceCount;
|
||||
uint32_t attributeCount;
|
||||
ShaderConstant* constants;
|
||||
ShaderResource* resources;
|
||||
ShaderAttribute* attributes;
|
||||
uint32_t flagCount;
|
||||
uint32_t overrideCount;
|
||||
gpu_shader_flag* flags;
|
||||
uint32_t* flagLookup;
|
||||
bool hasCustomAttributes;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -239,7 +240,7 @@ static struct {
|
|||
Texture* defaultTexture;
|
||||
Sampler* defaultSamplers[2];
|
||||
Shader* defaultShaders[DEFAULT_SHADER_COUNT];
|
||||
VertexFormat vertexFormats[DEFAULT_FORMAT_COUNT];
|
||||
gpu_vertex_format vertexFormats[DEFAULT_FORMAT_COUNT];
|
||||
arr_t(TempAttachment) attachments;
|
||||
map_t pipelineLookup;
|
||||
arr_t(gpu_pipeline*) pipelines;
|
||||
|
@ -362,29 +363,28 @@ bool lovrGraphicsInit(bool debug, bool vsync) {
|
|||
beginFrame();
|
||||
gpu_clear_buffer(state.stream, state.defaultBuffer->gpu, 0, 4096);
|
||||
|
||||
state.vertexFormats[VERTEX_SHAPE].gpu = (gpu_vertex_format) {
|
||||
state.vertexFormats[VERTEX_SHAPE] = (gpu_vertex_format) {
|
||||
.bufferCount = 2,
|
||||
.attributeCount = 3,
|
||||
.attributeCount = 5,
|
||||
.bufferStrides[1] = sizeof(ShapeVertex),
|
||||
.attributes[0] = { 1, 0, offsetof(ShapeVertex, position), GPU_TYPE_F32x3 },
|
||||
.attributes[1] = { 1, 1, offsetof(ShapeVertex, normal), GPU_TYPE_F32x3 },
|
||||
.attributes[2] = { 1, 2, offsetof(ShapeVertex, uv), GPU_TYPE_F32x2 }
|
||||
.attributes[0] = { 1, 10, offsetof(ShapeVertex, position), GPU_TYPE_F32x3 },
|
||||
.attributes[1] = { 1, 11, offsetof(ShapeVertex, normal), GPU_TYPE_F32x3 },
|
||||
.attributes[2] = { 1, 12, offsetof(ShapeVertex, uv), GPU_TYPE_F32x2 },
|
||||
.attributes[3] = { 0, 13, 0, GPU_TYPE_F32x4 },
|
||||
.attributes[4] = { 0, 14, 0, GPU_TYPE_F32x4 }
|
||||
};
|
||||
|
||||
state.vertexFormats[VERTEX_POINT].gpu = (gpu_vertex_format) {
|
||||
state.vertexFormats[VERTEX_POINT] = (gpu_vertex_format) {
|
||||
.bufferCount = 2,
|
||||
.attributeCount = 1,
|
||||
.bufferStrides[1] = 12,
|
||||
.attributes[0] = { 1, 0, 0, GPU_TYPE_F32x3 }
|
||||
.attributes[0] = { 1, 10, 0, GPU_TYPE_F32x3 },
|
||||
.attributes[1] = { 0, 11, 0, GPU_TYPE_F32x4 },
|
||||
.attributes[2] = { 0, 12, 0, GPU_TYPE_F32x4 },
|
||||
.attributes[3] = { 0, 13, 0, GPU_TYPE_F32x4 },
|
||||
.attributes[4] = { 0, 14, 0, GPU_TYPE_F32x4 }
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < COUNTOF(state.vertexFormats); i++) {
|
||||
for (uint32_t j = 0; j < state.vertexFormats[i].gpu.attributeCount; j++) {
|
||||
state.vertexFormats[i].mask |= (1 << state.vertexFormats[i].gpu.attributes[j].location);
|
||||
}
|
||||
state.vertexFormats[i].hash = hash64(&state.vertexFormats[i].gpu, sizeof(gpu_vertex_format));
|
||||
}
|
||||
|
||||
float16Init();
|
||||
glslang_initialize_process();
|
||||
state.initialized = true;
|
||||
|
@ -470,9 +470,9 @@ void lovrGraphicsGetLimits(GraphicsLimits* limits) {
|
|||
limits->storageBufferRange = state.limits.storageBufferRange;
|
||||
limits->uniformBufferAlign = state.limits.uniformBufferAlign;
|
||||
limits->storageBufferAlign = state.limits.storageBufferAlign;
|
||||
limits->vertexAttributes = state.limits.vertexAttributes;
|
||||
limits->vertexAttributes = 10;
|
||||
limits->vertexBufferStride = state.limits.vertexBufferStride;
|
||||
limits->vertexShaderOutputs = state.limits.vertexShaderOutputs;
|
||||
limits->vertexShaderOutputs = 10;
|
||||
limits->clipDistances = state.limits.clipDistances;
|
||||
limits->cullDistances = state.limits.cullDistances;
|
||||
limits->clipAndCullDistances = state.limits.clipAndCullDistances;
|
||||
|
@ -663,23 +663,6 @@ void lovrGraphicsWait() {
|
|||
|
||||
// Buffer
|
||||
|
||||
static void lovrBufferInitFormat(VertexFormat* format, BufferInfo* info) {
|
||||
format->mask = 0;
|
||||
format->gpu.bufferCount = 2;
|
||||
format->gpu.bufferStrides[1] = info->stride;
|
||||
format->gpu.attributeCount = info->fieldCount;
|
||||
for (uint32_t i = 0; i < info->fieldCount; i++) {
|
||||
format->gpu.attributes[i] = (gpu_attribute) {
|
||||
.buffer = 1,
|
||||
.location = info->fields[i].location,
|
||||
.offset = info->fields[i].offset,
|
||||
.type = (gpu_attribute_type) info->fields[i].type
|
||||
};
|
||||
format->mask |= (1 << i);
|
||||
}
|
||||
format->hash = hash64(&format->gpu, sizeof(format->gpu));
|
||||
}
|
||||
|
||||
Buffer* lovrGraphicsGetBuffer(BufferInfo* info, void** data) {
|
||||
uint32_t size = info->length * info->stride;
|
||||
lovrCheck(size > 0, "Buffer size can not be zero");
|
||||
|
@ -690,11 +673,10 @@ Buffer* lovrGraphicsGetBuffer(BufferInfo* info, void** data) {
|
|||
buffer->size = size;
|
||||
buffer->gpu = (gpu_buffer*) (buffer + 1);
|
||||
buffer->info = *info;
|
||||
buffer->hash = hash64(info->fields, info->fieldCount * sizeof(BufferField));
|
||||
|
||||
buffer->pointer = gpu_map(buffer->gpu, size, state.limits.uniformBufferAlign, GPU_MAP_WRITE);
|
||||
|
||||
lovrBufferInitFormat(&buffer->format, info);
|
||||
|
||||
if (data) {
|
||||
*data = buffer->pointer;
|
||||
}
|
||||
|
@ -713,6 +695,7 @@ Buffer* lovrBufferCreate(BufferInfo* info, void** data) {
|
|||
buffer->size = size;
|
||||
buffer->gpu = (gpu_buffer*) (buffer + 1);
|
||||
buffer->info = *info;
|
||||
buffer->hash = hash64(info->fields, info->fieldCount * sizeof(BufferField));
|
||||
|
||||
gpu_buffer_init(buffer->gpu, &(gpu_buffer_info) {
|
||||
.size = buffer->size,
|
||||
|
@ -720,8 +703,6 @@ Buffer* lovrBufferCreate(BufferInfo* info, void** data) {
|
|||
.pointer = data
|
||||
});
|
||||
|
||||
lovrBufferInitFormat(&buffer->format, info);
|
||||
|
||||
if (data && *data == NULL) {
|
||||
beginFrame();
|
||||
gpu_buffer* scratchpad = tempAlloc(gpu_sizeof_buffer());
|
||||
|
@ -1045,16 +1026,33 @@ Blob* lovrGraphicsCompileShader(ShaderStage stage, Blob* source) {
|
|||
[STAGE_COMPUTE] = GLSLANG_STAGE_COMPUTE
|
||||
};
|
||||
|
||||
const glslang_resource_t* resource = glslang_default_resource();
|
||||
const char* prefix = ""
|
||||
"#version 460\n"
|
||||
"#extension GL_EXT_multiview : require\n"
|
||||
"#extension GL_GOOGLE_include_directive : require\n";
|
||||
|
||||
const char* suffixes[] = {
|
||||
[STAGE_VERTEX] = "void main() { FragColor = Color * VertexColor, FragUV = VertexUV, Position = lovrmain(); }",
|
||||
[STAGE_FRAGMENT] = "void main() { PixelColors[0] = lovrmain(); }",
|
||||
[STAGE_COMPUTE] = "void main() { lovrmain(); }"
|
||||
};
|
||||
|
||||
const char* strings[] = {
|
||||
source->data
|
||||
prefix,
|
||||
(const char*) etc_shaders_lovr_glsl,
|
||||
source->data,
|
||||
suffixes[stage]
|
||||
};
|
||||
|
||||
int lengths[] = {
|
||||
source->size
|
||||
-1,
|
||||
etc_shaders_lovr_glsl_len,
|
||||
source->size,
|
||||
-1
|
||||
};
|
||||
|
||||
const glslang_resource_t* resource = glslang_default_resource();
|
||||
|
||||
glslang_input_t input = {
|
||||
.language = GLSLANG_SOURCE_GLSL,
|
||||
.stage = stages[stage],
|
||||
|
@ -1064,7 +1062,7 @@ Blob* lovrGraphicsCompileShader(ShaderStage stage, Blob* source) {
|
|||
.target_language_version = GLSLANG_TARGET_SPV_1_3,
|
||||
.strings = strings,
|
||||
.lengths = lengths,
|
||||
.string_count = 1,
|
||||
.string_count = COUNTOF(strings),
|
||||
.default_version = 460,
|
||||
.default_profile = GLSLANG_NO_PROFILE,
|
||||
.resource = resource
|
||||
|
@ -1191,6 +1189,7 @@ Shader* lovrShaderCreate(ShaderInfo* info) {
|
|||
spv[i].features = tempAlloc(spv[i].featureCount * sizeof(uint32_t));
|
||||
spv[i].specConstants = tempAlloc(spv[i].specConstantCount * sizeof(spv_spec_constant));
|
||||
spv[i].pushConstants = tempAlloc(spv[i].pushConstantCount * sizeof(spv_push_constant));
|
||||
spv[i].attributes = tempAlloc(spv[i].attributeCount * sizeof(spv_attribute));
|
||||
spv[i].resources = tempAlloc(spv[i].resourceCount * sizeof(spv_resource));
|
||||
|
||||
result = spv_parse(info->stages[i]->data, info->stages[i]->size, &spv[i]);
|
||||
|
@ -1201,15 +1200,19 @@ Shader* lovrShaderCreate(ShaderInfo* info) {
|
|||
|
||||
uint32_t constantStage = spv[0].pushConstantSize > spv[1].pushConstantSize ? 0 : 1;
|
||||
uint32_t maxFlags = spv[0].specConstantCount + spv[1].specConstantCount;
|
||||
shader->constantCount = spv[constantStage].pushConstantCount;
|
||||
shader->attributeCount = spv[0].attributeCount;
|
||||
|
||||
shader->attributeMask = spv[0].inputLocationMask;
|
||||
shader->constantSize = MAX(spv[0].pushConstantSize, spv[1].pushConstantSize);
|
||||
shader->constants = malloc(spv[constantStage].pushConstantCount * sizeof(ShaderConstant));
|
||||
shader->resources = malloc((spv[0].resourceCount + spv[1].resourceCount) * sizeof(ShaderResource));
|
||||
shader->attributes = malloc(spv[0].attributeCount * sizeof(ShaderAttribute));
|
||||
gpu_slot* slots = tempAlloc((spv[0].resourceCount + spv[1].resourceCount) * sizeof(gpu_slot));
|
||||
shader->flags = malloc(maxFlags * sizeof(gpu_shader_flag));
|
||||
shader->flagLookup = malloc(maxFlags * sizeof(uint32_t));
|
||||
lovrAssert(shader->constants && shader->resources && shader->flags && shader->flagLookup, "Out of memory");
|
||||
lovrAssert(shader->constants && shader->resources && shader->attributes, "Out of memory");
|
||||
lovrAssert(shader->flags && shader->flagLookup, "Out of memory");
|
||||
|
||||
|
||||
// Push constants
|
||||
for (uint32_t i = 0; i < spv[constantStage].pushConstantCount; i++) {
|
||||
|
@ -1310,6 +1313,13 @@ Shader* lovrShaderCreate(ShaderInfo* info) {
|
|||
}
|
||||
}
|
||||
|
||||
// Attributes
|
||||
for (uint32_t i = 0; i < spv[0].attributeCount; i++) {
|
||||
shader->attributes[i].location = spv[0].attributes[i].location;
|
||||
shader->attributes[i].hash = (uint32_t) hash64(spv[0].attributes[i].name, strlen(spv[0].attributes[i].name));
|
||||
shader->hasCustomAttributes |= shader->attributes[i].location < 10;
|
||||
}
|
||||
|
||||
// Specialization constants
|
||||
for (uint32_t s = 0; s < stageCount; s++) {
|
||||
for (uint32_t i = 0; i < spv[s].specConstantCount; i++) {
|
||||
|
@ -1383,7 +1393,6 @@ Shader* lovrShaderClone(Shader* parent, ShaderFlag* flags, uint32_t count) {
|
|||
shader->info.flags = flags;
|
||||
shader->info.flagCount = count;
|
||||
shader->layout = parent->layout;
|
||||
shader->attributeMask = parent->attributeMask;
|
||||
shader->bufferMask = parent->bufferMask;
|
||||
shader->textureMask = parent->textureMask;
|
||||
shader->samplerMask = parent->samplerMask;
|
||||
|
@ -2064,21 +2073,57 @@ static void flushPipeline(Pass* pass, Draw* draw, Shader* shader) {
|
|||
pipeline->dirty = true;
|
||||
}
|
||||
|
||||
VertexFormat* format = draw->vertex.buffer ? &draw->vertex.buffer->format : &state.vertexFormats[draw->vertex.format];
|
||||
// Builtin vertex format
|
||||
if (!draw->vertex.buffer && pipeline->formatHash != 1 + draw->vertex.format) {
|
||||
pipeline->formatHash = 1 + draw->vertex.format;
|
||||
pipeline->info.vertex = state.vertexFormats[draw->vertex.format];
|
||||
pipeline->dirty = true;
|
||||
|
||||
if (format->hash != pipeline->formatHash) {
|
||||
pipeline->info.vertex = format->gpu;
|
||||
gpu_vertex_format* vertex = &pipeline->info.vertex;
|
||||
uint32_t missingAttributes = shader->attributeMask & ~format->mask;
|
||||
|
||||
if (missingAttributes) {
|
||||
vertex->bufferStrides[0] = 0;
|
||||
for (uint32_t i = 0; i < 32 && missingAttributes; i++) {
|
||||
if (missingAttributes & (1 << i)) { // TODO clz
|
||||
missingAttributes &= ~(1 << i);
|
||||
vertex->attributes[vertex->attributeCount++] = (gpu_attribute) {
|
||||
if (shader->hasCustomAttributes) {
|
||||
for (uint32_t i = 0; i < shader->attributeCount; i++) {
|
||||
if (shader->attributes[i].location < 10) {
|
||||
pipeline->info.vertex.attributes[pipeline->info.vertex.attributeCount++] = (gpu_attribute) {
|
||||
.buffer = 0,
|
||||
.location = i,
|
||||
.location = shader->attributes[i].location,
|
||||
.type = GPU_TYPE_F32x4,
|
||||
.offset = 0
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Custom vertex format
|
||||
if (draw->vertex.buffer && pipeline->formatHash != draw->vertex.buffer->hash) {
|
||||
pipeline->formatHash = draw->vertex.buffer->hash;
|
||||
pipeline->info.vertex.bufferCount = 2;
|
||||
pipeline->info.vertex.attributeCount = shader->attributeCount;
|
||||
pipeline->info.vertex.bufferStrides[0] = 0;
|
||||
pipeline->info.vertex.bufferStrides[1] = draw->vertex.buffer->info.stride;
|
||||
pipeline->dirty = true;
|
||||
|
||||
for (uint32_t i = 0; i < shader->attributeCount; i++) {
|
||||
ShaderAttribute* attribute = &shader->attributes[i];
|
||||
|
||||
bool found = false;
|
||||
for (uint32_t j = 0; j < draw->vertex.buffer->info.fieldCount; j++) {
|
||||
BufferField field = draw->vertex.buffer->info.fields[j];
|
||||
if (field.hash ? (field.hash == attribute->hash) : (field.location == attribute->location)) {
|
||||
pipeline->info.vertex.attributes[i] = (gpu_attribute) {
|
||||
.buffer = 1,
|
||||
.location = attribute->location,
|
||||
.offset = field.offset,
|
||||
.type = field.type
|
||||
};
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
pipeline->info.vertex.attributes[i] = (gpu_attribute) {
|
||||
.buffer = 0,
|
||||
.location = attribute->location,
|
||||
.offset = 0,
|
||||
.type = GPU_TYPE_F32x4
|
||||
};
|
||||
|
@ -2086,10 +2131,6 @@ static void flushPipeline(Pass* pass, Draw* draw, Shader* shader) {
|
|||
}
|
||||
}
|
||||
|
||||
pipeline->formatHash = format->hash;
|
||||
pipeline->dirty = true;
|
||||
}
|
||||
|
||||
if (!pipeline->dirty) {
|
||||
return;
|
||||
}
|
||||
|
@ -2205,7 +2246,7 @@ static void flushBuffers(Pass* pass, Draw* draw) {
|
|||
|
||||
if (!draw->vertex.buffer && draw->vertex.count > 0) {
|
||||
lovrCheck(draw->vertex.count < UINT16_MAX, "This draw has too many vertices (max is 65534), try splitting it up into multiple draws or using a Buffer");
|
||||
uint32_t stride = state.vertexFormats[draw->vertex.format].gpu.bufferStrides[1];
|
||||
uint32_t stride = state.vertexFormats[draw->vertex.format].bufferStrides[1];
|
||||
uint32_t size = draw->vertex.count * stride;
|
||||
|
||||
gpu_buffer* scratchpad = tempAlloc(gpu_sizeof_buffer());
|
||||
|
|
|
@ -129,9 +129,10 @@ typedef enum {
|
|||
} FieldType;
|
||||
|
||||
typedef struct {
|
||||
uint16_t offset;
|
||||
uint8_t location;
|
||||
uint8_t type;
|
||||
uint32_t hash;
|
||||
uint32_t location;
|
||||
uint32_t type;
|
||||
uint32_t offset;
|
||||
} BufferField;
|
||||
|
||||
typedef enum {
|
||||
|
|
Loading…
Reference in New Issue