Rework Gfx_Image stuff

This commit is contained in:
Charlie 2024-07-07 09:09:01 +02:00
parent ebaa52c326
commit 83c0371dcb
6 changed files with 182 additions and 98 deletions

View file

@ -83,9 +83,6 @@ typedef struct Draw_Frame {
Matrix4 projection;
Matrix4 view;
Gfx_Handle garbage_stack[4096];
u64 garbage_stack_count;
} Draw_Frame;
// This frame is passed to the platform layer and rendered in os_update.
// Resets every frame.
@ -196,40 +193,3 @@ Draw_Quad *draw_image_xform(Gfx_Image *image, Matrix4 xform, Vector2 size, Vecto
#define COLOR_WHITE ((Vector4){1.0, 1.0, 1.0, 1.0})
#define COLOR_BLACK ((Vector4){0.0, 0.0, 0.0, 1.0})
Gfx_Image *load_image_from_disk(string path, Allocator allocator) {
string png;
bool ok = os_read_entire_file(path, &png, allocator);
if (!ok) return 0;
Gfx_Image *image = alloc(allocator, sizeof(Gfx_Image));
// Use stb_image to load and decode the PNG
int width, height, channels;
stbi_set_flip_vertically_on_load(1); // stb_image can flip the image on load
unsigned char* stb_data = stbi_load_from_memory(png.data, png.count, &width, &height, &channels, STBI_rgb_alpha);
if (!stb_data) {
dealloc(allocator, image);
dealloc_string(allocator, png);
return 0;
}
image->data = stb_data;
image->width = width;
image->height = height;
image->gfx_handle = GFX_INVALID_HANDLE; // This is handled in gfx
image->allocator = allocator;
dealloc_string(allocator, png);
return image;
}
void delete_image(Gfx_Image *image) {
stbi_image_free(image->data); // Free the image data allocated by stb_image
image->width = 0;
image->height = 0;
draw_frame.garbage_stack[draw_frame.garbage_stack_count] = image->gfx_handle;
draw_frame.garbage_stack_count += 1;
dealloc(image->allocator, image);
}

View file

@ -15,6 +15,14 @@ int entry(int argc, char **argv) {
Gfx_Image *hammer_image = load_image_from_disk(STR("oogabooga/examples/hammer.png"), get_heap_allocator());
assert(hammer_image, "Failed loading hammer.png");
void *my_data = alloc(get_heap_allocator(), 32*32*4);
memset(my_data, 0xffffffff, 32*32*4);
Gfx_Image *my_image = make_image(32, 32, 4, my_data, get_heap_allocator());
for (int *c = (int*)my_data; c < (int*)my_data+16*16; c += 1) {
*c = 0xff0000ff;
}
gfx_set_image_data(my_image, 0, 0, 16, 16, my_data);
seed_for_random = os_get_current_cycle_count();
const float64 fps_limit = 69000;
@ -94,7 +102,7 @@ int entry(int argc, char **argv) {
Matrix4 hammer_xform = m4_scalar(1.0);
hammer_xform = m4_rotate_z(hammer_xform, (f32)now);
hammer_xform = m4_translate(hammer_xform, v3(-.25f, -.25f, 0));
draw_image_xform(hammer_image, hammer_xform, v2(.5f, .5f), COLOR_RED);
draw_image_xform(my_image, hammer_xform, v2(.5f, .5f), COLOR_RED);
Vector2 hover_position = v2_rotate_point_around_pivot(v2(-.5, -.5), v2(0, 0), (f32)now);
Vector2 local_pivot = v2(.125f, .125f);

View file

@ -13,7 +13,7 @@ const Gfx_Handle GFX_INVALID_HANDLE = 0;
string temp_win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16);
typedef struct alignat(16) D3D11_Vertex {
typedef struct alignat(16) D3D11_Vertex {
Vector4 color;
Vector4 position;
Vector2 uv;
@ -22,8 +22,8 @@ typedef struct alignat(16) D3D11_Vertex {
ID3D11Debug *d3d11_debug = 0;
ID3D11Device* d3d11_device = 0;
ID3D11DeviceContext* d3d11_context = 0;
ID3D11Device *d3d11_device = 0;
ID3D11DeviceContext *d3d11_context = 0;
ID3D11RenderTargetView *d3d11_window_render_target_view = 0;
ID3D11Texture2D *d3d11_back_buffer = 0;
D3D_DRIVER_TYPE d3d11_driver_type = 0;
@ -518,23 +518,6 @@ void gfx_update() {
HRESULT hr;
tm_scope_cycles("Frame setup") {
///
// purge garbage
for (u64 i = 0; i < draw_frame.garbage_stack_count; i++) {
ID3D11ShaderResourceView *view = draw_frame.garbage_stack[i];
ID3D11Resource *resource = 0;
VTABLE(GetResource, view, &resource);
ID3D11Texture2D *texture = 0;
hr = VTABLE(QueryInterface, resource, &IID_ID3D11Texture2D, (void**)&texture);
if (SUCCEEDED(hr)) {
D3D11Release(view);
D3D11Release(texture);
log("Destroyed an image");
} else {
panic("Unhandled D3D11 resource deletion");
}
}
///
// Maybe resize swap chain
@ -595,33 +578,6 @@ void gfx_update() {
int texture_index = -1;
if (q->image) {
if (!q->image->gfx_handle) {
D3D11_TEXTURE2D_DESC desc = ZERO(D3D11_TEXTURE2D_DESC);
desc.Width = q->image->width;
desc.Height = q->image->height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA data = ZERO(D3D11_SUBRESOURCE_DATA);
data.pSysMem = q->image->data;
data.SysMemPitch = q->image->width * 4; // #Magicvalue assuming 4 channels
ID3D11Texture2D* texture = 0;
HRESULT hr = VTABLE(CreateTexture2D, d3d11_device, &desc, &data, &texture);
win32_check_hr(hr);
hr = VTABLE(CreateShaderResourceView, d3d11_device, (ID3D11Resource*)texture, 0, &q->image->gfx_handle);
win32_check_hr(hr);
log_verbose("Created an image of width %d and height %d.", q->image->width, q->image->height);
}
if (last_texture == q->image->gfx_handle) {
texture_index = (int)(num_textures-1);
@ -742,3 +698,75 @@ void gfx_update() {
reset_draw_frame(&draw_frame);
}
void gfx_init_image(Gfx_Image *image, void *data) {
D3D11_TEXTURE2D_DESC desc = ZERO(D3D11_TEXTURE2D_DESC);
desc.Width = image->width;
desc.Height = image->height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA data_desc = ZERO(D3D11_SUBRESOURCE_DATA);
data_desc.pSysMem = data;
data_desc.SysMemPitch = image->width * image->channels;
ID3D11Texture2D* texture = 0;
HRESULT hr = VTABLE(CreateTexture2D, d3d11_device, &desc, &data_desc, &texture);
win32_check_hr(hr);
hr = VTABLE(CreateShaderResourceView, d3d11_device, (ID3D11Resource*)texture, 0, &image->gfx_handle);
win32_check_hr(hr);
log_verbose("Created an image of width %d and height %d.", image->width, image->height);
}
void gfx_set_image_data(Gfx_Image *image, u32 x, u32 y, u32 w, u32 h, void *data) {
assert(image && data, "Bad parameters passed to gfx_set_image_data");
ID3D11ShaderResourceView *view = image->gfx_handle;
ID3D11Resource *resource = NULL;
VTABLE(GetResource, view, &resource);
assert(resource, "Invalid image passed to gfx_set_image_data");
assert(x+w < image->width && y+h < image->height, "Specified subregion in image is out of bounds");
ID3D11Texture2D *texture = NULL;
HRESULT hr = VTABLE(QueryInterface, resource, &IID_ID3D11Texture2D, (void**)&texture);
assert(SUCCEEDED(hr), "Expected gfx resource to be a texture but it wasn't");
D3D11_BOX destBox;
destBox.left = x;
destBox.right = x + w;
destBox.top = y;
destBox.bottom = y + h;
destBox.front = 0;
destBox.back = 1;
// #Incomplete bit-width 8 assumed
VTABLE(UpdateSubresource, d3d11_context, resource, 0, &destBox, data, w * image->channels, 0);
log_verbose("Updated image data at region (%u, %u) with dimensions (%u, %u).", x, y, w, h);
}
void gfx_deinit_image(Gfx_Image *image) {
ID3D11ShaderResourceView *view = image->gfx_handle;
ID3D11Resource *resource = 0;
VTABLE(GetResource, view, &resource);
ID3D11Texture2D *texture = 0;
HRESULT hr = VTABLE(QueryInterface, resource, &IID_ID3D11Texture2D, (void**)&texture);
if (SUCCEEDED(hr)) {
D3D11Release(view);
D3D11Release(texture);
log("Destroyed an image");
} else {
panic("Unhandled D3D11 resource deletion");
}
}

View file

@ -18,15 +18,106 @@
forward_global const Gfx_Handle GFX_INVALID_HANDLE;
typedef struct Gfx_Image {
u32 width, height;
u8 *data;
u32 width, height, channels;
Gfx_Handle gfx_handle;
Allocator allocator;
} Gfx_Image;
Gfx_Image *make_image(u32 width, u32 height, u32 channels, void *initial_data, Allocator allocator);
Gfx_Image *load_image_from_disk(string path, Allocator allocator);
void delete_image(Gfx_Image *image);
void gfx_init_image(Gfx_Image *image, void *data);
void gfx_set_image_data(Gfx_Image *image, u32 x, u32 y, u32 w, u32 h, void *data);
void gfx_deinit_image(Gfx_Image *image);
#define FONT_ATLAS_WIDTH 4096
#define FONT_ATLAS_HEIGHT 4096
#define MAX_FONT_HEIGHT 256
typedef struct Gfx_Font_Metrics {
u32 latin_ascent;
u32 latin_descent;
u32 max_ascent;
u32 max_descent;
u32 line_height;
u32 line_spacing;
} Gfx_Font_Metrics;
typedef struct Gfx_Font_Atlas {
Gfx_Image image;
} Gfx_Font_Atlas;
typedef struct Gfx_Font_Variation {
u32 height;
Gfx_Font_Metrics metrics;
u32 codepoint_range_per_atlas;
Hash_Table atlases; // u32 atlas_index, Gfx_Font_Atlas
bool initted;
} Gfx_Font_Variation;
typedef struct Gfx_Font {
u32 width, height;
u8 *data;
Gfx_Handle gfx_handle;
Gfx_Font_Variation variations[MAX_FONT_HEIGHT]; // Variation per font height
Allocator allocator;
} Gfx_Font;
// initial_data can be null to leave image data uninitialized
Gfx_Image *make_image(u32 width, u32 height, u32 channels, void *initial_data, Allocator allocator) {
Gfx_Image *image = alloc(allocator, sizeof(Gfx_Image) + width*height*channels);
assert(channels > 0 && channels <= 4, "Only 1, 2, 3 or 4 channels allowed on images. Got %d", channels);
image->width = width;
image->height = height;
image->gfx_handle = GFX_INVALID_HANDLE; // This is handled in gfx
image->allocator = allocator;
image->channels = 4;
gfx_init_image(image, initial_data);
return image;
}
Gfx_Image *load_image_from_disk(string path, Allocator allocator) {
string png;
bool ok = os_read_entire_file(path, &png, allocator);
if (!ok) return 0;
Gfx_Image *image = alloc(allocator, sizeof(Gfx_Image));
int width, height, channels;
stbi_set_flip_vertically_on_load(1);
unsigned char* stb_data = stbi_load_from_memory(png.data, png.count, &width, &height, &channels, STBI_rgb_alpha);
if (!stb_data) {
dealloc(allocator, image);
dealloc_string(allocator, png);
return 0;
}
image->width = width;
image->height = height;
image->gfx_handle = GFX_INVALID_HANDLE; // This is handled in gfx
image->allocator = allocator;
image->channels = 4;
dealloc_string(allocator, png);
gfx_init_image(image, stb_data);
stbi_image_free(stb_data);
return image;
}
void delete_image(Gfx_Image *image) {
// Free the image data allocated by stb_image
image->width = 0;
image->height = 0;
gfx_deinit_image(image);
dealloc(image->allocator, image);
}

View file

@ -1,7 +1,6 @@
// Very naive implementation for now but it should be cache efficient so not really a
// problem until very large (in which case you should probably write your own data structure
// anyways)
// Very naive implementation but it should be very cache efficient so it's alright
// for non-excessive use for now.
/*

View file

@ -1081,8 +1081,6 @@ void oogabooga_run_tests() {
print("OK!\n");
// #Temporary
// This makes entire os freeze in release lol
#if CONFIGURATION != RELEASE
print("Thread bombing allocator... ");
Thread* threads[100];