diff --git a/src/common.h b/src/common.h index a8044567..78fa6b8b 100644 --- a/src/common.h +++ b/src/common.h @@ -487,10 +487,6 @@ struct buffer { u8 *data; }; -struct renderer_handle { - u64 v[1]; -}; - struct entity_handle { u64 idx; u64 gen; diff --git a/src/draw.c b/src/draw.c index 0b5ef7d2..3de47fbb 100644 --- a/src/draw.c +++ b/src/draw.c @@ -7,7 +7,7 @@ #include "collider.h" GLOBAL struct { - struct renderer_handle solid_white; + struct renderer_texture solid_white; } G = ZI, DEBUG_ALIAS(G, G_draw); /* ========================== * @@ -20,7 +20,7 @@ struct draw_startup_receipt draw_startup(struct renderer_startup_receipt *render (UNUSED)renderer_sr; (UNUSED)font_sr; u32 pixel_white = 0xFFFFFFFF; - G.solid_white = renderer_texture_image_alloc((struct image_rgba) { .width = 1, .height = 1, .pixels = &pixel_white } ); + G.solid_white = renderer_texture_alloc(RENDERER_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, 1, 1, &pixel_white); return (struct draw_startup_receipt) { 0 }; } @@ -28,7 +28,7 @@ struct draw_startup_receipt draw_startup(struct renderer_startup_receipt *render * Texture * ========================== */ -void draw_quad_texture_ex(struct renderer_cmd_buffer *cmdbuff, struct renderer_handle texture, struct sprite_tag sprite, struct clip_rect clip, u32 tint0, u32 tint1, struct quad quad) +void draw_quad_texture_ex(struct renderer_cmd_buffer *cmdbuff, struct renderer_texture texture, struct sprite_tag sprite, struct clip_rect clip, u32 tint0, u32 tint1, struct quad quad) { struct renderer_cmd_parameters cmd_params = ZI; cmd_params.kind = SHADER_TEXTURE; @@ -365,7 +365,7 @@ void draw_text_ex(struct renderer_cmd_buffer *cmdbuff, struct font *font, struct }; struct quad quad = quad_from_rect(RECT(x, y, width, height)); - draw_quad_texture_ex(cmdbuff, font->image_renderer_handle, sprite_tag_nil(), clip, 0xFFFFFFFF, 0xFFFFFFFF, quad); + draw_quad_texture_ex(cmdbuff, font->texture, sprite_tag_nil(), clip, 0xFFFFFFFF, 0xFFFFFFFF, quad); draw_pos.x += glyph->advance * scale; } diff --git a/src/draw.h b/src/draw.h index b412e711..2fdfc2f0 100644 --- a/src/draw.h +++ b/src/draw.h @@ -1,6 +1,8 @@ #ifndef DRAW_H #define DRAW_H +#include "renderer.h" + struct renderer_cmd_buffer; struct font; struct renderer_startup_receipt; @@ -13,7 +15,7 @@ struct font_startup_receipt; }) struct draw_texture_params { - struct renderer_handle texture; /* Overrides sprite if set */ + struct renderer_texture texture; /* Overrides sprite if set */ struct sprite_tag sprite; struct clip_rect clip; u32 tint; @@ -23,7 +25,7 @@ struct draw_startup_receipt { i32 _; }; struct draw_startup_receipt draw_startup(struct renderer_startup_receipt *renderer_sr, struct font_startup_receipt *font_sr); -void draw_quad_texture_ex(struct renderer_cmd_buffer *cmdbuff, struct renderer_handle texture, struct sprite_tag sprite, struct clip_rect clip, u32 tint0, u32 tint1, struct quad quad); +void draw_quad_texture_ex(struct renderer_cmd_buffer *cmdbuff, struct renderer_texture texture, struct sprite_tag sprite, struct clip_rect clip, u32 tint0, u32 tint1, struct quad quad); void draw_quad_texture(struct renderer_cmd_buffer *cmdbuff, struct draw_texture_params params, struct quad quad); void draw_poly(struct renderer_cmd_buffer *cmdbuff, struct v2_array array, u32 color); diff --git a/src/font.c b/src/font.c index 88dd62da..d7bbc80c 100644 --- a/src/font.c +++ b/src/font.c @@ -120,7 +120,7 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams) resource_close(res); /* Send texture to GPU */ - struct renderer_handle image_renderer_handle = renderer_texture_image_alloc(result.image_data); + struct renderer_texture texture = renderer_texture_alloc(RENDERER_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, result.image_data.width, result.image_data.height, result.image_data.pixels); /* Allocate store memory */ struct font *font = NULL; @@ -133,7 +133,7 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams) } /* Set font data */ - font->image_renderer_handle = image_renderer_handle; + font->texture = texture; font->image_width = result.image_data.width; font->image_height = result.image_data.height; font->glyphs_count = result.glyphs_count; diff --git a/src/font.h b/src/font.h index 1472b598..53be6a09 100644 --- a/src/font.h +++ b/src/font.h @@ -2,6 +2,7 @@ #define FONT_H #include "util.h" +#include "renderer.h" struct asset; struct work_startup_receipt; @@ -20,7 +21,7 @@ struct font_glyph { }; struct font { - struct renderer_handle image_renderer_handle; + struct renderer_texture texture; u32 image_width; u32 image_height; f32 point_size; diff --git a/src/renderer.h b/src/renderer.h index cdca9a53..e8719f40 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -11,6 +11,10 @@ typedef u32 vidx; struct renderer_cmd_buffer; +struct renderer_texture { + u64 handle; +}; + /* ========================== * * Shaders * ========================== */ @@ -27,7 +31,7 @@ struct renderer_cmd_parameters { enum shader_kind kind; union { struct { - struct renderer_handle texture; /* Overrides sprite if set */ + struct renderer_texture texture; /* Overrides sprite if set */ struct sprite_tag sprite; } texture_params; }; @@ -54,6 +58,38 @@ PACK(struct grid_shader_vertex { struct renderer_startup_receipt { i32 _; }; struct renderer_startup_receipt renderer_startup(struct sys_window *window); +/* ========================== * + * Texture + * ========================== */ + +enum renderer_texture_format { + RENDERER_TEXTURE_FORMAT_NONE, + + RENDERER_TEXTURE_FORMAT_R8G8B8A8_UNORM, + + NUM_RENDERER_TEXTURE_FORMATS +}; + +#define RENDERER_TEXTURE_FLAG_NONE (0) +#define RENDERER_TEXTURE_FLAG_TARGET (1<<0) + +struct renderer_texture renderer_texture_alloc(enum renderer_texture_format format, u32 flags, u32 width, u32 height, void *initial_data); +void renderer_texture_release(struct renderer_texture t); + +void renderer_texture_clear(struct renderer_texture target_texture, u32 clear_color); +void renderer_texture_render(struct renderer_texture texture, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope); + +/* ========================== * + * Backbuffer + * ========================== */ + + /* Returns a texture linking to the internal backbuffer. Lifetime is managed by renderer. */ +struct renderer_texture renderer_get_backbuffer_texture(void); + +void renderer_backbuffer_resize(u32 width, u32 height); + +void renderer_backbuffer_present(i32 vsync); + /* ========================== * * Cmd buffer * ========================== */ @@ -78,32 +114,5 @@ void renderer_cmd_buffer_ensure_cmd(struct renderer_cmd_buffer *cmdbuff, struct void renderer_cmd_buffer_send_to_gpu(struct renderer_cmd_buffer *cmdbuff); -void renderer_render_to_texture(struct renderer_handle target_handle, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope); - -void renderer_render_to_backbuffer(struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope); - -void renderer_clear_texture(struct renderer_handle target_handle, u32 clear_color); - -void renderer_clear_backbuffer(u32 clear_color); - -void renderer_resize_backbuffer(struct v2 size); - -void renderer_present_backbuffer(i32 vsync); - -/* ========================== * - * Texture - * ========================== */ - -INLINE struct renderer_handle renderer_handle_nil(void) { return (struct renderer_handle) { 0 }; } -INLINE b32 renderer_handle_is_nil(struct renderer_handle h) { return h.v[0] == 0; } - -/* Allocates a texture on the GPU filled with supplied image data */ -struct renderer_handle renderer_texture_image_alloc(struct image_rgba data); - -/* Allocates a texture on the GPU that can be rendered to */ -struct renderer_handle renderer_texture_target_alloc(struct v2 size); - -void renderer_texture_release(struct renderer_handle handle); -b32 renderer_texture_is_nil(struct renderer_handle handle); #endif diff --git a/src/renderer_d3d11.c b/src/renderer_d3d11.c index e00ed75c..b1c4ca23 100644 --- a/src/renderer_d3d11.c +++ b/src/renderer_d3d11.c @@ -60,7 +60,7 @@ struct dx11_buffer { struct renderer_cmd { struct dx11_shader *shader; - struct renderer_handle texture_handle; /* Overrides sprite */ + struct renderer_texture texture; /* Overrides sprite if set */ struct sprite_tag sprite; /* Associated buffer data */ @@ -88,6 +88,20 @@ struct renderer_cmd_buffer { b32 valid; /* False if uninitialized (in sparse array) */ }; +struct dx11_format { + DXGI_FORMAT format; + u32 pixel_size; +}; + +struct dx11_texture { + ID3D11Texture2D *texture; + b32 is_backbuffer; + + struct dx11_texture *prev; + struct dx11_texture *next; + struct dx11_texture *next_free; +}; + INTERNAL void renderer_capture_image_for_profiler(void); /* ========================== * @@ -123,6 +137,7 @@ GLOBAL struct { ID3D11DeviceContext *devcon; IDXGISwapChain1 *swapchain; + struct dx11_texture backbuffer_texture; ID3D11BlendState *blend_state; ID3D11RasterizerState *rasterizer_state; @@ -131,13 +146,17 @@ GLOBAL struct { ID3D11Buffer *vs_constant_buffer; - struct handle_store handle_store; + /* Texture store */ + struct sys_mutex textures_mutex; + struct arena textures_arena; + struct dx11_texture *textures_first; + struct dx11_texture *textures_last; + struct dx11_texture *textures_first_free; /* Sparse array (cmdbuff.valid) */ struct renderer_cmd_buffer cmdbuffs[MAX_CMD_BUFFERS]; struct dx11_shader shaders[NUM_SHADERS]; - struct dx11_shader_desc shader_info[NUM_SHADERS]; } G = ZI, DEBUG_ALIAS(G, G_renderer_d3d11); @@ -166,122 +185,6 @@ INTERNAL void send_constant_buffer_data(ID3D11Buffer *buffer, struct mat4x4 vp) ID3D11DeviceContext_Unmap(G.devcon, (ID3D11Resource *)buffer, 0); } -/* ========================== * - * Handle - * ========================== */ - -/* Handle layout - * bits 0-32: Index - * bits 33-64: Generation */ - -#define HANDLE_IDX_MASK 0x00000000FFFFFFFF -#define HANDLE_GEN_MASK 0xFFFFFFFF00000000 - -#define HANDLE_IDX_MAX (U32_MAX) -#define HANDLE_GEN_MAX (U32_MAX) - -#define HANDLE_CREATE(idx, gen) ((struct renderer_handle) { .v[0] = (u64)(gen) << 32 | ((u64)(idx) & 0xFFFFFFFF) } ) -#define HANDLE_IDX(handle) ((u32)((handle).v[0] & HANDLE_IDX_MASK)) -#define HANDLE_GEN(handle) ((u32)(((handle).v[0] & HANDLE_GEN_MASK) >> 32)) - -INTERNAL struct renderer_handle handle_alloc(void *data) -{ - __prof; - - struct handle_store *store = &G.handle_store; - struct handle_slot *slot = NULL; - - struct sys_lock lock = sys_mutex_lock_e(&store->mutex); - { - if (store->head_free) { - /* Take first from free list */ - slot = store->head_free; - store->head_free = slot->next_free; - slot->next_free = NULL; - ++slot->gen; - } else { - /* Or push onto arena */ - if (store->count + 1 >= HANDLE_IDX_MAX) { - sys_panic(STR("Maximum renderer handles exceeded")); - } - slot = arena_push_zero(&store->arena, struct handle_slot); - slot->idx = store->count; - slot->gen = 1; - ++store->count; - } - slot->data = data; - } - sys_mutex_unlock(&lock); - - struct renderer_handle handle = HANDLE_CREATE(slot->idx, slot->gen); - return handle; -} - -INTERNAL void handle_release(struct renderer_handle handle) -{ - __prof; - - struct handle_store *store = &G.handle_store; - u32 idx = HANDLE_IDX(handle); - u32 gen = HANDLE_GEN(handle); - - struct sys_lock lock = sys_mutex_lock_e(&store->mutex); - { - if (idx < store->count) { - struct handle_slot *slot = &store->array[idx]; - if (slot->gen == gen) { - /* Insert into free list */ - if (gen + 1 < HANDLE_GEN_MAX) { - slot->next_free = store->head_free; - store->head_free = slot; - } else { - /* Maximum generations exceeded. Not a runtime error since it - * shouldn't cause issues in practice (just can't recycle this handle). - * Still probably means there's a problem in the code. */ - ASSERT(false); - } - ++slot->gen; - } else { - /* Tried to release handle not in store (non-matching generation) */ - ASSERT(false); - } - } else { - /* Tried to release out-of-bounds handle */ - ASSERT(false); - } - } - sys_mutex_unlock(&lock); -} - -INTERNAL void *handle_data(struct renderer_handle handle) -{ - __prof; - void *data = NULL; - - struct handle_store *store = &G.handle_store; - u32 idx = HANDLE_IDX(handle); - u32 gen = HANDLE_GEN(handle); - if (idx < store->count) { - struct handle_slot *slot = &store->array[idx]; - if (slot->gen == gen) { - data = slot->data; - } - } - - return data; -} - -INTERNAL b32 handle_eq(struct renderer_handle h1, struct renderer_handle h2) -{ - CT_ASSERT(sizeof(struct renderer_handle) == 8); - return h1.v[0] == h2.v[0]; -} - -INTERNAL b32 handle_is_nil(struct renderer_handle h) -{ - return h.v[0] == 0; -} - /* ========================== * * Shader * ========================== */ @@ -394,7 +297,6 @@ INTERNAL void shader_init(struct dx11_shader *shader, enum shader_kind kind) scratch_end(scratch); } - /* ========================== * * Startup * ========================== */ @@ -405,10 +307,9 @@ struct renderer_startup_receipt renderer_startup(struct sys_window *window) G.arena = arena_alloc(GIGABYTE(64)); - /* Allocate store */ - G.handle_store.arena = arena_alloc(GIGABYTE(64)); - G.handle_store.array = (struct handle_slot *)G.handle_store.arena.base; - G.handle_store.mutex = sys_mutex_alloc(); + /* Initialize texture store */ + G.textures_mutex = sys_mutex_alloc(); + G.textures_arena = arena_alloc(GIGABYTE(64)); /* Load shader archive */ struct buffer embedded_data = inc_shaders_tar(); @@ -494,7 +395,7 @@ struct renderer_startup_receipt renderer_startup(struct sys_window *window) .BufferCount = 2, .Scaling = DXGI_SCALING_NONE, - /* Use more efficient FLIP presentation model. + /* More efficient FLIP presentation model. * Windows 10 allows to use DXGI_SWAP_EFFECT_FLIP_DISCARD * For Windows 8 compatibility use DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL * For Windows 7 compatibility use DXGI_SWAP_EFFECT_DISCARD @@ -617,9 +518,330 @@ struct renderer_startup_receipt renderer_startup(struct sys_window *window) shader_init(&G.shaders[i], i); } + /* Set backbuffer texture */ + MEMZERO_STRUCT(&G.backbuffer_texture); + IDXGISwapChain_GetBuffer(G.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&G.backbuffer_texture.texture); + G.backbuffer_texture.is_backbuffer = true; + return (struct renderer_startup_receipt) { 0 }; } +/* ========================== * + * Render + * ========================== */ + + /* TODO: Lock cmdbuff or at least global state? (in-case multi-threaded present). + * Another option is to store a separate device on each cmdbuff (need to + * research if that is smart first). + * + * I'm thinking we may also just need to lock texture modification access while presenting */ +INTERNAL void dx11_render_to_target(ID3D11RenderTargetView *target, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) +{ + __prof; + ID3D11DeviceContext_OMSetRenderTargets(G.devcon, 1, &target, NULL); + + D3D11_VIEWPORT d3d11_viewport = ZI; + d3d11_viewport.Width = viewport.width; + d3d11_viewport.Height = viewport.height; + d3d11_viewport.MinDepth = 0.0f; + d3d11_viewport.MaxDepth = 1.0f; + d3d11_viewport.TopLeftX = viewport.x; + d3d11_viewport.TopLeftY = viewport.y; + ID3D11DeviceContext_RSSetViewports(G.devcon, 1, &d3d11_viewport); + + /* Fill and set constant buffer + * NOTE: We're only doing this once per render, rather than once per + * draw call since the only constant right now is VP. */ + struct mat4x4 vp_matrix = calculate_vp(view, viewport.width, viewport.height); + send_constant_buffer_data(G.vs_constant_buffer, vp_matrix); + ID3D11DeviceContext_VSSetConstantBuffers(G.devcon, 0, 1, &G.vs_constant_buffer); + + struct dx11_shader *last_shader = NULL; + + struct renderer_cmd *cmd = cmdbuff ? cmdbuff->gpu_cmd_store.cmd_first : NULL; + for (; cmd; cmd = cmd->next) { + struct dx11_shader *shader = cmd->shader; + struct dx11_buffer *buffer = &cmdbuff->buffers[shader->kind]; + + /* Activate shader */ + if (shader != last_shader) { + ID3D11DeviceContext_VSSetShader(G.devcon, shader->vs, 0, 0); + ID3D11DeviceContext_PSSetShader(G.devcon, shader->ps, 0, 0); + ID3D11DeviceContext_IASetInputLayout(G.devcon, shader->input_layout); + last_shader = shader; + } + + ID3D11ShaderResourceView *null_srv[1] = { NULL }; + + switch (shader->kind) { + default: + { + /* Unknown shader */ + ASSERT(false); + } break; + + case SHADER_TEXTURE: + { + /* FIXME: Texture refcount needs to be increased here to prevent release mid-render */ + ID3D11Texture2D *texture = NULL; + if (cmd->texture.handle) { + /* Load texture if handle is set */ + texture = ((struct dx11_texture *)cmd->texture.handle)->texture; + } else { + /* Otherwise load sprite */ + struct sprite_texture *sprite_texture = sprite_texture_from_tag_async(sprite_scope, cmd->sprite); + if (sprite_texture->loaded) { + texture = ((struct dx11_texture *)sprite_texture->texture.handle)->texture; + } + } + + if (texture) { + /* Bind texture */ + D3D11_TEXTURE2D_DESC texture_desc = ZI; + ID3D11Texture2D_GetDesc(texture, &texture_desc); + + /* Create SRV */ + D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = { .Format = texture_desc.Format, .ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D, .Texture2D.MipLevels = texture_desc.MipLevels, .Texture2D.MostDetailedMip = 0 }; + ID3D11ShaderResourceView *texture_srv = NULL; + ID3D11Device_CreateShaderResourceView(G.dev, (ID3D11Resource *)texture, &srv_desc, &texture_srv); + + ID3D11DeviceContext_PSSetShaderResources(G.devcon, 0, 1, &texture_srv); + + ID3D11DeviceContext_IASetPrimitiveTopology(G.devcon, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + /* Activate buffer */ + u32 zero = 0; + UINT vertex_stride = shader->vertex_size; + ID3D11DeviceContext_IASetVertexBuffers(G.devcon, 0, 1, &buffer->gpu_vertex_buffer, &vertex_stride, &zero); + ID3D11DeviceContext_IASetIndexBuffer(G.devcon, buffer->gpu_index_buffer, DXGI_FORMAT_R32_UINT, zero); + + /* Draw */ + u32 vertex_offset = cmd->vertex_offset; + u32 index_offset = cmd->index_offset; + u32 index_count = cmd->index_count; + ID3D11DeviceContext_DrawIndexed(G.devcon, index_count, index_offset, vertex_offset); + + /* Release SRV */ + ID3D11ShaderResourceView_Release(texture_srv); + + /* Unbind */ + ID3D11DeviceContext_PSSetShaderResources(G.devcon, 0, 1, null_srv); + } + } break; + + case SHADER_GRID: + { + ID3D11DeviceContext_IASetPrimitiveTopology(G.devcon, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + /* Activate buffer */ + u32 zero = 0; + UINT vertex_stride = shader->vertex_size; + ID3D11DeviceContext_IASetVertexBuffers(G.devcon, 0, 1, &buffer->gpu_vertex_buffer, &vertex_stride, &zero); + ID3D11DeviceContext_IASetIndexBuffer(G.devcon, buffer->gpu_index_buffer, DXGI_FORMAT_R32_UINT, zero); + + /* Draw */ + u32 vertex_offset = cmd->vertex_offset; + u32 index_offset = cmd->index_offset; + u32 index_count = cmd->index_count; + ID3D11DeviceContext_DrawIndexed(G.devcon, index_count, index_offset, vertex_offset); + } break; + } + } +} + +/* ========================== * + * Texture + * ========================== */ + +INTERNAL struct dx11_format dx11_format_from_renderer_format(enum renderer_texture_format format) +{ + LOCAL_PERSIST const struct dx11_format sizes[NUM_RENDERER_TEXTURE_FORMATS] = { + [RENDERER_TEXTURE_FORMAT_R8G8B8A8_UNORM] = { + .format = DXGI_FORMAT_R8G8B8A8_UNORM, + .pixel_size = 4 + } + }; + struct dx11_format res = ZI; + if ((u32)format < ARRAY_COUNT(sizes)) { + res = sizes[format]; + } + return res; +} + +INTERNAL struct dx11_texture *dx11_texture_alloc(enum renderer_texture_format format, u32 flags, u32 width, u32 height, void *initial_data) +{ + struct dx11_texture *t = NULL; + { + /* Allocate to list */ + struct sys_lock lock = sys_mutex_lock_e(&G.textures_mutex); + if (G.textures_first_free) { + t = G.textures_first_free; + G.textures_first_free = t->next_free; + } else { + t = arena_push(&G.textures_arena, struct dx11_texture); + } + MEMZERO_STRUCT(t); + if (!G.textures_first) { + G.textures_first = t; + } else { + G.textures_last->next = t; + } + t->prev = G.textures_last; + G.textures_last = t; + sys_mutex_unlock(&lock); + } + struct dx11_format dx11_format = dx11_format_from_renderer_format(format); + if (dx11_format.format == DXGI_FORMAT_UNKNOWN) { + /* Unknown format */ + ASSERT(false); + dx11_format = (struct dx11_format) { .format = DXGI_FORMAT_R8G8B8A8_UNORM, .pixel_size = 4 }; + } + + u32 bind_flags = D3D11_BIND_SHADER_RESOURCE; + if (flags & RENDERER_TEXTURE_FLAG_TARGET) { + bind_flags |= D3D11_BIND_RENDER_TARGET; + } + + D3D11_TEXTURE2D_DESC desc = ZI; + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.SampleDesc.Count = 1; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.CPUAccessFlags = 0; + desc.BindFlags = bind_flags; + desc.Format = dx11_format.format; + + ID3D11Texture2D *texture = NULL; + if (initial_data) { + D3D11_SUBRESOURCE_DATA subresource_data = { .pSysMem = initial_data, .SysMemPitch = width * dx11_format.pixel_size, .SysMemSlicePitch = 0 }; + ID3D11Device_CreateTexture2D(G.dev, &desc, &subresource_data, &texture); + } else { + ID3D11Device_CreateTexture2D(G.dev, &desc, NULL, &texture); + } + ASSERT(texture != NULL); + t->texture = texture; + + return t; +} + +INTERNAL void dx11_texture_release(struct dx11_texture *t) +{ + if (!t->is_backbuffer) { + { + /* Free from list */ + struct sys_lock lock = sys_mutex_lock_e(&G.textures_mutex); + struct dx11_texture *prev = t->prev; + struct dx11_texture *next = t->next; + if (prev) { + prev->next = next; + } + if (next) { + next->prev = prev; + } + if (G.textures_first == t) { + G.textures_first = next; + } + if (G.textures_last == t) { + G.textures_last = prev; + } + t->next_free = G.textures_first_free; + G.textures_first_free = t; + sys_mutex_unlock(&lock); + } + if (t->texture) { + ID3D11Texture2D_Release(t->texture); + } + } +} + +struct renderer_texture renderer_texture_alloc(enum renderer_texture_format format, u32 flags, u32 width, u32 height, void *initial_data) +{ + __prof; + struct renderer_texture res = ZI; + struct dx11_texture *t = dx11_texture_alloc(format, flags, width, height, initial_data); + res.handle = (u64)t; + return res; +} + +void renderer_texture_release(struct renderer_texture t) +{ + __prof; + dx11_texture_release((struct dx11_texture *)t.handle); +} + +void renderer_texture_clear(struct renderer_texture target_texture, u32 clear_color) +{ + __prof; + + ID3D11Texture2D *texture = ((struct dx11_texture *)target_texture.handle)->texture; + + ID3D11RenderTargetView *target_view = NULL; + ID3D11Device_CreateRenderTargetView(G.dev, (ID3D11Resource *)texture, NULL, &target_view); + if (target_view) { + f32 r = (f32)((clear_color >> 0) & 0xFF) / 255.0f; + f32 g = (f32)((clear_color >> 8) & 0xFF) / 255.0f; + f32 b = (f32)((clear_color >> 16) & 0xFF) / 255.0f; + f32 a = (f32)((clear_color >> 24) & 0xFF) / 255.0f; + f32 fill[4] = { r, g, b, a }; + ID3D11DeviceContext_ClearRenderTargetView(G.devcon, target_view, fill); + } + + if (target_view) { + ID3D11RenderTargetView_Release(target_view); + } +} + +void renderer_texture_render(struct renderer_texture texture, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) +{ + __prof; + + struct dx11_texture *t = (struct dx11_texture *)texture.handle; + + ID3D11RenderTargetView *target_view = NULL; + ID3D11Device_CreateRenderTargetView(G.dev, (ID3D11Resource *)t->texture, NULL, &target_view); + if (target_view) { + dx11_render_to_target(target_view, cmdbuff, view, viewport, sprite_scope); + } + + if (target_view) { + ID3D11RenderTargetView_Release(target_view); + } +} + +/* ========================== * + * Backbuffer + * ========================== */ + +struct renderer_texture renderer_get_backbuffer_texture(void) +{ + struct renderer_texture res = ZI; + res.handle = (u64)&G.backbuffer_texture; + return res; +} + +void renderer_backbuffer_resize(u32 width, u32 height) +{ + __prof; + ID3D11Texture2D_Release(G.backbuffer_texture.texture); + IDXGISwapChain_ResizeBuffers(G.swapchain, 0, width, height, DXGI_FORMAT_UNKNOWN, 0); + IDXGISwapChain_GetBuffer(G.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&G.backbuffer_texture.texture); +} + +void renderer_backbuffer_present(i32 vsync) +{ + __prof; + + { + __profscope(IDXGISwapchain_Present); + IDXGISwapChain1_Present(G.swapchain, vsync, 0); + __profframe(0); + } + + renderer_capture_image_for_profiler(); +} + /* ========================== * * Cmd buffer * ========================== */ @@ -719,12 +941,12 @@ void renderer_cmd_buffer_ensure_cmd(struct renderer_cmd_buffer *cmdbuff, struct { if (!last_cmd || last_cmd->shader->kind != SHADER_TEXTURE - || !handle_eq(last_cmd->texture_handle, params->texture_params.texture) + || (last_cmd->texture.handle != params->texture_params.texture.handle) || !sprite_tag_eq(last_cmd->sprite, params->texture_params.sprite)) { new_cmd = arena_push(&cmdbuff->cpu_cmd_store.arena, struct renderer_cmd); *new_cmd = (struct renderer_cmd) { .shader = &G.shaders[SHADER_TEXTURE], - .texture_handle = params->texture_params.texture, + .texture = params->texture_params.texture, .sprite = params->texture_params.sprite }; } @@ -751,10 +973,6 @@ void renderer_cmd_buffer_ensure_cmd(struct renderer_cmd_buffer *cmdbuff, struct } } -/* ========================== * - * Send cmdbuff to GPU - * ========================== */ - void renderer_cmd_buffer_send_to_gpu(struct renderer_cmd_buffer *cmdbuff) { __prof; @@ -822,351 +1040,6 @@ void renderer_cmd_buffer_send_to_gpu(struct renderer_cmd_buffer *cmdbuff) arena_reset(&cmdbuff->cpu_cmd_store.arena); } -/* ========================== * - * Render - * ========================== */ - -/* TODO: Lock cmdbuff or at least global state? (in-case multi-threaded present). - * Another option is to store a separate device on each cmdbuff (need to - * research if that is smart first). - * - * I'm thinking we may also just need to lock texture modification access while presenting */ -INTERNAL void dx11_render_to_target(ID3D11RenderTargetView *target, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) -{ - __prof; - ID3D11DeviceContext_OMSetRenderTargets(G.devcon, 1, &target, NULL); - - D3D11_VIEWPORT d3d11_viewport = ZI; - d3d11_viewport.Width = viewport.width; - d3d11_viewport.Height = viewport.height; - d3d11_viewport.MinDepth = 0.0f; - d3d11_viewport.MaxDepth = 1.0f; - d3d11_viewport.TopLeftX = viewport.x; - d3d11_viewport.TopLeftY = viewport.y; - ID3D11DeviceContext_RSSetViewports(G.devcon, 1, &d3d11_viewport); - - /* Fill and set constant buffer - * NOTE: We're only doing this once per render, rather than once per - * draw call since the only constant right now is VP. */ - struct mat4x4 vp_matrix = calculate_vp(view, viewport.width, viewport.height); - send_constant_buffer_data(G.vs_constant_buffer, vp_matrix); - ID3D11DeviceContext_VSSetConstantBuffers(G.devcon, 0, 1, &G.vs_constant_buffer); - - struct dx11_shader *last_shader = NULL; - - struct renderer_cmd *cmd = cmdbuff ? cmdbuff->gpu_cmd_store.cmd_first : NULL; - for (; cmd; cmd = cmd->next) { - struct dx11_shader *shader = cmd->shader; - struct dx11_buffer *buffer = &cmdbuff->buffers[shader->kind]; - - /* Activate shader */ - if (shader != last_shader) { - ID3D11DeviceContext_VSSetShader(G.devcon, shader->vs, 0, 0); - ID3D11DeviceContext_PSSetShader(G.devcon, shader->ps, 0, 0); - ID3D11DeviceContext_IASetInputLayout(G.devcon, shader->input_layout); - last_shader = shader; - } - - switch (shader->kind) { - default: - { - /* Unknown shader */ - ASSERT(false); - } break; - - case SHADER_TEXTURE: - { - b32 texture_loaded; - struct renderer_handle texture_handle; - if (!handle_is_nil(cmd->texture_handle)) { - /* Load texture if handle is set */ - texture_loaded = true; - texture_handle = cmd->texture_handle; - /* FIXME: Texture SRV refcount needs to be increased here to prevent release mid-render */ - } else { - /* Otherwise load sprite */ - struct sprite_texture *sprite_texture = sprite_texture_from_tag_async(sprite_scope, cmd->sprite); - texture_loaded = sprite_texture->loaded; - texture_handle = sprite_texture->renderer_handle; - } - - if (texture_loaded) { - /* Bind texture */ - ID3D11ShaderResourceView *texture_srv = handle_data(texture_handle); - ID3D11DeviceContext_PSSetShaderResources(G.devcon, 0, 1, &texture_srv); - - ID3D11DeviceContext_IASetPrimitiveTopology(G.devcon, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - /* Activate buffer */ - u32 zero = 0; - UINT vertex_stride = shader->vertex_size; - ID3D11DeviceContext_IASetVertexBuffers(G.devcon, 0, 1, &buffer->gpu_vertex_buffer, &vertex_stride, &zero); - ID3D11DeviceContext_IASetIndexBuffer(G.devcon, buffer->gpu_index_buffer, DXGI_FORMAT_R32_UINT, zero); - - /* Draw */ - u32 vertex_offset = cmd->vertex_offset; - u32 index_offset = cmd->index_offset; - u32 index_count = cmd->index_count; - ID3D11DeviceContext_DrawIndexed(G.devcon, index_count, index_offset, vertex_offset); - - /* Unbind */ - ID3D11ShaderResourceView *null_srv[1] = { NULL }; - ID3D11DeviceContext_PSSetShaderResources(G.devcon, 0, 1, null_srv); - } - } break; - - case SHADER_GRID: - { - ID3D11DeviceContext_IASetPrimitiveTopology(G.devcon, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - /* Activate buffer */ - u32 zero = 0; - UINT vertex_stride = shader->vertex_size; - ID3D11DeviceContext_IASetVertexBuffers(G.devcon, 0, 1, &buffer->gpu_vertex_buffer, &vertex_stride, &zero); - ID3D11DeviceContext_IASetIndexBuffer(G.devcon, buffer->gpu_index_buffer, DXGI_FORMAT_R32_UINT, zero); - - /* Draw */ - u32 vertex_offset = cmd->vertex_offset; - u32 index_offset = cmd->index_offset; - u32 index_count = cmd->index_count; - ID3D11DeviceContext_DrawIndexed(G.devcon, index_count, index_offset, vertex_offset); - } break; - } - } -} - -void renderer_render_to_texture(struct renderer_handle target_handle, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) -{ - __prof; - - ID3D11ShaderResourceView *target_srv = handle_data(target_handle); - if (!target_srv) { - /* Invalid handle */ - ASSERT(false); - return; - } - - ID3D11Texture2D *target_texture = NULL; - ID3D11View_GetResource(target_srv, (ID3D11Resource **)&target_texture); - - ID3D11RenderTargetView *target_view = NULL; - ID3D11Device_CreateRenderTargetView(G.dev, (ID3D11Resource *)target_texture, NULL, &target_view); - if (target_view) { - dx11_render_to_target(target_view, cmdbuff, view, viewport, sprite_scope); - } - - if (target_view) { - ID3D11RenderTargetView_Release(target_view); - } - if (target_texture) { - ID3D11Texture2D_Release(target_texture); - } -} - -void renderer_render_to_backbuffer(struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) -{ - __prof; - - ID3D11Texture2D *backbuffer_texture = NULL; - IDXGISwapChain_GetBuffer(G.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&backbuffer_texture); - - ID3D11RenderTargetView *backbuffer_view = NULL; - ID3D11Device_CreateRenderTargetView(G.dev, (ID3D11Resource *)backbuffer_texture, NULL, &backbuffer_view); - - if (backbuffer_view) { - dx11_render_to_target(backbuffer_view, cmdbuff, view, viewport, sprite_scope); - } - - if (backbuffer_view) { - ID3D11RenderTargetView_Release(backbuffer_view); - } - if (backbuffer_texture) { - ID3D11Texture2D_Release(backbuffer_texture); - } -} - -void renderer_clear_texture(struct renderer_handle target_handle, u32 clear_color) -{ - __prof; - - ID3D11ShaderResourceView *target_srv = handle_data(target_handle); - if (!target_srv) { - /* Invalid handle */ - ASSERT(false); - return; - } - - ID3D11Texture2D *target_resource = NULL; - ID3D11View_GetResource(target_srv, (ID3D11Resource **)&target_resource); - - ID3D11RenderTargetView *target_view = NULL; - ID3D11Device_CreateRenderTargetView(G.dev, (ID3D11Resource *)target_resource, NULL, &target_view); - if (target_view) { - f32 r = (f32)((clear_color >> 0) & 0xFF) / 255.0f; - f32 g = (f32)((clear_color >> 8) & 0xFF) / 255.0f; - f32 b = (f32)((clear_color >> 16) & 0xFF) / 255.0f; - f32 a = (f32)((clear_color >> 24) & 0xFF) / 255.0f; - f32 fill[4] = { r, g, b, a }; - ID3D11DeviceContext_ClearRenderTargetView(G.devcon, target_view, fill); - } - - - if (target_view) { - ID3D11RenderTargetView_Release(target_view); - } - if (target_resource) { - ID3D11Texture2D_Release(target_resource); - } -} - -void renderer_clear_backbuffer(u32 clear_color) -{ - __prof; - - ID3D11Texture2D *backbuffer_texture = NULL; - IDXGISwapChain_GetBuffer(G.swapchain, 0, &IID_ID3D11Texture2D, (LPVOID *)&backbuffer_texture); - - ID3D11RenderTargetView *backbuffer_view = NULL; - ID3D11Device_CreateRenderTargetView(G.dev, (ID3D11Resource *)backbuffer_texture, NULL, &backbuffer_view); - - if (backbuffer_view) { - f32 r = (f32)((clear_color >> 0) & 0xFF) / 255.0f; - f32 g = (f32)((clear_color >> 8) & 0xFF) / 255.0f; - f32 b = (f32)((clear_color >> 16) & 0xFF) / 255.0f; - f32 a = (f32)((clear_color >> 24) & 0xFF) / 255.0f; - f32 fill[4] = { r, g, b, a }; - ID3D11DeviceContext_ClearRenderTargetView(G.devcon, backbuffer_view, fill); - } - - if (backbuffer_view) { - ID3D11RenderTargetView_Release(backbuffer_view); - } - if (backbuffer_texture) { - ID3D11Texture2D_Release(backbuffer_texture); - } -} - -void renderer_resize_backbuffer(struct v2 size) -{ - __prof; - IDXGISwapChain_ResizeBuffers(G.swapchain, 0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0); -} - -void renderer_present_backbuffer(i32 vsync) -{ - __prof; - - /* Present */ - { - __profscope(IDXGISwapchain_Present); - IDXGISwapChain1_Present(G.swapchain, vsync, 0); - __profframe(0); - } - - renderer_capture_image_for_profiler(); -} - -/* ========================== * - * Texture - * ========================== */ - -struct renderer_handle renderer_texture_image_alloc(struct image_rgba data) -{ - __prof; - - /* Create texture */ - ID3D11Texture2D *texture = NULL; - D3D11_TEXTURE2D_DESC desc = { - .Width = data.width, - .Height = data.height, - .MipLevels = 1, - .ArraySize = 1, - .Format = DXGI_FORMAT_R8G8B8A8_UNORM, - .SampleDesc.Count = 1, - .Usage = D3D11_USAGE_DEFAULT, - .BindFlags = D3D11_BIND_SHADER_RESOURCE, - .CPUAccessFlags = 0 - }; - D3D11_SUBRESOURCE_DATA subresource_data = { - .pSysMem = data.pixels, - .SysMemPitch = data.width * 4, - .SysMemSlicePitch = 0 - }; - ID3D11Device_CreateTexture2D(G.dev, &desc, &subresource_data, &texture); - - /* Create srv */ - ID3D11ShaderResourceView *texture_srv = NULL; - if (texture) { - D3D11_SHADER_RESOURCE_VIEW_DESC shader_resource_view_desc = { - .Format = desc.Format, - .ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D, - .Texture2D.MipLevels = desc.MipLevels, - .Texture2D.MostDetailedMip = 0 - }; - ID3D11Device_CreateShaderResourceView(G.dev, (ID3D11Resource *)texture, &shader_resource_view_desc, &texture_srv); - ID3D11Texture2D_Release(texture); - } - ASSERT(texture_srv != NULL); - - struct renderer_handle handle = handle_alloc(texture_srv); - - return handle; -} - -struct renderer_handle renderer_texture_target_alloc(struct v2 size) -{ - __prof; - - /* Create texture */ - ID3D11Texture2D *texture = NULL; - D3D11_TEXTURE2D_DESC desc = { - .Width = size.x, - .Height = size.y, - .MipLevels = 1, - .ArraySize = 1, - .Format = DXGI_FORMAT_R8G8B8A8_UNORM, - .SampleDesc.Count = 1, - .Usage = D3D11_USAGE_DEFAULT, - .BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, - .CPUAccessFlags = 0 - }; - ID3D11Device_CreateTexture2D(G.dev, &desc, NULL, &texture); - - /* Create srv */ - ID3D11ShaderResourceView *texture_srv = NULL; - if (texture) { - D3D11_SHADER_RESOURCE_VIEW_DESC shader_resource_view_desc = { - .Format = desc.Format, - .ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D, - .Texture2D.MipLevels = desc.MipLevels, - .Texture2D.MostDetailedMip = 0 - }; - ID3D11Device_CreateShaderResourceView(G.dev, (ID3D11Resource *)texture, &shader_resource_view_desc, &texture_srv); - ID3D11Texture2D_Release(texture); - } - ASSERT(texture_srv != NULL); - - struct renderer_handle handle = handle_alloc(texture_srv); - - return handle; -} - -void renderer_texture_release(struct renderer_handle handle) -{ - __prof; - - ID3D11ShaderResourceView *texture_srv = handle_data(handle); - if (texture_srv) { - ID3D11ShaderResourceView_Release(texture_srv); - } - handle_release(handle); -} - -b32 renderer_texture_is_nil(struct renderer_handle handle) -{ - return handle_is_nil(handle); -} - /* ========================== * * Profiling frame capture * ========================== */ diff --git a/src/sprite.c b/src/sprite.c index 94becf81..4419db44 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -229,7 +229,7 @@ struct sprite_startup_receipt sprite_startup(struct renderer_startup_receipt *re { struct temp_arena scratch = scratch_begin_no_conflict(); struct image_rgba purple_black_image = generate_purple_black_image(scratch.arena, 64, 64); - G.nil_texture->renderer_handle = renderer_texture_image_alloc(purple_black_image); + G.nil_texture->texture = renderer_texture_alloc(RENDERER_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, purple_black_image.width, purple_black_image.height, purple_black_image.pixels); scratch_end(scratch); } @@ -365,7 +365,7 @@ INTERNAL void cache_node_load_texture(struct cache_node *n, struct sprite_tag ta n->texture = arena_push(&n->arena, struct sprite_texture); n->texture->width = decoded.image.width; n->texture->height = decoded.image.height; - n->texture->renderer_handle = renderer_texture_image_alloc(decoded.image); + n->texture->texture = renderer_texture_alloc(RENDERER_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, decoded.image.width, decoded.image.height, decoded.image.pixels); n->texture->valid = true; n->texture->loaded = true; /* TODO: Query renderer for more accurate texture size in VRAM */ @@ -1196,7 +1196,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg) for (struct evict_node *en = head_evicted; en; en = en->next_evicted) { struct cache_node *n = en->cache_node; if (n->kind == CACHE_NODE_KIND_TEXTURE && n->texture->valid) { - renderer_texture_release(n->texture->renderer_handle); + renderer_texture_release(n->texture->texture); } arena_release(&n->arena); } diff --git a/src/sprite.h b/src/sprite.h index b8122657..54ed9c3b 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -1,6 +1,7 @@ #ifndef SPRITE_H #define SPRITE_H +#include "renderer.h" #include "util.h" struct renderer_startup_receipt; @@ -45,7 +46,7 @@ void sprite_scope_end(struct sprite_scope *scope); struct sprite_texture { b32 loaded; b32 valid; - struct renderer_handle renderer_handle; + struct renderer_texture texture; u32 width; u32 height; }; diff --git a/src/user.c b/src/user.c index eb5f762f..44b33d50 100644 --- a/src/user.c +++ b/src/user.c @@ -42,13 +42,14 @@ GLOBAL struct { struct sys_window *window; /* Render targets */ - struct renderer_handle final_rt; - struct renderer_handle world_rt; - struct renderer_handle ui_rt; + struct renderer_texture final_rt; + struct renderer_texture world_rt; + struct renderer_texture ui_rt; + struct renderer_texture backbuffer_rt; struct v2 ui_rt_resolution; struct v2 world_rt_resolution; - struct v2 backbuffer_size; + struct v2 backbuffer_rt_resolution; struct renderer_cmd_buffer *world_cmd_buffer; struct renderer_cmd_buffer *ui_cmd_buffer; @@ -1604,36 +1605,39 @@ INTERNAL void user_update(void) struct rect backbuffer_viewport = RECT_FROM_V2(V2(0, 0), G.screen_size); /* Allocate rt textures */ + struct v2 backbuffer_rt_resolution = G.screen_size; struct v2 ui_rt_resolution = G.ui_size; struct v2 world_rt_resolution = V2(target_viewport.width + target_viewport.x, target_viewport.height + target_viewport.y); { /* World rt */ - if (renderer_handle_is_nil(G.world_rt) || !v2_eq(G.world_rt_resolution, world_rt_resolution)) { - if (!renderer_handle_is_nil(G.world_rt)) { + if (!G.world_rt.handle || !v2_eq(G.world_rt_resolution, world_rt_resolution)) { + if (G.world_rt.handle) { renderer_texture_release(G.world_rt); } - G.world_rt = renderer_texture_target_alloc(world_rt_resolution); + G.world_rt = renderer_texture_alloc(RENDERER_TEXTURE_FORMAT_R8G8B8A8_UNORM, RENDERER_TEXTURE_FLAG_TARGET, math_round_to_int(world_rt_resolution.x), math_round_to_int(world_rt_resolution.y), NULL); } /* Ui rt */ - if (renderer_handle_is_nil(G.ui_rt) || !v2_eq(G.ui_rt_resolution, ui_rt_resolution)) { - if (!renderer_handle_is_nil(G.ui_rt)) { + if (!G.ui_rt.handle || !v2_eq(G.ui_rt_resolution, ui_rt_resolution)) { + if (G.ui_rt.handle) { renderer_texture_release(G.ui_rt); } - G.ui_rt = renderer_texture_target_alloc(ui_rt_resolution); + G.ui_rt = renderer_texture_alloc(RENDERER_TEXTURE_FORMAT_R8G8B8A8_UNORM, RENDERER_TEXTURE_FLAG_TARGET, math_round_to_int(ui_rt_resolution.x), math_round_to_int(ui_rt_resolution.y), NULL); } /* Final rt */ - if (renderer_handle_is_nil(G.final_rt) || !v2_eq(G.ui_rt_resolution, ui_rt_resolution)) { - if (!renderer_handle_is_nil(G.final_rt)) { + if (!G.final_rt.handle || !v2_eq(G.ui_rt_resolution, ui_rt_resolution)) { + if (G.final_rt.handle) { renderer_texture_release(G.final_rt); } - G.final_rt = renderer_texture_target_alloc(ui_rt_resolution); + G.final_rt = renderer_texture_alloc(RENDERER_TEXTURE_FORMAT_R8G8B8A8_UNORM, RENDERER_TEXTURE_FLAG_TARGET, math_round_to_int(ui_rt_resolution.x), math_round_to_int(ui_rt_resolution.y), NULL); } - G.world_rt_resolution = world_rt_resolution; + /* Backbuffer rt */ + if (!G.backbuffer_rt.handle || !v2_eq(G.backbuffer_rt_resolution, backbuffer_rt_resolution)) { + renderer_backbuffer_resize(math_round_to_int(backbuffer_rt_resolution.x), math_round_to_int(backbuffer_rt_resolution.y)); + G.backbuffer_rt = renderer_get_backbuffer_texture(); + } + G.backbuffer_rt_resolution = backbuffer_rt_resolution; G.ui_rt_resolution = ui_rt_resolution; - } - if (!v2_eq(G.backbuffer_size, G.screen_size)) { - G.backbuffer_size = G.screen_size; - renderer_resize_backbuffer(G.backbuffer_size); + G.world_rt_resolution = world_rt_resolution; } { @@ -1668,26 +1672,26 @@ INTERNAL void user_update(void) /* Execute render cmds */ { /* Clear textures */ - renderer_clear_texture(G.world_rt, RGBA_32_F(0.2f, 0.2f, 0.2f, 1.f)); - renderer_clear_texture(G.ui_rt, RGBA_32_F(0, 0, 0, 0)); - renderer_clear_texture(G.final_rt, RGBA_32_F(0, 0, 0, 0)); - renderer_clear_backbuffer(RGBA_32_F(0, 0, 0, 1)); + renderer_texture_clear(G.world_rt, RGBA_32_F(0.2f, 0.2f, 0.2f, 1.f)); + renderer_texture_clear(G.ui_rt, RGBA_32_F(0, 0, 0, 0)); + renderer_texture_clear(G.final_rt, RGBA_32_F(0, 0, 0, 0)); + renderer_texture_clear(G.backbuffer_rt, RGBA_32_F(0, 0, 0, 1)); /* Render to world texture */ - renderer_render_to_texture(G.world_rt, G.world_cmd_buffer, G.world_to_ui_xf, target_viewport, sprite_frame_scope); + renderer_texture_render(G.world_rt, G.world_cmd_buffer, G.world_to_ui_xf, target_viewport, sprite_frame_scope); /* Render to UI texture */ - renderer_render_to_texture(G.ui_rt, G.ui_cmd_buffer, XFORM_IDENT, target_viewport, sprite_frame_scope); + renderer_texture_render(G.ui_rt, G.ui_cmd_buffer, XFORM_IDENT, target_viewport, sprite_frame_scope); /* Render to final texture */ - renderer_render_to_texture(G.final_rt, G.final_cmd_buffer, XFORM_IDENT, target_viewport, sprite_frame_scope); + renderer_texture_render(G.final_rt, G.final_cmd_buffer, XFORM_IDENT, target_viewport, sprite_frame_scope); /* Render to backbuffer */ - renderer_render_to_backbuffer(G.backbuffer_cmd_buffer, XFORM_IDENT, backbuffer_viewport, sprite_frame_scope); + renderer_texture_render(G.backbuffer_rt, G.backbuffer_cmd_buffer, XFORM_IDENT, backbuffer_viewport, sprite_frame_scope); } /* Present */ - renderer_present_backbuffer(VSYNC_ENABLED); + renderer_backbuffer_present(VSYNC_ENABLED); } /* ========================== *