summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile13
-rw-r--r--asset.cpp18
-rw-r--r--asset.hpp11
-rw-r--r--c2.cpp42
-rw-r--r--convtexture.c217
-rw-r--r--intermediate/22.bmpbin0 -> 4194442 bytes
-rw-r--r--todo.txt2
-rw-r--r--video.cpp584
-rw-r--r--video.hpp30
10 files changed, 769 insertions, 149 deletions
diff --git a/.gitignore b/.gitignore
index 1468a38..31453af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ tags
/c2
/pack
/packer
+/convtexture
diff --git a/Makefile b/Makefile
index 1d01b16..f8ecd68 100644
--- a/Makefile
+++ b/Makefile
@@ -3,8 +3,9 @@
target = c2
data_dir = data
shaders = $(data_dir)/triangle.csh
-packed_files = $(shaders)
-tools = qstd cfg sc packer
+textures = $(data_dir)/22.tex
+packed_files = $(shaders) $(textures)
+tools = qstd cfg sc
objects = app.o c2.o video.o pipeline.o asset.o
includes = -Iqstd
defines = -Dplat_x86 -Dplat_posix -Dplat_x11 -Dallocation_default_alignment=8
@@ -13,7 +14,7 @@ libs = -lX11 -lm
lflags = $(libs) $(DEBUG_LINK_FLAG)
.PHONY: all clean $(tools)
-all: $(target) $(shaders) $(tools) $(objects)
+all: $(target) $(shaders) $(tools) $(objects) pack
qstd:
$(MAKE) -C qstd
@@ -27,12 +28,18 @@ sc: qstd cfg
packer: packer.c | qstd
$(CC) $(cflags) packer.c $(lflags) -Lqstd -lqstd -o packer
+convtexture: convtexture.c | qstd
+ $(CC) $(cflags) convtexture.c $(lflags) -Lqstd -lqstd -o convtexture
+
pack: $(packed_files) packer
./packer pack $(data_dir) $(packed_files)
data/triangle.csh: intermediate/triangle.glsl | $(data_dir) sc
./sc/sc intermediate/triangle.glsl $(data_dir)/triangle.csh
+data/22.tex: intermediate/22.bmp | $(data_dir) convtexture
+ ./convtexture intermediate/22.bmp $(data_dir)/22.tex bc1
+
app.o:
$(CXX) -c $(cflags) app.cpp -o app.o
diff --git a/asset.cpp b/asset.cpp
index 09260e0..fc6d22b 100644
--- a/asset.cpp
+++ b/asset.cpp
@@ -8,6 +8,7 @@ extern "C" {
}
#define max_asset_types 32
+#define asset_scratch_size (1024 * 1024)
struct RLoader {
char magic[4];
@@ -68,13 +69,19 @@ void register_asset_loader(
void Asset_Arena::init(Arena* arena, const char* pack_name) {
p = pack_open(pack_name, arena);
a = arena;
+ s = (Arena*)arena_alloc(a, sizeof *s);
+ init_arena(
+ s,
+ arena_alloc(a, asset_scratch_size),
+ asset_scratch_size
+ );
assets = 0;
}
void Asset_Arena::destroy() {
Asset* a;
for (a = assets; a; a = a->next) {
- a->unload(a->loader);
+ a->loader->unload(a);
}
pack_close(p);
}
@@ -93,9 +100,12 @@ Asset* Asset_Arena::load(const char* name) {
pack_read(f, magic, 4);
pack_seek(f, 0, seek_rel_start);
Asset_Loader& loader = manager.get_loader(magic);
- Asset* asset = loader.load(a, f);
- asset->loader = &loader;
+ clear_arena(s);
+ Asset* asset = loader.load(a, s, f);
+ if (asset) {
+ asset->loader = &loader;
+ claim(asset);
+ }
pack_close_file(f);
- claim(asset);
return asset;
}
diff --git a/asset.hpp b/asset.hpp
index 27ac990..db53414 100644
--- a/asset.hpp
+++ b/asset.hpp
@@ -9,21 +9,16 @@ struct Pack;
struct Asset {
Asset* next;
Asset_Loader* loader;
- virtual bool load(
- Asset_Loader* loader,
- Arena* a,
- Pack_File* f
- ) = 0;
- virtual void unload(Asset_Loader* loader) = 0;
};
struct Asset_Loader {
- virtual Asset* load(Arena* a, Pack_File* f) = 0;
+ virtual Asset* load(Arena* a, Arena* s, Pack_File* f) = 0;
+ virtual void unload(Asset* a) = 0;
};
struct Asset_Arena {
Pack* p;
- Arena* a;
+ Arena* a, * s;
Asset* assets;
void init(Arena* arena, const char* pack_name);
diff --git a/c2.cpp b/c2.cpp
index 9510c6a..af912e5 100644
--- a/c2.cpp
+++ b/c2.cpp
@@ -23,12 +23,39 @@ struct C2 : public App {
}
};
+static Buffer_Id upload_verts(Device* dev) {
+ Buffer_Id stage = dev->create_buffer(
+ sizeof verts,
+ Buffer_Flags::copy_src |
+ Buffer_Flags::cpu_readwrite
+ );
+ Buffer_Id vbo = dev->create_buffer(
+ sizeof verts,
+ Buffer_Flags::vertex_buffer |
+ Buffer_Flags::copy_dst
+ );
+ {
+ void* mem;
+ mem = dev->map_buffer(stage, 0, sizeof verts);
+ memcpy(mem, verts, sizeof verts);
+ dev->unmap_buffer(stage);
+ }
+ {
+ Context& ctx = dev->acquire();
+ ctx.copy(vbo, stage);
+ dev->submit(ctx);
+ }
+ dev->destroy_buffer(stage);
+ return vbo;
+}
+
int main() {
Arena video_arena;
Arena asset_arena;
Asset_Arena assets;
Device* dev;
Shader* shader;
+ Texture* texture;
Buffer_Id vbo;
C2* app = App::create<C2>("c2");
void* per_frame;
@@ -47,23 +74,14 @@ int main() {
dev = Device::create(&video_arena, app);
app->dev = dev;
shader = (Shader*)assets.load("triangle.csh");
+ texture = (Texture*)assets.load("22.tex");
per_frame = heap_alloc(
dev->heap,
per_frame_memory_size
);
assert(per_frame != 0);
uint8_t r = 0;
- vbo = dev->create_buffer(
- sizeof verts,
- Buffer_Flags::vertex_buffer |
- Buffer_Flags::cpu_readwrite
- );
- {
- void* mem;
- mem = dev->map_buffer(vbo, 0, sizeof verts);
- memcpy(mem, verts, sizeof verts);
- dev->unmap_buffer(vbo);
- }
+ vbo = upload_verts(dev);
while (app->running) {
Arena frame_arena;
init_arena(&frame_arena, per_frame, per_frame_memory_size);
@@ -92,7 +110,7 @@ int main() {
draw.vertex_count = 3;
draw.instance_count = 1;
- dev->get_ctx().submit(*dev, draw, pip, pass);
+ dev->get_ctx().submit(draw, pip, pass);
/* dev->get_ctx().submit(*dev, pass);*/
r += 10;
diff --git a/convtexture.c b/convtexture.c
new file mode 100644
index 0000000..a04e3c9
--- /dev/null
+++ b/convtexture.c
@@ -0,0 +1,217 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "plat.h"
+#include "str.h"
+#include "vid_enums.h"
+
+typedef struct {
+ float r, g, b;
+} vec3;
+
+typedef struct {
+ unsigned char r, g, b, a;
+} Colour;
+
+typedef struct {
+ Colour* pixels;
+ int w, h;
+} Image;
+
+typedef struct {
+ vec3 start, end;
+ unsigned char indices[4 * 4];
+} Block;
+
+const char* format_names[] = {
+#define x(n) #n,
+ texture_format_xmacro()
+#undef x
+};
+
+void get_block(Block* block, Colour* pixels, int stride) {
+ int x, y, i;
+ vec3 cols[4 * 4];
+ vec3 s, e;
+ float cd;
+ for (y = 0; y < 4; y++) {
+ for (x = 0; x < 4; x++) {
+ Colour pixel = pixels[x + y * stride];
+ vec3 vec;
+ vec.r = (float)pixel.r / 255.0f;
+ vec.g = (float)pixel.g / 255.0f;
+ vec.b = (float)pixel.b / 255.0f;
+ cols[x + y * 4] = vec;
+ }
+ }
+ cd = -1.0f;
+ for (i = 0; i < 4 * 4; i++) {
+ int j;
+ vec3* a = &cols[i];
+ for (j = i + 1; j < 4 * 4; j++) {
+ vec3* b = &cols[j];
+ float d =
+ (b->r - a->r) * (b->r - a->r) +
+ (b->g - a->g) * (b->g - a->g) +
+ (b->b - a->b) * (b->b - a->b);
+ if (d > cd) {
+ cd = d;
+ s = *a;
+ e = *b;
+ }
+ }
+ }
+ for (i = 0; i < 4 * 4; i++) {
+ vec3* col = &cols[i];
+ float d;
+ d =
+ (e.r - col->r) * (e.r - col->r) +
+ (e.g - col->g) * (e.g - col->g) +
+ (e.b - col->b) * (e.b - col->b);
+ if (cd < 0.0001f)
+ block->indices[i] = 0;
+ else {
+ d = d / cd;
+ block->indices[i] = (int)((1.0f - d) * 3.1f);
+ }
+ }
+ block->start = s;
+ block->end = e;
+}
+
+void compress_block(const Block* block, FILE* f) {
+ int i;
+ unsigned start =
+ ((unsigned)(block->start.r * 31.9999f) << 11) |
+ ((unsigned)(block->start.g * 63.9999f) << 5) |
+ ((unsigned)(block->start.b * 31.9999f));
+ unsigned end =
+ ((unsigned)(block->end.r * 31.9999f) << 11) |
+ ((unsigned)(block->end.g * 63.9999f) << 5) |
+ ((unsigned)(block->end.b * 31.9999f));
+ unsigned palette = (start << 16) | end;
+ unsigned indices = 0;
+ fwrite(&palette, 1, 4, f);
+ for (i = 0; i < 4 * 4; i++) {
+ indices |= block->indices[i] << (i * 2);
+ }
+ fwrite(&indices, 1, 4, f);
+}
+
+void compress_bc1(Colour* pixels, int w, int h, FILE* f) {
+ int x, y, cw, ch;
+ Block block;
+ cw = w / 4;
+ ch = h / 4;
+ for (y = 0; y < ch; y++) {
+ for (x = 0; x < cw; x++) {
+ get_block(&block, &pixels[x * 4 + y * 4 * w], w);
+ compress_block(&block, f);
+ }
+ }
+}
+
+void convert(Image* image, Texture_Format target, FILE* f) {
+ fwrite("TXTR", 1, 4, f);
+ fwrite(&image->w, 1, 4, f);
+ fwrite(&image->h, 1, 4, f);
+ fwrite(&target, 1, 4, f);
+ switch (target) {
+ case texture_format_bc1:
+ compress_bc1(image->pixels, image->w, image->h, f);
+ break;
+ default:
+ print_err("Unsupported target format.\n");
+ pbreak(40);
+ }
+}
+
+Texture_Format texture_format_from_string(const char* s) {
+ int i, e = sizeof format_names / sizeof *format_names;
+ for (i = 0; i < e; i++)
+ if (string_equal(s, format_names[i]))
+ return (Texture_Format)i;
+ print_err("Invalid texture format %s\n", s);
+ pbreak(10);
+ return (Texture_Format)0;
+}
+
+int main(int argc, const char** argv) {
+ FILE* outfile, * infile;
+ char bmp_magic[2];
+ unsigned bmp_offset;
+ int bmp_w, bmp_h, s, x, y;
+ unsigned short bmp_bits;
+ Colour* buffer;
+ Image img;
+ Colour pixel;
+ Texture_Format target;
+
+ if (argc < 4) {
+ print_err("Usage: %s infile outfile format.\n", argv[0]);
+ return 1;
+ }
+
+ infile = fopen(argv[1], "rb");
+ if (!infile) {
+ print_err("Failed to open %s.\n", argv[1]);
+ return 2;
+ }
+ target = texture_format_from_string(argv[3]);
+
+ fread(bmp_magic, 2, 1, infile);
+ if (bmp_magic[0] != 'B' || bmp_magic[1] != 'M') {
+ print_err("Not a valid bitmap file.\n");
+ return 3;
+ }
+
+ fseek(infile, 10, SEEK_SET);
+ fread(&bmp_offset, 4, 1, infile);
+ fseek(infile, 18, SEEK_SET);
+ fread(&bmp_w, 4, 1, infile);
+ fread(&bmp_h, 4, 1, infile);
+ fseek(infile, 28, SEEK_SET);
+ fread(&bmp_bits, 2, 1, infile);
+
+ if (bmp_bits != 32) {
+ print_err("Bitmap must have 32 bit pixels. Instead has %d bit pixels.\n", bmp_bits);
+ return 4;
+ }
+
+ if (bmp_w % 4 != 0 || bmp_h % 4 != 0) {
+ print_err("Bitmap must have a size divisible by four.\n");
+ return 5;
+ }
+
+ fseek(infile, bmp_offset, SEEK_SET);
+ s = bmp_w * bmp_h;
+ buffer = malloc(s * 4);
+ /* Flip & read. */
+ for (y = 0; y < bmp_h; y++) {
+ for (x = 0; x < bmp_w; x++) {
+ unsigned char t;
+ fread(&pixel, 1, 4, infile);
+ t = pixel.r;
+ pixel.r = pixel.b;
+ pixel.b = t;
+ if (pixel.a == 0) {
+ pixel.r = 0;
+ pixel.g = 0;
+ pixel.b = 0;
+ }
+ buffer[x + (bmp_h - y - 1) * bmp_w] = pixel;
+ }
+ }
+ outfile = fopen(argv[2], "wb");
+ if (!outfile) {
+ print_err("Failed to open %s.\n", argv[2]);
+ return 6;
+ }
+ img.pixels = buffer;
+ img.w = bmp_w;
+ img.h = bmp_h;
+ convert(&img, target, outfile);
+ fclose(outfile);
+ return 0;
+}
+
diff --git a/intermediate/22.bmp b/intermediate/22.bmp
new file mode 100644
index 0000000..22570e5
--- /dev/null
+++ b/intermediate/22.bmp
Binary files differ
diff --git a/todo.txt b/todo.txt
index 693e3aa..7ac8f90 100644
--- a/todo.txt
+++ b/todo.txt
@@ -3,7 +3,7 @@ todo list
- [x] windowing + input
- [x] vulkan device and swapchain, etc
- [x] draw a triangle
- - [ ] texture conversion + compression, etc
+ - [x] texture conversion + compression, etc
- [ ] texture the triangle
- [ ] simple text rendering
- [ ] 3D maths library
diff --git a/video.cpp b/video.cpp
index 1670a61..8bc5080 100644
--- a/video.cpp
+++ b/video.cpp
@@ -176,6 +176,35 @@ struct Hash_Map {
}
};
+static VkFormat get_vk_format(Texture_Format fmt) {
+ switch (fmt) {
+ case texture_format_r8i: return VK_FORMAT_R8_UNORM;
+ case texture_format_r16f: return VK_FORMAT_R16_SFLOAT;
+ case texture_format_r32f: return VK_FORMAT_R32_SFLOAT;
+ case texture_format_rg8i: return VK_FORMAT_R8G8_UNORM;
+ case texture_format_rg16f: return VK_FORMAT_R16G16_SFLOAT;
+ case texture_format_rg32f: return VK_FORMAT_R32G32_SFLOAT;
+ case texture_format_rgb8i: return VK_FORMAT_R8G8B8_UNORM;
+ case texture_format_rgb16f: return VK_FORMAT_R16G16B16_SFLOAT;
+ case texture_format_rgb32f: return VK_FORMAT_R32G32B32_SFLOAT;
+ case texture_format_rgba8i: return VK_FORMAT_R8G8B8A8_UNORM;
+ case texture_format_rgba16f: return VK_FORMAT_R16G16B16A16_SFLOAT;
+ case texture_format_rgba32f: return VK_FORMAT_R32G32B32A32_SFLOAT;
+ case texture_format_bc1: return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
+ default: assert(0); return VK_FORMAT_UNDEFINED;
+ }
+}
+
+VkImageLayout state_to_image_layout(Resource_State s) {
+ switch (s) {
+ case undefined: return VK_IMAGE_LAYOUT_UNDEFINED;
+ case copy_dst: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ case copy_src: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ case shader_read: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ default: assert(0); return VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+}
+
static void* vk_alloc(
void* uptr,
size_t size,
@@ -295,6 +324,12 @@ static void deinit_swap_cap(
if (cap->pms) heap_free(d->heap, cap->pms);
}
+struct Late_Terminated {
+ Late_Terminated* next;
+
+ virtual void destroy(Device_Vk* dev) = 0;
+};
+
struct Swapchain {
VkSwapchainKHR swapchain;
Texture_Id* textures;
@@ -308,6 +343,14 @@ struct Swapchain {
void recreate(const App& app, Device_Vk* dev);
void get_images(Device_Vk* dev);
void destroy(Device_Vk* dev);
+
+ Texture_Id create_image(
+ Device_Vk* dev,
+ VkImage image,
+ VkImageView view,
+ int w,
+ int h
+ );
};
#define max_contexts 16
@@ -317,7 +360,7 @@ enum {
context_state_init = 1 << 1
};
-struct Shader_Vk : public Shader {
+struct Shader_Vk : public Shader, public Late_Terminated {
struct Attribute {
char name[28];
SVariable_Type type;
@@ -361,7 +404,7 @@ struct Shader_Vk : public Shader {
Device_Vk* dev,
FILE* f
);
- void destroy_internal(Device_Vk* dev);
+ void destroy(Device_Vk* dev) override;
static VkShaderStageFlagBits stage(Shader_Type type) {
switch (type) {
@@ -379,37 +422,42 @@ struct Shader_Vk : public Shader {
struct Renderpass_Vk;
struct Context_Vk : public Context {
int state;
+ Device_Vk* dev;
VkCommandBuffer cb;
VkCommandPool pool;
VkFence fence;
VkSemaphore semaphore;
- void init_pool(Device_Vk* dev);
- void init_cb(Device_Vk* dev);
- void init_sync(Device_Vk* dev);
- void init(Device_Vk* dev);
- void begin_record(Device_Vk* dev);
- Context_Vk& acquire(Device_Vk* dev);
+ void init_pool();
+ void init_cb();
+ void init_sync();
+ void init(Device_Vk* device);
+ void begin_record();
+ Context_Vk& acquire(Device_Vk* device);
void release();
- void destroy(Device_Vk* dev);
+ void destroy();
- Renderpass_Vk& begin_rp(Device& d, const Render_Pass& rp);
+ Renderpass_Vk& begin_rp(const Render_Pass& rp);
void end_rp(Renderpass_Vk& rpo);
};
-struct Texture_Vk : public Texture {
+struct Texture_Vk : public Texture, public Late_Terminated {
VkImage image;
VkImageView view;
+ VkDeviceMemory memory;
+ Resource_State state;
+
+ void destroy(Device_Vk*) override;
};
-struct Buffer_Vk : public Buffer {
+struct Buffer_Vk : public Buffer, public Late_Terminated {
VkBuffer buf;
VkDeviceMemory memory;
VkDeviceSize size;
int flags;
void init(Device_Vk* dev, int flags, VkDeviceSize size);
- void destroy(Device_Vk* dev);
+ void destroy(Device_Vk* dev) override;
static VkBufferUsageFlags get_usage(int flags) {
VkBufferUsageFlags r = 0;
@@ -600,7 +648,44 @@ struct std::hash<Render_Pass> {
struct Shader_Loader : public Asset_Loader {
Device_Vk* dev;
void init(Device_Vk* d);
- Asset* load(Arena* a, Pack_File* f) override;
+ Asset* load(Arena* a, Arena* s, Pack_File* f) override;
+ void unload(Asset* a) override;
+};
+
+struct Texture_Loader : public Asset_Loader {
+ Device_Vk* dev;
+ static size_t calc_size(Texture_Format fmt, int w, int h);
+ void init(Device_Vk* d);
+ Asset* load(Arena* a, Arena* s, Pack_File* f) override;
+ void unload(Asset* a) override;
+
+ Buffer_Id upload(void* buf, size_t size);
+ Texture_Id create_tex(
+ Texture_Format fmt,
+ int w,
+ int h
+ );
+};
+
+struct Terminator {
+ Late_Terminated* queue;
+
+ void execute(Device_Vk* dev) {
+ Late_Terminated* obj = queue;
+ for (; obj; obj = obj->next)
+ obj->destroy(dev);
+ queue = 0;
+ }
+
+ void add(Late_Terminated* obj) {
+ if (queue) {
+ obj->next = queue;
+ queue = obj;
+ } else {
+ obj->next = 0;
+ queue = obj;
+ }
+ }
};
struct Device_Vk : public Device {
@@ -619,6 +704,7 @@ struct Device_Vk : public Device {
Context_Vk contexts[max_contexts];
Context_Vk* current_ctx;
Shader_Loader shader_loader;
+ Texture_Loader texture_loader;
#ifdef DEBUG
VkDebugUtilsMessengerEXT msg;
#endif
@@ -639,11 +725,10 @@ struct Device_Vk : public Device {
Hash_Map<Render_Pass, Renderpass_Vk, max_rpos> rpo_cache;
Hash_Map<Pso_Key, Pipeline_Vk, max_pipelines> pso_cache;
- Texture_Id alloc_texture(
- VkImage img,
- VkImageView view,
- const Texture& copy
- );
+ Terminator* terminators;
+ uint32_t terminator_index;
+
+ Texture_Id alloc_texture();
Buffer_Id alloc_buffer();
Vertex_Format_Id alloc_vf();
Vertex_Format_Id create_vf(Shader_Vk& shader);
@@ -669,6 +754,8 @@ struct Device_Vk : public Device {
Pipeline_Vk& get_pso(const Pso_Key& pop);
void collect_garbage();
+ void queue_destroy(Late_Terminated* obj);
+ void create_terminators();
int find_memory_type(
uint32_t filter,
@@ -980,7 +1067,9 @@ void Device_Vk::init_internal() {
rpo_cache.init();
pso_cache.init();
shader_loader.init(this);
+ texture_loader.init(this);
register_asset_loader("CSH2", &shader_loader);
+ register_asset_loader("TXTR", &texture_loader);
find_exts(exts, ext_count);
init_ac();
create_inst(exts, ext_count);
@@ -993,12 +1082,31 @@ void Device_Vk::init_internal() {
gladLoaderLoadVulkan(inst, phys_dev, dev);
vkGetDeviceQueue(dev, (uint32_t)queue_index, 0, &queue);
swapchain.init(*app, this);
+ terminators = 0;
+ terminator_index = 0;
+ create_terminators();
for (i = 0; i < max_contexts; i++)
contexts[i].state = context_state_avail;
}
+void Device_Vk::create_terminators() {
+ int i, count = swapchain.image_count;
+ if (terminators) {
+ for (i = 0; i < count; i++)
+ terminators[i].execute(this);
+ heap_free(heap, terminators);
+ }
+ terminators = (Terminator*)heap_alloc(
+ heap,
+ count * sizeof *terminators
+ );
+ for (i = 0; i < count; i++) {
+ terminators[i].queue = 0;
+ }
+}
+
void Device_Vk::deinit_internal() {
- int i;
+ int i, image_count = swapchain.image_count;
vkDeviceWaitIdle(dev);
swapchain.destroy(this);
deinit_swap_cap(this, &swap_cap);
@@ -1010,7 +1118,10 @@ void Device_Vk::deinit_internal() {
for (i = 0; i < max_contexts; i++) {
auto& context = contexts[i];
if (context.state & context_state_init)
- context.destroy(this);
+ context.destroy();
+ }
+ for (i = 0; i < image_count; i++) {
+ terminators[i].execute(this);
}
vkDestroyDevice(dev, &ac);
#ifdef DEBUG
@@ -1030,6 +1141,7 @@ void Device_Vk::on_resize_internal(int w, int h) {
deinit_swap_cap(this, &swap_cap);
get_swap_cap(this, phys_dev, surf, &swap_cap);
swapchain.recreate(*app, this);
+ create_terminators();
}
Renderpass_Vk& Device_Vk::create_rpo(const Render_Pass& rp) {
@@ -1073,10 +1185,11 @@ void Renderpass_Vk::destroy(Device_Vk* dev) {
}
void Device_Vk::collect_garbage() {
+ int max_age = swapchain.image_count + 3;
for (const auto& i: rpo_cache) {
auto& rp = i.second;
rp.age++;
- if (rp.age > 3) {
+ if (rp.age > max_age) {
rp.destroy(this);
rpo_cache.remove(i.first);
}
@@ -1084,13 +1197,17 @@ void Device_Vk::collect_garbage() {
for (const auto& i: pso_cache) {
auto& pip = i.second;
pip.age++;
- if (pip.age > 3) {
+ if (pip.age > max_age) {
pip.destroy(this);
pso_cache.remove(i.first);
}
}
}
+void Device_Vk::queue_destroy(Late_Terminated* obj) {
+ terminators[terminator_index].add(obj);
+}
+
int Device_Vk::find_memory_type(
uint32_t filter,
VkMemoryPropertyFlags flags
@@ -1271,14 +1388,27 @@ void Swapchain::recreate(const App& app, Device_Vk* dev) {
old.destroy(dev);
}
+Texture_Id Swapchain::create_image(
+ Device_Vk* dev,
+ VkImage image,
+ VkImageView view,
+ int w,
+ int h
+) {
+ Texture_Id id = dev->alloc_texture();
+ Texture_Vk& tex = *(Texture_Vk*)&dev->get_texture(id);
+ tex.image = image;
+ tex.view = view;
+ tex.w = w;
+ tex.h = h;
+ tex.alias = true;
+ return id;
+}
+
void Swapchain::get_images(Device_Vk* dev) {
unsigned count;
int i;
VkImage* images;
- Texture info{};
- info.w = size.width;
- info.h = size.height;
- info.alias = true;
vkGetSwapchainImagesKHR(dev->dev, swapchain, &count, 0);
image_count = count;
images = (VkImage*)heap_alloc(
@@ -1296,7 +1426,13 @@ void Swapchain::get_images(Device_Vk* dev) {
format.format,
VK_IMAGE_ASPECT_COLOR_BIT
);
- textures[i] = dev->alloc_texture(images[i], view, info);
+ textures[i] = create_image(
+ dev,
+ images[i],
+ view,
+ size.width,
+ size.height
+ );
}
heap_free(dev->heap, images);
}
@@ -1339,6 +1475,9 @@ void Device::begin_frame() {
Device_Vk* dev = (Device_Vk*)this;
dev->collect_garbage();
dev->current_ctx = (Context_Vk*)&acquire();
+ dev->terminator_index++;
+ dev->terminator_index %= dev->swapchain.image_count;
+ dev->terminators[dev->terminator_index].execute(dev);
vkAcquireNextImageKHR(
dev->dev,
dev->swapchain.swapchain,
@@ -1353,20 +1492,18 @@ void Device::begin_frame() {
void Device::submit(Context& ctx_) {
Context_Vk* ctx = (Context_Vk*)&ctx_;
Device_Vk* dev = (Device_Vk*)this;
- VkPipelineStageFlags stage =
- VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo si{};
si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- si.waitSemaphoreCount = 1;
+/* si.waitSemaphoreCount = 1;
si.pWaitSemaphores = &ctx->semaphore;
si.pWaitDstStageMask = &stage;
si.signalSemaphoreCount = 1;
- si.pSignalSemaphores = &ctx->semaphore;
+ si.pSignalSemaphores = &ctx->semaphore;*/
si.commandBufferCount = 1;
si.pCommandBuffers = &ctx->cb;
vkEndCommandBuffer(ctx->cb);
vkQueueSubmit(dev->queue, 1, &si, ctx->fence);
- ctx->wait(*dev);
+ ctx->wait();
ctx->release();
}
@@ -1374,18 +1511,27 @@ void Device::present() {
Device_Vk* dev = (Device_Vk*)this;
Context_Vk* ctx = dev->current_ctx;
VkPresentInfoKHR pi{};
- VkSemaphore s[1];
- VkSwapchainKHR sw[1];
- submit(*ctx);
- s[0] = ctx->semaphore;
- sw[0] = dev->swapchain.swapchain;
+ VkSubmitInfo si{};
+ VkPipelineStageFlags stage =
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ si.waitSemaphoreCount = 1;
+ si.pWaitSemaphores = &ctx->semaphore;
+ si.pWaitDstStageMask = &stage;
+ si.signalSemaphoreCount = 1;
+ si.pSignalSemaphores = &ctx->semaphore;
+ si.commandBufferCount = 1;
+ si.pCommandBuffers = &ctx->cb;
+ vkEndCommandBuffer(ctx->cb);
+ vkQueueSubmit(dev->queue, 1, &si, ctx->fence);
pi.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
pi.waitSemaphoreCount = 1;
- pi.pWaitSemaphores = s;
+ pi.pWaitSemaphores = &ctx->semaphore;
pi.swapchainCount = 1;
- pi.pSwapchains = sw;
+ pi.pSwapchains = &dev->swapchain.swapchain;
pi.pImageIndices = &dev->backbuffer_index;
vkQueuePresentKHR(dev->queue, &pi);
+ ctx->release();
}
Texture_Id Device::get_backbuffer() {
@@ -1396,16 +1542,9 @@ Texture& Device::get_texture(Texture_Id id) {
return ((Device_Vk*)this)->textures[id];
}
-Texture_Id Device_Vk::alloc_texture(
- VkImage img,
- VkImageView view,
- const Texture& copy
-) {
+Texture_Id Device_Vk::alloc_texture() {
Texture_Vk tex{};
Texture_Id id(texture_count++);
- memcpy(&tex, &copy, sizeof(Texture));
- tex.image = img;
- tex.view = view;
textures.set(id, tex);
return id;
}
@@ -1445,16 +1584,12 @@ Shader_Id Device_Vk::alloc_shader() {
void Device::destroy_texture(Texture_Id id) {
Device_Vk* dev = (Device_Vk*)this;
- Texture_Vk& tex = dev->textures[id];
- if (!tex.alias)
- vkDestroyImage(dev->dev, tex.image, &dev->ac);
- vkDestroyImageView(dev->dev, tex.view, &dev->ac);
- dev->textures.remove(id);
+ dev->queue_destroy((Texture_Vk*)&dev->get_texture(id));
}
-void Context::wait(Device& d) {
+void Context::wait() {
Context_Vk* ctx = (Context_Vk*)this;
- Device_Vk* dev = (Device_Vk*)&d;
+ Device_Vk* dev = ctx->dev;
vkWaitForFences(
dev->dev,
1,
@@ -1465,17 +1600,16 @@ void Context::wait(Device& d) {
}
void Context::submit(
- Device& d,
const Draw& draw,
const Pipeline& p,
const Render_Pass& rp
) {
- Device_Vk* dev = (Device_Vk*)&d;
Context_Vk* ctx = (Context_Vk*)this;
+ Device_Vk* dev = ctx->dev;
Vertex_Buffer_Binding* binding;
Pso_Key pso_key = { p, rp };
Pipeline_Vk& pso = dev->get_pso(pso_key);
- auto& rpo = ctx->begin_rp(d, rp);
+ auto& rpo = ctx->begin_rp(rp);
vkCmdBindPipeline(
ctx->cb,
VK_PIPELINE_BIND_POINT_GRAPHICS,
@@ -1498,13 +1632,13 @@ void Context::submit(
}
void Context::submit(
- Device& d,
const Draw* draws,
int count,
const Pipeline& p,
const Render_Pass& rp
) {
- Device_Vk* dev = (Device_Vk*)&d;
+ Context_Vk* ctx = (Context_Vk*)this;
+ Device_Vk* dev = ctx->dev;
(void)draws;
(void)count;
(void)p;
@@ -1514,8 +1648,115 @@ void Context::submit(
/* todo */
}
-Renderpass_Vk& Context_Vk::begin_rp(Device& d, const Render_Pass& rp) {
- Device_Vk* dev = (Device_Vk*)&d;
+void Context::copy(Buffer_Id dst, Buffer_Id src) {
+ Context_Vk* ctx = (Context_Vk*)this;
+ Device_Vk* dev = ctx->dev;
+ Buffer_Vk& a = *(Buffer_Vk*)&dev->get_buffer(dst);
+ Buffer_Vk& b = *(Buffer_Vk*)&dev->get_buffer(src);
+ VkBufferCopy region{};
+ region.srcOffset = 0;
+ region.dstOffset = 0;
+ region.size = b.size;
+ vkCmdCopyBuffer(
+ ctx->cb,
+ b.buf,
+ a.buf,
+ 1,
+ &region
+ );
+}
+
+void Context::copy(Texture_Id dst, Buffer_Id src) {
+ Context_Vk* ctx = (Context_Vk*)this;
+ Device_Vk* dev = ctx->dev;
+ Texture_Vk& a = *(Texture_Vk*)&dev->get_texture(dst);
+ Buffer_Vk& b = *(Buffer_Vk*)&dev->get_buffer(src);
+ VkBufferImageCopy c{};
+ c.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ c.imageSubresource.layerCount = 1;
+ c.imageExtent.width = a.w;
+ c.imageExtent.height = a.h;
+ c.imageExtent.depth = 1;
+ vkCmdCopyBufferToImage(
+ ctx->cb,
+ b.buf,
+ a.image,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ 1,
+ &c
+ );
+}
+
+void Context::transition(Texture_Id id, Resource_State state) {
+ Context_Vk* ctx = (Context_Vk*)this;
+ Device_Vk* dev = ctx->dev;
+ Texture_Vk& tex = *(Texture_Vk*)&dev->get_texture(id);
+ VkImageMemoryBarrier b{};
+ VkImageLayout src_layout = state_to_image_layout(tex.state);
+ VkImageLayout dst_layout = state_to_image_layout(state);
+ VkPipelineStageFlags src_stage, dst_stage;
+ b.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ b.oldLayout = src_layout;
+ b.newLayout = dst_layout;
+ b.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ b.image = tex.image;
+ b.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ b.subresourceRange.baseMipLevel = 0;
+ b.subresourceRange.levelCount = 1;
+ b.subresourceRange.baseArrayLayer = 0;
+ b.subresourceRange.layerCount = 1;
+ if (
+ src_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
+ dst_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
+ ) {
+ b.srcAccessMask = 0;
+ b.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ src_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ dst_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ } else if (
+ src_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
+ dst_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
+ ) {
+ b.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ b.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ src_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ dst_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ } else if (
+ src_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
+ dst_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+ ) {
+ b.srcAccessMask = 0;
+ b.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ src_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dst_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ } else if (
+ src_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
+ dst_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
+ ) {
+ b.srcAccessMask = 0;
+ b.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ src_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ dst_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ } else {
+ print_err("Bad resource transition.\n");
+ pbreak(389);
+ }
+ vkCmdPipelineBarrier(
+ ctx->cb,
+ src_stage,
+ dst_stage,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ &b
+ );
+}
+
+Renderpass_Vk& Context_Vk::begin_rp(const Render_Pass& rp) {
Renderpass_Vk& rpo = dev->get_rpo(rp);
VkRenderPassBeginInfo rpbi{};
rpbi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
@@ -1537,13 +1778,13 @@ void Context_Vk::end_rp(Renderpass_Vk& rpo) {
rpo.on_submit();
}
-void Context::submit(Device& d, const Render_Pass& rp) {
+void Context::submit(const Render_Pass& rp) {
Context_Vk* ctx = (Context_Vk*)this;
- auto& rpo = ctx->begin_rp(d, rp);
+ auto& rpo = ctx->begin_rp(rp);
ctx->end_rp(rpo);
}
-void Context_Vk::init_pool(Device_Vk* dev) {
+void Context_Vk::init_pool() {
VkCommandPoolCreateInfo pi{};
VkResult r;
pi.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
@@ -1556,7 +1797,7 @@ void Context_Vk::init_pool(Device_Vk* dev) {
}
}
-void Context_Vk::init_cb(Device_Vk* dev) {
+void Context_Vk::init_cb() {
VkCommandBufferAllocateInfo ci{};
VkResult r;
ci.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
@@ -1570,7 +1811,7 @@ void Context_Vk::init_cb(Device_Vk* dev) {
}
}
-void Context_Vk::init_sync(Device_Vk* dev) {
+void Context_Vk::init_sync() {
VkFenceCreateInfo fi{};
VkSemaphoreCreateInfo si{};
VkResult r;
@@ -1589,26 +1830,28 @@ void Context_Vk::init_sync(Device_Vk* dev) {
}
}
-void Context_Vk::init(Device_Vk* dev) {
- init_pool(dev);
- init_cb(dev);
- init_sync(dev);
+void Context_Vk::init(Device_Vk* device) {
+ dev = device;
+ init_pool();
+ init_cb();
+ init_sync();
state |= context_state_init;
}
-void Context_Vk::begin_record(Device_Vk* dev) {
+void Context_Vk::begin_record() {
VkCommandBufferBeginInfo bi{};
bi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ wait();
vkResetFences(dev->dev, 1, &fence);
vkResetCommandBuffer(cb, 0);
vkBeginCommandBuffer(cb, &bi);
}
-Context_Vk& Context_Vk::acquire(Device_Vk* dev) {
+Context_Vk& Context_Vk::acquire(Device_Vk* device) {
if (~state & context_state_init)
- init(dev);
+ init(device);
state &= ~context_state_avail;
- begin_record(dev);
+ begin_record();
return *this;
}
@@ -1616,7 +1859,7 @@ void Context_Vk::release() {
state |= context_state_avail;
}
-void Context_Vk::destroy(Device_Vk* dev) {
+void Context_Vk::destroy() {
state &= ~context_state_init;
vkDestroyCommandPool(dev->dev, pool, &dev->ac);
vkDestroySemaphore(dev->dev, semaphore, &dev->ac);
@@ -2116,17 +2359,14 @@ void Shader_Vk::Vertex_Format::destroy(Device_Vk* dev) {
heap_free(dev->heap, attributes);
}
-void Shader_Vk::destroy_internal(Device_Vk* dev) {
+void Shader_Vk::destroy(Device_Vk* dev) {
int i;
for (i = 0; i < shader_type_count; i++)
if (modules[i])
vkDestroyShaderModule(dev->dev, modules[i], &dev->ac);
vfd.destroy(dev);
dev->destroy_vf(vf);
-}
-
-void Shader::destroy(Device* dev) {
- ((Shader_Vk*)this)->destroy_internal((Device_Vk*)dev);
+ dev->shaders.remove(id);
}
int Shader::binding_index(const char* name) {
@@ -2148,11 +2388,12 @@ int Shader::attribute_index(const char* name) {
void Buffer_Vk::init(
Device_Vk* dev,
int flags,
- VkDeviceSize size
+ VkDeviceSize s
) {
VkBufferCreateInfo bi{};
VkMemoryRequirements req;
VkResult r;
+ size = s;
bi.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bi.size = size;
bi.usage = get_usage(flags);
@@ -2190,6 +2431,7 @@ void Buffer_Vk::init(
void Buffer_Vk::destroy(Device_Vk* dev) {
vkDestroyBuffer(dev->dev, buf, &dev->ac);
vkFreeMemory(dev->dev, memory, &dev->ac);
+ dev->buffers.remove(id);
}
Buffer_Id Device::create_buffer(size_t size, int flags) {
@@ -2202,9 +2444,8 @@ Buffer_Id Device::create_buffer(size_t size, int flags) {
void Device::destroy_buffer(Buffer_Id id) {
Device_Vk* dev = (Device_Vk*)this;
- Buffer_Vk& buf = *(Buffer_Vk*)&get_buffer(id);
- buf.destroy(dev);
- dev->buffers.remove(id);
+ Buffer_Vk* buf = (Buffer_Vk*)&get_buffer(id);
+ dev->queue_destroy(buf);
}
void* Device::map_buffer(
@@ -2240,42 +2481,32 @@ Shader& Device::get_shader(Shader_Id id) {
return ((Device_Vk*)this)->shaders[id];
}
-bool Shader::load(
- Asset_Loader* loader,
- Arena* a,
- Pack_File* f
-) {
- Device_Vk* dev = ((Shader_Loader*)loader)->dev;
- Shader_Vk& sh = *(Shader_Vk*)this;
- return sh.init(dev, f);
-}
-
-void Shader::unload(Asset_Loader* loader_) {
- Shader_Loader* loader = (Shader_Loader*)loader_;
- Device_Vk* dev = loader->dev;
- Shader_Vk& sh = *(Shader_Vk*)this;
- sh.destroy(dev);
- dev->shaders.remove(id);
-}
-
void Shader_Loader::init(Device_Vk* d) {
dev = d;
}
Asset* Shader_Loader::load(
Arena* a,
+ Arena* s,
Pack_File* f
) {
- Shader_Vk* s;
+ Shader_Vk* shader;
Shader_Id id;
+ (void)s;
+ (void)a;
id = dev->alloc_shader();
- s = (Shader_Vk*)&dev->get_shader(id);
- s->id = id;
- if (!s->load(this, a, f)) {
+ shader = (Shader_Vk*)&dev->get_shader(id);
+ shader->id = id;
+ if (!shader->init(dev, f)) {
dev->shaders.remove(id);
return 0;
}
- return s;
+ return shader;
+}
+
+void Shader_Loader::unload(Asset* a) {
+ Shader_Vk* sh = (Shader_Vk*)a;
+ dev->queue_destroy(sh);
}
bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) {
@@ -2323,3 +2554,140 @@ bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) {
return true;
}
+void Texture_Loader::init(Device_Vk* d) {
+ dev = d;
+}
+
+size_t Texture_Loader::calc_size(
+ Texture_Format fmt,
+ int w,
+ int h
+) {
+ switch (fmt) {
+ case texture_format_bc1:
+ return (w / 4) * (h / 4) * 8;
+ default:
+ print_err("Can't load this texture format.\n");
+ pbreak(45498);
+ return 0;
+ }
+}
+
+Buffer_Id Texture_Loader::upload(void* buf, size_t size) {
+ void* mem;
+ Buffer_Id id = dev->create_buffer(
+ size,
+ Buffer_Flags::copy_src |
+ Buffer_Flags::cpu_readwrite
+ );
+ mem = dev->map_buffer(id, 0, size);
+ memcpy(mem, buf, size);
+ dev->unmap_buffer(id);
+ return id;
+}
+
+Texture_Id Texture_Loader::create_tex(
+ Texture_Format fmt,
+ int w,
+ int h
+) {
+ VkImageCreateInfo ii{};
+ VkResult r;
+ Texture_Id id = dev->alloc_texture();
+ Texture_Vk& tex = *(Texture_Vk*)&dev->get_texture(id);
+ VkMemoryRequirements req;
+ ii.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ ii.imageType = VK_IMAGE_TYPE_2D;
+ ii.extent.width = w;
+ ii.extent.height = h;
+ ii.extent.depth = 1;
+ ii.mipLevels = 1;
+ ii.arrayLayers = 1;
+ ii.format = get_vk_format(fmt);
+ ii.tiling = VK_IMAGE_TILING_OPTIMAL;
+ ii.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ ii.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+ ii.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ ii.samples = VK_SAMPLE_COUNT_1_BIT;
+ r = vkCreateImage(dev->dev, &ii, &dev->ac, &tex.image);
+ if (r != VK_SUCCESS) {
+ print_err("Failed to create an image.\n");
+ }
+ vkGetImageMemoryRequirements(dev->dev, tex.image, &req);
+ {
+ VkMemoryPropertyFlags props =
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ int mt = dev->find_memory_type(req.memoryTypeBits, props);
+ VkMemoryAllocateInfo ai{};
+ if (mt < 0) {
+ print("Failed to find a satisfying memory type index.\n");
+ pbreak(mt);
+ }
+ ai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ ai.allocationSize = req.size;
+ ai.memoryTypeIndex = mt;
+ r = vkAllocateMemory(dev->dev, &ai, &dev->ac, &tex.memory);
+ if (r == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
+ print_err("Out of video memory.\n");
+ pbreak(r);
+ }
+ if (r != VK_SUCCESS) {
+ print_err("VRAM allocation failed.\n");
+ pbreak(r);
+ }
+ }
+ vkBindImageMemory(dev->dev, tex.image, tex.memory, 0);
+ tex.w = w;
+ tex.h = h;
+ tex.alias = false;
+ tex.view = make_view(
+ dev,
+ tex.image,
+ ii.format,
+ VK_IMAGE_ASPECT_COLOR_BIT
+ );
+ return id;
+}
+
+Asset* Texture_Loader::load(Arena* a, Arena* s, Pack_File* f) {
+ char magic[4];
+ void* data;
+ int w, h;
+ size_t size;
+ Texture_Format fmt;
+ pack_read(f, magic, 4);
+ pack_read(f, &w, 4);
+ pack_read(f, &h, 4);
+ pack_read(f, &fmt, 4);
+ size = calc_size(fmt, w, h);
+ data = arena_alloc(s, size);
+ pack_read(f, data, size);
+ {
+ Buffer_Id buf = upload(data, size);
+ Texture_Id tex = create_tex(fmt, w, h);
+ {
+ Context& ctx = dev->acquire();
+ ctx.transition(tex, Resource_State::copy_dst);
+ ctx.copy(tex, buf);
+ ctx.transition(tex, Resource_State::shader_read);
+ dev->submit(ctx);
+ dev->destroy_buffer(buf);
+ }
+ return &dev->get_texture(tex);
+ }
+}
+
+void Texture_Loader::unload(Asset* a) {
+ Texture_Vk* tex = (Texture_Vk*)a;
+ tex->destroy(dev);
+}
+
+void Texture_Vk::destroy(Device_Vk* dev) {
+ if (!alias) {
+ vkDestroyImage(dev->dev, image, &dev->ac);
+ vkFreeMemory(dev->dev, memory, &dev->ac);
+ }
+ vkDestroyImageView(dev->dev, view, &dev->ac);
+ dev->textures.remove(id);
+}
+
diff --git a/video.hpp b/video.hpp
index 786d013..f05af57 100644
--- a/video.hpp
+++ b/video.hpp
@@ -96,7 +96,15 @@ struct Pipeline_Builder {
void validate();
};
-struct Texture {
+enum Resource_State {
+ undefined,
+ copy_dst,
+ copy_src,
+ shader_read
+};
+
+struct Texture : public Asset {
+ Texture_Id id;
int w, h;
bool alias;
};
@@ -114,7 +122,9 @@ namespace Buffer_Flags {
};
};
-struct Buffer {};
+struct Buffer {
+ Buffer_Id id;
+};
struct Context;
struct Shader;
@@ -149,21 +159,22 @@ struct Device {
};
struct Context {
- void wait(Device& d);
+ void wait();
void submit(
- Device& d,
const Draw& draw,
const Pipeline& p,
const Render_Pass& rp
);
void submit(
- Device& d,
const Draw* draws,
int count,
const Pipeline& p,
const Render_Pass& rp
);
- void submit(Device& d, const Render_Pass& rp);
+ void submit(const Render_Pass& rp);
+ void copy(Buffer_Id dst, Buffer_Id src);
+ void copy(Texture_Id dst, Buffer_Id src);
+ void transition(Texture_Id id, Resource_State state);
};
struct Shader : public Asset {
@@ -175,13 +186,6 @@ struct Shader : public Asset {
int binding_index(const char* name);
int attribute_index(const char* name);
int target_index(const char* name);
-
- bool load(
- Asset_Loader* loader,
- Arena* a,
- Pack_File* f
- ) override;
- void unload(Asset_Loader* loader) override;
};
#endif