From 88ab79e436aec6ede0fca4949570f534ffb1b853 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 9 Mar 2024 09:29:52 -0800 Subject: Rename RenderBackend -> GfxCore. --- game/src/game.c | 12 +- game/src/plugins/texture_view.c | 8 +- game/src/plugins/viewer.c | 22 +- gfx-iso/src/app.c | 36 +-- gfx/CMakeLists.txt | 2 +- gfx/include/gfx/asset.h | 2 +- gfx/include/gfx/core.h | 498 ++++++++++++++++++++++++++++++++++ gfx/include/gfx/gfx.h | 10 +- gfx/include/gfx/render_backend.h | 499 ----------------------------------- gfx/include/gfx/renderer.h | 6 +- gfx/include/gfx/scene/material.h | 2 +- gfx/include/gfx/util/geometry.h | 6 +- gfx/include/gfx/util/ibl.h | 21 +- gfx/include/gfx/util/shader.h | 26 +- gfx/include/gfx/util/skyquad.h | 14 +- gfx/src/asset/asset_cache.c | 4 +- gfx/src/asset/model.c | 69 +++-- gfx/src/asset/texture.c | 9 +- gfx/src/asset/texture.h | 2 +- gfx/src/gfx.c | 22 +- gfx/src/render/buffer.c | 4 +- gfx/src/render/buffer.h | 2 +- gfx/src/render/core.c | 414 +++++++++++++++++++++++++++++ gfx/src/render/core_impl.h | 66 +++++ gfx/src/render/framebuffer.h | 2 +- gfx/src/render/geometry.c | 101 +++---- gfx/src/render/geometry.h | 6 +- gfx/src/render/render_backend.c | 425 ----------------------------- gfx/src/render/render_backend_impl.h | 66 ----- gfx/src/render/renderbuffer.h | 2 +- gfx/src/render/shader.h | 2 +- gfx/src/render/shader_program.h | 6 +- gfx/src/render/texture.h | 2 +- gfx/src/renderer/imm_renderer.c | 29 +- gfx/src/renderer/imm_renderer_impl.h | 4 +- gfx/src/renderer/renderer.c | 62 +++-- gfx/src/renderer/renderer_impl.h | 8 +- gfx/src/scene/material.c | 2 +- gfx/src/scene/object.c | 2 +- gfx/src/util/geometry.c | 12 +- gfx/src/util/ibl.c | 106 ++++---- gfx/src/util/shader.c | 76 +++--- gfx/src/util/skyquad.c | 22 +- 43 files changed, 1323 insertions(+), 1368 deletions(-) create mode 100644 gfx/include/gfx/core.h delete mode 100644 gfx/include/gfx/render_backend.h create mode 100644 gfx/src/render/core.c create mode 100644 gfx/src/render/core_impl.h delete mode 100644 gfx/src/render/render_backend.c delete mode 100644 gfx/src/render/render_backend_impl.h diff --git a/game/src/game.c b/game/src/game.c index bc85691..425119f 100644 --- a/game/src/game.c +++ b/game/src/game.c @@ -11,8 +11,8 @@ #include "plugins/plugin.h" #include +#include #include -#include #include #include #include @@ -204,18 +204,18 @@ void app_update(Game* game, double t, double dt) { } void app_render(const Game* game) { - RenderBackend* render_backend = gfx_get_render_backend(game->gfx); - gfx_start_frame(render_backend); + GfxCore* gfxcore = gfx_get_core(game->gfx); + gfx_start_frame(gfxcore); render_plugin(game); - gfx_end_frame(render_backend); + gfx_end_frame(gfxcore); } void app_resize(Game* game, int width, int height) { game->width = width; game->height = height; - RenderBackend* render_backend = gfx_get_render_backend(game->gfx); - gfx_set_viewport(render_backend, width, height); + GfxCore* gfxcore = gfx_get_core(game->gfx); + gfx_set_viewport(gfxcore, width, height); resize_plugin(game, width, height); } diff --git a/game/src/plugins/texture_view.c b/game/src/plugins/texture_view.c index 52dff57..a8b2a94 100644 --- a/game/src/plugins/texture_view.c +++ b/game/src/plugins/texture_view.c @@ -1,7 +1,7 @@ #include "plugin.h" #include -#include +#include #include #include #include @@ -33,7 +33,7 @@ bool init(Game* game, State** pp_state) { // Usage: [texture file] const char* texture_file = game->argc > 1 ? game->argv[1] : DEFAULT_TEXTURE; - RenderBackend* render_backend = gfx_get_render_backend(game->gfx); + GfxCore* gfxcore = gfx_get_core(game->gfx); const Texture* texture = gfx_load_texture( game->gfx, &(LoadTextureCmd){ @@ -46,12 +46,12 @@ bool init(Game* game, State** pp_state) { goto cleanup; } - ShaderProgram* shader = gfx_make_view_texture_shader(render_backend); + ShaderProgram* shader = gfx_make_view_texture_shader(gfxcore); if (!shader) { goto cleanup; } - Geometry* geometry = gfx_make_quad_11(render_backend); + Geometry* geometry = gfx_make_quad_11(gfxcore); if (!geometry) { goto cleanup; } diff --git a/game/src/plugins/viewer.c b/game/src/plugins/viewer.c index 5e8d7d3..f621b00 100644 --- a/game/src/plugins/viewer.c +++ b/game/src/plugins/viewer.c @@ -58,14 +58,14 @@ static SceneNode* load_skyquad(Gfx* gfx, SceneNode* root) { assert(gfx); assert(root); - RenderBackend* render_backend = gfx_get_render_backend(gfx); + GfxCore* gfxcore = gfx_get_core(gfx); const Texture* environment_map = load_environment_map(gfx); if (!environment_map) { return 0; } - return gfx_setup_skyquad(render_backend, root, environment_map); + return gfx_setup_skyquad(gfxcore, root, environment_map); } /// Load the 3D scene. @@ -222,17 +222,17 @@ static void render_bounding_boxes(const Game* game, const State* state) { assert(game); assert(state); - RenderBackend* render_backend = gfx_get_render_backend(game->gfx); - ImmRenderer* imm = gfx_get_imm_renderer(game->gfx); - assert(render_backend); + GfxCore* gfxcore = gfx_get_core(game->gfx); + ImmRenderer* imm = gfx_get_imm_renderer(game->gfx); + assert(gfxcore); assert(imm); const mat4 id = mat4_id(); Anima* anima = 0; - gfx_set_blending(render_backend, true); - gfx_set_depth_mask(render_backend, false); - gfx_set_polygon_offset(render_backend, -1.5f, -1.0f); + gfx_set_blending(gfxcore, true); + gfx_set_depth_mask(gfxcore, false); + gfx_set_polygon_offset(gfxcore, -1.5f, -1.0f); gfx_imm_start(imm); gfx_imm_set_camera(imm, gfx_get_camera_camera(state->camera)); @@ -240,9 +240,9 @@ static void render_bounding_boxes(const Game* game, const State* state) { render_bounding_boxes_rec(imm, anima, &id, gfx_get_scene_root(state->scene)); gfx_imm_end(imm); - gfx_reset_polygon_offset(render_backend); - gfx_set_depth_mask(render_backend, true); - gfx_set_blending(render_backend, false); + gfx_reset_polygon_offset(gfxcore); + gfx_set_depth_mask(gfxcore, true); + gfx_set_blending(gfxcore, false); } void render(const Game* game, const State* state) { diff --git a/gfx-iso/src/app.c b/gfx-iso/src/app.c index 8e0a45a..e07f318 100644 --- a/gfx-iso/src/app.c +++ b/gfx-iso/src/app.c @@ -2,8 +2,8 @@ #include #include +#include #include -#include #include #include #include @@ -58,26 +58,26 @@ static bool init(GfxAppState* gfx_app_state, int argc, const char** argv) { if (!(state->gfx = gfx_init())) { goto cleanup; } - RenderBackend* render_backend = gfx_get_render_backend(state->gfx); + GfxCore* gfxcore = gfx_get_core(state->gfx); if (!(state->screen_texture = gfx_make_texture( - render_backend, &(TextureDesc){ - .width = texture_width, - .height = texture_height, - .dimension = Texture2D, - .format = TextureSRGBA8, - .filtering = NearestFiltering, - .wrap = ClampToEdge, - .mipmaps = false}))) { + gfxcore, &(TextureDesc){ + .width = texture_width, + .height = texture_height, + .dimension = Texture2D, + .format = TextureSRGBA8, + .filtering = NearestFiltering, + .wrap = ClampToEdge, + .mipmaps = false}))) { goto cleanup; } - ShaderProgram* shader = gfx_make_view_texture_shader(render_backend); + ShaderProgram* shader = gfx_make_view_texture_shader(gfxcore); if (!shader) { goto cleanup; } - Geometry* geometry = gfx_make_quad_11(render_backend); + Geometry* geometry = gfx_make_quad_11(gfxcore); if (!geometry) { goto cleanup; } @@ -155,22 +155,22 @@ static void render(GfxAppState* gfx_app_state) { gfx_update_texture( state->screen_texture, &(TextureDataDesc){.pixels = screen}); - RenderBackend* render_backend = gfx_get_render_backend(state->gfx); - Renderer* renderer = gfx_get_renderer(state->gfx); + GfxCore* gfxcore = gfx_get_core(state->gfx); + Renderer* renderer = gfx_get_renderer(state->gfx); - gfx_start_frame(render_backend); + gfx_start_frame(gfxcore); gfx_render_scene( renderer, &(RenderSceneParams){ .mode = RenderDefault, .scene = state->scene, .camera = 0}); - gfx_end_frame(render_backend); + gfx_end_frame(gfxcore); } static void resize(GfxAppState* gfx_app_state, int width, int height) { assert(gfx_app_state); AppState* state = &gfx_app_state->state; - RenderBackend* render_backend = gfx_get_render_backend(state->gfx); - gfx_set_viewport(render_backend, width, height); + GfxCore* gfxcore = gfx_get_core(state->gfx); + gfx_set_viewport(gfxcore, width, height); } void iso_run(int argc, const char** argv, IsoGfxApp* app) { diff --git a/gfx/CMakeLists.txt b/gfx/CMakeLists.txt index 6c8640c..c835bd9 100644 --- a/gfx/CMakeLists.txt +++ b/gfx/CMakeLists.txt @@ -37,9 +37,9 @@ add_library(gfx SHARED src/asset/model.c src/asset/texture.c src/render/buffer.c + src/render/core.c src/render/framebuffer.c src/render/geometry.c - src/render/render_backend.c src/render/renderbuffer.c src/render/shader_program.c src/render/shader.c diff --git a/gfx/include/gfx/asset.h b/gfx/include/gfx/asset.h index 1a4e551..caf40c1 100644 --- a/gfx/include/gfx/asset.h +++ b/gfx/include/gfx/asset.h @@ -1,7 +1,7 @@ /* Asset Management */ #pragma once -#include +#include #include diff --git a/gfx/include/gfx/core.h b/gfx/include/gfx/core.h new file mode 100644 index 0000000..7d31cca --- /dev/null +++ b/gfx/include/gfx/core.h @@ -0,0 +1,498 @@ +/// Render Backend. +/// +/// The Render Backend creates and owns graphics objects and performs low-level +/// rendering operations. +#pragma once + +#include "sizes.h" + +#include +#include +#include +#include + +#include + +#include +#include + +// Implementation objects. +typedef struct Buffer Buffer; +typedef struct FrameBuffer FrameBuffer; +typedef struct Geometry Geometry; +typedef struct GfxCore GfxCore; +typedef struct RenderBuffer RenderBuffer; +typedef struct Shader Shader; +typedef struct ShaderProgram ShaderProgram; +typedef struct Texture Texture; + +/// Data type for vertex indices. +/// Might need U32 for bigger models. +typedef uint8_t VertexIndex8; +typedef uint16_t VertexIndex16; +typedef uint16_t VertexCount; + +/// Geometry drawing modes. +typedef enum PrimitiveType { + Triangles, + TriangleFan, + TriangleStrip +} PrimitiveType; + +/// Buffer usage. +typedef enum BufferUsage { BufferStatic, BufferDynamic } BufferUsage; + +/// Buffer type. +typedef enum BufferType { + BufferUntyped, + Buffer2d, + Buffer3d, + Buffer4d, + BufferFloat, + BufferU8, + BufferU16 +} BufferType; + +/// Buffer data descriptor. +typedef struct BufferDataDesc { + union { + const void* data; + const vec2* vec2s; + const vec3* vec3s; + const float* floats; + const uint8_t* u8s; + const uint16_t* u16s; + }; + size_t count; +} BufferDataDesc; + +/// Buffer descriptor. +/// +/// 'count' is the number of elements in the array. For untyped buffers, this is +/// the size in bytes of the 'data' array. For other types, it is the number of +/// vec2s, vec3s, etc. in the corresponding array. +/// +/// The data pointers can also be null. In such a case, a buffer of the given +/// size is created with its contents uninitialized. +/// +/// TODO: Think about typed buffers (Buffer, Buffer2d, Buffer3d, BufferU8, etc). +/// Typed buffers don't work well with interleaved vertex attributes. Not sure +/// this is really worth it. +typedef struct BufferDesc { + BufferUsage usage; + BufferType type; + BufferDataDesc data; +} BufferDesc; + +/// A buffer view for vertex data (attributes or indices). +/// Either 'data' or 'buffer' must be set. +#define MAKE_BUFFER_VIEW(NAME, TYPE) \ + typedef struct NAME { \ + const TYPE* data; \ + Buffer* buffer; \ + size_t offset_bytes; \ + size_t size_bytes; \ + size_t stride_bytes; \ + } NAME; + +/// A buffer view for untyped data. +MAKE_BUFFER_VIEW(BufferView, void) + +/// A buffer view for 2D vectors. +MAKE_BUFFER_VIEW(BufferView2d, vec2) + +/// A buffer view for 3D vectors. +MAKE_BUFFER_VIEW(BufferView3d, vec3) + +/// A buffer view for 4D vectors. +MAKE_BUFFER_VIEW(BufferView4d, vec4) + +/// A buffer view for floats. +MAKE_BUFFER_VIEW(BufferViewFloat, float) + +/// A buffer view for 8-bit unsigned integers. +MAKE_BUFFER_VIEW(BufferViewU8, uint8_t) + +/// A buffer view for 16-bit unsigned integers. +MAKE_BUFFER_VIEW(BufferViewU16, uint16_t) + +/// A buffer view for 8-bit vertex indices. +MAKE_BUFFER_VIEW(BufferViewIdx8, uint16_t) + +/// A buffer view for 16-bit vertex indices. +MAKE_BUFFER_VIEW(BufferViewIdx16, uint16_t) + +/// Describes a piece of geometry. +/// +/// Buffer views may point to either already-existing GPU buffers or to data in +/// host memory. +/// +/// If the buffer views do not already point to GPU buffers, GPU buffers are +/// created for the geometry. The 'buffer_usage' field specifies the usage for +/// the created buffers. Use BufferStatic for static geometry and BufferDynamic +/// for dynamic geometry. +/// +/// Currently we support only up to 16-bit vertex indices. Might have to change +/// this to support a larger variety of 3D models. +typedef struct GeometryDesc { + BufferView2d positions2d; + BufferView3d positions3d; + BufferView3d normals; + BufferView4d tangents; + BufferView2d texcoords; + struct { + BufferViewU8 u8; + BufferViewU16 u16; + } joints; // uvec4. + struct { + BufferViewFloat floats; + BufferViewU8 u8; + BufferViewU16 u16; + } weights; // vec4 or uvec4. + BufferViewIdx8 indices8; + BufferViewIdx16 indices16; + VertexCount num_verts; + size_t num_indices; + PrimitiveType type; + BufferUsage buffer_usage; + aabb3 aabb; +} GeometryDesc; + +/// Shader compiler define. +typedef struct ShaderCompilerDefine { + sstring name; + sstring value; +} ShaderCompilerDefine; + +/// Shader types. +typedef enum { VertexShader, FragmentShader } ShaderType; + +/// Describes a shader. +typedef struct ShaderDesc { + ShaderType type; + const char* code; + ShaderCompilerDefine defines[GFX_MAX_SHADER_COMPILER_DEFINES]; + size_t num_defines; +} ShaderDesc; + +/// Describes a shader program. +typedef struct ShaderProgramDesc { + const Shader* vertex_shader; + const Shader* fragment_shader; +} ShaderProgramDesc; + +/// Shader uniform type. +typedef enum { + UniformFloat, + UniformMat4, + UniformTexture, + UniformVec3, + UniformVec4, + UniformMat4Array +} UniformType; + +/// Shader uniform. +/// +/// For uniform arrays, the client must ensure that the array is still valid by +/// the time the uniform data is passed to the GPU. +typedef struct ShaderUniform { + sstring name; + UniformType type; + union { + const Texture* texture; + mat4 mat4; + vec3 vec3; + vec4 vec4; + float scalar; + struct { + size_t count; + union { + const mat4* values; + }; + } array; + } value; +} ShaderUniform; + +/// Texture dimension. +typedef enum { Texture2D, TextureCubeMap } TextureDimension; + +/// Texture data format. +typedef enum { + TextureDepth, + TextureRG16, + TextureRG16F, + TextureRGB8, + TextureR11G11B10F, + TextureRGBA8, + TextureSRGB8, + TextureSRGBA8 +} TextureFormat; + +/// Texture filtering. +typedef enum { NearestFiltering, LinearFiltering } TextureFiltering; + +/// Texture wrap mode. +typedef enum { Repeat, ClampToEdge } TextureWrapping; + +/// Cubemap faces. +typedef enum { + CubemapFacePosX, + CubemapFaceNegX, + CubemapFacePosY, + CubemapFaceNegY, + CubemapFacePosZ, + CubemapFaceNegZ +} CubemapFace; + +/// Texture data descriptor. +typedef struct TextureDataDesc { + union { + const void* pixels; + struct { + const void* pixels_pos_x; + const void* pixels_neg_x; + const void* pixels_pos_y; + const void* pixels_neg_y; + const void* pixels_pos_z; + const void* pixels_neg_z; + } cubemap; + }; +} TextureDataDesc; + +/// Describes a texture. +typedef struct TextureDesc { + int width; + int height; + int depth; // Not used until 3D textures are exposed. + TextureDimension dimension; + TextureFormat format; + TextureFiltering filtering; + TextureWrapping wrap; + bool mipmaps; + TextureDataDesc data; +} TextureDesc; + +/// Describes a renderbuffer. +typedef struct RenderBufferDesc { + int width; + int height; + TextureFormat texture_format; +} RenderBufferDesc; + +/// Framebuffer attachment type. +typedef enum FrameBufferAttachmentType { + FrameBufferNoAttachment, + FrameBufferTexture, + FrameBufferCubemapTexture, + FrameBufferRenderBuffer +} FrameBufferAttachmentType; + +/// Describes a framebuffer attachment. +typedef struct FrameBufferAttachment { + FrameBufferAttachmentType type; + union { + struct { + Texture* texture; + int mip_level; + } texture; + struct { + Texture* texture; + int mip_level; + CubemapFace face; + } cubemap; + RenderBuffer* renderbuffer; + }; +} FrameBufferAttachment; + +/// Describes a framebuffer. +typedef struct FrameBufferDesc { + FrameBufferAttachment colour; + FrameBufferAttachment depth; +} FrameBufferDesc; + +// ----------------------------------------------------------------------------- +// Render commands. +// ----------------------------------------------------------------------------- + +/// Start a new frame. +void gfx_start_frame(GfxCore*); + +/// End a frame. +void gfx_end_frame(GfxCore*); + +/// Set the render backend's viewport dimensions. +void gfx_set_viewport(GfxCore*, int width, int height); + +/// Get the render backend's viewport dimensions. +void gfx_get_viewport(GfxCore*, int* width, int* height); + +/// Set blending state. +void gfx_set_blending(GfxCore*, bool enable); + +/// Set depth mask. +void gfx_set_depth_mask(GfxCore*, bool enable); + +/// Set cull mode. +void gfx_set_culling(GfxCore*, bool enable); + +/// Set polygon offset. +void gfx_set_polygon_offset(GfxCore*, float scale, float bias); + +/// Reset the polygon offset. +void gfx_reset_polygon_offset(GfxCore*); + +// ----------------------------------------------------------------------------- +// Buffers. +// ----------------------------------------------------------------------------- + +/// Create a buffer from raw data. +Buffer* gfx_make_buffer(GfxCore*, const BufferDesc*); + +/// Destroy the buffer. +void gfx_destroy_buffer(GfxCore*, Buffer**); + +/// Update the buffer's data. +void gfx_update_buffer(Buffer*, const BufferDataDesc*); + +// ----------------------------------------------------------------------------- +// Geometry. +// ----------------------------------------------------------------------------- + +/// Create geometry. +Geometry* gfx_make_geometry(GfxCore*, const GeometryDesc*); + +/// Destroy the geometry. +void gfx_destroy_geometry(GfxCore*, Geometry**); + +/// Upload new vertex data for the geometry. +/// +/// This is similar to gfx_make_geometry(), but the geometry need not be +/// entirely specified. +/// +/// Only the vertex attributes, vertex count, and index count set in the +/// descriptor are updated. Index data, primitive type, and other properties of +/// the geometry are not updated. +/// +/// New data must be given as arrays in host memory. That is, the buffer views +/// in the descriptor must point to CPU arrays, not GPU buffers. +/// +/// Note that the descriptor cannot specify a larger vertex or index count than +/// what the geometry was created with. If the geometry size or any other +/// attribute not handled by this update function needs to be changed, then a +/// new geometry must be created. +void gfx_update_geometry(Geometry*, const GeometryDesc*); + +/// Render the geometry. +void gfx_render_geometry(const Geometry*); + +/// Return the geometry's bounding box. +aabb3 gfx_get_geometry_aabb(const Geometry*); + +// ----------------------------------------------------------------------------- +// Textures. +// ----------------------------------------------------------------------------- + +/// Create a texture. +Texture* gfx_make_texture(GfxCore*, const TextureDesc*); + +/// Destroy the texture. +void gfx_destroy_texture(GfxCore*, Texture**); + +/// Update the texture. +void gfx_update_texture(Texture*, const TextureDataDesc*); + +// ----------------------------------------------------------------------------- +// Renderbuffers. +// ----------------------------------------------------------------------------- + +/// Create a renderbuffer. +RenderBuffer* gfx_make_renderbuffer(GfxCore*, const RenderBufferDesc*); + +/// Destroy the renderbuffer. +void gfx_destroy_renderbuffer(GfxCore*, RenderBuffer**); + +// ----------------------------------------------------------------------------- +// Framebuffers. +// ----------------------------------------------------------------------------- + +/// Create a framebuffer. +FrameBuffer* gfx_make_framebuffer(GfxCore*, const FrameBufferDesc*); + +/// Destroy the framebuffer. +void gfx_destroy_framebuffer(GfxCore*, FrameBuffer**); + +/// Attach a colour buffer to the framebuffer. +bool gfx_framebuffer_attach_colour(FrameBuffer*, const FrameBufferAttachment*); + +/// Attach a depth buffer to the framebuffer. +bool gfx_framebuffer_attach_depth(FrameBuffer*, const FrameBufferAttachment*); + +/// Activate the framebuffer. +/// Subsequent draw calls write to this framebuffer. +void gfx_activate_framebuffer(const FrameBuffer*); + +/// Deactivate the framebuffer. +/// Subsequent draw calls write to the default framebuffer. +void gfx_deactivate_framebuffer(const FrameBuffer*); + +/// Set the framebuffer's viewport. +/// This function should be called every time the framebuffer is activated. +void gfx_framebuffer_set_viewport( + FrameBuffer*, int x, int y, int width, int height); + +// ----------------------------------------------------------------------------- +// Shaders. +// ----------------------------------------------------------------------------- + +/// Create a shader. +Shader* gfx_make_shader(GfxCore*, const ShaderDesc*); + +/// Destroy the shader. +void gfx_destroy_shader(GfxCore*, Shader**); + +/// Create a shader program. +ShaderProgram* gfx_make_shader_program(GfxCore*, const ShaderProgramDesc*); + +/// Destroy the shader program. +void gfx_destroy_shader_program(GfxCore*, ShaderProgram**); + +/// Activate the shader program. +void gfx_activate_shader_program(const ShaderProgram*); + +/// Deactivate the shader program. +void gfx_deactivate_shader_program(const ShaderProgram*); + +/// Apply the shader program's uniform variables. +/// +/// Calls to gfx_set_XYZ_uniform save the values of the uniform variables in the +/// graphics library. By calling this function, those values are passed on to +/// the graphics driver for rendering. +/// +/// This function should be called after setting all of the uniform variables +/// and prior to issuing a draw call. +void gfx_apply_uniforms(const ShaderProgram*); + +/// Set the texture uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_texture_uniform(ShaderProgram*, const char* name, const Texture*); + +/// Set the matrix uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_mat4_uniform(ShaderProgram*, const char* name, const mat4*); + +/// Set the vec3 uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_vec3_uniform(ShaderProgram*, const char* name, vec3); + +/// Set the vec4 uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_vec4_uniform(ShaderProgram*, const char* name, vec4); + +/// Set the float uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_float_uniform(ShaderProgram*, const char* name, float value); + +/// Set the matrix array uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_mat4_array_uniform( + ShaderProgram*, const char* name, const mat4*, size_t count); diff --git a/gfx/include/gfx/gfx.h b/gfx/include/gfx/gfx.h index bfc457f..7c670a5 100644 --- a/gfx/include/gfx/gfx.h +++ b/gfx/include/gfx/gfx.h @@ -1,9 +1,9 @@ #pragma once -typedef struct AssetCache AssetCache; -typedef struct ImmRenderer ImmRenderer; -typedef struct RenderBackend RenderBackend; -typedef struct Renderer Renderer; +typedef struct AssetCache AssetCache; +typedef struct GfxCore GfxCore; +typedef struct ImmRenderer ImmRenderer; +typedef struct Renderer Renderer; typedef struct Gfx Gfx; @@ -14,7 +14,7 @@ Gfx* gfx_init(void); void gfx_destroy(Gfx**); /// Get the render backend. -RenderBackend* gfx_get_render_backend(Gfx*); +GfxCore* gfx_get_core(Gfx*); /// Get the renderer. Renderer* gfx_get_renderer(Gfx*); diff --git a/gfx/include/gfx/render_backend.h b/gfx/include/gfx/render_backend.h deleted file mode 100644 index 8d3c42b..0000000 --- a/gfx/include/gfx/render_backend.h +++ /dev/null @@ -1,499 +0,0 @@ -/// Render Backend. -/// -/// The Render Backend creates and owns graphics objects and performs low-level -/// rendering operations. -#pragma once - -#include "sizes.h" - -#include -#include -#include -#include - -#include - -#include -#include - -// Implementation objects. -typedef struct Buffer Buffer; -typedef struct FrameBuffer FrameBuffer; -typedef struct Geometry Geometry; -typedef struct RenderBuffer RenderBuffer; -typedef struct Shader Shader; -typedef struct ShaderProgram ShaderProgram; -typedef struct Texture Texture; -typedef struct RenderBackend RenderBackend; - -/// Data type for vertex indices. -/// Might need U32 for bigger models. -typedef uint8_t VertexIndex8; -typedef uint16_t VertexIndex16; -typedef uint16_t VertexCount; - -/// Geometry drawing modes. -typedef enum PrimitiveType { - Triangles, - TriangleFan, - TriangleStrip -} PrimitiveType; - -/// Buffer usage. -typedef enum BufferUsage { BufferStatic, BufferDynamic } BufferUsage; - -/// Buffer type. -typedef enum BufferType { - BufferUntyped, - Buffer2d, - Buffer3d, - Buffer4d, - BufferFloat, - BufferU8, - BufferU16 -} BufferType; - -/// Buffer data descriptor. -typedef struct BufferDataDesc { - union { - const void* data; - const vec2* vec2s; - const vec3* vec3s; - const float* floats; - const uint8_t* u8s; - const uint16_t* u16s; - }; - size_t count; -} BufferDataDesc; - -/// Buffer descriptor. -/// -/// 'count' is the number of elements in the array. For untyped buffers, this is -/// the size in bytes of the 'data' array. For other types, it is the number of -/// vec2s, vec3s, etc. in the corresponding array. -/// -/// The data pointers can also be null. In such a case, a buffer of the given -/// size is created with its contents uninitialized. -/// -/// TODO: Think about typed buffers (Buffer, Buffer2d, Buffer3d, BufferU8, etc). -/// Typed buffers don't work well with interleaved vertex attributes. Not sure -/// this is really worth it. -typedef struct BufferDesc { - BufferUsage usage; - BufferType type; - BufferDataDesc data; -} BufferDesc; - -/// A buffer view for vertex data (attributes or indices). -/// Either 'data' or 'buffer' must be set. -#define MAKE_BUFFER_VIEW(NAME, TYPE) \ - typedef struct NAME { \ - const TYPE* data; \ - Buffer* buffer; \ - size_t offset_bytes; \ - size_t size_bytes; \ - size_t stride_bytes; \ - } NAME; - -/// A buffer view for untyped data. -MAKE_BUFFER_VIEW(BufferView, void) - -/// A buffer view for 2D vectors. -MAKE_BUFFER_VIEW(BufferView2d, vec2) - -/// A buffer view for 3D vectors. -MAKE_BUFFER_VIEW(BufferView3d, vec3) - -/// A buffer view for 4D vectors. -MAKE_BUFFER_VIEW(BufferView4d, vec4) - -/// A buffer view for floats. -MAKE_BUFFER_VIEW(BufferViewFloat, float) - -/// A buffer view for 8-bit unsigned integers. -MAKE_BUFFER_VIEW(BufferViewU8, uint8_t) - -/// A buffer view for 16-bit unsigned integers. -MAKE_BUFFER_VIEW(BufferViewU16, uint16_t) - -/// A buffer view for 8-bit vertex indices. -MAKE_BUFFER_VIEW(BufferViewIdx8, uint16_t) - -/// A buffer view for 16-bit vertex indices. -MAKE_BUFFER_VIEW(BufferViewIdx16, uint16_t) - -/// Describes a piece of geometry. -/// -/// Buffer views may point to either already-existing GPU buffers or to data in -/// host memory. -/// -/// If the buffer views do not already point to GPU buffers, GPU buffers are -/// created for the geometry. The 'buffer_usage' field specifies the usage for -/// the created buffers. Use BufferStatic for static geometry and BufferDynamic -/// for dynamic geometry. -/// -/// Currently we support only up to 16-bit vertex indices. Might have to change -/// this to support a larger variety of 3D models. -typedef struct GeometryDesc { - BufferView2d positions2d; - BufferView3d positions3d; - BufferView3d normals; - BufferView4d tangents; - BufferView2d texcoords; - struct { - BufferViewU8 u8; - BufferViewU16 u16; - } joints; // uvec4. - struct { - BufferViewFloat floats; - BufferViewU8 u8; - BufferViewU16 u16; - } weights; // vec4 or uvec4. - BufferViewIdx8 indices8; - BufferViewIdx16 indices16; - VertexCount num_verts; - size_t num_indices; - PrimitiveType type; - BufferUsage buffer_usage; - aabb3 aabb; -} GeometryDesc; - -/// Shader compiler define. -typedef struct ShaderCompilerDefine { - sstring name; - sstring value; -} ShaderCompilerDefine; - -/// Shader types. -typedef enum { VertexShader, FragmentShader } ShaderType; - -/// Describes a shader. -typedef struct ShaderDesc { - ShaderType type; - const char* code; - ShaderCompilerDefine defines[GFX_MAX_SHADER_COMPILER_DEFINES]; - size_t num_defines; -} ShaderDesc; - -/// Describes a shader program. -typedef struct ShaderProgramDesc { - const Shader* vertex_shader; - const Shader* fragment_shader; -} ShaderProgramDesc; - -/// Shader uniform type. -typedef enum { - UniformFloat, - UniformMat4, - UniformTexture, - UniformVec3, - UniformVec4, - UniformMat4Array -} UniformType; - -/// Shader uniform. -/// -/// For uniform arrays, the client must ensure that the array is still valid by -/// the time the uniform data is passed to the GPU. -typedef struct ShaderUniform { - sstring name; - UniformType type; - union { - const Texture* texture; - mat4 mat4; - vec3 vec3; - vec4 vec4; - float scalar; - struct { - size_t count; - union { - const mat4* values; - }; - } array; - } value; -} ShaderUniform; - -/// Texture dimension. -typedef enum { Texture2D, TextureCubeMap } TextureDimension; - -/// Texture data format. -typedef enum { - TextureDepth, - TextureRG16, - TextureRG16F, - TextureRGB8, - TextureR11G11B10F, - TextureRGBA8, - TextureSRGB8, - TextureSRGBA8 -} TextureFormat; - -/// Texture filtering. -typedef enum { NearestFiltering, LinearFiltering } TextureFiltering; - -/// Texture wrap mode. -typedef enum { Repeat, ClampToEdge } TextureWrapping; - -/// Cubemap faces. -typedef enum { - CubemapFacePosX, - CubemapFaceNegX, - CubemapFacePosY, - CubemapFaceNegY, - CubemapFacePosZ, - CubemapFaceNegZ -} CubemapFace; - -/// Texture data descriptor. -typedef struct TextureDataDesc { - union { - const void* pixels; - struct { - const void* pixels_pos_x; - const void* pixels_neg_x; - const void* pixels_pos_y; - const void* pixels_neg_y; - const void* pixels_pos_z; - const void* pixels_neg_z; - } cubemap; - }; -} TextureDataDesc; - -/// Describes a texture. -typedef struct TextureDesc { - int width; - int height; - int depth; // Not used until 3D textures are exposed. - TextureDimension dimension; - TextureFormat format; - TextureFiltering filtering; - TextureWrapping wrap; - bool mipmaps; - TextureDataDesc data; -} TextureDesc; - -/// Describes a renderbuffer. -typedef struct RenderBufferDesc { - int width; - int height; - TextureFormat texture_format; -} RenderBufferDesc; - -/// Framebuffer attachment type. -typedef enum FrameBufferAttachmentType { - FrameBufferNoAttachment, - FrameBufferTexture, - FrameBufferCubemapTexture, - FrameBufferRenderBuffer -} FrameBufferAttachmentType; - -/// Describes a framebuffer attachment. -typedef struct FrameBufferAttachment { - FrameBufferAttachmentType type; - union { - struct { - Texture* texture; - int mip_level; - } texture; - struct { - Texture* texture; - int mip_level; - CubemapFace face; - } cubemap; - RenderBuffer* renderbuffer; - }; -} FrameBufferAttachment; - -/// Describes a framebuffer. -typedef struct FrameBufferDesc { - FrameBufferAttachment colour; - FrameBufferAttachment depth; -} FrameBufferDesc; - -// ----------------------------------------------------------------------------- -// Render commands. -// ----------------------------------------------------------------------------- - -/// Start a new frame. -void gfx_start_frame(RenderBackend*); - -/// End a frame. -void gfx_end_frame(RenderBackend*); - -/// Set the render backend's viewport dimensions. -void gfx_set_viewport(RenderBackend*, int width, int height); - -/// Get the render backend's viewport dimensions. -void gfx_get_viewport(RenderBackend*, int* width, int* height); - -/// Set blending state. -void gfx_set_blending(RenderBackend*, bool enable); - -/// Set depth mask. -void gfx_set_depth_mask(RenderBackend*, bool enable); - -/// Set cull mode. -void gfx_set_culling(RenderBackend*, bool enable); - -/// Set polygon offset. -void gfx_set_polygon_offset(RenderBackend*, float scale, float bias); - -/// Reset the polygon offset. -void gfx_reset_polygon_offset(RenderBackend*); - -// ----------------------------------------------------------------------------- -// Buffers. -// ----------------------------------------------------------------------------- - -/// Create a buffer from raw data. -Buffer* gfx_make_buffer(RenderBackend*, const BufferDesc*); - -/// Destroy the buffer. -void gfx_destroy_buffer(RenderBackend*, Buffer**); - -/// Update the buffer's data. -void gfx_update_buffer(Buffer*, const BufferDataDesc*); - -// ----------------------------------------------------------------------------- -// Geometry. -// ----------------------------------------------------------------------------- - -/// Create geometry. -Geometry* gfx_make_geometry(RenderBackend*, const GeometryDesc*); - -/// Destroy the geometry. -void gfx_destroy_geometry(RenderBackend*, Geometry**); - -/// Upload new vertex data for the geometry. -/// -/// This is similar to gfx_make_geometry(), but the geometry need not be -/// entirely specified. -/// -/// Only the vertex attributes, vertex count, and index count set in the -/// descriptor are updated. Index data, primitive type, and other properties of -/// the geometry are not updated. -/// -/// New data must be given as arrays in host memory. That is, the buffer views -/// in the descriptor must point to CPU arrays, not GPU buffers. -/// -/// Note that the descriptor cannot specify a larger vertex or index count than -/// what the geometry was created with. If the geometry size or any other -/// attribute not handled by this update function needs to be changed, then a -/// new geometry must be created. -void gfx_update_geometry(Geometry*, const GeometryDesc*); - -/// Render the geometry. -void gfx_render_geometry(const Geometry*); - -/// Return the geometry's bounding box. -aabb3 gfx_get_geometry_aabb(const Geometry*); - -// ----------------------------------------------------------------------------- -// Textures. -// ----------------------------------------------------------------------------- - -/// Create a texture. -Texture* gfx_make_texture(RenderBackend*, const TextureDesc*); - -/// Destroy the texture. -void gfx_destroy_texture(RenderBackend*, Texture**); - -/// Update the texture. -void gfx_update_texture(Texture*, const TextureDataDesc*); - -// ----------------------------------------------------------------------------- -// Renderbuffers. -// ----------------------------------------------------------------------------- - -/// Create a renderbuffer. -RenderBuffer* gfx_make_renderbuffer(RenderBackend*, const RenderBufferDesc*); - -/// Destroy the renderbuffer. -void gfx_destroy_renderbuffer(RenderBackend*, RenderBuffer**); - -// ----------------------------------------------------------------------------- -// Framebuffers. -// ----------------------------------------------------------------------------- - -/// Create a framebuffer. -FrameBuffer* gfx_make_framebuffer(RenderBackend*, const FrameBufferDesc*); - -/// Destroy the framebuffer. -void gfx_destroy_framebuffer(RenderBackend*, FrameBuffer**); - -/// Attach a colour buffer to the framebuffer. -bool gfx_framebuffer_attach_colour(FrameBuffer*, const FrameBufferAttachment*); - -/// Attach a depth buffer to the framebuffer. -bool gfx_framebuffer_attach_depth(FrameBuffer*, const FrameBufferAttachment*); - -/// Activate the framebuffer. -/// Subsequent draw calls write to this framebuffer. -void gfx_activate_framebuffer(const FrameBuffer*); - -/// Deactivate the framebuffer. -/// Subsequent draw calls write to the default framebuffer. -void gfx_deactivate_framebuffer(const FrameBuffer*); - -/// Set the framebuffer's viewport. -/// This function should be called every time the framebuffer is activated. -void gfx_framebuffer_set_viewport( - FrameBuffer*, int x, int y, int width, int height); - -// ----------------------------------------------------------------------------- -// Shaders. -// ----------------------------------------------------------------------------- - -/// Create a shader. -Shader* gfx_make_shader(RenderBackend*, const ShaderDesc*); - -/// Destroy the shader. -void gfx_destroy_shader(RenderBackend*, Shader**); - -/// Create a shader program. -ShaderProgram* gfx_make_shader_program( - RenderBackend*, const ShaderProgramDesc*); - -/// Destroy the shader program. -void gfx_destroy_shader_program(RenderBackend*, ShaderProgram**); - -/// Activate the shader program. -void gfx_activate_shader_program(const ShaderProgram*); - -/// Deactivate the shader program. -void gfx_deactivate_shader_program(const ShaderProgram*); - -/// Apply the shader program's uniform variables. -/// -/// Calls to gfx_set_XYZ_uniform save the values of the uniform variables in the -/// graphics library. By calling this function, those values are passed on to -/// the graphics driver for rendering. -/// -/// This function should be called after setting all of the uniform variables -/// and prior to issuing a draw call. -void gfx_apply_uniforms(const ShaderProgram*); - -/// Set the texture uniform. -/// Has no effect if the shader does not contain the given uniform. -void gfx_set_texture_uniform(ShaderProgram*, const char* name, const Texture*); - -/// Set the matrix uniform. -/// Has no effect if the shader does not contain the given uniform. -void gfx_set_mat4_uniform(ShaderProgram*, const char* name, const mat4*); - -/// Set the vec3 uniform. -/// Has no effect if the shader does not contain the given uniform. -void gfx_set_vec3_uniform(ShaderProgram*, const char* name, vec3); - -/// Set the vec4 uniform. -/// Has no effect if the shader does not contain the given uniform. -void gfx_set_vec4_uniform(ShaderProgram*, const char* name, vec4); - -/// Set the float uniform. -/// Has no effect if the shader does not contain the given uniform. -void gfx_set_float_uniform(ShaderProgram*, const char* name, float value); - -/// Set the matrix array uniform. -/// Has no effect if the shader does not contain the given uniform. -void gfx_set_mat4_array_uniform( - ShaderProgram*, const char* name, const mat4*, size_t count); diff --git a/gfx/include/gfx/renderer.h b/gfx/include/gfx/renderer.h index 9236e3f..2a4ada1 100644 --- a/gfx/include/gfx/renderer.h +++ b/gfx/include/gfx/renderer.h @@ -8,9 +8,9 @@ #include #include -typedef struct RenderBackend RenderBackend; -typedef struct Scene Scene; -typedef struct SceneCamera SceneCamera; +typedef struct GfxCore GfxCore; +typedef struct Scene Scene; +typedef struct SceneCamera SceneCamera; typedef struct ImmRenderer ImmRenderer; typedef struct Renderer Renderer; diff --git a/gfx/include/gfx/scene/material.h b/gfx/include/gfx/scene/material.h index 07e31d4..bca664e 100644 --- a/gfx/include/gfx/scene/material.h +++ b/gfx/include/gfx/scene/material.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include typedef struct Material Material; diff --git a/gfx/include/gfx/util/geometry.h b/gfx/include/gfx/util/geometry.h index c62022b..a962291 100644 --- a/gfx/include/gfx/util/geometry.h +++ b/gfx/include/gfx/util/geometry.h @@ -1,13 +1,13 @@ /// Functions to construct geometry procedurally. #pragma once -#include +#include #include #include /// Construct a quad with positions in the range [-1, 1]^2. -Geometry* gfx_make_quad_11(RenderBackend*); +Geometry* gfx_make_quad_11(GfxCore*); /// Construct a quad with positions in the range [0, 1]^2. -Geometry* gfx_make_quad_01(RenderBackend*); +Geometry* gfx_make_quad_01(GfxCore*); diff --git a/gfx/include/gfx/util/ibl.h b/gfx/include/gfx/util/ibl.h index 5d76e54..6e39180 100644 --- a/gfx/include/gfx/util/ibl.h +++ b/gfx/include/gfx/util/ibl.h @@ -3,26 +3,23 @@ typedef struct IBL IBL; -typedef struct RenderBackend RenderBackend; +typedef struct GfxCore GfxCore; typedef struct Texture Texture; /// Create an environment map filterer for IBL. -IBL* gfx_make_ibl(RenderBackend*); +IBL* gfx_make_ibl(GfxCore*); /// Destroy the environment map filterer. -void gfx_destroy_ibl(RenderBackend*, IBL**); +void gfx_destroy_ibl(GfxCore*, IBL**); /// Create a BRDF integration map for IBL. -Texture* gfx_make_brdf_integration_map(IBL*, RenderBackend*, int width, - int height); +Texture* gfx_make_brdf_integration_map(IBL*, GfxCore*, int width, int height); /// Create an irradiance map (cubemap) from an environment map for IBL. -Texture* gfx_make_irradiance_map(IBL*, RenderBackend*, - const Texture* environment_map, int width, - int height); +Texture* gfx_make_irradiance_map( + IBL*, GfxCore*, const Texture* environment_map, int width, int height); /// Create a prefiltered environment map (cubemap) for IBL. -Texture* gfx_make_prefiltered_environment_map(IBL*, RenderBackend*, - const Texture* environment_map, - int width, int height, - int* max_mip_level); +Texture* gfx_make_prefiltered_environment_map( + IBL*, GfxCore*, const Texture* environment_map, int width, int height, + int* max_mip_level); diff --git a/gfx/include/gfx/util/shader.h b/gfx/include/gfx/util/shader.h index 9bde8cf..bd058f4 100644 --- a/gfx/include/gfx/util/shader.h +++ b/gfx/include/gfx/util/shader.h @@ -3,44 +3,44 @@ #include -typedef struct RenderBackend RenderBackend; +typedef struct GfxCore GfxCore; typedef struct ShaderCompilerDefine ShaderCompilerDefine; typedef struct ShaderProgram ShaderProgram; /// Create a BRDF integration map shader. -ShaderProgram* gfx_make_brdf_integration_map_shader(RenderBackend*); +ShaderProgram* gfx_make_brdf_integration_map_shader(GfxCore*); /// Create a Cook-Torrance shader. -ShaderProgram* gfx_make_cook_torrance_shader(RenderBackend*); +ShaderProgram* gfx_make_cook_torrance_shader(GfxCore*); /// Create a Cook-Torrance shader with additional shader compiler defines. /// This function can be used to create shader permutations. ShaderProgram* gfx_make_cook_torrance_shader_perm( - RenderBackend*, const ShaderCompilerDefine*, size_t num_defines); + GfxCore*, const ShaderCompilerDefine*, size_t num_defines); /// Create a 3D debugging shader. -ShaderProgram* gfx_make_debug3d_shader(RenderBackend*); +ShaderProgram* gfx_make_debug3d_shader(GfxCore*); /// Create a shader for drawing in immediate mode. -ShaderProgram* gfx_make_immediate_mode_shader(RenderBackend*); +ShaderProgram* gfx_make_immediate_mode_shader(GfxCore*); /// Create a shader for computing irradiance maps from cube maps. -ShaderProgram* gfx_make_irradiance_map_shader(RenderBackend*); +ShaderProgram* gfx_make_irradiance_map_shader(GfxCore*); /// Create a shader for computing prefiltered environment maps from cube maps. -ShaderProgram* gfx_make_prefiltered_environment_map_shader(RenderBackend*); +ShaderProgram* gfx_make_prefiltered_environment_map_shader(GfxCore*); /// Create a skyquad shader. -ShaderProgram* gfx_make_skyquad_shader(RenderBackend*); +ShaderProgram* gfx_make_skyquad_shader(GfxCore*); /// Create a shader to view normal-mapped normals. -ShaderProgram* gfx_make_view_normal_mapped_normals_shader(RenderBackend*); +ShaderProgram* gfx_make_view_normal_mapped_normals_shader(GfxCore*); /// Create a shader to view vertex normals. -ShaderProgram* gfx_make_view_normals_shader(RenderBackend*); +ShaderProgram* gfx_make_view_normals_shader(GfxCore*); /// Create a shader to view vertex tangents. -ShaderProgram* gfx_make_view_tangents_shader(RenderBackend*); +ShaderProgram* gfx_make_view_tangents_shader(GfxCore*); /// Create a shader to view textures. -ShaderProgram* gfx_make_view_texture_shader(RenderBackend*); +ShaderProgram* gfx_make_view_texture_shader(GfxCore*); diff --git a/gfx/include/gfx/util/skyquad.h b/gfx/include/gfx/util/skyquad.h index 923c6e5..2b3fe17 100644 --- a/gfx/include/gfx/util/skyquad.h +++ b/gfx/include/gfx/util/skyquad.h @@ -1,14 +1,14 @@ /// A skyquad is like a skybox but with a single quad. #pragma once -typedef struct RenderBackend RenderBackend; -typedef struct Scene Scene; -typedef struct SceneNode SceneNode; -typedef struct SceneObject SceneObject; -typedef struct Texture Texture; +typedef struct GfxCore GfxCore; +typedef struct Scene Scene; +typedef struct SceneNode SceneNode; +typedef struct SceneObject SceneObject; +typedef struct Texture Texture; /// Create a skyquad. -SceneObject* gfx_make_skyquad(RenderBackend*, const Texture*); +SceneObject* gfx_make_skyquad(GfxCore*, const Texture*); /// Set up a skyquad in the scene. /// @@ -19,4 +19,4 @@ SceneObject* gfx_make_skyquad(RenderBackend*, const Texture*); /// Return the light node under which objects affected by the light can be /// rooted. SceneNode* gfx_setup_skyquad( - RenderBackend*, SceneNode* root, const Texture* environment_map); + GfxCore*, SceneNode* root, const Texture* environment_map); diff --git a/gfx/src/asset/asset_cache.c b/gfx/src/asset/asset_cache.c index d077421..16c4d5c 100644 --- a/gfx/src/asset/asset_cache.c +++ b/gfx/src/asset/asset_cache.c @@ -237,8 +237,8 @@ const Texture* gfx_load_texture(Gfx* gfx, const LoadTextureCmd* cmd) { // Asset not found in the cache. // Load it, insert it into the cache, and return it. - RenderBackend* render_backend = gfx_get_render_backend(gfx); - const Texture* texture = gfx_texture_load(render_backend, cmd); + GfxCore* gfxcore = gfx_get_core(gfx); + const Texture* texture = gfx_texture_load(gfxcore, cmd); if (texture) { *(Asset*)mempool_alloc(&cache->assets) = (Asset){ .type = TextureAsset, diff --git a/gfx/src/asset/model.c b/gfx/src/asset/model.c index 2053dc4..75f922f 100644 --- a/gfx/src/asset/model.c +++ b/gfx/src/asset/model.c @@ -82,8 +82,8 @@ #include "asset/model.h" #include "asset/texture.h" +#include "gfx/core.h" #include "gfx/gfx.h" -#include "gfx/render_backend.h" #include "gfx/scene/animation.h" #include "gfx/scene/camera.h" #include "gfx/scene/material.h" @@ -208,7 +208,7 @@ static size_t make_defines( /// Compile a shader permutation. static ShaderProgram* make_shader_permutation( - RenderBackend* render_backend, MeshPermutation perm) { + GfxCore* gfxcore, MeshPermutation perm) { LOGD( "Compiling Cook-Torrance shader permutation: texcoords: %d, normals: " "%d, tangents: %d, joints: %d, weights: %d, albedo map: %d, " @@ -221,8 +221,7 @@ static ShaderProgram* make_shader_permutation( ShaderCompilerDefine defines[GFX_MAX_SHADER_COMPILER_DEFINES]; const size_t num_defines = make_defines(perm, defines); - return gfx_make_cook_torrance_shader_perm( - render_backend, defines, num_defines); + return gfx_make_cook_torrance_shader_perm(gfxcore, defines, num_defines); } /// Map a texture type to the name of the shader uniform used to access the @@ -570,20 +569,20 @@ static size_t get_total_primitives(const cgltf_data* data) { /// TODO: There is no need to load the inverse bind matrices buffer into the /// GPU. Might need to lazily load buffers. static bool load_buffers( - const cgltf_data* data, RenderBackend* render_backend, Buffer** buffers) { + const cgltf_data* data, GfxCore* gfxcore, Buffer** buffers) { assert(data); - assert(render_backend); + assert(gfxcore); assert(buffers); for (cgltf_size i = 0; i < data->buffers_count; ++i) { const cgltf_buffer* buffer = &data->buffers[i]; assert(buffer->data); buffers[i] = gfx_make_buffer( - render_backend, &(BufferDesc){ - .usage = BufferStatic, - .type = BufferUntyped, - .data.data = buffer->data, - .data.count = buffer->size}); + gfxcore, &(BufferDesc){ + .usage = BufferStatic, + .type = BufferUntyped, + .data.data = buffer->data, + .data.count = buffer->size}); if (!buffers[i]) { return false; } @@ -595,21 +594,21 @@ static bool load_buffers( /// Load tangent buffers. static bool load_tangent_buffers( const cgltfTangentBuffer* cgltf_tangent_buffers, - cgltf_size num_tangent_buffers, RenderBackend* render_backend, + cgltf_size num_tangent_buffers, GfxCore* gfxcore, Buffer** tangent_buffers) { assert(cgltf_tangent_buffers); - assert(render_backend); + assert(gfxcore); assert(tangent_buffers); for (cgltf_size i = 0; i < num_tangent_buffers; ++i) { const cgltfTangentBuffer* buffer = &cgltf_tangent_buffers[i]; assert(buffer->data); tangent_buffers[i] = gfx_make_buffer( - render_backend, &(BufferDesc){ - .usage = BufferStatic, - .type = BufferUntyped, - .data.data = buffer->data, - .data.count = buffer->size_bytes}); + gfxcore, &(BufferDesc){ + .usage = BufferStatic, + .type = BufferUntyped, + .data.data = buffer->data, + .data.count = buffer->size_bytes}); if (!tangent_buffers[i]) { return false; } @@ -631,10 +630,10 @@ static bool load_tangent_buffers( /// Return an array of LoadTextureCmds such that the index of each cmd matches /// the index of each glTF texture in the scene. static void load_textures_lazy( - const cgltf_data* data, RenderBackend* render_backend, - const char* directory, LoadTextureCmd* load_texture_cmds) { + const cgltf_data* data, GfxCore* gfxcore, const char* directory, + LoadTextureCmd* load_texture_cmds) { assert(data); - assert(render_backend); + assert(gfxcore); assert(load_texture_cmds); for (cgltf_size i = 0; i < data->textures_count; ++i) { @@ -908,7 +907,7 @@ aabb3 compute_aabb(const cgltf_accessor* accessor) { /// Load all meshes from the glTF scene. static bool load_meshes( - const cgltf_data* data, RenderBackend* render_backend, Buffer** buffers, + const cgltf_data* data, GfxCore* gfxcore, Buffer** buffers, Buffer** tangent_buffers, const cgltfTangentBuffer* cgltf_tangent_buffers, cgltf_size num_tangent_buffers, Material** materials, ShaderProgram* const shader, size_t primitive_count, Geometry** geometries, @@ -924,7 +923,7 @@ static bool load_meshes( // Accessor + buffer view BufferView // Buffer Buffer assert(data); - assert(render_backend); + assert(gfxcore); assert(buffers); assert(materials); assert(geometries); @@ -1175,7 +1174,7 @@ static bool load_meshes( } assert(material); - geometries[next_mesh] = gfx_make_geometry(render_backend, &geometry_desc); + geometries[next_mesh] = gfx_make_geometry(gfxcore, &geometry_desc); if (!geometries[next_mesh]) { return false; } @@ -1190,7 +1189,7 @@ static bool load_meshes( // values. Also, changing uniforms is much faster than swapping shaders, // so shader caching is the most important thing here. ShaderProgram* mesh_shader = - shader ? shader : make_shader_permutation(render_backend, perm); + shader ? shader : make_shader_permutation(gfxcore, perm); assert(mesh_shader); meshes[next_mesh] = gfx_make_mesh(&(MeshDesc){ @@ -1277,7 +1276,7 @@ static void compute_joint_bounding_boxes( for (int i = 0; i < 4; ++i) { const size_t joint_index = j[i]; assert((size_t)joint_index < num_joints); - + joint_descs[joint_index].box = aabb3_add(joint_descs[joint_index].box, p); } @@ -1699,8 +1698,8 @@ static Model* load_scene( bool success = false; - RenderBackend* render_backend = gfx_get_render_backend(gfx); - const size_t primitive_count = get_total_primitives(data); + GfxCore* gfxcore = gfx_get_core(gfx); + const size_t primitive_count = get_total_primitives(data); const mstring directory = mstring_dirname(*filepath); LOGD("Filepath: %s", mstring_cstr(filepath)); @@ -1745,18 +1744,18 @@ static Model* load_scene( if ((num_tangent_buffers > 0) && !load_tangent_buffers( - cgltf_tangent_buffers, num_tangent_buffers, render_backend, + cgltf_tangent_buffers, num_tangent_buffers, gfxcore, tangent_buffers)) { goto cleanup; } - if (!load_buffers(data, render_backend, buffers)) { + if (!load_buffers(data, gfxcore, buffers)) { goto cleanup; } if (data->textures_count > 0) { load_textures_lazy( - data, render_backend, mstring_cstr(&directory), load_texture_cmds); + data, gfxcore, mstring_cstr(&directory), load_texture_cmds); } if (!load_materials(data, gfx, load_texture_cmds, textures, materials)) { @@ -1764,7 +1763,7 @@ static Model* load_scene( } if (!load_meshes( - data, render_backend, buffers, tangent_buffers, cgltf_tangent_buffers, + data, gfxcore, buffers, tangent_buffers, cgltf_tangent_buffers, num_tangent_buffers, materials, shader, primitive_count, geometries, meshes, scene_objects)) { goto cleanup; @@ -1823,7 +1822,7 @@ cleanup: if (!success) { for (cgltf_size i = 0; i < num_tangent_buffers; ++i) { if (tangent_buffers[i]) { - gfx_destroy_buffer(render_backend, &tangent_buffers[i]); + gfx_destroy_buffer(gfxcore, &tangent_buffers[i]); } } } @@ -1833,7 +1832,7 @@ cleanup: if (!success) { for (cgltf_size i = 0; i < data->buffers_count; ++i) { if (buffers[i]) { - gfx_destroy_buffer(render_backend, &buffers[i]); + gfx_destroy_buffer(gfxcore, &buffers[i]); } } } @@ -1859,7 +1858,7 @@ cleanup: if (!success) { for (size_t i = 0; i < primitive_count; ++i) { if (geometries[i]) { - gfx_destroy_geometry(render_backend, &geometries[i]); + gfx_destroy_geometry(gfxcore, &geometries[i]); } } } diff --git a/gfx/src/asset/texture.c b/gfx/src/asset/texture.c index 3a82788..c790394 100644 --- a/gfx/src/asset/texture.c +++ b/gfx/src/asset/texture.c @@ -1,6 +1,6 @@ #include "texture.h" -#include "gfx/render_backend.h" +#include "gfx/core.h" #include "error.h" @@ -43,9 +43,8 @@ static void flip_horizontally( // For this reason, we do X and Y flips when doing cubemap textures so that we // can sample cubemaps as if they were given in the usual OpenGL coordinate // system. -Texture* gfx_texture_load( - RenderBackend* render_backend, const LoadTextureCmd* cmd) { - assert(render_backend); +Texture* gfx_texture_load(GfxCore* gfxcore, const LoadTextureCmd* cmd) { + assert(gfxcore); assert(cmd); assert(cmd->origin == AssetFromFile || cmd->origin == AssetFromMemory); assert(cmd->type == LoadTexture || cmd->type == LoadCubemap); @@ -168,7 +167,7 @@ Texture* gfx_texture_load( break; } - Texture* texture = gfx_make_texture(render_backend, &desc); + Texture* texture = gfx_make_texture(gfxcore, &desc); for (int i = 0; i < 6; ++i) { if (pixels[i]) { stbi_image_free(pixels[i]); diff --git a/gfx/src/asset/texture.h b/gfx/src/asset/texture.h index a3239fe..0d38bd9 100644 --- a/gfx/src/asset/texture.h +++ b/gfx/src/asset/texture.h @@ -4,4 +4,4 @@ #include /// Load a texture. -Texture* gfx_texture_load(RenderBackend*, const LoadTextureCmd*); +Texture* gfx_texture_load(GfxCore*, const LoadTextureCmd*); diff --git a/gfx/src/gfx.c b/gfx/src/gfx.c index 7095ea1..8c513a1 100644 --- a/gfx/src/gfx.c +++ b/gfx/src/gfx.c @@ -1,7 +1,7 @@ #include #include "asset/asset_cache.h" -#include "render/render_backend_impl.h" +#include "render/core_impl.h" #include "renderer/imm_renderer_impl.h" #include "renderer/renderer_impl.h" #include "scene/scene_graph.h" @@ -15,10 +15,10 @@ #include typedef struct Gfx { - AssetCache asset_cache; - RenderBackend render_backend; - Renderer renderer; - ImmRenderer imm_renderer; + AssetCache asset_cache; + GfxCore gfxcore; + Renderer renderer; + ImmRenderer imm_renderer; } Gfx; Gfx* gfx_init(void) { @@ -31,12 +31,12 @@ Gfx* gfx_init(void) { if (!gfx) { return 0; } - gfx_init_render_backend(&gfx->render_backend); - if (!renderer_make(&gfx->renderer, &gfx->render_backend)) { + gfx_init_gfxcore(&gfx->gfxcore); + if (!renderer_make(&gfx->renderer, &gfx->gfxcore)) { gfx_destroy(&gfx); return 0; } - if (!imm_renderer_make(&gfx->imm_renderer, &gfx->render_backend)) { + if (!imm_renderer_make(&gfx->imm_renderer, &gfx->gfxcore)) { // TODO: Add error logs to the initialization failure cases here and inside // the renderers. gfx_destroy(&gfx); @@ -55,14 +55,14 @@ void gfx_destroy(Gfx** gfx) { gfx_destroy_asset_cache(&(*gfx)->asset_cache); renderer_destroy(&(*gfx)->renderer); imm_renderer_destroy(&(*gfx)->imm_renderer); - gfx_del_render_backend(&(*gfx)->render_backend); + gfx_del_gfxcore(&(*gfx)->gfxcore); free(*gfx); *gfx = 0; } -RenderBackend* gfx_get_render_backend(Gfx* gfx) { +GfxCore* gfx_get_core(Gfx* gfx) { assert(gfx); - return &gfx->render_backend; + return &gfx->gfxcore; } Renderer* gfx_get_renderer(Gfx* gfx) { diff --git a/gfx/src/render/buffer.c b/gfx/src/render/buffer.c index 28877bb..3b7e4bc 100644 --- a/gfx/src/render/buffer.c +++ b/gfx/src/render/buffer.c @@ -1,6 +1,6 @@ #include "buffer.h" -#include +#include #include #include @@ -57,7 +57,7 @@ bool gfx_init_buffer(Buffer* buffer, const BufferDesc* desc) { glBufferData(GL_ARRAY_BUFFER, buffer->size_bytes, desc->data.data, usage); glBindBuffer(GL_ARRAY_BUFFER, 0); ASSERT_GL; - + return true; } diff --git a/gfx/src/render/buffer.h b/gfx/src/render/buffer.h index 3adfd8e..b9080f0 100644 --- a/gfx/src/render/buffer.h +++ b/gfx/src/render/buffer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "gl_util.h" diff --git a/gfx/src/render/core.c b/gfx/src/render/core.c new file mode 100644 index 0000000..7a6d9cc --- /dev/null +++ b/gfx/src/render/core.c @@ -0,0 +1,414 @@ +#include "core_impl.h" + +#include "gl_util.h" + +// #include + +#include + +void gfx_init_gfxcore(GfxCore* gfxcore) { + assert(gfxcore); + + mempool_make(&gfxcore->buffers); + mempool_make(&gfxcore->framebuffers); + mempool_make(&gfxcore->geometries); + mempool_make(&gfxcore->renderbuffers); + mempool_make(&gfxcore->shaders); + mempool_make(&gfxcore->shader_programs); + mempool_make(&gfxcore->textures); + + mempool_make(&gfxcore->shader_cache); + mempool_make(&gfxcore->program_cache); + + glEnable(GL_CULL_FACE); + glFrontFace(GL_CCW); + glCullFace(GL_BACK); + + glEnable(GL_DEPTH_TEST); + + // Filter cubemaps across their faces to avoid seams. + // https://www.khronos.org/opengl/wiki/Cubemap_Texture#Seamless_cubemap + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); +} + +// Conveniently destroy any objects that have not been destroyed by the +// application. +void gfx_del_gfxcore(GfxCore* gfxcore) { + assert(gfxcore); + + mempool_foreach(&gfxcore->buffers, buffer, { gfx_del_buffer(buffer); }); + + mempool_foreach(&gfxcore->framebuffers, framebuffer, { + gfx_del_framebuffer(framebuffer); + }); + + mempool_foreach( + &gfxcore->geometries, geometry, { gfx_del_geometry(geometry); }); + + mempool_foreach(&gfxcore->renderbuffers, renderbuffer, { + gfx_del_renderbuffer(renderbuffer); + }); + + mempool_foreach( + &gfxcore->shader_programs, prog, { gfx_del_shader_program(prog); }); + + mempool_foreach(&gfxcore->shaders, shader, { gfx_del_shader(shader); }); + + mempool_foreach(&gfxcore->textures, texture, { gfx_del_texture(texture); }); +} + +// ----------------------------------------------------------------------------- +// Render commands. +// ----------------------------------------------------------------------------- + +void gfx_start_frame(GfxCore* gfxcore) { + assert(gfxcore); + + glViewport(0, 0, gfxcore->viewport.width, gfxcore->viewport.height); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + ASSERT_GL; +} + +void gfx_end_frame(GfxCore* gfxcore) { + assert(gfxcore); + ASSERT_GL; +} + +void gfx_set_viewport(GfxCore* gfxcore, int width, int height) { + assert(gfxcore); + gfxcore->viewport.width = width; + gfxcore->viewport.height = height; +} + +void gfx_get_viewport(GfxCore* gfxcore, int* width, int* height) { + assert(gfxcore); + assert(width); + assert(height); + *width = gfxcore->viewport.width; + *height = gfxcore->viewport.height; +} + +void gfx_set_blending(GfxCore* gfxcore, bool enable) { + assert(gfxcore); + if (enable) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } else { + glDisable(GL_BLEND); + } +} + +void gfx_set_depth_mask(GfxCore* gfxcore, bool enable) { + assert(gfxcore); + glDepthMask(enable ? GL_TRUE : GL_FALSE); +} + +void gfx_set_culling(GfxCore* gfxcore, bool enable) { + assert(gfxcore); + if (enable) { + glEnable(GL_CULL_FACE); + } else { + glDisable(GL_CULL_FACE); + } +} + +void gfx_set_polygon_offset(GfxCore* gfxcore, float scale, float bias) { + assert(gfxcore); + if ((scale != 0.0f) || (bias != 0.0f)) { + glEnable(GL_POLYGON_OFFSET_FILL); + } else { + glDisable(GL_POLYGON_OFFSET_FILL); + } + glPolygonOffset(scale, bias); +} + +void gfx_reset_polygon_offset(GfxCore* gfxcore) { + assert(gfxcore); + glPolygonOffset(0, 0); + glDisable(GL_POLYGON_OFFSET_FILL); +} + +// ----------------------------------------------------------------------------- +// Buffers. +// ----------------------------------------------------------------------------- + +Buffer* gfx_make_buffer(GfxCore* gfxcore, const BufferDesc* desc) { + assert(gfxcore); + assert(desc); + + Buffer* buffer = mempool_alloc(&gfxcore->buffers); + if (!gfx_init_buffer(buffer, desc)) { + mempool_free(&gfxcore->buffers, &buffer); + return 0; + } + return buffer; +} + +void gfx_destroy_buffer(GfxCore* gfxcore, Buffer** buffer) { + assert(gfxcore); + assert(buffer); + if (*buffer) { + gfx_del_buffer(*buffer); + mempool_free(&gfxcore->buffers, buffer); + } +} + +// ----------------------------------------------------------------------------- +// Geometry. +// ----------------------------------------------------------------------------- + +Geometry* gfx_make_geometry(GfxCore* gfxcore, const GeometryDesc* desc) { + assert(gfxcore); + assert(desc); + + Geometry* geometry = mempool_alloc(&gfxcore->geometries); + if (!gfx_init_geometry(geometry, gfxcore, desc)) { + mempool_free(&gfxcore->geometries, &geometry); + return 0; + } + return geometry; +} + +void gfx_destroy_geometry(GfxCore* gfxcore, Geometry** geometry) { + assert(gfxcore); + assert(geometry); + + if (*geometry) { + gfx_del_geometry(*geometry); + mempool_free(&gfxcore->geometries, geometry); + } +} + +// ----------------------------------------------------------------------------- +// Textures. +// ----------------------------------------------------------------------------- + +Texture* gfx_make_texture(GfxCore* gfxcore, const TextureDesc* desc) { + assert(gfxcore); + assert(desc); + + Texture* texture = mempool_alloc(&gfxcore->textures); + if (!gfx_init_texture(texture, desc)) { + mempool_free(&gfxcore->textures, &texture); + return 0; + } + return texture; +} + +void gfx_destroy_texture(GfxCore* gfxcore, Texture** texture) { + assert(gfxcore); + assert(texture); + assert(*texture); + + if (*texture) { + gfx_del_texture(*texture); + mempool_free(&gfxcore->textures, texture); + } +} + +// ----------------------------------------------------------------------------- +// Renderbuffers. +// ----------------------------------------------------------------------------- + +RenderBuffer* gfx_make_renderbuffer( + GfxCore* gfxcore, const RenderBufferDesc* desc) { + assert(gfxcore); + assert(desc); + + RenderBuffer* renderbuffer = mempool_alloc(&gfxcore->renderbuffers); + if (!gfx_init_renderbuffer(renderbuffer, desc)) { + mempool_free(&gfxcore->renderbuffers, &renderbuffer); + } + return renderbuffer; +} + +void gfx_destroy_renderbuffer(GfxCore* gfxcore, RenderBuffer** renderbuffer) { + assert(gfxcore); + assert(renderbuffer); + assert(*renderbuffer); + + if (*renderbuffer) { + gfx_del_renderbuffer(*renderbuffer); + mempool_free(&gfxcore->renderbuffers, renderbuffer); + } +} + +// ----------------------------------------------------------------------------- +// Framebuffers. +// ----------------------------------------------------------------------------- + +FrameBuffer* gfx_make_framebuffer( + GfxCore* gfxcore, const FrameBufferDesc* desc) { + assert(gfxcore); + assert(desc); + + FrameBuffer* framebuffer = mempool_alloc(&gfxcore->framebuffers); + if (!gfx_init_framebuffer(framebuffer, desc)) { + mempool_free(&gfxcore->framebuffers, &framebuffer); + return 0; + } + return framebuffer; +} + +void gfx_destroy_framebuffer(GfxCore* gfxcore, FrameBuffer** framebuffer) { + assert(gfxcore); + assert(framebuffer); + assert(*framebuffer); + + if (*framebuffer) { + gfx_del_framebuffer(*framebuffer); + mempool_free(&gfxcore->framebuffers, framebuffer); + } +} + +// ----------------------------------------------------------------------------- +// Shaders. +// ----------------------------------------------------------------------------- + +static uint64_t hash_shader_desc(const ShaderDesc* desc) { + assert(desc); + // Note that defines may affect shader permutations, so we need to hash those + // as well. + uint64_t hash = 0; + for (size_t i = 0; i < desc->num_defines; ++i) { + const ShaderCompilerDefine* define = &desc->defines[i]; + hash = (((hash << 13) + sstring_hash(define->name)) << 7) + + sstring_hash(define->value); + } + return (hash << 17) + cstring_hash(desc->code); +} + +static uint64_t hash_program_desc(const ShaderProgramDesc* desc) { + assert(desc); + return ((uint64_t)desc->vertex_shader->id << 32) | + (uint64_t)desc->fragment_shader->id; +} + +static Shader* find_cached_shader(ShaderCache* cache, uint64_t hash) { + assert(cache); + mempool_foreach(cache, entry, { + if (entry->hash == hash) { + return entry->shader; + } + }); + return 0; +} + +static ShaderProgram* find_cached_program(ProgramCache* cache, uint64_t hash) { + assert(cache); + mempool_foreach(cache, entry, { + if (entry->hash == hash) { + return entry->program; + } + }); + return 0; +} + +static ShaderCacheEntry* find_shader_cache_entry( + ShaderCache* cache, const Shader* shader) { + assert(cache); + assert(shader); + mempool_foreach(cache, entry, { + if (entry->shader == shader) { + return entry; + } + }); + return 0; +} + +static ShaderProgramCacheEntry* find_program_cache_entry( + ProgramCache* cache, const ShaderProgram* prog) { + assert(cache); + assert(prog); + mempool_foreach(cache, entry, { + if (entry->program == prog) { + return entry; + } + }); + return 0; +} + +Shader* gfx_make_shader(GfxCore* gfxcore, const ShaderDesc* desc) { + assert(gfxcore); + assert(desc); + + // Check the shader cache first. + ShaderCache* cache = &gfxcore->shader_cache; + const uint64_t hash = hash_shader_desc(desc); + Shader* shader = find_cached_shader(cache, hash); + if (shader) { + // LOGD("Found cached shader with hash [%lx]", hash); + return shader; + } + + shader = mempool_alloc(&gfxcore->shaders); + if (!shader) { + return 0; + } + if (!gfx_compile_shader(shader, desc)) { + mempool_free(&gfxcore->shaders, &shader); + return 0; + } + ShaderCacheEntry* entry = mempool_alloc(cache); + *entry = (ShaderCacheEntry){.hash = hash, .shader = shader}; + // LOGD("Added shader with hash [%lx] to cache", hash); + return shader; +} + +void gfx_destroy_shader(GfxCore* gfxcore, Shader** shader) { + assert(gfxcore); + assert(shader); + + if (*shader) { + // Remove the shader from the cache. + ShaderCache* cache = &gfxcore->shader_cache; + ShaderCacheEntry* entry = find_shader_cache_entry(cache, *shader); + assert(entry); // Must be there, shaders can't go untracked. + mempool_free(cache, &entry); + + gfx_del_shader(*shader); + mempool_free(&gfxcore->shaders, shader); + } +} + +ShaderProgram* gfx_make_shader_program( + GfxCore* gfxcore, const ShaderProgramDesc* desc) { + assert(gfxcore); + assert(desc); + + // Check the shader program cache first. + ProgramCache* cache = &gfxcore->program_cache; + const uint64_t hash = hash_program_desc(desc); + ShaderProgram* prog = find_cached_program(cache, hash); + if (prog) { + // LOGD("Found cached shader program with hash [%lx]", hash); + return prog; + } + + prog = mempool_alloc(&gfxcore->shader_programs); + if (!gfx_build_shader_program(prog, desc)) { + mempool_free(&gfxcore->shader_programs, &prog); + return 0; + } + ShaderProgramCacheEntry* entry = mempool_alloc(cache); + *entry = (ShaderProgramCacheEntry){.hash = hash, .program = prog}; + // LOGD("Added shader program with hash [%lx] to cache", hash); + return prog; +} + +void gfx_destroy_shader_program(GfxCore* gfxcore, ShaderProgram** prog) { + assert(gfxcore); + assert(prog); + if (*prog) { + // Remove the shader program from the cache. + ProgramCache* cache = &gfxcore->program_cache; + ShaderProgramCacheEntry* entry = find_program_cache_entry(cache, *prog); + assert(entry); // Must be there, shaders can't go untracked. + mempool_free(cache, &entry); + + gfx_del_shader_program(*prog); + mempool_free(&gfxcore->shader_programs, prog); + } +} diff --git a/gfx/src/render/core_impl.h b/gfx/src/render/core_impl.h new file mode 100644 index 0000000..e27c0f2 --- /dev/null +++ b/gfx/src/render/core_impl.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include + +#include "buffer.h" +#include "framebuffer.h" +#include "geometry.h" +#include "renderbuffer.h" +#include "shader.h" +#include "shader_program.h" +#include "texture.h" + +#include + +#include + +// TODO: Make a generic (hash, void*) structure and define functions over it. +// Then define a macro that defines type-safe macros given the type of the +// entry. +typedef struct ShaderCacheEntry { + uint64_t hash; + Shader* shader; +} ShaderCacheEntry; + +typedef struct ShaderProgramCacheEntry { + uint64_t hash; + ShaderProgram* program; +} ShaderProgramCacheEntry; + +DEF_MEMPOOL(buffer_pool, Buffer, GFX_MAX_NUM_BUFFERS) +DEF_MEMPOOL(framebuffer_pool, FrameBuffer, GFX_MAX_NUM_FRAMEBUFFERS) +DEF_MEMPOOL(geometry_pool, Geometry, GFX_MAX_NUM_GEOMETRIES) +DEF_MEMPOOL(renderbuffer_pool, RenderBuffer, GFX_MAX_NUM_RENDERBUFFERS) +DEF_MEMPOOL(shader_pool, Shader, GFX_MAX_NUM_SHADERS) +DEF_MEMPOOL(shader_program_pool, ShaderProgram, GFX_MAX_NUM_SHADER_PROGRAMS) +DEF_MEMPOOL(texture_pool, Texture, GFX_MAX_NUM_TEXTURES) + +DEF_MEMPOOL(ShaderCache, ShaderCacheEntry, GFX_MAX_NUM_SHADERS) +DEF_MEMPOOL(ProgramCache, ShaderProgramCacheEntry, GFX_MAX_NUM_SHADER_PROGRAMS) + +typedef struct { + int width; + int height; +} Viewport; + +typedef struct GfxCore { + Viewport viewport; + // mempools for render-specific objects: textures, geometry, etc. + buffer_pool buffers; + framebuffer_pool framebuffers; + geometry_pool geometries; + renderbuffer_pool renderbuffers; + shader_pool shaders; + shader_program_pool shader_programs; + texture_pool textures; + // Caches. + ShaderCache shader_cache; + ProgramCache program_cache; +} GfxCore; + +/// Create a new render backend. +void gfx_init_gfxcore(GfxCore*); + +/// Destroy the render backend. +void gfx_del_gfxcore(GfxCore*); diff --git a/gfx/src/render/framebuffer.h b/gfx/src/render/framebuffer.h index 7153b30..1a3439c 100644 --- a/gfx/src/render/framebuffer.h +++ b/gfx/src/render/framebuffer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "gl_util.h" diff --git a/gfx/src/render/geometry.c b/gfx/src/render/geometry.c index 8974387..cfc749f 100644 --- a/gfx/src/render/geometry.c +++ b/gfx/src/render/geometry.c @@ -30,11 +30,11 @@ static GLenum primitive_type_to_gl(PrimitiveType type) { /// Create a typed buffer for the buffer view if the view does not already point /// to a buffer. void init_view_buffer( - RenderBackend* render_backend, BufferView* view, BufferType buffer_type, + GfxCore* gfxcore, BufferView* view, BufferType buffer_type, BufferUsage buffer_usage) { if (!view->buffer) { view->buffer = gfx_make_buffer( - render_backend, + gfxcore, &(BufferDesc){ .usage = buffer_usage, .type = buffer_type, @@ -47,10 +47,10 @@ void init_view_buffer( /// Configure the buffer in teh VAO. static void configure_buffer( - RenderBackend* render_backend, const GeometryDesc* desc, BufferView* view, + GfxCore* gfxcore, const GeometryDesc* desc, BufferView* view, size_t num_components, size_t component_size_bytes, GLenum component_type, GLboolean normalized, GLuint channel) { - assert(render_backend); + assert(gfxcore); assert(desc); assert(view); assert(view->buffer); @@ -78,127 +78,117 @@ static void configure_buffer( glBindBuffer(GL_ARRAY_BUFFER, 0); } -static bool configure_vertex_attributes( - RenderBackend* render_backend, GeometryDesc* desc) { - assert(render_backend); +static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) { + assert(gfxcore); assert(desc); if (view_is_populated(desc->positions3d)) { init_view_buffer( - render_backend, (BufferView*)&desc->positions3d, Buffer3d, - desc->buffer_usage); + gfxcore, (BufferView*)&desc->positions3d, Buffer3d, desc->buffer_usage); if (!desc->positions3d.buffer) { return false; } configure_buffer( - render_backend, desc, (BufferView*)&desc->positions3d, 3, sizeof(float), + gfxcore, desc, (BufferView*)&desc->positions3d, 3, sizeof(float), GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL); } else if (view_is_populated(desc->positions2d)) { init_view_buffer( - render_backend, (BufferView*)&desc->positions2d, Buffer2d, - desc->buffer_usage); + gfxcore, (BufferView*)&desc->positions2d, Buffer2d, desc->buffer_usage); if (!desc->positions2d.buffer) { return false; } configure_buffer( - render_backend, desc, (BufferView*)&desc->positions2d, 2, sizeof(float), + gfxcore, desc, (BufferView*)&desc->positions2d, 2, sizeof(float), GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL); } if (view_is_populated(desc->normals)) { init_view_buffer( - render_backend, (BufferView*)&desc->normals, Buffer3d, - desc->buffer_usage); + gfxcore, (BufferView*)&desc->normals, Buffer3d, desc->buffer_usage); if (!desc->normals.buffer) { return false; } configure_buffer( - render_backend, desc, (BufferView*)&desc->normals, 3, sizeof(float), - GL_FLOAT, GL_FALSE, GFX_NORMAL_CHANNEL); + gfxcore, desc, (BufferView*)&desc->normals, 3, sizeof(float), GL_FLOAT, + GL_FALSE, GFX_NORMAL_CHANNEL); } if (view_is_populated(desc->tangents)) { init_view_buffer( - render_backend, (BufferView*)&desc->tangents, Buffer4d, - desc->buffer_usage); + gfxcore, (BufferView*)&desc->tangents, Buffer4d, desc->buffer_usage); if (!desc->tangents.buffer) { return false; } configure_buffer( - render_backend, desc, (BufferView*)&desc->tangents, 4, sizeof(float), - GL_FLOAT, GL_FALSE, GFX_TANGENT_CHANNEL); + gfxcore, desc, (BufferView*)&desc->tangents, 4, sizeof(float), GL_FLOAT, + GL_FALSE, GFX_TANGENT_CHANNEL); } if (view_is_populated(desc->texcoords)) { init_view_buffer( - render_backend, (BufferView*)&desc->texcoords, Buffer2d, - desc->buffer_usage); + gfxcore, (BufferView*)&desc->texcoords, Buffer2d, desc->buffer_usage); if (!desc->texcoords.buffer) { return false; } configure_buffer( - render_backend, desc, (BufferView*)&desc->texcoords, 2, sizeof(float), + gfxcore, desc, (BufferView*)&desc->texcoords, 2, sizeof(float), GL_FLOAT, GL_FALSE, GFX_TEXCOORDS_CHANNEL); } if (view_is_populated(desc->joints.u8)) { init_view_buffer( - render_backend, (BufferView*)&desc->joints.u8, BufferU8, - desc->buffer_usage); + gfxcore, (BufferView*)&desc->joints.u8, BufferU8, desc->buffer_usage); if (!desc->joints.u8.buffer) { return false; } configure_buffer( - render_backend, desc, (BufferView*)&desc->joints.u8, 4, sizeof(uint8_t), + gfxcore, desc, (BufferView*)&desc->joints.u8, 4, sizeof(uint8_t), GL_UNSIGNED_BYTE, GL_FALSE, GFX_JOINTS_CHANNEL); } else if (view_is_populated(desc->joints.u16)) { init_view_buffer( - render_backend, (BufferView*)&desc->joints.u16, BufferU16, - desc->buffer_usage); + gfxcore, (BufferView*)&desc->joints.u16, BufferU16, desc->buffer_usage); if (!desc->joints.u16.buffer) { return false; } configure_buffer( - render_backend, desc, (BufferView*)&desc->joints.u16, 4, - sizeof(uint16_t), GL_UNSIGNED_SHORT, GL_FALSE, GFX_JOINTS_CHANNEL); + gfxcore, desc, (BufferView*)&desc->joints.u16, 4, sizeof(uint16_t), + GL_UNSIGNED_SHORT, GL_FALSE, GFX_JOINTS_CHANNEL); } // If weights are given as unsigned integers, then they are normalized // when read by the shader. if (view_is_populated(desc->weights.u8)) { init_view_buffer( - render_backend, (BufferView*)&desc->weights.u8, BufferU8, - desc->buffer_usage); + gfxcore, (BufferView*)&desc->weights.u8, BufferU8, desc->buffer_usage); if (!desc->weights.u8.buffer) { return false; } configure_buffer( - render_backend, desc, (BufferView*)&desc->weights.u8, 4, - sizeof(uint8_t), GL_UNSIGNED_BYTE, GL_TRUE, GFX_WEIGHTS_CHANNEL); + gfxcore, desc, (BufferView*)&desc->weights.u8, 4, sizeof(uint8_t), + GL_UNSIGNED_BYTE, GL_TRUE, GFX_WEIGHTS_CHANNEL); } else if (view_is_populated(desc->weights.u16)) { init_view_buffer( - render_backend, (BufferView*)&desc->weights.u16, BufferU16, + gfxcore, (BufferView*)&desc->weights.u16, BufferU16, desc->buffer_usage); if (!desc->weights.u16.buffer) { return false; } configure_buffer( - render_backend, desc, (BufferView*)&desc->weights.u16, 4, - sizeof(uint16_t), GL_UNSIGNED_SHORT, GL_TRUE, GFX_WEIGHTS_CHANNEL); + gfxcore, desc, (BufferView*)&desc->weights.u16, 4, sizeof(uint16_t), + GL_UNSIGNED_SHORT, GL_TRUE, GFX_WEIGHTS_CHANNEL); } else if (view_is_populated(desc->weights.floats)) { init_view_buffer( - render_backend, (BufferView*)&desc->weights.floats, BufferFloat, + gfxcore, (BufferView*)&desc->weights.floats, BufferFloat, desc->buffer_usage); if (!desc->weights.floats.buffer) { return false; } configure_buffer( - render_backend, desc, (BufferView*)&desc->weights.floats, 4, - sizeof(float), GL_FLOAT, GL_FALSE, GFX_WEIGHTS_CHANNEL); + gfxcore, desc, (BufferView*)&desc->weights.floats, 4, sizeof(float), + GL_FLOAT, GL_FALSE, GFX_WEIGHTS_CHANNEL); } return true; } -static bool configure_indices( - RenderBackend* render_backend, GeometryDesc* desc) { - assert(render_backend); +static bool configure_indices(GfxCore* gfxcore, GeometryDesc* desc) { + assert(gfxcore); assert(desc); if (view_is_populated(desc->indices8)) { @@ -206,8 +196,7 @@ static bool configure_indices( assert( desc->num_indices <= desc->indices8.size_bytes / sizeof(VertexIndex8)); init_view_buffer( - render_backend, (BufferView*)&desc->indices8, BufferU8, - desc->buffer_usage); + gfxcore, (BufferView*)&desc->indices8, BufferU8, desc->buffer_usage); if (!desc->indices8.buffer) { return false; } @@ -217,8 +206,7 @@ static bool configure_indices( desc->num_indices <= desc->indices16.size_bytes / sizeof(VertexIndex16)); init_view_buffer( - render_backend, (BufferView*)&desc->indices16, BufferU16, - desc->buffer_usage); + gfxcore, (BufferView*)&desc->indices16, BufferU16, desc->buffer_usage); if (!desc->indices16.buffer) { return false; } @@ -228,20 +216,19 @@ static bool configure_indices( } bool gfx_init_geometry( - Geometry* geometry, RenderBackend* render_backend, - const GeometryDesc* input_desc) { + Geometry* geometry, GfxCore* gfxcore, const GeometryDesc* input_desc) { assert(geometry); - assert(render_backend); + assert(gfxcore); assert(input_desc); assert( view_is_populated(input_desc->positions3d) || view_is_populated(input_desc->positions2d)); assert(input_desc->num_verts > 0); - geometry->mode = primitive_type_to_gl(input_desc->type); - geometry->desc = *input_desc; - geometry->num_verts = input_desc->num_verts; - geometry->render_backend = render_backend; + geometry->mode = primitive_type_to_gl(input_desc->type); + geometry->desc = *input_desc; + geometry->num_verts = input_desc->num_verts; + geometry->gfxcore = gfxcore; // The geometry's copy of the descriptor is manipulated below. Create a // shorter name for it. @@ -249,10 +236,10 @@ bool gfx_init_geometry( glGenVertexArrays(1, &geometry->vao); glBindVertexArray(geometry->vao); - if (!configure_vertex_attributes(render_backend, desc)) { + if (!configure_vertex_attributes(gfxcore, desc)) { goto cleanup; } - if (!configure_indices(render_backend, desc)) { + if (!configure_indices(gfxcore, desc)) { goto cleanup; } glBindVertexArray(0); diff --git a/gfx/src/render/geometry.h b/gfx/src/render/geometry.h index 484934d..c37a76f 100644 --- a/gfx/src/render/geometry.h +++ b/gfx/src/render/geometry.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "gl_util.h" @@ -18,11 +18,11 @@ typedef struct Geometry { GeometryDesc desc; size_t num_verts; // May differ from the initial value in the descriptor if // the geometry is updated. - RenderBackend* render_backend; + GfxCore* gfxcore; } Geometry; /// Create new geometry. -bool gfx_init_geometry(Geometry*, RenderBackend*, const GeometryDesc*); +bool gfx_init_geometry(Geometry*, GfxCore*, const GeometryDesc*); /// Destroy the geometry. void gfx_del_geometry(Geometry*); diff --git a/gfx/src/render/render_backend.c b/gfx/src/render/render_backend.c deleted file mode 100644 index 8e88feb..0000000 --- a/gfx/src/render/render_backend.c +++ /dev/null @@ -1,425 +0,0 @@ -#include "render_backend_impl.h" - -#include "gl_util.h" - -// #include - -#include - -void gfx_init_render_backend(RenderBackend* render_backend) { - assert(render_backend); - - mempool_make(&render_backend->buffers); - mempool_make(&render_backend->framebuffers); - mempool_make(&render_backend->geometries); - mempool_make(&render_backend->renderbuffers); - mempool_make(&render_backend->shaders); - mempool_make(&render_backend->shader_programs); - mempool_make(&render_backend->textures); - - mempool_make(&render_backend->shader_cache); - mempool_make(&render_backend->program_cache); - - glEnable(GL_CULL_FACE); - glFrontFace(GL_CCW); - glCullFace(GL_BACK); - - glEnable(GL_DEPTH_TEST); - - // Filter cubemaps across their faces to avoid seams. - // https://www.khronos.org/opengl/wiki/Cubemap_Texture#Seamless_cubemap - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); -} - -// Conveniently destroy any objects that have not been destroyed by the -// application. -void gfx_del_render_backend(RenderBackend* render_backend) { - assert(render_backend); - - mempool_foreach( - &render_backend->buffers, buffer, { gfx_del_buffer(buffer); }); - - mempool_foreach(&render_backend->framebuffers, framebuffer, { - gfx_del_framebuffer(framebuffer); - }); - - mempool_foreach( - &render_backend->geometries, geometry, { gfx_del_geometry(geometry); }); - - mempool_foreach(&render_backend->renderbuffers, renderbuffer, { - gfx_del_renderbuffer(renderbuffer); - }); - - mempool_foreach(&render_backend->shader_programs, prog, { - gfx_del_shader_program(prog); - }); - - mempool_foreach( - &render_backend->shaders, shader, { gfx_del_shader(shader); }); - - mempool_foreach( - &render_backend->textures, texture, { gfx_del_texture(texture); }); -} - -// ----------------------------------------------------------------------------- -// Render commands. -// ----------------------------------------------------------------------------- - -void gfx_start_frame(RenderBackend* render_backend) { - assert(render_backend); - - glViewport( - 0, 0, render_backend->viewport.width, render_backend->viewport.height); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - ASSERT_GL; -} - -void gfx_end_frame(RenderBackend* render_backend) { - assert(render_backend); - ASSERT_GL; -} - -void gfx_set_viewport(RenderBackend* render_backend, int width, int height) { - assert(render_backend); - render_backend->viewport.width = width; - render_backend->viewport.height = height; -} - -void gfx_get_viewport(RenderBackend* render_backend, int* width, int* height) { - assert(render_backend); - assert(width); - assert(height); - *width = render_backend->viewport.width; - *height = render_backend->viewport.height; -} - -void gfx_set_blending(RenderBackend* render_backend, bool enable) { - assert(render_backend); - if (enable) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } else { - glDisable(GL_BLEND); - } -} - -void gfx_set_depth_mask(RenderBackend* render_backend, bool enable) { - assert(render_backend); - glDepthMask(enable ? GL_TRUE : GL_FALSE); -} - -void gfx_set_culling(RenderBackend* render_backend, bool enable) { - assert(render_backend); - if (enable) { - glEnable(GL_CULL_FACE); - } else { - glDisable(GL_CULL_FACE); - } -} - -void gfx_set_polygon_offset( - RenderBackend* render_backend, float scale, float bias) { - assert(render_backend); - if ((scale != 0.0f) || (bias != 0.0f)) { - glEnable(GL_POLYGON_OFFSET_FILL); - } else { - glDisable(GL_POLYGON_OFFSET_FILL); - } - glPolygonOffset(scale, bias); -} - -void gfx_reset_polygon_offset(RenderBackend* render_backend) { - assert(render_backend); - glPolygonOffset(0, 0); - glDisable(GL_POLYGON_OFFSET_FILL); -} - -// ----------------------------------------------------------------------------- -// Buffers. -// ----------------------------------------------------------------------------- - -Buffer* gfx_make_buffer(RenderBackend* render_backend, const BufferDesc* desc) { - assert(render_backend); - assert(desc); - - Buffer* buffer = mempool_alloc(&render_backend->buffers); - if (!gfx_init_buffer(buffer, desc)) { - mempool_free(&render_backend->buffers, &buffer); - return 0; - } - return buffer; -} - -void gfx_destroy_buffer(RenderBackend* render_backend, Buffer** buffer) { - assert(render_backend); - assert(buffer); - if (*buffer) { - gfx_del_buffer(*buffer); - mempool_free(&render_backend->buffers, buffer); - } -} - -// ----------------------------------------------------------------------------- -// Geometry. -// ----------------------------------------------------------------------------- - -Geometry* gfx_make_geometry( - RenderBackend* render_backend, const GeometryDesc* desc) { - assert(render_backend); - assert(desc); - - Geometry* geometry = mempool_alloc(&render_backend->geometries); - if (!gfx_init_geometry(geometry, render_backend, desc)) { - mempool_free(&render_backend->geometries, &geometry); - return 0; - } - return geometry; -} - -void gfx_destroy_geometry(RenderBackend* render_backend, Geometry** geometry) { - assert(render_backend); - assert(geometry); - - if (*geometry) { - gfx_del_geometry(*geometry); - mempool_free(&render_backend->geometries, geometry); - } -} - -// ----------------------------------------------------------------------------- -// Textures. -// ----------------------------------------------------------------------------- - -Texture* gfx_make_texture( - RenderBackend* render_backend, const TextureDesc* desc) { - assert(render_backend); - assert(desc); - - Texture* texture = mempool_alloc(&render_backend->textures); - if (!gfx_init_texture(texture, desc)) { - mempool_free(&render_backend->textures, &texture); - return 0; - } - return texture; -} - -void gfx_destroy_texture(RenderBackend* render_backend, Texture** texture) { - assert(render_backend); - assert(texture); - assert(*texture); - - if (*texture) { - gfx_del_texture(*texture); - mempool_free(&render_backend->textures, texture); - } -} - -// ----------------------------------------------------------------------------- -// Renderbuffers. -// ----------------------------------------------------------------------------- - -RenderBuffer* gfx_make_renderbuffer( - RenderBackend* render_backend, const RenderBufferDesc* desc) { - assert(render_backend); - assert(desc); - - RenderBuffer* renderbuffer = mempool_alloc(&render_backend->renderbuffers); - if (!gfx_init_renderbuffer(renderbuffer, desc)) { - mempool_free(&render_backend->renderbuffers, &renderbuffer); - } - return renderbuffer; -} - -void gfx_destroy_renderbuffer( - RenderBackend* render_backend, RenderBuffer** renderbuffer) { - assert(render_backend); - assert(renderbuffer); - assert(*renderbuffer); - - if (*renderbuffer) { - gfx_del_renderbuffer(*renderbuffer); - mempool_free(&render_backend->renderbuffers, renderbuffer); - } -} - -// ----------------------------------------------------------------------------- -// Framebuffers. -// ----------------------------------------------------------------------------- - -FrameBuffer* gfx_make_framebuffer( - RenderBackend* render_backend, const FrameBufferDesc* desc) { - assert(render_backend); - assert(desc); - - FrameBuffer* framebuffer = mempool_alloc(&render_backend->framebuffers); - if (!gfx_init_framebuffer(framebuffer, desc)) { - mempool_free(&render_backend->framebuffers, &framebuffer); - return 0; - } - return framebuffer; -} - -void gfx_destroy_framebuffer( - RenderBackend* render_backend, FrameBuffer** framebuffer) { - assert(render_backend); - assert(framebuffer); - assert(*framebuffer); - - if (*framebuffer) { - gfx_del_framebuffer(*framebuffer); - mempool_free(&render_backend->framebuffers, framebuffer); - } -} - -// ----------------------------------------------------------------------------- -// Shaders. -// ----------------------------------------------------------------------------- - -static uint64_t hash_shader_desc(const ShaderDesc* desc) { - assert(desc); - // Note that defines may affect shader permutations, so we need to hash those - // as well. - uint64_t hash = 0; - for (size_t i = 0; i < desc->num_defines; ++i) { - const ShaderCompilerDefine* define = &desc->defines[i]; - hash = (((hash << 13) + sstring_hash(define->name)) << 7) + - sstring_hash(define->value); - } - return (hash << 17) + cstring_hash(desc->code); -} - -static uint64_t hash_program_desc(const ShaderProgramDesc* desc) { - assert(desc); - return ((uint64_t)desc->vertex_shader->id << 32) | - (uint64_t)desc->fragment_shader->id; -} - -static Shader* find_cached_shader(ShaderCache* cache, uint64_t hash) { - assert(cache); - mempool_foreach(cache, entry, { - if (entry->hash == hash) { - return entry->shader; - } - }); - return 0; -} - -static ShaderProgram* find_cached_program(ProgramCache* cache, uint64_t hash) { - assert(cache); - mempool_foreach(cache, entry, { - if (entry->hash == hash) { - return entry->program; - } - }); - return 0; -} - -static ShaderCacheEntry* find_shader_cache_entry( - ShaderCache* cache, const Shader* shader) { - assert(cache); - assert(shader); - mempool_foreach(cache, entry, { - if (entry->shader == shader) { - return entry; - } - }); - return 0; -} - -static ShaderProgramCacheEntry* find_program_cache_entry( - ProgramCache* cache, const ShaderProgram* prog) { - assert(cache); - assert(prog); - mempool_foreach(cache, entry, { - if (entry->program == prog) { - return entry; - } - }); - return 0; -} - -Shader* gfx_make_shader(RenderBackend* render_backend, const ShaderDesc* desc) { - assert(render_backend); - assert(desc); - - // Check the shader cache first. - ShaderCache* cache = &render_backend->shader_cache; - const uint64_t hash = hash_shader_desc(desc); - Shader* shader = find_cached_shader(cache, hash); - if (shader) { - // LOGD("Found cached shader with hash [%lx]", hash); - return shader; - } - - shader = mempool_alloc(&render_backend->shaders); - if (!shader) { - return 0; - } - if (!gfx_compile_shader(shader, desc)) { - mempool_free(&render_backend->shaders, &shader); - return 0; - } - ShaderCacheEntry* entry = mempool_alloc(cache); - *entry = (ShaderCacheEntry){.hash = hash, .shader = shader}; - // LOGD("Added shader with hash [%lx] to cache", hash); - return shader; -} - -void gfx_destroy_shader(RenderBackend* render_backend, Shader** shader) { - assert(render_backend); - assert(shader); - - if (*shader) { - // Remove the shader from the cache. - ShaderCache* cache = &render_backend->shader_cache; - ShaderCacheEntry* entry = find_shader_cache_entry(cache, *shader); - assert(entry); // Must be there, shaders can't go untracked. - mempool_free(cache, &entry); - - gfx_del_shader(*shader); - mempool_free(&render_backend->shaders, shader); - } -} - -ShaderProgram* gfx_make_shader_program( - RenderBackend* render_backend, const ShaderProgramDesc* desc) { - assert(render_backend); - assert(desc); - - // Check the shader program cache first. - ProgramCache* cache = &render_backend->program_cache; - const uint64_t hash = hash_program_desc(desc); - ShaderProgram* prog = find_cached_program(cache, hash); - if (prog) { - // LOGD("Found cached shader program with hash [%lx]", hash); - return prog; - } - - prog = mempool_alloc(&render_backend->shader_programs); - if (!gfx_build_shader_program(prog, desc)) { - mempool_free(&render_backend->shader_programs, &prog); - return 0; - } - ShaderProgramCacheEntry* entry = mempool_alloc(cache); - *entry = (ShaderProgramCacheEntry){.hash = hash, .program = prog}; - // LOGD("Added shader program with hash [%lx] to cache", hash); - return prog; -} - -void gfx_destroy_shader_program( - RenderBackend* render_backend, ShaderProgram** prog) { - assert(render_backend); - assert(prog); - if (*prog) { - // Remove the shader program from the cache. - ProgramCache* cache = &render_backend->program_cache; - ShaderProgramCacheEntry* entry = find_program_cache_entry(cache, *prog); - assert(entry); // Must be there, shaders can't go untracked. - mempool_free(cache, &entry); - - gfx_del_shader_program(*prog); - mempool_free(&render_backend->shader_programs, prog); - } -} diff --git a/gfx/src/render/render_backend_impl.h b/gfx/src/render/render_backend_impl.h deleted file mode 100644 index e149e98..0000000 --- a/gfx/src/render/render_backend_impl.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include -#include - -#include "buffer.h" -#include "framebuffer.h" -#include "geometry.h" -#include "renderbuffer.h" -#include "shader.h" -#include "shader_program.h" -#include "texture.h" - -#include - -#include - -// TODO: Make a generic (hash, void*) structure and define functions over it. -// Then define a macro that defines type-safe macros given the type of the -// entry. -typedef struct ShaderCacheEntry { - uint64_t hash; - Shader* shader; -} ShaderCacheEntry; - -typedef struct ShaderProgramCacheEntry { - uint64_t hash; - ShaderProgram* program; -} ShaderProgramCacheEntry; - -DEF_MEMPOOL(buffer_pool, Buffer, GFX_MAX_NUM_BUFFERS) -DEF_MEMPOOL(framebuffer_pool, FrameBuffer, GFX_MAX_NUM_FRAMEBUFFERS) -DEF_MEMPOOL(geometry_pool, Geometry, GFX_MAX_NUM_GEOMETRIES) -DEF_MEMPOOL(renderbuffer_pool, RenderBuffer, GFX_MAX_NUM_RENDERBUFFERS) -DEF_MEMPOOL(shader_pool, Shader, GFX_MAX_NUM_SHADERS) -DEF_MEMPOOL(shader_program_pool, ShaderProgram, GFX_MAX_NUM_SHADER_PROGRAMS) -DEF_MEMPOOL(texture_pool, Texture, GFX_MAX_NUM_TEXTURES) - -DEF_MEMPOOL(ShaderCache, ShaderCacheEntry, GFX_MAX_NUM_SHADERS) -DEF_MEMPOOL(ProgramCache, ShaderProgramCacheEntry, GFX_MAX_NUM_SHADER_PROGRAMS) - -typedef struct { - int width; - int height; -} Viewport; - -typedef struct RenderBackend { - Viewport viewport; - // mempools for render-specific objects: textures, geometry, etc. - buffer_pool buffers; - framebuffer_pool framebuffers; - geometry_pool geometries; - renderbuffer_pool renderbuffers; - shader_pool shaders; - shader_program_pool shader_programs; - texture_pool textures; - // Caches. - ShaderCache shader_cache; - ProgramCache program_cache; -} RenderBackend; - -/// Create a new render backend. -void gfx_init_render_backend(RenderBackend*); - -/// Destroy the render backend. -void gfx_del_render_backend(RenderBackend*); diff --git a/gfx/src/render/renderbuffer.h b/gfx/src/render/renderbuffer.h index 458dc83..ea11610 100644 --- a/gfx/src/render/renderbuffer.h +++ b/gfx/src/render/renderbuffer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "gl_util.h" diff --git a/gfx/src/render/shader.h b/gfx/src/render/shader.h index a1aaec2..b9f5679 100644 --- a/gfx/src/render/shader.h +++ b/gfx/src/render/shader.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "gl_util.h" diff --git a/gfx/src/render/shader_program.h b/gfx/src/render/shader_program.h index c269190..1443663 100644 --- a/gfx/src/render/shader_program.h +++ b/gfx/src/render/shader_program.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include "gl_util.h" @@ -12,9 +12,9 @@ typedef struct Texture Texture; typedef struct ShaderProgram { - GLuint id; + GLuint id; ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_SHADER]; - int num_uniforms; + int num_uniforms; } ShaderProgram; /// Create a new shader program. diff --git a/gfx/src/render/texture.h b/gfx/src/render/texture.h index f667752..4af41e9 100644 --- a/gfx/src/render/texture.h +++ b/gfx/src/render/texture.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "gl_util.h" diff --git a/gfx/src/renderer/imm_renderer.c b/gfx/src/renderer/imm_renderer.c index dd5e2cb..8cf3a10 100644 --- a/gfx/src/renderer/imm_renderer.c +++ b/gfx/src/renderer/imm_renderer.c @@ -1,6 +1,6 @@ #include "imm_renderer_impl.h" -#include +#include #include #include @@ -8,27 +8,26 @@ #include #include // memcpy -bool imm_renderer_make(ImmRenderer* renderer, RenderBackend* render_backend) { +bool imm_renderer_make(ImmRenderer* renderer, GfxCore* gfxcore) { assert(renderer); - assert(render_backend); + assert(gfxcore); const size_t num_triangle_verts = IMM_MAX_NUM_TRIANGLES * 3; - renderer->render_backend = render_backend; + renderer->gfxcore = gfxcore; renderer->triangles = gfx_make_geometry( - render_backend, - &(GeometryDesc){ - .type = Triangles, - .buffer_usage = BufferDynamic, - .num_verts = num_triangle_verts, - .positions3d = - (BufferView3d){.size_bytes = num_triangle_verts * sizeof(vec3)}}); + gfxcore, &(GeometryDesc){ + .type = Triangles, + .buffer_usage = BufferDynamic, + .num_verts = num_triangle_verts, + .positions3d = (BufferView3d){ + .size_bytes = num_triangle_verts * sizeof(vec3)}}); if (!renderer->triangles) { goto cleanup; } - renderer->shader = gfx_make_immediate_mode_shader(render_backend); + renderer->shader = gfx_make_immediate_mode_shader(gfxcore); if (!renderer->shader) { goto cleanup; } @@ -47,15 +46,15 @@ cleanup: void imm_renderer_destroy(ImmRenderer* renderer) { assert(renderer); - assert(renderer->render_backend); + assert(renderer->gfxcore); if (renderer->triangles) { - gfx_destroy_geometry(renderer->render_backend, &renderer->triangles); + gfx_destroy_geometry(renderer->gfxcore, &renderer->triangles); // TODO: Could also destroy the geometry's buffers here. } if (renderer->shader) { - gfx_destroy_shader_program(renderer->render_backend, &renderer->shader); + gfx_destroy_shader_program(renderer->gfxcore, &renderer->shader); } } diff --git a/gfx/src/renderer/imm_renderer_impl.h b/gfx/src/renderer/imm_renderer_impl.h index 7769855..5ece354 100644 --- a/gfx/src/renderer/imm_renderer_impl.h +++ b/gfx/src/renderer/imm_renderer_impl.h @@ -18,7 +18,7 @@ typedef struct ShaderProgram ShaderProgram; /// of primitives per frame. It does not adjust this number dynamically. Keeps /// things simple while the extra complexity is not needed. typedef struct ImmRenderer { - RenderBackend* render_backend; + GfxCore* gfxcore; ShaderProgram* shader; Geometry* triangles; size_t num_triangle_verts; // Number of triangle verts this frame. @@ -35,7 +35,7 @@ typedef struct ImmRenderer { } ImmRenderer; /// Create a new immediate mode renderer. -bool imm_renderer_make(ImmRenderer*, RenderBackend*); +bool imm_renderer_make(ImmRenderer*, GfxCore*); /// Destroy the immediate mode renderer. void imm_renderer_destroy(ImmRenderer*); diff --git a/gfx/src/renderer/renderer.c b/gfx/src/renderer/renderer.c index 2244733..d615918 100644 --- a/gfx/src/renderer/renderer.c +++ b/gfx/src/renderer/renderer.c @@ -11,7 +11,7 @@ #include "scene/scene_impl.h" #include "scene/scene_memory.h" -#include +#include #include #include @@ -29,11 +29,11 @@ static const int PREFILTERED_ENVIRONMENT_MAP_HEIGHT = 128; static const int BRDF_INTEGRATION_MAP_WIDTH = 512; static const int BRDF_INTEGRATION_MAP_HEIGHT = 512; -bool renderer_make(Renderer* renderer, RenderBackend* render_backend) { +bool renderer_make(Renderer* renderer, GfxCore* gfxcore) { assert(renderer); - assert(render_backend); + assert(gfxcore); - renderer->render_backend = render_backend; + renderer->gfxcore = gfxcore; return true; } @@ -42,23 +42,23 @@ void renderer_destroy(Renderer* renderer) { if (!renderer) { return; } - assert(renderer->render_backend); - RenderBackend* render_backend = renderer->render_backend; + assert(renderer->gfxcore); + GfxCore* gfxcore = renderer->gfxcore; if (renderer->ibl) { - gfx_destroy_ibl(render_backend, &renderer->ibl); + gfx_destroy_ibl(gfxcore, &renderer->ibl); } if (renderer->shaders.debug) { - gfx_destroy_shader_program(render_backend, &renderer->shaders.debug); + gfx_destroy_shader_program(gfxcore, &renderer->shaders.debug); } if (renderer->shaders.normals) { - gfx_destroy_shader_program(render_backend, &renderer->shaders.normals); + gfx_destroy_shader_program(gfxcore, &renderer->shaders.normals); } if (renderer->shaders.normal_mapped_normals) { gfx_destroy_shader_program( - render_backend, &renderer->shaders.normal_mapped_normals); + gfxcore, &renderer->shaders.normal_mapped_normals); } if (renderer->shaders.tangents) { - gfx_destroy_shader_program(render_backend, &renderer->shaders.tangents); + gfx_destroy_shader_program(gfxcore, &renderer->shaders.tangents); } } @@ -66,14 +66,13 @@ void renderer_destroy(Renderer* renderer) { static bool init_ibl(Renderer* renderer) { assert(renderer); - if (!renderer->ibl && - !(renderer->ibl = gfx_make_ibl(renderer->render_backend))) { + if (!renderer->ibl && !(renderer->ibl = gfx_make_ibl(renderer->gfxcore))) { return false; } if (!renderer->brdf_integration_map && !(renderer->brdf_integration_map = gfx_make_brdf_integration_map( - renderer->ibl, renderer->render_backend, BRDF_INTEGRATION_MAP_WIDTH, + renderer->ibl, renderer->gfxcore, BRDF_INTEGRATION_MAP_WIDTH, BRDF_INTEGRATION_MAP_HEIGHT))) { return false; } @@ -84,13 +83,13 @@ static bool init_ibl(Renderer* renderer) { static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) { assert(renderer); -#define LOAD_AND_RETURN(pShader, constructor) \ - { \ - if (!pShader) { \ - pShader = constructor(renderer->render_backend); \ - } \ - assert(pShader); \ - return pShader; \ +#define LOAD_AND_RETURN(pShader, constructor) \ + { \ + if (!pShader) { \ + pShader = constructor(renderer->gfxcore); \ + } \ + assert(pShader); \ + return pShader; \ } switch (mode) { @@ -121,8 +120,7 @@ static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) { /// Computes irradiance and prefiltered environment maps for the light if they /// have not been already computed. static bool setup_environment_light( - Renderer* renderer, RenderBackend* render_backend, - EnvironmentLight* light) { + Renderer* renderer, GfxCore* gfxcore, EnvironmentLight* light) { assert(renderer); assert(light); @@ -139,14 +137,14 @@ static bool setup_environment_light( Texture* prefiltered_environment_map = 0; if (!(irradiance_map = gfx_make_irradiance_map( - renderer->ibl, render_backend, light->environment_map, + renderer->ibl, gfxcore, light->environment_map, IRRADIANCE_MAP_WIDTH, IRRADIANCE_MAP_HEIGHT))) { goto cleanup; } int max_mip_level = 0; if (!(prefiltered_environment_map = gfx_make_prefiltered_environment_map( - renderer->ibl, render_backend, light->environment_map, + renderer->ibl, gfxcore, light->environment_map, PREFILTERED_ENVIRONMENT_MAP_WIDTH, PREFILTERED_ENVIRONMENT_MAP_HEIGHT, &max_mip_level))) { goto cleanup; @@ -160,16 +158,16 @@ static bool setup_environment_light( cleanup: if (irradiance_map) { - gfx_destroy_texture(render_backend, &irradiance_map); + gfx_destroy_texture(gfxcore, &irradiance_map); } if (prefiltered_environment_map) { - gfx_destroy_texture(render_backend, &prefiltered_environment_map); + gfx_destroy_texture(gfxcore, &prefiltered_environment_map); } return false; } typedef struct RenderState { - RenderBackend* render_backend; + GfxCore* gfxcore; Renderer* renderer; ShaderProgram* shader; // Null to use scene shaders. const Scene* scene; @@ -220,7 +218,7 @@ static void draw_recursively( if (light->type == EnvironmentLightType) { bool result = setup_environment_light( - state->renderer, state->render_backend, &light->environment); + state->renderer, state->gfxcore, &light->environment); // TODO: Handle the result in a better way. assert(result); state->environment_light = light; @@ -329,7 +327,7 @@ void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) { const Scene* scene = params->scene; const SceneCamera* camera = params->camera; - RenderBackend* render_backend = renderer->render_backend; + GfxCore* gfxcore = renderer->gfxcore; mat4 projection, camera_rotation, view_matrix; if (camera) { @@ -344,11 +342,11 @@ void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) { } int width, height; - gfx_get_viewport(render_backend, &width, &height); + gfx_get_viewport(gfxcore, &width, &height); const float aspect = (float)width / (float)height; RenderState state = { - .render_backend = render_backend, + .gfxcore = gfxcore, .renderer = renderer, .shader = shader, .scene = scene, diff --git a/gfx/src/renderer/renderer_impl.h b/gfx/src/renderer/renderer_impl.h index 1e28eb5..fc14dcb 100644 --- a/gfx/src/renderer/renderer_impl.h +++ b/gfx/src/renderer/renderer_impl.h @@ -9,9 +9,9 @@ typedef struct ShaderProgram ShaderProgram; typedef struct Texture Texture; typedef struct Renderer { - RenderBackend* render_backend; - IBL* ibl; - Texture* brdf_integration_map; + GfxCore* gfxcore; + IBL* ibl; + Texture* brdf_integration_map; struct { ShaderProgram* debug; ShaderProgram* normals; @@ -21,7 +21,7 @@ typedef struct Renderer { } Renderer; /// Create a new renderer. -bool renderer_make(Renderer*, RenderBackend*); +bool renderer_make(Renderer*, GfxCore*); /// Destroy the renderer. void renderer_destroy(Renderer*); diff --git a/gfx/src/scene/material.c b/gfx/src/scene/material.c index b32d791..3248243 100644 --- a/gfx/src/scene/material.c +++ b/gfx/src/scene/material.c @@ -2,7 +2,7 @@ #include "scene_memory.h" -#include +#include static void material_make(Material* material, const MaterialDesc* desc) { assert(material); diff --git a/gfx/src/scene/object.c b/gfx/src/scene/object.c index 406c81f..e8e3ee6 100644 --- a/gfx/src/scene/object.c +++ b/gfx/src/scene/object.c @@ -1,6 +1,6 @@ #include "object_impl.h" -#include +#include #include "mesh_impl.h" #include "node_impl.h" diff --git a/gfx/src/util/geometry.c b/gfx/src/util/geometry.c index 84435ce..afe0109 100644 --- a/gfx/src/util/geometry.c +++ b/gfx/src/util/geometry.c @@ -25,20 +25,20 @@ static GeometryDesc make_quad_desc(vec2 positions[4]) { return desc; } -Geometry* gfx_make_quad_11(RenderBackend* render_backend) { - assert(render_backend); +Geometry* gfx_make_quad_11(GfxCore* gfxcore) { + assert(gfxcore); vec2 positions[4]; make_quad_11_positions(positions); const GeometryDesc geometry_desc = make_quad_desc(positions); - return gfx_make_geometry(render_backend, &geometry_desc); + return gfx_make_geometry(gfxcore, &geometry_desc); } -Geometry* gfx_make_quad_01(RenderBackend* render_backend) { - assert(render_backend); +Geometry* gfx_make_quad_01(GfxCore* gfxcore) { + assert(gfxcore); vec2 positions[4]; make_quad_01_positions(positions); const GeometryDesc geometry_desc = make_quad_desc(positions); - return gfx_make_geometry(render_backend, &geometry_desc); + return gfx_make_geometry(gfxcore, &geometry_desc); } diff --git a/gfx/src/util/ibl.c b/gfx/src/util/ibl.c index 6b7465c..5a79990 100644 --- a/gfx/src/util/ibl.c +++ b/gfx/src/util/ibl.c @@ -1,6 +1,6 @@ #include -#include +#include #include #include #include @@ -36,15 +36,15 @@ static const float flips[6] = { -1.0f, // Front. }; -IBL* gfx_make_ibl(RenderBackend* render_backend) { - assert(render_backend); +IBL* gfx_make_ibl(GfxCore* gfxcore) { + assert(gfxcore); IBL* ibl = calloc(1, sizeof(IBL)); if (!ibl) { return 0; } - if (!(ibl->quad = gfx_make_quad_11(render_backend))) { + if (!(ibl->quad = gfx_make_quad_11(gfxcore))) { goto cleanup; } @@ -53,24 +53,23 @@ IBL* gfx_make_ibl(RenderBackend* render_backend) { // shader is fully compiled up front anyway, since the driver will typically // defer full compilation to the first draw call. if (!(ibl->brdf_integration_map_shader = - gfx_make_brdf_integration_map_shader(render_backend))) { + gfx_make_brdf_integration_map_shader(gfxcore))) { goto cleanup; } - if (!(ibl->irradiance_map_shader = - gfx_make_irradiance_map_shader(render_backend))) { + if (!(ibl->irradiance_map_shader = gfx_make_irradiance_map_shader(gfxcore))) { goto cleanup; } if (!(ibl->prefiltered_environment_map_shader = - gfx_make_prefiltered_environment_map_shader(render_backend))) { + gfx_make_prefiltered_environment_map_shader(gfxcore))) { goto cleanup; } // Create an empty framebuffer for now. Will attach the colour buffer later // as we render the faces of the cube. if (!(ibl->framebuffer = gfx_make_framebuffer( - render_backend, + gfxcore, &(FrameBufferDesc){ .colour = (FrameBufferAttachment){.type = FrameBufferNoAttachment}, @@ -116,42 +115,41 @@ IBL* gfx_make_ibl(RenderBackend* render_backend) { return ibl; cleanup: - gfx_destroy_ibl(render_backend, &ibl); + gfx_destroy_ibl(gfxcore, &ibl); return 0; } -void gfx_destroy_ibl(RenderBackend* render_backend, IBL** ibl) { +void gfx_destroy_ibl(GfxCore* gfxcore, IBL** ibl) { if (!ibl) { return; } if ((*ibl)->quad) { - gfx_destroy_geometry(render_backend, &(*ibl)->quad); + gfx_destroy_geometry(gfxcore, &(*ibl)->quad); } if ((*ibl)->brdf_integration_map_shader) { - gfx_destroy_shader_program( - render_backend, &(*ibl)->brdf_integration_map_shader); + gfx_destroy_shader_program(gfxcore, &(*ibl)->brdf_integration_map_shader); } if ((*ibl)->irradiance_map_shader) { - gfx_destroy_shader_program(render_backend, &(*ibl)->irradiance_map_shader); + gfx_destroy_shader_program(gfxcore, &(*ibl)->irradiance_map_shader); } if ((*ibl)->prefiltered_environment_map_shader) { gfx_destroy_shader_program( - render_backend, &(*ibl)->prefiltered_environment_map_shader); + gfxcore, &(*ibl)->prefiltered_environment_map_shader); } if ((*ibl)->brdf_integration_map) { - gfx_destroy_texture(render_backend, &(*ibl)->brdf_integration_map); + gfx_destroy_texture(gfxcore, &(*ibl)->brdf_integration_map); } if ((*ibl)->framebuffer) { - gfx_destroy_framebuffer(render_backend, &(*ibl)->framebuffer); + gfx_destroy_framebuffer(gfxcore, &(*ibl)->framebuffer); } free(*ibl); *ibl = 0; } Texture* gfx_make_brdf_integration_map( - IBL* ibl, RenderBackend* render_backend, int width, int height) { + IBL* ibl, GfxCore* gfxcore, int width, int height) { assert(ibl); - assert(render_backend); + assert(gfxcore); if (ibl->brdf_integration_map) { return ibl->brdf_integration_map; @@ -160,15 +158,15 @@ Texture* gfx_make_brdf_integration_map( bool success = false; if (!(ibl->brdf_integration_map = gfx_make_texture( - render_backend, &(TextureDesc){ - .width = width, - .height = height, - .depth = 1, - .dimension = Texture2D, - .format = TextureRG16F, - .filtering = LinearFiltering, - .wrap = ClampToEdge, - .mipmaps = false}))) { + gfxcore, &(TextureDesc){ + .width = width, + .height = height, + .depth = 1, + .dimension = Texture2D, + .format = TextureRG16F, + .filtering = LinearFiltering, + .wrap = ClampToEdge, + .mipmaps = false}))) { goto cleanup; } @@ -190,7 +188,7 @@ cleanup: gfx_deactivate_shader_program(ibl->brdf_integration_map_shader); gfx_deactivate_framebuffer(ibl->framebuffer); if (!success && ibl->brdf_integration_map) { - gfx_destroy_texture(render_backend, &ibl->brdf_integration_map); + gfx_destroy_texture(gfxcore, &ibl->brdf_integration_map); return 0; } else { return ibl->brdf_integration_map; @@ -198,10 +196,10 @@ cleanup: } Texture* gfx_make_irradiance_map( - IBL* ibl, RenderBackend* render_backend, const Texture* environment_map, - int width, int height) { + IBL* ibl, GfxCore* gfxcore, const Texture* environment_map, int width, + int height) { assert(ibl); - assert(render_backend); + assert(gfxcore); assert(environment_map); bool success = false; @@ -215,14 +213,14 @@ Texture* gfx_make_irradiance_map( // Make sure to use a float colour format to avoid [0,1] clamping when the // irradiance values are computed! if (!(irradiance_map = gfx_make_texture( - render_backend, &(TextureDesc){ - .width = width, - .height = height, - .depth = 1, - .dimension = TextureCubeMap, - .format = TextureR11G11B10F, - .filtering = LinearFiltering, - .mipmaps = false}))) { + gfxcore, &(TextureDesc){ + .width = width, + .height = height, + .depth = 1, + .dimension = TextureCubeMap, + .format = TextureR11G11B10F, + .filtering = LinearFiltering, + .mipmaps = false}))) { goto cleanup; } @@ -251,7 +249,7 @@ cleanup: gfx_deactivate_shader_program(ibl->irradiance_map_shader); gfx_deactivate_framebuffer(ibl->framebuffer); if (!success && irradiance_map) { - gfx_destroy_texture(render_backend, &irradiance_map); + gfx_destroy_texture(gfxcore, &irradiance_map); return 0; } else { return irradiance_map; @@ -259,10 +257,10 @@ cleanup: } Texture* gfx_make_prefiltered_environment_map( - IBL* ibl, RenderBackend* render_backend, const Texture* environment_map, - int width, int height, int* max_mip_level) { + IBL* ibl, GfxCore* gfxcore, const Texture* environment_map, int width, + int height, int* max_mip_level) { assert(ibl); - assert(render_backend); + assert(gfxcore); assert(environment_map); assert(max_mip_level); @@ -271,14 +269,14 @@ Texture* gfx_make_prefiltered_environment_map( Texture* prefiltered_env_map = 0; if (!(prefiltered_env_map = gfx_make_texture( - render_backend, &(TextureDesc){ - .width = width, - .height = height, - .depth = 1, - .dimension = TextureCubeMap, - .format = TextureR11G11B10F, - .filtering = LinearFiltering, - .mipmaps = true}))) { + gfxcore, &(TextureDesc){ + .width = width, + .height = height, + .depth = 1, + .dimension = TextureCubeMap, + .format = TextureR11G11B10F, + .filtering = LinearFiltering, + .mipmaps = true}))) { goto cleanup; } @@ -322,7 +320,7 @@ cleanup: gfx_deactivate_shader_program(ibl->prefiltered_environment_map_shader); gfx_deactivate_framebuffer(ibl->framebuffer); if (!success && prefiltered_env_map) { - gfx_destroy_texture(render_backend, &prefiltered_env_map); + gfx_destroy_texture(gfxcore, &prefiltered_env_map); return 0; } else { return prefiltered_env_map; diff --git a/gfx/src/util/shader.c b/gfx/src/util/shader.c index ed81f79..f5c22cc 100644 --- a/gfx/src/util/shader.c +++ b/gfx/src/util/shader.c @@ -1,6 +1,6 @@ #include -#include +#include #include #include #include @@ -27,10 +27,9 @@ #include static ShaderProgram* make_shader_program( - RenderBackend* render_backend, const char* vert_source, - const char* frag_source, const ShaderCompilerDefine* defines, - size_t num_defines) { - assert(render_backend); + GfxCore* gfxcore, const char* vert_source, const char* frag_source, + const ShaderCompilerDefine* defines, size_t num_defines) { + assert(gfxcore); assert(vert_source); assert(frag_source); @@ -49,19 +48,18 @@ static ShaderProgram* make_shader_program( fragment_shader_desc.defines, defines, num_defines * sizeof(ShaderCompilerDefine)); } - vert = gfx_make_shader(render_backend, &vertex_shader_desc); + vert = gfx_make_shader(gfxcore, &vertex_shader_desc); if (!vert) { goto cleanup; } - frag = gfx_make_shader(render_backend, &fragment_shader_desc); + frag = gfx_make_shader(gfxcore, &fragment_shader_desc); if (!frag) { goto cleanup; } ShaderProgramDesc shader_program_desc = { .vertex_shader = vert, .fragment_shader = frag}; - ShaderProgram* prog = - gfx_make_shader_program(render_backend, &shader_program_desc); + ShaderProgram* prog = gfx_make_shader_program(gfxcore, &shader_program_desc); if (!prog) { goto cleanup; } @@ -69,76 +67,70 @@ static ShaderProgram* make_shader_program( cleanup: if (vert) { - gfx_destroy_shader(render_backend, &vert); + gfx_destroy_shader(gfxcore, &vert); } if (frag) { - gfx_destroy_shader(render_backend, &frag); + gfx_destroy_shader(gfxcore, &frag); } return 0; } -ShaderProgram* gfx_make_brdf_integration_map_shader( - RenderBackend* render_backend) { +ShaderProgram* gfx_make_brdf_integration_map_shader(GfxCore* gfxcore) { return make_shader_program( - render_backend, quad_vert, brdf_integration_map_frag, 0, 0); + gfxcore, quad_vert, brdf_integration_map_frag, 0, 0); } -ShaderProgram* gfx_make_cook_torrance_shader(RenderBackend* render_backend) { +ShaderProgram* gfx_make_cook_torrance_shader(GfxCore* gfxcore) { return make_shader_program( - render_backend, cook_torrance_vert, cook_torrance_frag, 0, 0); + gfxcore, cook_torrance_vert, cook_torrance_frag, 0, 0); } ShaderProgram* gfx_make_cook_torrance_shader_perm( - RenderBackend* render_backend, const ShaderCompilerDefine* defines, - size_t num_defines) { + GfxCore* gfxcore, const ShaderCompilerDefine* defines, size_t num_defines) { return make_shader_program( - render_backend, cook_torrance_vert, cook_torrance_frag, defines, - num_defines); + gfxcore, cook_torrance_vert, cook_torrance_frag, defines, num_defines); } -ShaderProgram* gfx_make_immediate_mode_shader(RenderBackend* render_backend) { +ShaderProgram* gfx_make_immediate_mode_shader(GfxCore* gfxcore) { return make_shader_program( - render_backend, immediate_mode_vert, immediate_mode_frag, 0, 0); + gfxcore, immediate_mode_vert, immediate_mode_frag, 0, 0); } -ShaderProgram* gfx_make_irradiance_map_shader(RenderBackend* render_backend) { +ShaderProgram* gfx_make_irradiance_map_shader(GfxCore* gfxcore) { return make_shader_program( - render_backend, cubemap_filtering_vert, irradiance_map_frag, 0, 0); + gfxcore, cubemap_filtering_vert, irradiance_map_frag, 0, 0); } -ShaderProgram* gfx_make_prefiltered_environment_map_shader( - RenderBackend* render_backend) { +ShaderProgram* gfx_make_prefiltered_environment_map_shader(GfxCore* gfxcore) { return make_shader_program( - render_backend, cubemap_filtering_vert, prefiltered_environment_map_frag, - 0, 0); + gfxcore, cubemap_filtering_vert, prefiltered_environment_map_frag, 0, 0); } -ShaderProgram* gfx_make_debug3d_shader(RenderBackend* render_backend) { - return make_shader_program(render_backend, debug3d_vert, debug3d_frag, 0, 0); +ShaderProgram* gfx_make_debug3d_shader(GfxCore* gfxcore) { + return make_shader_program(gfxcore, debug3d_vert, debug3d_frag, 0, 0); } -ShaderProgram* gfx_make_skyquad_shader(RenderBackend* render_backend) { - return make_shader_program(render_backend, skyquad_vert, skyquad_frag, 0, 0); +ShaderProgram* gfx_make_skyquad_shader(GfxCore* gfxcore) { + return make_shader_program(gfxcore, skyquad_vert, skyquad_frag, 0, 0); } -ShaderProgram* gfx_make_view_normal_mapped_normals_shader( - RenderBackend* render_backend) { +ShaderProgram* gfx_make_view_normal_mapped_normals_shader(GfxCore* gfxcore) { return make_shader_program( - render_backend, view_normal_mapped_normals_vert, - view_normal_mapped_normals_frag, 0, 0); + gfxcore, view_normal_mapped_normals_vert, view_normal_mapped_normals_frag, + 0, 0); } -ShaderProgram* gfx_make_view_normals_shader(RenderBackend* render_backend) { +ShaderProgram* gfx_make_view_normals_shader(GfxCore* gfxcore) { return make_shader_program( - render_backend, view_normals_vert, view_normals_frag, 0, 0); + gfxcore, view_normals_vert, view_normals_frag, 0, 0); } -ShaderProgram* gfx_make_view_tangents_shader(RenderBackend* render_backend) { +ShaderProgram* gfx_make_view_tangents_shader(GfxCore* gfxcore) { return make_shader_program( - render_backend, view_tangents_vert, view_tangents_frag, 0, 0); + gfxcore, view_tangents_vert, view_tangents_frag, 0, 0); } -ShaderProgram* gfx_make_view_texture_shader(RenderBackend* render_backend) { +ShaderProgram* gfx_make_view_texture_shader(GfxCore* gfxcore) { return make_shader_program( - render_backend, view_texture_vert, view_texture_frag, 0, 0); + gfxcore, view_texture_vert, view_texture_frag, 0, 0); } diff --git a/gfx/src/util/skyquad.c b/gfx/src/util/skyquad.c index 5027705..ff8f73f 100644 --- a/gfx/src/util/skyquad.c +++ b/gfx/src/util/skyquad.c @@ -1,7 +1,7 @@ #include +#include #include -#include #include #include #include @@ -15,9 +15,8 @@ #include -SceneObject* gfx_make_skyquad( - RenderBackend* render_backend, const Texture* texture) { - assert(render_backend); +SceneObject* gfx_make_skyquad(GfxCore* gfxcore, const Texture* texture) { + assert(gfxcore); assert(texture); ShaderProgram* shader = 0; @@ -26,12 +25,12 @@ SceneObject* gfx_make_skyquad( Mesh* mesh = 0; SceneObject* object = 0; - shader = gfx_make_skyquad_shader(render_backend); + shader = gfx_make_skyquad_shader(gfxcore); if (!shader) { goto cleanup; } - geometry = gfx_make_quad_11(render_backend); + geometry = gfx_make_quad_11(gfxcore); if (!geometry) { goto cleanup; } @@ -65,10 +64,10 @@ SceneObject* gfx_make_skyquad( cleanup: if (shader) { - gfx_destroy_shader_program(render_backend, &shader); + gfx_destroy_shader_program(gfxcore, &shader); } if (geometry) { - gfx_destroy_geometry(render_backend, &geometry); + gfx_destroy_geometry(gfxcore, &geometry); } if (material) { gfx_destroy_material(&material); @@ -116,9 +115,8 @@ cleanup: } SceneNode* gfx_setup_skyquad( - RenderBackend* render_backend, SceneNode* root, - const Texture* environment_map) { - assert(render_backend); + GfxCore* gfxcore, SceneNode* root, const Texture* environment_map) { + assert(gfxcore); assert(root); assert(environment_map); @@ -127,7 +125,7 @@ SceneNode* gfx_setup_skyquad( SceneNode* light_node = 0; // Create the skyquad object. - skyquad_object = gfx_make_skyquad(render_backend, environment_map); + skyquad_object = gfx_make_skyquad(gfxcore, environment_map); if (!skyquad_object) { goto cleanup; } -- cgit v1.2.3