refactor renderer_handle -> renderer_texture. retrieve backbuffer as texture.
This commit is contained in:
parent
ceb1ac2059
commit
cebaed5aa5
@ -487,10 +487,6 @@ struct buffer {
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
struct renderer_handle {
|
||||
u64 v[1];
|
||||
};
|
||||
|
||||
struct entity_handle {
|
||||
u64 idx;
|
||||
u64 gen;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
* ========================== */
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
58
src/user.c
58
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);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
|
||||
Loading…
Reference in New Issue
Block a user