Shaders; Rework vertex formats;

This commit is contained in:
bjorn 2022-06-15 20:46:43 -07:00
parent 70e0f5c5cf
commit 7de6bdf242
10 changed files with 264 additions and 143 deletions

View File

@ -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

View File

@ -1,2 +1,4 @@
#include "shaders/unlit.vert.h"
#include "shaders/unlit.frag.h"
#include "shaders/lovr.glsl.h"

86
etc/shaders/lovr.glsl Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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++;

View File

@ -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

View File

@ -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

View File

@ -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,30 +2073,62 @@ 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,
.offset = 0,
.type = GPU_TYPE_F32x4
.location = shader->attributes[i].location,
.type = GPU_TYPE_F32x4,
.offset = 0
};
}
}
}
}
pipeline->formatHash = format->hash;
// 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
};
}
}
}
if (!pipeline->dirty) {
@ -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());

View File

@ -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 {