summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2024-12-26 22:06:57 +1100
committerquou <quou@disroot.org>2024-12-26 22:06:57 +1100
commit7fa078995b3ed62925788ce2460441bc3d373392 (patch)
tree3ea7cb6288319ed56b28b7443d628a4f40a4e5fd
parentdac7103df9f748d3409ac87ac3d015e329f6c7f5 (diff)
constant buffers
-rw-r--r--c2.cpp28
-rw-r--r--intermediate/triangle.glsl13
-rw-r--r--pipeline.cpp15
-rw-r--r--sc/sc.cpp127
-rw-r--r--video.cpp34
-rw-r--r--video.hpp34
6 files changed, 226 insertions, 25 deletions
diff --git a/c2.cpp b/c2.cpp
index 3b46920..052ebf0 100644
--- a/c2.cpp
+++ b/c2.cpp
@@ -5,6 +5,7 @@ extern "C" {
#include "memory.h"
}
#include <string.h>
+#include <math.h>
#define video_arena_size (1024 * 1024 * 16)
#define asset_arena_size (1024 * 1024 * 4)
@@ -58,6 +59,10 @@ static Sampler_Id create_clamped_linear(Device* dev) {
return dev->create_sampler(s);
}
+struct Config_Buffer {
+ float offset[2];
+};
+
int main() {
Arena video_arena;
Arena asset_arena;
@@ -66,7 +71,7 @@ int main() {
Shader* shader;
Texture* texture;
Texture* texture2;
- Buffer_Id vbo;
+ Buffer_Id vbo, cbuf;
Sampler_Id clamped_linear;
C2* app = App::create<C2>("c2");
void* per_frame;
@@ -88,6 +93,11 @@ int main() {
shader = (Shader*)assets.load("triangle.csh");
texture = (Texture*)assets.load("22.tex");
texture2 = (Texture*)assets.load("kita.tex");
+ cbuf = dev->create_buffer(
+ sizeof verts,
+ Buffer_Flags::constant_buffer |
+ Buffer_Flags::cpu_readwrite
+ );
per_frame = heap_alloc(
dev->heap,
per_frame_memory_size
@@ -103,6 +113,15 @@ int main() {
app->begin();
dev->begin_frame();
+ {
+ void* mem;
+ mem = dev->map_buffer(cbuf, 0, sizeof(Config_Buffer));
+ Config_Buffer* c = (Config_Buffer*)mem;
+ c->offset[0] = sinf((float)frame / 10.0f);
+ c->offset[1] = cosf((float)frame / 30.0f);
+ dev->unmap_buffer(cbuf);
+ }
+
Pipeline_Builder pb(&frame_arena);
pb.begin_rp();
pb.rp_target(dev->get_backbuffer(), { r, 0x00, 0xff, 0xff });
@@ -112,10 +131,14 @@ int main() {
pb.shader(shader->id);
pb.vertex_format(shader->vf);
pb.texture(
- shader->descriptor_index("colour_texture"),
+ shader->descriptor_binding("colour_texture"),
frame % 2? texture->id: texture2->id,
clamped_linear
);
+ pb.cbuffer(
+ shader->descriptor_binding("config_buffer"),
+ cbuf
+ );
Pipeline& pip = pb.build();
Vertex_Buffer_Binding binding[] = {{
@@ -139,6 +162,7 @@ int main() {
assets.destroy();
dev->destroy_sampler(clamped_linear);
dev->destroy_buffer(vbo);
+ dev->destroy_buffer(cbuf);
dev->destroy();
app->destroy();
}
diff --git a/intermediate/triangle.glsl b/intermediate/triangle.glsl
index 8f3b586..1e883f5 100644
--- a/intermediate/triangle.glsl
+++ b/intermediate/triangle.glsl
@@ -33,6 +33,17 @@ name: colour_texture
stage: fragment
dimension: 2
+[struct]
+name: Config
+[variable]
+name: offset
+type: vec2
+
+[cbuffer]
+name: config_buffer
+type: Config
+stage: vertex
+
#endif
#ifdef VERTEX_SHADER
@@ -40,7 +51,7 @@ dimension: 2
void main() {
interpolator.colour = colour;
interpolator.uv = uv;
- gl_Position = vec4(position, 0.0, 1.0);
+ gl_Position = vec4(position + config_buffer.offset, 0.0, 1.0);
}
#endif
diff --git a/pipeline.cpp b/pipeline.cpp
index 527c1e7..89f606d 100644
--- a/pipeline.cpp
+++ b/pipeline.cpp
@@ -56,6 +56,17 @@ void Pipeline_Builder::texture(
td->texture = t;
}
+void Pipeline_Builder::cbuffer(int binding, Buffer_Id id) {
+ Descriptor* d;
+ Constant_Buffer_Descriptor* cd;
+ assert(pip->descriptor_count < pipeline_max_descriptors);
+ d = &pip->descriptors[pip->descriptor_count++];
+ cd = (Constant_Buffer_Descriptor*)d->payload;
+ d->slot = binding;
+ d->type = Descriptor::Type::constant_buffer;
+ cd->buffer = id;
+}
+
void Pipeline_Builder::vertex_format(Vertex_Format_Id vf) {
pip->vertex_format = vf;
}
@@ -83,6 +94,10 @@ Pipeline& Pipeline_Builder::build() {
h(pip->descriptor_resource_hash, td->sampler);
h(pip->descriptor_resource_hash, td->texture);
} break;
+ case Descriptor::Type::constant_buffer: {
+ auto cd = (Constant_Buffer_Descriptor*)d->payload;
+ h(pip->descriptor_resource_hash, cd->buffer);
+ } break;
}
}
}
diff --git a/sc/sc.cpp b/sc/sc.cpp
index f7acc1a..e806dd4 100644
--- a/sc/sc.cpp
+++ b/sc/sc.cpp
@@ -156,6 +156,27 @@ struct Desc {
int type;
std::string name;
std::string tname;
+
+ std::pair<int, int> size() const {
+ switch (type) {
+ case svariable_type_float:
+ return { 4, 4 };
+ case svariable_type_vec2:
+ return { 8, 8 };
+ case svariable_type_vec3:
+ return { 12, 16 };
+ case svariable_type_vec4:
+ return { 16, 16 };
+ }
+ assert(0);
+ return { 0, 0 };
+ }
+
+ int size(int coff) const {
+ auto [desired, align] = size();
+ int pad = align_size(coff, align) - coff;
+ return desired + pad;
+ }
};
struct Binding {
SBinding_Rate rate;
@@ -171,11 +192,24 @@ struct Desc {
int slot;
int stage;
};
+ struct Struct {
+ std::string name;
+ std::vector<Variable> vars;
+ };
+ struct CBuffer {
+ int size;
+ int stage;
+ int var_count;
+ std::string strct;
+ std::unordered_map<std::string, int> offsets;
+ };
int type;
std::vector<Binding> bindings;
std::vector<Variable> trgts;
std::vector<Variable> interp;
+ std::unordered_map<std::string, Struct> structs;
std::unordered_map<std::string, Texture> textures;
+ std::unordered_map<std::string, CBuffer> cbuffers;
std::vector<Descriptor> descriptors;
std::string entrypoints[shader_type_count];
void read_var(Variable& d, cfg_Object* desc) {
@@ -243,6 +277,66 @@ struct Desc {
t.stage |= 1 << stage_from_string(sstage);
t.dimension = find_int_default(desc, "dimension", 2);
}
+ cfg_Object* read_struct(cfg_Object* desc) {
+ const char* sname = find_string_default(desc, "name", 0);
+ if (!sname) {
+ print_err("%s must have a name.\n", desc->name);
+ pbreak(901);
+ }
+ std::string n = std::string(sname);
+ if (structs.contains(n)) {
+ print_err("Already a struct with the name %s.\n", sname);
+ pbreak(903);
+ }
+ desc = desc->next;
+ Struct& s = structs[n];
+ while (desc && !strcmp(desc->name, "variable")) {
+ Variable v;
+ read_var(v, desc);
+ s.vars.push_back(v);
+ desc = desc->next;
+ }
+ return desc;
+ }
+
+ void read_cbuffer(cfg_Object* desc) {
+ const char* sname = find_string_default(desc, "name", 0);
+ if (!sname) {
+ print_err("%s must have a name.\n", desc->name);
+ pbreak(951);
+ }
+ const char* stype = find_string_default(desc, "type", 0);
+ if (!stype) {
+ print_err("%s must define a type.\n", desc->name);
+ }
+ std::string n = std::string(sname);
+ std::string t = std::string(stype);
+ if (n.size() > 23) {
+ print_err("CBuffer name too long (max 23 chars).\n");
+ pbreak(952);
+ }
+ if (!structs.contains(t)) {
+ print_err("No such struct %s\n", stype);
+ pbreak(953);
+ }
+ const char* sstage = find_string_default(desc, "stage", 0);
+ if (!sstage) {
+ print_err("%s must define a stage.\n", sname);
+ pbreak(954);
+ }
+ Struct& strct = structs[t];
+ CBuffer& buf = cbuffers[n];
+ int offset = 0;
+ buf.strct = t;
+ buf.stage |= 1 << stage_from_string(sstage);
+ buf.var_count = strct.vars.size();
+ for (const auto& v : strct.vars) {
+ buf.offsets[v.name] = offset;
+ offset += v.size(offset);
+ }
+ buf.size = offset;
+ }
+
void build(cfg_Object* desc) {
int i;
Binding* cur_binding = 0;
@@ -289,6 +383,11 @@ struct Desc {
interp.push_back(v);
} else if (!strcmp(desc->name, "texture")) {
read_texture(desc);
+ } else if (!strcmp(desc->name, "cbuffer")) {
+ read_cbuffer(desc);
+ } else if (!strcmp(desc->name, "struct")) {
+ desc = read_struct(desc);
+ continue;
}
desc = desc->next;
}
@@ -311,7 +410,7 @@ struct Desc {
void build_descriptors() {
int slot = 0;
- descriptors.resize(textures.size());
+ descriptors.resize(textures.size() + cbuffers.size());
for (auto& i : textures) {
Descriptor* d = find_desc(i.first.c_str());
d->name = i.first;
@@ -319,6 +418,13 @@ struct Desc {
d->stage = i.second.stage;
slot++;
}
+ for (auto& i : cbuffers) {
+ Descriptor* d = find_desc(i.first.c_str());
+ d->name = i.first;
+ d->slot = slot;
+ d->stage = i.second.stage;
+ slot++;
+ }
}
void add_textures(std::stringstream& ss, Shader_Type stage) {
@@ -334,6 +440,23 @@ struct Desc {
}
}
+ void add_cbuffers(std::stringstream& ss, Shader_Type stage) {
+ for (const auto& it : cbuffers) {
+ const auto& cbuffer = it.second;
+ if (cbuffer.stage & (1 << stage)) {
+ const Struct& s = structs[cbuffer.strct];
+ Descriptor* d = find_desc(it.first.c_str());
+ assert(d != 0);
+ ss << "layout (std140, binding = " << d->slot << ") ";
+ ss << "uniform " << cbuffer.strct << "{\n";
+ for (const auto& v : s.vars) {
+ ss << v.tname << " " << v.name << ";\n";
+ }
+ ss << "} " << it.first << ";\n";
+ }
+ }
+ }
+
std::string build_vs() {
std::stringstream ss;
size_t i, li = bindings.size();
@@ -353,6 +476,7 @@ struct Desc {
ss << i.tname << " " << i.name << ";\n";
ss << "} interpolator;\n";
add_textures(ss, shader_type_vertex);
+ add_cbuffers(ss, shader_type_vertex);
return ss.str();
}
@@ -370,6 +494,7 @@ struct Desc {
ss << i.tname << " " << i.name << ";\n";
ss << "} interpolator;\n";
add_textures(ss, shader_type_fragment);
+ add_cbuffers(ss, shader_type_fragment);
return ss.str();
}
};
diff --git a/video.cpp b/video.cpp
index 7335a32..7c88b54 100644
--- a/video.cpp
+++ b/video.cpp
@@ -479,7 +479,7 @@ struct Buffer_Vk : public Buffer, public Late_Terminated {
r |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
if (flags & Buffer_Flags::vertex_buffer)
r |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
- if (flags & Buffer_Flags::uniform_buffer)
+ if (flags & Buffer_Flags::constant_buffer)
r |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
if (flags & Buffer_Flags::storage_buffer)
r |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
@@ -2266,8 +2266,8 @@ void Pipeline_Vk::init_descriptors(
case Descriptor::Type::texture:
dst.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
break;
- default:
- assert(0);
+ case Descriptor::Type::constant_buffer:
+ dst.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
break;
}
dst.binding = src.slot;
@@ -2382,8 +2382,8 @@ void Descriptor_Set_Vk::init(
case Descriptor::Type::texture:
sampler_count++;
break;
- default:
- assert(0);
+ case Descriptor::Type::constant_buffer:
+ cbuffer_count++;
break;
}
}
@@ -2428,6 +2428,7 @@ void Descriptor_Set_Vk::init(
}
for (i = 0; i < count; i++) {
VkDescriptorImageInfo img{};
+ VkDescriptorBufferInfo buf{};
VkWriteDescriptorSet wd{};
auto& src = desc.descriptors[i];
wd.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@@ -2439,16 +2440,27 @@ void Descriptor_Set_Vk::init(
switch (src.type) {
case Descriptor::Type::texture: {
Texture_Descriptor* td = (Texture_Descriptor*)src.payload;
- assert(td->texture);
- assert(td->sampler);
Texture_Vk& t = *(Texture_Vk*)&dev->get_texture(td->texture);
Sampler_Vk& s = *(Sampler_Vk*)&dev->samplers[td->sampler];
+ assert(td->texture);
+ assert(td->sampler);
img.imageView = t.view;
img.sampler = s.sampler;
img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
wd.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
wd.pImageInfo = &img;
} break;
+ case Descriptor::Type::constant_buffer: {
+ Constant_Buffer_Descriptor* cd =
+ (Constant_Buffer_Descriptor*)src.payload;
+ Buffer_Vk& b = *(Buffer_Vk*)&dev->get_buffer(cd->buffer);
+ assert(cd->buffer);
+ buf.buffer = b.buf;
+ buf.offset = 0;
+ buf.range = b.size;
+ wd.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ wd.pBufferInfo = &buf;
+ } break;
}
vkUpdateDescriptorSets(dev->dev, 1, &wd, 0, 0);
}
@@ -2667,7 +2679,7 @@ int Shader::binding_index(const char* name) {
Shader_Vk* sh = (Shader_Vk*)this;
idx = sh->vfd.find_binding(name);
if (idx < 0 || !sh->vfd.bindings[idx].name[0]) return -1;
- return idx;
+ return sh->vfd.bindings[idx].index;
}
int Shader::attribute_index(const char* name) {
@@ -2675,15 +2687,15 @@ int Shader::attribute_index(const char* name) {
Shader_Vk* sh = (Shader_Vk*)this;
idx = sh->vfd.find_attribute(name);
if (idx < 0 || !sh->vfd.attributes[idx].name[0]) return -1;
- return idx;
+ return sh->vfd.attributes[idx].index;
}
-int Shader::descriptor_index(const char* name) {
+int Shader::descriptor_binding(const char* name) {
int idx;
Shader_Vk* sh = (Shader_Vk*)this;
idx = sh->find_descriptor(name);
if (idx < 0 || !sh->descs[idx].name[0]) return -1;
- return idx;
+ return sh->descs[idx].slot;
}
int Shader::descriptor_stage(int slot) {
diff --git a/video.hpp b/video.hpp
index 3e01ab9..7639b50 100644
--- a/video.hpp
+++ b/video.hpp
@@ -48,7 +48,8 @@ struct Sampler_Id : public Primitive_Id<uint32_t> {
struct Descriptor {
enum class Type {
- texture
+ texture,
+ constant_buffer
} type;
int slot;
uint8_t payload[descriptor_payload_size];
@@ -59,7 +60,12 @@ struct Texture_Descriptor {
Sampler_Id sampler;
};
+struct Constant_Buffer_Descriptor {
+ Buffer_Id buffer;
+};
+
static_assert(sizeof(Texture_Descriptor) <= descriptor_payload_size);
+static_assert(sizeof(Constant_Buffer_Descriptor) <= descriptor_payload_size);
#define pipeline_max_descriptors 16
@@ -103,6 +109,13 @@ struct Pipeline {
if (ta->texture != tb->texture) return false;
if (ta->sampler != tb->sampler) return false;
} break;
+ case Descriptor::Type::constant_buffer: {
+ Constant_Buffer_Descriptor* ca =
+ (Constant_Buffer_Descriptor*)a.payload;
+ Constant_Buffer_Descriptor* cb =
+ (Constant_Buffer_Descriptor*)b.payload;
+ if (ca->buffer != cb->buffer) return false;
+ } break;
}
}
return true;
@@ -157,6 +170,7 @@ struct Pipeline_Builder {
void shader(Shader_Id s);
void vertex_format(Vertex_Format_Id vf);
void texture(int binding, Texture_Id t, Sampler_Id s);
+ void cbuffer(int binding, Buffer_Id id);
Pipeline& build();
void validate();
};
@@ -176,14 +190,14 @@ struct Texture : public Asset {
namespace Buffer_Flags {
enum {
- index_buffer = 1 << 0,
- vertex_buffer = 1 << 1,
- uniform_buffer = 1 << 2,
- storage_buffer = 1 << 3,
- cpu_read = 1 << 4,
- cpu_readwrite = 1 << 5,
- copy_src = 1 << 6,
- copy_dst = 1 << 7
+ index_buffer = 1 << 0,
+ vertex_buffer = 1 << 1,
+ constant_buffer = 1 << 2,
+ storage_buffer = 1 << 3,
+ cpu_read = 1 << 4,
+ cpu_readwrite = 1 << 5,
+ copy_src = 1 << 6,
+ copy_dst = 1 << 7
};
};
@@ -301,7 +315,7 @@ struct Shader : public Asset {
int binding_index(const char* name);
int attribute_index(const char* name);
int target_index(const char* name);
- int descriptor_index(const char* name);
+ int descriptor_binding(const char* name);
int descriptor_stage(int slot);
};