diff --git a/bindings/bf/bgfx.bf b/bindings/bf/bgfx.bf index 39f28662d..005c00f90 100644 --- a/bindings/bf/bgfx.bf +++ b/bindings/bf/bgfx.bf @@ -1847,6 +1847,27 @@ public static class bgfx Count } + [AllowDuplicates] + public enum UniformFreq : uint32 + { + /// + /// Changing per draw call. + /// + Draw, + + /// + /// Changing per view. + /// + View, + + /// + /// Changing per frame. + /// + Frame, + + Count + } + [AllowDuplicates] public enum BackbufferRatio : uint32 { @@ -3432,6 +3453,41 @@ public static class bgfx [LinkName("bgfx_create_uniform")] public static extern UniformHandle create_uniform(char8* _name, UniformType _type, uint16 _num); + /// + /// Create shader uniform parameter. + /// @remarks + /// 1. Uniform names are unique. It's valid to call `bgfx::createUniform` + /// multiple times with the same uniform name. The library will always + /// return the same handle, but the handle reference count will be + /// incremented. This means that the same number of `bgfx::destroyUniform` + /// must be called to properly destroy the uniform. + /// 2. Predefined uniforms (declared in `bgfx_shader.sh`): + /// - `u_viewRect vec4(x, y, width, height)` - view rectangle for current + /// view, in pixels. + /// - `u_viewTexel vec4(1.0/width, 1.0/height, undef, undef)` - inverse + /// width and height + /// - `u_view mat4` - view matrix + /// - `u_invView mat4` - inverted view matrix + /// - `u_proj mat4` - projection matrix + /// - `u_invProj mat4` - inverted projection matrix + /// - `u_viewProj mat4` - concatenated view projection matrix + /// - `u_invViewProj mat4` - concatenated inverted view projection matrix + /// - `u_model mat4[BGFX_CONFIG_MAX_BONES]` - array of model matrices. + /// - `u_modelView mat4` - concatenated model view matrix, only first + /// model matrix from array is used. + /// - `u_invModelView mat4` - inverted concatenated model view matrix. + /// - `u_modelViewProj mat4` - concatenated model view projection matrix. + /// - `u_alphaRef float` - alpha reference value for alpha test. + /// + /// + /// Uniform name in shader. + /// Uniform change frequency (See: `bgfx::UniformFreq`). + /// Type of uniform (See: `bgfx::UniformType`). + /// Number of elements in array. + /// + [LinkName("bgfx_create_uniform_with_freq")] + public static extern UniformHandle create_uniform_with_freq(char8* _name, UniformFreq _freq, UniformType _type, uint16 _num); + /// /// Retrieve uniform info. /// @@ -3804,6 +3860,31 @@ public static class bgfx [LinkName("bgfx_encoder_set_uniform")] public static extern void encoder_set_uniform(Encoder* _this, UniformHandle _handle, void* _value, uint16 _num); + /// + /// Set shader uniform parameter for view. + /// @attention Uniform must be created with `bgfx::UniformFreq::View` argument. + /// + /// + /// View id. + /// Uniform. + /// Pointer to uniform data. + /// Number of elements. Passing `UINT16_MAX` will use the _num passed on uniform creation. + /// + [LinkName("bgfx_set_view_uniform")] + public static extern void set_view_uniform(ViewId _id, UniformHandle _handle, void* _value, uint16 _num); + + /// + /// Set shader uniform parameter for frame. + /// @attention Uniform must be created with `bgfx::UniformFreq::View` argument. + /// + /// + /// Uniform. + /// Pointer to uniform data. + /// Number of elements. Passing `UINT16_MAX` will use the _num passed on uniform creation. + /// + [LinkName("bgfx_set_frame_uniform")] + public static extern void set_frame_uniform(UniformHandle _handle, void* _value, uint16 _num); + /// /// Set index buffer for draw primitive. /// diff --git a/bindings/c3/bgfx.c3 b/bindings/c3/bgfx.c3 index 4eab1f66b..9ea22ca84 100644 --- a/bindings/c3/bgfx.c3 +++ b/bindings/c3/bgfx.c3 @@ -1185,6 +1185,20 @@ enum UniformType : uint COUNT } +enum UniformFreq : uint +{ + // Changing per draw call. + DRAW, + + // Changing per view. + VIEW, + + // Changing per frame. + FRAME, + + COUNT +} + enum BackbufferRatio : uint { // Equal to backbuffer. @@ -2452,6 +2466,36 @@ extern fn void destroy_frame_buffer(FrameBufferHandle _handle) @extern("bgfx_des // _num : `Number of elements in array.` extern fn UniformHandle create_uniform(ZString _name, UniformType _type, ushort _num) @extern("bgfx_create_uniform"); +// Create shader uniform parameter. +// @remarks +// 1. Uniform names are unique. It's valid to call `bgfx::createUniform` +// multiple times with the same uniform name. The library will always +// return the same handle, but the handle reference count will be +// incremented. This means that the same number of `bgfx::destroyUniform` +// must be called to properly destroy the uniform. +// 2. Predefined uniforms (declared in `bgfx_shader.sh`): +// - `u_viewRect vec4(x, y, width, height)` - view rectangle for current +// view, in pixels. +// - `u_viewTexel vec4(1.0/width, 1.0/height, undef, undef)` - inverse +// width and height +// - `u_view mat4` - view matrix +// - `u_invView mat4` - inverted view matrix +// - `u_proj mat4` - projection matrix +// - `u_invProj mat4` - inverted projection matrix +// - `u_viewProj mat4` - concatenated view projection matrix +// - `u_invViewProj mat4` - concatenated inverted view projection matrix +// - `u_model mat4[BGFX_CONFIG_MAX_BONES]` - array of model matrices. +// - `u_modelView mat4` - concatenated model view matrix, only first +// model matrix from array is used. +// - `u_invModelView mat4` - inverted concatenated model view matrix. +// - `u_modelViewProj mat4` - concatenated model view projection matrix. +// - `u_alphaRef float` - alpha reference value for alpha test. +// _name : `Uniform name in shader.` +// _freq : `Uniform change frequency (See: `bgfx::UniformFreq`).` +// _type : `Type of uniform (See: `bgfx::UniformType`).` +// _num : `Number of elements in array.` +extern fn UniformHandle create_uniform_with_freq(ZString _name, UniformFreq _freq, UniformType _type, ushort _num) @extern("bgfx_create_uniform_with_freq"); + // Retrieve uniform info. // _handle : `Handle to uniform object.` // _info : `Uniform info.` @@ -2666,6 +2710,21 @@ extern fn uint encoder_alloc_transform(Encoder* _this, Transform* _transform, us // _num : `Number of elements. Passing `UINT16_MAX` will use the _num passed on uniform creation.` extern fn void encoder_set_uniform(Encoder* _this, UniformHandle _handle, void* _value, ushort _num) @extern("bgfx_encoder_set_uniform"); +// Set shader uniform parameter for view. +// @attention Uniform must be created with `bgfx::UniformFreq::View` argument. +// _id : `View id.` +// _handle : `Uniform.` +// _value : `Pointer to uniform data.` +// _num : `Number of elements. Passing `UINT16_MAX` will use the _num passed on uniform creation.` +extern fn void set_view_uniform(ushort _id, UniformHandle _handle, void* _value, ushort _num) @extern("bgfx_set_view_uniform"); + +// Set shader uniform parameter for frame. +// @attention Uniform must be created with `bgfx::UniformFreq::View` argument. +// _handle : `Uniform.` +// _value : `Pointer to uniform data.` +// _num : `Number of elements. Passing `UINT16_MAX` will use the _num passed on uniform creation.` +extern fn void set_frame_uniform(UniformHandle _handle, void* _value, ushort _num) @extern("bgfx_set_frame_uniform"); + // Set index buffer for draw primitive. // _handle : `Index buffer.` // _firstIndex : `First index to render.` diff --git a/bindings/cs/bgfx.cs b/bindings/cs/bgfx.cs index 2c07d4b73..ee0f5286a 100644 --- a/bindings/cs/bgfx.cs +++ b/bindings/cs/bgfx.cs @@ -1839,6 +1839,26 @@ public static partial class bgfx Count } + public enum UniformFreq + { + /// + /// Changing per draw call. + /// + Draw, + + /// + /// Changing per view. + /// + View, + + /// + /// Changing per frame. + /// + Frame, + + Count + } + public enum BackbufferRatio { /// @@ -3386,6 +3406,41 @@ public static partial class bgfx [DllImport(DllName, EntryPoint="bgfx_create_uniform", CallingConvention = CallingConvention.Cdecl)] public static extern unsafe UniformHandle create_uniform([MarshalAs(UnmanagedType.LPStr)] string _name, UniformType _type, ushort _num); + /// + /// Create shader uniform parameter. + /// @remarks + /// 1. Uniform names are unique. It's valid to call `bgfx::createUniform` + /// multiple times with the same uniform name. The library will always + /// return the same handle, but the handle reference count will be + /// incremented. This means that the same number of `bgfx::destroyUniform` + /// must be called to properly destroy the uniform. + /// 2. Predefined uniforms (declared in `bgfx_shader.sh`): + /// - `u_viewRect vec4(x, y, width, height)` - view rectangle for current + /// view, in pixels. + /// - `u_viewTexel vec4(1.0/width, 1.0/height, undef, undef)` - inverse + /// width and height + /// - `u_view mat4` - view matrix + /// - `u_invView mat4` - inverted view matrix + /// - `u_proj mat4` - projection matrix + /// - `u_invProj mat4` - inverted projection matrix + /// - `u_viewProj mat4` - concatenated view projection matrix + /// - `u_invViewProj mat4` - concatenated inverted view projection matrix + /// - `u_model mat4[BGFX_CONFIG_MAX_BONES]` - array of model matrices. + /// - `u_modelView mat4` - concatenated model view matrix, only first + /// model matrix from array is used. + /// - `u_invModelView mat4` - inverted concatenated model view matrix. + /// - `u_modelViewProj mat4` - concatenated model view projection matrix. + /// - `u_alphaRef float` - alpha reference value for alpha test. + /// + /// + /// Uniform name in shader. + /// Uniform change frequency (See: `bgfx::UniformFreq`). + /// Type of uniform (See: `bgfx::UniformType`). + /// Number of elements in array. + /// + [DllImport(DllName, EntryPoint="bgfx_create_uniform_with_freq", CallingConvention = CallingConvention.Cdecl)] + public static extern unsafe UniformHandle create_uniform_with_freq([MarshalAs(UnmanagedType.LPStr)] string _name, UniformFreq _freq, UniformType _type, ushort _num); + /// /// Retrieve uniform info. /// @@ -3758,6 +3813,31 @@ public static partial class bgfx [DllImport(DllName, EntryPoint="bgfx_encoder_set_uniform", CallingConvention = CallingConvention.Cdecl)] public static extern unsafe void encoder_set_uniform(Encoder* _this, UniformHandle _handle, void* _value, ushort _num); + /// + /// Set shader uniform parameter for view. + /// @attention Uniform must be created with `bgfx::UniformFreq::View` argument. + /// + /// + /// View id. + /// Uniform. + /// Pointer to uniform data. + /// Number of elements. Passing `UINT16_MAX` will use the _num passed on uniform creation. + /// + [DllImport(DllName, EntryPoint="bgfx_set_view_uniform", CallingConvention = CallingConvention.Cdecl)] + public static extern unsafe void set_view_uniform(ushort _id, UniformHandle _handle, void* _value, ushort _num); + + /// + /// Set shader uniform parameter for frame. + /// @attention Uniform must be created with `bgfx::UniformFreq::View` argument. + /// + /// + /// Uniform. + /// Pointer to uniform data. + /// Number of elements. Passing `UINT16_MAX` will use the _num passed on uniform creation. + /// + [DllImport(DllName, EntryPoint="bgfx_set_frame_uniform", CallingConvention = CallingConvention.Cdecl)] + public static extern unsafe void set_frame_uniform(UniformHandle _handle, void* _value, ushort _num); + /// /// Set index buffer for draw primitive. /// diff --git a/bindings/d/impl.d b/bindings/d/impl.d index d96108c2e..08c09a7d3 100644 --- a/bindings/d/impl.d +++ b/bindings/d/impl.d @@ -54,6 +54,11 @@ extern(C++, "bgfx") package final abstract class UniformType{ sampler,end,vec4,mat3,mat4,count } } +extern(C++, "bgfx") package final abstract class UniformFreq{ + enum Enum{ + draw,view,frame,count + } +} extern(C++, "bgfx") package final abstract class BackbufferRatio{ enum Enum{ equal,half,quarter,eighth,sixteenth,double_,count diff --git a/bindings/d/package.d b/bindings/d/package.d index d9989f2f4..34ad90ac0 100644 --- a/bindings/d/package.d +++ b/bindings/d/package.d @@ -9,7 +9,7 @@ import bindbc.common.types: c_int64, c_uint64, va_list; import bindbc.bgfx.config; static import bgfx.impl; -enum uint apiVersion = 133; +enum uint apiVersion = 134; alias ViewID = ushort; @@ -771,6 +771,14 @@ enum UniformType: bgfx.impl.UniformType.Enum{ count = bgfx.impl.UniformType.Enum.count, } +///Uniform frequency enum. +enum UniformFreq: bgfx.impl.UniformFreq.Enum{ + draw = bgfx.impl.UniformFreq.Enum.draw, + view = bgfx.impl.UniformFreq.Enum.view, + frame = bgfx.impl.UniformFreq.Enum.frame, + count = bgfx.impl.UniformFreq.Enum.count, +} + ///Backbuffer ratio enum. enum BackbufferRatio: bgfx.impl.BackbufferRatio.Enum{ equal = bgfx.impl.BackbufferRatio.Enum.equal, @@ -2848,6 +2856,39 @@ mixin(joinFnBinds((){ */ {q{UniformHandle}, q{createUniform}, q{const(char)* name, bgfx.impl.UniformType.Enum type, ushort num=1}, ext: `C++, "bgfx"`}, + /** + * Create shader uniform parameter. + * Remarks: + * 1. Uniform names are unique. It's valid to call `bgfx::createUniform` + * multiple times with the same uniform name. The library will always + * return the same handle, but the handle reference count will be + * incremented. This means that the same number of `bgfx::destroyUniform` + * must be called to properly destroy the uniform. + * 2. Predefined uniforms (declared in `bgfx_shader.sh`): + * - `u_viewRect vec4(x, y, width, height)` - view rectangle for current + * view, in pixels. + * - `u_viewTexel vec4(1.0/width, 1.0/height, undef, undef)` - inverse + * width and height + * - `u_view mat4` - view matrix + * - `u_invView mat4` - inverted view matrix + * - `u_proj mat4` - projection matrix + * - `u_invProj mat4` - inverted projection matrix + * - `u_viewProj mat4` - concatenated view projection matrix + * - `u_invViewProj mat4` - concatenated inverted view projection matrix + * - `u_model mat4[BGFX_CONFIG_MAX_BONES]` - array of model matrices. + * - `u_modelView mat4` - concatenated model view matrix, only first + * model matrix from array is used. + * - `u_invModelView mat4` - inverted concatenated model view matrix. + * - `u_modelViewProj mat4` - concatenated model view projection matrix. + * - `u_alphaRef float` - alpha reference value for alpha test. + Params: + name = Uniform name in shader. + freq = Uniform change frequency (See: `bgfx::UniformFreq`). + type = Type of uniform (See: `bgfx::UniformType`). + num = Number of elements in array. + */ + {q{UniformHandle}, q{createUniform}, q{const(char)* name, bgfx.impl.UniformFreq.Enum freq, bgfx.impl.UniformType.Enum type, ushort num=1}, ext: `C++, "bgfx"`}, + /** * Retrieve uniform info. Params: @@ -3065,6 +3106,29 @@ mixin(joinFnBinds((){ */ {q{void}, q{end}, q{Encoder* encoder}, ext: `C++, "bgfx"`}, + /** + * Set shader uniform parameter for view. + * Attention: Uniform must be created with `bgfx::UniformFreq::View` argument. + Params: + id = View id. + handle = Uniform. + value = Pointer to uniform data. + num = Number of elements. Passing `UINT16_MAX` will + use the _num passed on uniform creation. + */ + {q{void}, q{setViewUniform}, q{ViewID id, UniformHandle handle, const(void)* value, ushort num=1}, ext: `C++, "bgfx"`}, + + /** + * Set shader uniform parameter for frame. + * Attention: Uniform must be created with `bgfx::UniformFreq::View` argument. + Params: + handle = Uniform. + value = Pointer to uniform data. + num = Number of elements. Passing `UINT16_MAX` will + use the _num passed on uniform creation. + */ + {q{void}, q{setFrameUniform}, q{UniformHandle handle, const(void)* value, ushort num=1}, ext: `C++, "bgfx"`}, + /** * Request screen shot of window back buffer. * Remarks: diff --git a/bindings/zig/bgfx.zig b/bindings/zig/bgfx.zig index 0c6bb2635..e1157755a 100644 --- a/bindings/zig/bgfx.zig +++ b/bindings/zig/bgfx.zig @@ -1151,6 +1151,19 @@ pub const UniformType = enum(c_int) { Count }; +pub const UniformFreq = enum(c_int) { + /// Changing per draw call. + Draw, + + /// Changing per view. + View, + + /// Changing per frame. + Frame, + + Count +}; + pub const BackbufferRatio = enum(c_int) { /// Equal to backbuffer. Equal, @@ -2760,6 +2773,39 @@ pub inline fn createUniform(_name: [*c]const u8, _type: UniformType, _num: u16) } extern fn bgfx_create_uniform(_name: [*c]const u8, _type: UniformType, _num: u16) UniformHandle; +/// Create shader uniform parameter. +/// @remarks +/// 1. Uniform names are unique. It's valid to call `bgfx::createUniform` +/// multiple times with the same uniform name. The library will always +/// return the same handle, but the handle reference count will be +/// incremented. This means that the same number of `bgfx::destroyUniform` +/// must be called to properly destroy the uniform. +/// 2. Predefined uniforms (declared in `bgfx_shader.sh`): +/// - `u_viewRect vec4(x, y, width, height)` - view rectangle for current +/// view, in pixels. +/// - `u_viewTexel vec4(1.0/width, 1.0/height, undef, undef)` - inverse +/// width and height +/// - `u_view mat4` - view matrix +/// - `u_invView mat4` - inverted view matrix +/// - `u_proj mat4` - projection matrix +/// - `u_invProj mat4` - inverted projection matrix +/// - `u_viewProj mat4` - concatenated view projection matrix +/// - `u_invViewProj mat4` - concatenated inverted view projection matrix +/// - `u_model mat4[BGFX_CONFIG_MAX_BONES]` - array of model matrices. +/// - `u_modelView mat4` - concatenated model view matrix, only first +/// model matrix from array is used. +/// - `u_invModelView mat4` - inverted concatenated model view matrix. +/// - `u_modelViewProj mat4` - concatenated model view projection matrix. +/// - `u_alphaRef float` - alpha reference value for alpha test. +/// Uniform name in shader. +/// Uniform change frequency (See: `bgfx::UniformFreq`). +/// Type of uniform (See: `bgfx::UniformType`). +/// Number of elements in array. +pub inline fn createUniformWithFreq(_name: [*c]const u8, _freq: UniformFreq, _type: UniformType, _num: u16) UniformHandle { + return bgfx_create_uniform_with_freq(_name, _freq, _type, _num); +} +extern fn bgfx_create_uniform_with_freq(_name: [*c]const u8, _freq: UniformFreq, _type: UniformType, _num: u16) UniformHandle; + /// Retrieve uniform info. /// Handle to uniform object. /// Uniform info. @@ -3040,6 +3086,27 @@ extern fn bgfx_encoder_alloc_transform(self: ?*Encoder, _transform: [*c]Transfor /// Number of elements. Passing `UINT16_MAX` will use the _num passed on uniform creation. extern fn bgfx_encoder_set_uniform(self: ?*Encoder, _handle: UniformHandle, _value: ?*const anyopaque, _num: u16) void; +/// Set shader uniform parameter for view. +/// @attention Uniform must be created with `bgfx::UniformFreq::View` argument. +/// View id. +/// Uniform. +/// Pointer to uniform data. +/// Number of elements. Passing `UINT16_MAX` will use the _num passed on uniform creation. +pub inline fn setViewUniform(_id: ViewId, _handle: UniformHandle, _value: ?*const anyopaque, _num: u16) void { + return bgfx_set_view_uniform(_id, _handle, _value, _num); +} +extern fn bgfx_set_view_uniform(_id: ViewId, _handle: UniformHandle, _value: ?*const anyopaque, _num: u16) void; + +/// Set shader uniform parameter for frame. +/// @attention Uniform must be created with `bgfx::UniformFreq::View` argument. +/// Uniform. +/// Pointer to uniform data. +/// Number of elements. Passing `UINT16_MAX` will use the _num passed on uniform creation. +pub inline fn setFrameUniform(_handle: UniformHandle, _value: ?*const anyopaque, _num: u16) void { + return bgfx_set_frame_uniform(_handle, _value, _num); +} +extern fn bgfx_set_frame_uniform(_handle: UniformHandle, _value: ?*const anyopaque, _num: u16) void; + /// Set index buffer for draw primitive. /// Index buffer. /// First index to render. diff --git a/examples/04-mesh/mesh.cpp b/examples/04-mesh/mesh.cpp index 62d49ca7c..123cc56e2 100644 --- a/examples/04-mesh/mesh.cpp +++ b/examples/04-mesh/mesh.cpp @@ -49,7 +49,7 @@ public: , 0 ); - u_time = bgfx::createUniform("u_time", bgfx::UniformType::Vec4); + u_time = bgfx::createUniform("u_time", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); // Create program from shaders. m_program = loadProgram("vs_mesh", "fs_mesh"); @@ -104,7 +104,7 @@ public: bgfx::touch(0); float time = (float)( (bx::getHPCounter()-m_timeOffset)/double(bx::getHPFrequency() ) ); - bgfx::setUniform(u_time, &time); + bgfx::setFrameUniform(u_time, &time); const bx::Vec3 at = { 0.0f, 1.0f, 0.0f }; const bx::Vec3 eye = { 0.0f, 1.0f, -2.5f }; diff --git a/examples/08-update/update.cpp b/examples/08-update/update.cpp index f5f5b7ba7..6a774c2e0 100644 --- a/examples/08-update/update.cpp +++ b/examples/08-update/update.cpp @@ -367,7 +367,7 @@ public: s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Sampler); // Create time uniform. - u_time = bgfx::createUniform("u_time", bgfx::UniformType::Vec4); + u_time = bgfx::createUniform("u_time", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); for(uint32_t ii = 0; ii m_updateTime) { diff --git a/examples/09-hdr/hdr.cpp b/examples/09-hdr/hdr.cpp index 838a0051e..69ceec58d 100644 --- a/examples/09-hdr/hdr.cpp +++ b/examples/09-hdr/hdr.cpp @@ -187,9 +187,11 @@ public: s_texLum = bgfx::createUniform("s_texLum", bgfx::UniformType::Sampler); s_texBlur = bgfx::createUniform("s_texBlur", bgfx::UniformType::Sampler); u_mtx = bgfx::createUniform("u_mtx", bgfx::UniformType::Mat4); - u_tonemap = bgfx::createUniform("u_tonemap", bgfx::UniformType::Vec4); u_offset = bgfx::createUniform("u_offset", bgfx::UniformType::Vec4, 16); + // Tonemap value will be updated once per frame. + u_tonemap = bgfx::createUniform("u_tonemap", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + m_mesh = meshLoad("meshes/bunny.bin"); m_fbh.idx = bgfx::kInvalidHandle; @@ -515,7 +517,8 @@ public: // Set view and projection matrix for view hdrMesh. bgfx::setViewTransform(hdrMesh, view, proj); - float tonemap[4] = { m_middleGray, bx::square(m_white), m_threshold, m_time }; + const float tonemap[4] = { m_middleGray, bx::square(m_white), m_threshold, m_time }; + bgfx::setFrameUniform(u_tonemap, tonemap); // Render skybox into view hdrSkybox. bgfx::setTexture(0, s_texCube, m_uffizi); @@ -526,7 +529,6 @@ public: // Render m_mesh into view hdrMesh. bgfx::setTexture(0, s_texCube, m_uffizi); - bgfx::setUniform(u_tonemap, tonemap); meshSubmit(m_mesh, hdrMesh, m_meshProgram, NULL); // Calculate luminance. @@ -569,14 +571,12 @@ public: bgfx::setTexture(0, s_texColor, m_fbtextures[0]); bgfx::setTexture(1, s_texLum, bgfx::getTexture(m_lum[4]) ); bgfx::setState(BGFX_STATE_WRITE_RGB|BGFX_STATE_WRITE_A); - bgfx::setUniform(u_tonemap, tonemap); screenSpaceQuad(m_caps->originBottomLeft); bgfx::submit(hdrBrightness, m_brightProgram); // m_blur m_bright pass vertically. bgfx::setTexture(0, s_texColor, bgfx::getTexture(m_bright) ); bgfx::setState(BGFX_STATE_WRITE_RGB|BGFX_STATE_WRITE_A); - bgfx::setUniform(u_tonemap, tonemap); screenSpaceQuad(m_caps->originBottomLeft); bgfx::submit(hdrVBlur, m_blurProgram); diff --git a/examples/13-stencil/stencil.cpp b/examples/13-stencil/stencil.cpp index d082677ac..34f2a7e4b 100644 --- a/examples/13-stencil/stencil.cpp +++ b/examples/13-stencil/stencil.cpp @@ -288,21 +288,22 @@ struct Uniforms m_lightRgbInnerR[ii][3] = 1.0f; } + u_ambient = bgfx::createUniform("u_ambient", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_diffuse = bgfx::createUniform("u_diffuse", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_specular_shininess = bgfx::createUniform("u_specular_shininess", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_params = bgfx::createUniform("u_params", bgfx::UniformType::Vec4); - u_ambient = bgfx::createUniform("u_ambient", bgfx::UniformType::Vec4); - u_diffuse = bgfx::createUniform("u_diffuse", bgfx::UniformType::Vec4); - u_specular_shininess = bgfx::createUniform("u_specular_shininess", bgfx::UniformType::Vec4); u_color = bgfx::createUniform("u_color", bgfx::UniformType::Vec4); u_lightPosRadius = bgfx::createUniform("u_lightPosRadius", bgfx::UniformType::Vec4, MAX_NUM_LIGHTS); u_lightRgbInnerR = bgfx::createUniform("u_lightRgbInnerR", bgfx::UniformType::Vec4, MAX_NUM_LIGHTS); } //call this once at initialization - void submitConstUniforms() + void submitFrameUniforms() { - bgfx::setUniform(u_ambient, &m_ambient); - bgfx::setUniform(u_diffuse, &m_diffuse); - bgfx::setUniform(u_specular_shininess, &m_specular_shininess); + bgfx::setFrameUniform(u_ambient, &m_ambient); + bgfx::setFrameUniform(u_diffuse, &m_diffuse); + bgfx::setFrameUniform(u_specular_shininess, &m_specular_shininess); } //call this before each draw call @@ -979,7 +980,7 @@ public: imguiEndFrame(); - s_uniforms.submitConstUniforms(); + s_uniforms.submitFrameUniforms(); // Update settings. uint8_t numLights = (uint8_t)m_numLights; diff --git a/examples/16-shadowmaps/shadowmaps.cpp b/examples/16-shadowmaps/shadowmaps.cpp index f648a624a..c90d1105e 100644 --- a/examples/16-shadowmaps/shadowmaps.cpp +++ b/examples/16-shadowmaps/shadowmaps.cpp @@ -385,55 +385,49 @@ struct Uniforms m_csmFarDistances[2] = 180.0f; m_csmFarDistances[3] = 1000.0f; - m_tetraNormalGreen[0] = 0.0f; - m_tetraNormalGreen[1] = -0.57735026f; - m_tetraNormalGreen[2] = 0.81649661f; - - m_tetraNormalYellow[0] = 0.0f; - m_tetraNormalYellow[1] = -0.57735026f; - m_tetraNormalYellow[2] = -0.81649661f; - - m_tetraNormalBlue[0] = -0.81649661f; - m_tetraNormalBlue[1] = 0.57735026f; - m_tetraNormalBlue[2] = 0.0f; - - m_tetraNormalRed[0] = 0.81649661f; - m_tetraNormalRed[1] = 0.57735026f; - m_tetraNormalRed[2] = 0.0f; - m_XNum = 2.0f; m_YNum = 2.0f; m_XOffset = 10.0f/512.0f; m_YOffset = 10.0f/512.0f; u_params0 = bgfx::createUniform("u_params0", bgfx::UniformType::Vec4); - u_params1 = bgfx::createUniform("u_params1", bgfx::UniformType::Vec4); - u_params2 = bgfx::createUniform("u_params2", bgfx::UniformType::Vec4); + u_params1 = bgfx::createUniform("u_params1", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_params2 = bgfx::createUniform("u_params2", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); u_color = bgfx::createUniform("u_color", bgfx::UniformType::Vec4); - u_smSamplingParams = bgfx::createUniform("u_smSamplingParams", bgfx::UniformType::Vec4); - u_csmFarDistances = bgfx::createUniform("u_csmFarDistances", bgfx::UniformType::Vec4); + u_smSamplingParams = bgfx::createUniform("u_smSamplingParams", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_csmFarDistances = bgfx::createUniform("u_csmFarDistances", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); u_lightMtx = bgfx::createUniform("u_lightMtx", bgfx::UniformType::Mat4); - u_tetraNormalGreen = bgfx::createUniform("u_tetraNormalGreen", bgfx::UniformType::Vec4); - u_tetraNormalYellow = bgfx::createUniform("u_tetraNormalYellow", bgfx::UniformType::Vec4); - u_tetraNormalBlue = bgfx::createUniform("u_tetraNormalBlue", bgfx::UniformType::Vec4); - u_tetraNormalRed = bgfx::createUniform("u_tetraNormalRed", bgfx::UniformType::Vec4); + u_tetraNormalGreen = bgfx::createUniform("u_tetraNormalGreen", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_tetraNormalYellow = bgfx::createUniform("u_tetraNormalYellow", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_tetraNormalBlue = bgfx::createUniform("u_tetraNormalBlue", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_tetraNormalRed = bgfx::createUniform("u_tetraNormalRed", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + + const float tetraNormalGreen[] = { 0.0f, -0.57735026f, 0.81649661f }; + const float tetraNormalYellow[] = { 0.0f, -0.57735026f, -0.81649661f }; + const float tetraNormalBlue[] = { -0.81649661f, 0.57735026f, 0.0f }; + const float tetraNormalRed[] = { 0.81649661f, 0.57735026f, 0.0f }; + + bgfx::setFrameUniform(u_tetraNormalGreen, tetraNormalGreen); + bgfx::setFrameUniform(u_tetraNormalYellow, tetraNormalYellow); + bgfx::setFrameUniform(u_tetraNormalBlue, tetraNormalBlue); + bgfx::setFrameUniform(u_tetraNormalRed, tetraNormalRed); u_shadowMapMtx0 = bgfx::createUniform("u_shadowMapMtx0", bgfx::UniformType::Mat4); u_shadowMapMtx1 = bgfx::createUniform("u_shadowMapMtx1", bgfx::UniformType::Mat4); u_shadowMapMtx2 = bgfx::createUniform("u_shadowMapMtx2", bgfx::UniformType::Mat4); u_shadowMapMtx3 = bgfx::createUniform("u_shadowMapMtx3", bgfx::UniformType::Mat4); - u_lightPosition = bgfx::createUniform("u_lightPosition", bgfx::UniformType::Vec4); - u_lightAmbientPower = bgfx::createUniform("u_lightAmbientPower", bgfx::UniformType::Vec4); - u_lightDiffusePower = bgfx::createUniform("u_lightDiffusePower", bgfx::UniformType::Vec4); - u_lightSpecularPower = bgfx::createUniform("u_lightSpecularPower", bgfx::UniformType::Vec4); - u_lightSpotDirectionInner = bgfx::createUniform("u_lightSpotDirectionInner", bgfx::UniformType::Vec4); - u_lightAttenuationSpotOuter = bgfx::createUniform("u_lightAttenuationSpotOuter", bgfx::UniformType::Vec4); + u_lightPosition = bgfx::createUniform("u_lightPosition", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_lightAmbientPower = bgfx::createUniform("u_lightAmbientPower", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_lightDiffusePower = bgfx::createUniform("u_lightDiffusePower", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_lightSpecularPower = bgfx::createUniform("u_lightSpecularPower", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_lightSpotDirectionInner = bgfx::createUniform("u_lightSpotDirectionInner", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_lightAttenuationSpotOuter = bgfx::createUniform("u_lightAttenuationSpotOuter", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); - u_materialKa = bgfx::createUniform("u_materialKa", bgfx::UniformType::Vec4); - u_materialKd = bgfx::createUniform("u_materialKd", bgfx::UniformType::Vec4); - u_materialKs = bgfx::createUniform("u_materialKs", bgfx::UniformType::Vec4); + u_materialKa = bgfx::createUniform("u_materialKa", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_materialKd = bgfx::createUniform("u_materialKd", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); + u_materialKs = bgfx::createUniform("u_materialKs", bgfx::UniformFreq::Frame, bgfx::UniformType::Vec4); } @@ -450,33 +444,24 @@ struct Uniforms m_shadowMapMtx3 = _shadowMapMtx3; } - // Call this once at initialization. - void submitConstUniforms() - { - bgfx::setUniform(u_tetraNormalGreen, m_tetraNormalGreen); - bgfx::setUniform(u_tetraNormalYellow, m_tetraNormalYellow); - bgfx::setUniform(u_tetraNormalBlue, m_tetraNormalBlue); - bgfx::setUniform(u_tetraNormalRed, m_tetraNormalRed); - } - // Call this once per frame. void submitPerFrameUniforms() { - bgfx::setUniform(u_params1, m_params1); - bgfx::setUniform(u_params2, m_params2); - bgfx::setUniform(u_smSamplingParams, m_paramsBlur); - bgfx::setUniform(u_csmFarDistances, m_csmFarDistances); + bgfx::setFrameUniform(u_params1, m_params1); + bgfx::setFrameUniform(u_params2, m_params2); + bgfx::setFrameUniform(u_smSamplingParams, m_paramsBlur); + bgfx::setFrameUniform(u_csmFarDistances, m_csmFarDistances); - bgfx::setUniform(u_materialKa, &m_materialPtr->m_ka); - bgfx::setUniform(u_materialKd, &m_materialPtr->m_kd); - bgfx::setUniform(u_materialKs, &m_materialPtr->m_ks); + bgfx::setFrameUniform(u_materialKa, &m_materialPtr->m_ka); + bgfx::setFrameUniform(u_materialKd, &m_materialPtr->m_kd); + bgfx::setFrameUniform(u_materialKs, &m_materialPtr->m_ks); - bgfx::setUniform(u_lightPosition, &m_lightPtr->m_position_viewSpace); - bgfx::setUniform(u_lightAmbientPower, &m_lightPtr->m_ambientPower); - bgfx::setUniform(u_lightDiffusePower, &m_lightPtr->m_diffusePower); - bgfx::setUniform(u_lightSpecularPower, &m_lightPtr->m_specularPower); - bgfx::setUniform(u_lightSpotDirectionInner, &m_lightPtr->m_spotDirectionInner_viewSpace); - bgfx::setUniform(u_lightAttenuationSpotOuter, &m_lightPtr->m_attenuationSpotOuter); + bgfx::setFrameUniform(u_lightPosition, &m_lightPtr->m_position_viewSpace); + bgfx::setFrameUniform(u_lightAmbientPower, &m_lightPtr->m_ambientPower); + bgfx::setFrameUniform(u_lightDiffusePower, &m_lightPtr->m_diffusePower); + bgfx::setFrameUniform(u_lightSpecularPower, &m_lightPtr->m_specularPower); + bgfx::setFrameUniform(u_lightSpotDirectionInner, &m_lightPtr->m_spotDirectionInner_viewSpace); + bgfx::setFrameUniform(u_lightAttenuationSpotOuter, &m_lightPtr->m_attenuationSpotOuter); } // Call this before each draw call. @@ -576,10 +561,6 @@ struct Uniforms float m_paramsBlur[4]; }; - float m_tetraNormalGreen[3]; - float m_tetraNormalYellow[3]; - float m_tetraNormalBlue[3]; - float m_tetraNormalRed[3]; float m_csmFarDistances[4]; float* m_lightMtxPtr; @@ -1252,7 +1233,6 @@ public: , &m_shadowMapMtx[ShadowMapRenderTargets::Third][0] , &m_shadowMapMtx[ShadowMapRenderTargets::Fourth][0] ); - s_uniforms.submitConstUniforms(); // Settings. ShadowMapSettings smSettings[LightType::Count][DepthImpl::Count][SmImpl::Count] = @@ -1807,10 +1787,6 @@ public: float currentShadowMapSizef = float(int16_t(m_currentShadowMapSize) ); s_uniforms.m_shadowMapTexelSize = 1.0f / currentShadowMapSizef; - s_uniforms.submitConstUniforms(); - - // s_uniforms.submitConstUniforms(); - // Imgui. imguiBeginFrame(m_mouseState.m_mx , m_mouseState.m_my diff --git a/examples/42-bunnylod/bunnylod.cpp b/examples/42-bunnylod/bunnylod.cpp index 7192b4def..e1d8b417c 100644 --- a/examples/42-bunnylod/bunnylod.cpp +++ b/examples/42-bunnylod/bunnylod.cpp @@ -285,8 +285,6 @@ public: , 0 ); - u_tint = bgfx::createUniform("u_tint", bgfx::UniformType::Vec4); - // Create program from shaders. m_program = loadProgram("vs_bunnylod", "fs_bunnylod"); @@ -309,7 +307,6 @@ public: bgfx::destroy(m_program); bgfx::destroy(m_vb); bgfx::destroy(m_ib); - bgfx::destroy(u_tint); bx::free(entry::getAllocator(), m_map); bx::free(entry::getAllocator(), m_triangle); @@ -432,8 +429,6 @@ public: bgfx::touch(0); float time = (float)( (bx::getHPCounter()-m_timeOffset)/double(bx::getHPFrequency() ) ); - const float BasicColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - bgfx::setUniform(u_tint, BasicColor); const bx::Vec3 at = { 0.0f, 1.0f, 0.0f }; const bx::Vec3 eye = { 0.0f, 1.0f, -2.5f }; @@ -493,7 +488,6 @@ public: bgfx::VertexBufferHandle m_vb; bgfx::DynamicIndexBufferHandle m_ib; bgfx::ProgramHandle m_program; - bgfx::UniformHandle u_tint; }; } // namespace diff --git a/include/bgfx/bgfx.h b/include/bgfx/bgfx.h index 0edaf887b..e570926bd 100644 --- a/include/bgfx/bgfx.h +++ b/include/bgfx/bgfx.h @@ -284,6 +284,23 @@ namespace bgfx }; }; + /// Uniform frequency enum. + /// + /// @attention C99's equivalent binding is `bgfx_bgfx_uniform_freq_t`. + /// + struct UniformFreq + { + /// Uniform frequency: + enum Enum + { + Draw, //!< Changing per draw call. + View, //!< Changing per view. + Frame, //!< Changing per frame. + + Count + }; + }; + /// Backbuffer ratio enum. /// /// @attention C99's equivalent binding is `bgfx_backbuffer_ratio_t`. @@ -3279,6 +3296,48 @@ namespace bgfx , uint16_t _num = 1 ); + /// Create shader uniform parameter. + /// + /// @param[in] _name Uniform name in shader. + /// @param[in] _freq Uniform change frequency (See: `bgfx::UniformFreq`). + /// @param[in] _type Type of uniform (See: `bgfx::UniformType`). + /// @param[in] _num Number of elements in array. + /// + /// @returns Handle to uniform object. + /// + /// @remarks + /// 1. Uniform names are unique. It's valid to call `bgfx::createUniform` + /// multiple times with the same uniform name. The library will always + /// return the same handle, but the handle reference count will be + /// incremented. This means that the same number of `bgfx::destroyUniform` + /// must be called to properly destroy the uniform. + /// 2. Predefined uniforms (declared in `bgfx_shader.sh`): + /// - `u_viewRect vec4(x, y, width, height)` - view rectangle for current + /// view, in pixels. + /// - `u_viewTexel vec4(1.0/width, 1.0/height, undef, undef)` - inverse + /// width and height + /// - `u_view mat4` - view matrix + /// - `u_invView mat4` - inverted view matrix + /// - `u_proj mat4` - projection matrix + /// - `u_invProj mat4` - inverted projection matrix + /// - `u_viewProj mat4` - concatenated view projection matrix + /// - `u_invViewProj mat4` - concatenated inverted view projection matrix + /// - `u_model mat4[BGFX_CONFIG_MAX_BONES]` - array of model matrices. + /// - `u_modelView mat4` - concatenated model view matrix, only first + /// model matrix from array is used. + /// - `u_invModelView mat4` - inverted concatenated model view matrix. + /// - `u_modelViewProj mat4` - concatenated model view projection matrix. + /// - `u_alphaRef float` - alpha reference value for alpha test. + /// + /// @attention C99's equivalent binding is `bgfx_create_uniform_with_freq`. + /// + UniformHandle createUniform( + const char* _name + , UniformFreq::Enum _freq + , UniformType::Enum _type + , uint16_t _num = 1 + ); + /// Retrieve uniform info. /// /// @param[in] _handle Handle to uniform object. @@ -3740,6 +3799,40 @@ namespace bgfx , uint16_t _num = 1 ); + /// Set shader uniform parameter for view. + /// + /// @param[in] _id View id. + /// @param[in] _handle Uniform. + /// @param[in] _value Pointer to uniform data. + /// @param[in] _num Number of elements. Passing `UINT16_MAX` will + /// use the _num passed on uniform creation. + /// + /// @attention Uniform must be created with `bgfx::UniformFreq::View` argument. + /// @attention C99's equivalent binding is `bgfx_set_view_uniform`. + /// + void setViewUniform( + ViewId _id + , UniformHandle _handle + , const void* _value + , uint16_t _num = 1 + ); + + /// Set shader uniform parameter for frame. + /// + /// @param[in] _handle Uniform. + /// @param[in] _value Pointer to uniform data. + /// @param[in] _num Number of elements. Passing `UINT16_MAX` will + /// use the _num passed on uniform creation. + /// + /// @attention Uniform must be created with `bgfx::UniformFreq::View` argument. + /// @attention C99's equivalent binding is `bgfx_set_frame_uniform`. + /// + void setFrameUniform( + UniformHandle _handle + , const void* _value + , uint16_t _num = 1 + ); + /// Set index buffer for draw primitive. /// /// @param[in] _handle Index buffer. diff --git a/include/bgfx/c99/bgfx.h b/include/bgfx/c99/bgfx.h index 1c470a534..71a5b2da9 100644 --- a/include/bgfx/c99/bgfx.h +++ b/include/bgfx/c99/bgfx.h @@ -288,6 +288,20 @@ typedef enum bgfx_uniform_type } bgfx_uniform_type_t; +/** + * Uniform frequency enum. + * + */ +typedef enum bgfx_uniform_freq +{ + BGFX_UNIFORM_FREQ_DRAW, /** ( 0) Changing per draw call. */ + BGFX_UNIFORM_FREQ_VIEW, /** ( 1) Changing per view. */ + BGFX_UNIFORM_FREQ_FRAME, /** ( 2) Changing per frame. */ + + BGFX_UNIFORM_FREQ_COUNT + +} bgfx_uniform_freq_t; + /** * Backbuffer ratio enum. * @@ -2200,6 +2214,42 @@ BGFX_C_API void bgfx_destroy_frame_buffer(bgfx_frame_buffer_handle_t _handle); */ BGFX_C_API bgfx_uniform_handle_t bgfx_create_uniform(const char* _name, bgfx_uniform_type_t _type, uint16_t _num); +/** + * Create shader uniform parameter. + * @remarks + * 1. Uniform names are unique. It's valid to call `bgfx::createUniform` + * multiple times with the same uniform name. The library will always + * return the same handle, but the handle reference count will be + * incremented. This means that the same number of `bgfx::destroyUniform` + * must be called to properly destroy the uniform. + * 2. Predefined uniforms (declared in `bgfx_shader.sh`): + * - `u_viewRect vec4(x, y, width, height)` - view rectangle for current + * view, in pixels. + * - `u_viewTexel vec4(1.0/width, 1.0/height, undef, undef)` - inverse + * width and height + * - `u_view mat4` - view matrix + * - `u_invView mat4` - inverted view matrix + * - `u_proj mat4` - projection matrix + * - `u_invProj mat4` - inverted projection matrix + * - `u_viewProj mat4` - concatenated view projection matrix + * - `u_invViewProj mat4` - concatenated inverted view projection matrix + * - `u_model mat4[BGFX_CONFIG_MAX_BONES]` - array of model matrices. + * - `u_modelView mat4` - concatenated model view matrix, only first + * model matrix from array is used. + * - `u_invModelView mat4` - inverted concatenated model view matrix. + * - `u_modelViewProj mat4` - concatenated model view projection matrix. + * - `u_alphaRef float` - alpha reference value for alpha test. + * + * @param[in] _name Uniform name in shader. + * @param[in] _freq Uniform change frequency (See: `bgfx::UniformFreq`). + * @param[in] _type Type of uniform (See: `bgfx::UniformType`). + * @param[in] _num Number of elements in array. + * + * @returns Handle to uniform object. + * + */ +BGFX_C_API bgfx_uniform_handle_t bgfx_create_uniform_with_freq(const char* _name, bgfx_uniform_freq_t _freq, bgfx_uniform_type_t _type, uint16_t _num); + /** * Retrieve uniform info. * @@ -2573,6 +2623,31 @@ BGFX_C_API uint32_t bgfx_encoder_alloc_transform(bgfx_encoder_t* _this, bgfx_tra */ BGFX_C_API void bgfx_encoder_set_uniform(bgfx_encoder_t* _this, bgfx_uniform_handle_t _handle, const void* _value, uint16_t _num); +/** + * Set shader uniform parameter for view. + * @attention Uniform must be created with `bgfx::UniformFreq::View` argument. + * + * @param[in] _id View id. + * @param[in] _handle Uniform. + * @param[in] _value Pointer to uniform data. + * @param[in] _num Number of elements. Passing `UINT16_MAX` will + * use the _num passed on uniform creation. + * + */ +BGFX_C_API void bgfx_set_view_uniform(bgfx_view_id_t _id, bgfx_uniform_handle_t _handle, const void* _value, uint16_t _num); + +/** + * Set shader uniform parameter for frame. + * @attention Uniform must be created with `bgfx::UniformFreq::View` argument. + * + * @param[in] _handle Uniform. + * @param[in] _value Pointer to uniform data. + * @param[in] _num Number of elements. Passing `UINT16_MAX` will + * use the _num passed on uniform creation. + * + */ +BGFX_C_API void bgfx_set_frame_uniform(bgfx_uniform_handle_t _handle, const void* _value, uint16_t _num); + /** * Set index buffer for draw primitive. * @@ -3604,6 +3679,7 @@ typedef enum bgfx_function_id BGFX_FUNCTION_ID_GET_TEXTURE, BGFX_FUNCTION_ID_DESTROY_FRAME_BUFFER, BGFX_FUNCTION_ID_CREATE_UNIFORM, + BGFX_FUNCTION_ID_CREATE_UNIFORM_WITH_FREQ, BGFX_FUNCTION_ID_GET_UNIFORM_INFO, BGFX_FUNCTION_ID_DESTROY_UNIFORM, BGFX_FUNCTION_ID_CREATE_OCCLUSION_QUERY, @@ -3636,6 +3712,8 @@ typedef enum bgfx_function_id BGFX_FUNCTION_ID_ENCODER_SET_TRANSFORM_CACHED, BGFX_FUNCTION_ID_ENCODER_ALLOC_TRANSFORM, BGFX_FUNCTION_ID_ENCODER_SET_UNIFORM, + BGFX_FUNCTION_ID_SET_VIEW_UNIFORM, + BGFX_FUNCTION_ID_SET_FRAME_UNIFORM, BGFX_FUNCTION_ID_ENCODER_SET_INDEX_BUFFER, BGFX_FUNCTION_ID_ENCODER_SET_DYNAMIC_INDEX_BUFFER, BGFX_FUNCTION_ID_ENCODER_SET_TRANSIENT_INDEX_BUFFER, @@ -3811,6 +3889,7 @@ struct bgfx_interface_vtbl bgfx_texture_handle_t (*get_texture)(bgfx_frame_buffer_handle_t _handle, uint8_t _attachment); void (*destroy_frame_buffer)(bgfx_frame_buffer_handle_t _handle); bgfx_uniform_handle_t (*create_uniform)(const char* _name, bgfx_uniform_type_t _type, uint16_t _num); + bgfx_uniform_handle_t (*create_uniform_with_freq)(const char* _name, bgfx_uniform_freq_t _freq, bgfx_uniform_type_t _type, uint16_t _num); void (*get_uniform_info)(bgfx_uniform_handle_t _handle, bgfx_uniform_info_t * _info); void (*destroy_uniform)(bgfx_uniform_handle_t _handle); bgfx_occlusion_query_handle_t (*create_occlusion_query)(void); @@ -3843,6 +3922,8 @@ struct bgfx_interface_vtbl void (*encoder_set_transform_cached)(bgfx_encoder_t* _this, uint32_t _cache, uint16_t _num); uint32_t (*encoder_alloc_transform)(bgfx_encoder_t* _this, bgfx_transform_t* _transform, uint16_t _num); void (*encoder_set_uniform)(bgfx_encoder_t* _this, bgfx_uniform_handle_t _handle, const void* _value, uint16_t _num); + void (*set_view_uniform)(bgfx_view_id_t _id, bgfx_uniform_handle_t _handle, const void* _value, uint16_t _num); + void (*set_frame_uniform)(bgfx_uniform_handle_t _handle, const void* _value, uint16_t _num); void (*encoder_set_index_buffer)(bgfx_encoder_t* _this, bgfx_index_buffer_handle_t _handle, uint32_t _firstIndex, uint32_t _numIndices); void (*encoder_set_dynamic_index_buffer)(bgfx_encoder_t* _this, bgfx_dynamic_index_buffer_handle_t _handle, uint32_t _firstIndex, uint32_t _numIndices); void (*encoder_set_transient_index_buffer)(bgfx_encoder_t* _this, const bgfx_transient_index_buffer_t* _tib, uint32_t _firstIndex, uint32_t _numIndices); diff --git a/include/bgfx/defines.h b/include/bgfx/defines.h index 215ddc348..b74c6534e 100644 --- a/include/bgfx/defines.h +++ b/include/bgfx/defines.h @@ -15,7 +15,7 @@ #ifndef BGFX_DEFINES_H_HEADER_GUARD #define BGFX_DEFINES_H_HEADER_GUARD -#define BGFX_API_VERSION UINT32_C(133) +#define BGFX_API_VERSION UINT32_C(134) /** * Color RGB/alpha/depth write. When it's not specified write will be disabled. diff --git a/scripts/bgfx.idl b/scripts/bgfx.idl index 6d1d1aa01..e3e4f4a20 100644 --- a/scripts/bgfx.idl +++ b/scripts/bgfx.idl @@ -1,7 +1,7 @@ -- vim: syntax=lua -- bgfx interface -version(133) +version(134) typedef "bool" typedef "char" @@ -631,6 +631,13 @@ enum.UniformType { comment = "Uniform types:" } .Mat4 --- 4x4 matrix. () +--- Uniform frequency enum. +enum.UniformFreq { comment = "Uniform frequency:" } + .Draw --- Changing per draw call. + .View --- Changing per view. + .Frame --- Changing per frame. + () + --- Backbuffer ratio enum. enum.BackbufferRatio { comment = "Backbuffer ratios:" } .Equal --- Equal to backbuffer. @@ -1980,6 +1987,41 @@ func.createUniform .num "uint16_t" --- Number of elements in array. { default = 1 } +--- Create shader uniform parameter. +--- +--- @remarks +--- 1. Uniform names are unique. It's valid to call `bgfx::createUniform` +--- multiple times with the same uniform name. The library will always +--- return the same handle, but the handle reference count will be +--- incremented. This means that the same number of `bgfx::destroyUniform` +--- must be called to properly destroy the uniform. +--- +--- 2. Predefined uniforms (declared in `bgfx_shader.sh`): +--- - `u_viewRect vec4(x, y, width, height)` - view rectangle for current +--- view, in pixels. +--- - `u_viewTexel vec4(1.0/width, 1.0/height, undef, undef)` - inverse +--- width and height +--- - `u_view mat4` - view matrix +--- - `u_invView mat4` - inverted view matrix +--- - `u_proj mat4` - projection matrix +--- - `u_invProj mat4` - inverted projection matrix +--- - `u_viewProj mat4` - concatenated view projection matrix +--- - `u_invViewProj mat4` - concatenated inverted view projection matrix +--- - `u_model mat4[BGFX_CONFIG_MAX_BONES]` - array of model matrices. +--- - `u_modelView mat4` - concatenated model view matrix, only first +--- model matrix from array is used. +--- - `u_invModelView mat4` - inverted concatenated model view matrix. +--- - `u_modelViewProj mat4` - concatenated model view projection matrix. +--- - `u_alphaRef float` - alpha reference value for alpha test. +--- +func.createUniform { cname = "create_uniform_with_freq" } + "UniformHandle" --- Handle to uniform object. + .name "const char*" --- Uniform name in shader. + .freq "UniformFreq::Enum" --- Uniform change frequency (See: `bgfx::UniformFreq`). + .type "UniformType::Enum" --- Type of uniform (See: `bgfx::UniformType`). + .num "uint16_t" --- Number of elements in array. + { default = 1 } + --- Retrieve uniform info. func.getUniformInfo "void" @@ -2294,6 +2336,31 @@ func.Encoder.setUniform --- use the _num passed on uniform creation. { default = 1 } +--- Set shader uniform parameter for view. +--- +--- @attention Uniform must be created with `bgfx::UniformFreq::View` argument. +--- +func.setViewUniform + "void" + .id "ViewId" --- View id. + .handle "UniformHandle" --- Uniform. + .value "const void*" --- Pointer to uniform data. + .num "uint16_t" --- Number of elements. Passing `UINT16_MAX` will + --- use the _num passed on uniform creation. + { default = 1 } + +--- Set shader uniform parameter for frame. +--- +--- @attention Uniform must be created with `bgfx::UniformFreq::View` argument. +--- +func.setFrameUniform + "void" + .handle "UniformHandle" --- Uniform. + .value "const void*" --- Pointer to uniform data. + .num "uint16_t" --- Number of elements. Passing `UINT16_MAX` will + --- use the _num passed on uniform creation. + { default = 1 } + --- Set index buffer for draw primitive. func.Encoder.setIndexBuffer { cpponly } "void" diff --git a/src/bgfx.cpp b/src/bgfx.cpp index ad1b668cd..317628498 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -1430,6 +1430,8 @@ namespace bgfx } bx::radixSort(m_blitKeys, (uint32_t*)&s_ctx->m_tempKeys, m_numBlitItems); + + m_uniformCacheFrame.sort(viewRemap, s_ctx->m_tempKeys); } RenderFrame::Enum renderFrame(int32_t _msecs) @@ -1610,6 +1612,18 @@ namespace bgfx BX_TRACE("\t C Seq %016" PRIx64, kSortKeyComputeSeqMask); BX_TRACE("\t C Program %016" PRIx64, kSortKeyComputeProgramMask); + BX_TRACE(""); + BX_TRACE("Blit key masks:"); + BX_TRACE("\tView %08" PRIx32, BlitKey::kViewMask); + BX_TRACE("\tItem %08" PRIx32, BlitKey::kItemMask); + + BX_TRACE(""); + BX_TRACE("Uniform cache key masks:"); + BX_TRACE("\tView %016" PRIx64, UniformCacheKey::kViewMask); + BX_TRACE("\tHandle %016" PRIx64, UniformCacheKey::kHandleMask); + BX_TRACE("\tOffset %016" PRIx64, UniformCacheKey::kOffsetMask); + BX_TRACE("\tSize %016" PRIx64, UniformCacheKey::kSizeMask); + BX_TRACE(""); BX_TRACE("Capabilities (renderer %s, vendor 0x%04x, device 0x%04x):" , s_ctx->m_renderCtx->getRendererName() @@ -1779,7 +1793,12 @@ namespace bgfx const char* getName(UniformHandle _handle) { - return s_ctx->m_uniformRef[_handle.idx].m_name.getCPtr(); + return getUniformRef(_handle).m_name.getCPtr(); + } + + const UniformRef& getUniformRef(UniformHandle _handle) + { + return s_ctx->m_uniformRef[_handle.idx]; } const char* getName(ShaderHandle _handle) @@ -2241,7 +2260,9 @@ namespace bgfx for (uint16_t ii = 0, num = _frame->m_freeUniform.getNumQueued(); ii < num; ++ii) { - m_uniformHandle.free(_frame->m_freeUniform.get(ii).idx); + UniformHandle handle = _frame->m_freeUniform.get(ii); + m_uniformCache.invalidate(handle); + m_uniformHandle.free(handle.idx); } } @@ -2328,6 +2349,10 @@ namespace bgfx m_submit->m_perfStats.numViews = 0; bx::memCopy(m_submit->m_viewRemap, m_viewRemap, sizeof(m_viewRemap) ); + + m_uniformCache.frame(m_submit->m_uniformCacheFrame); + + static_assert(bx::isTriviallyCopyable(), "Must be memcopyiable..."); bx::memCopy(m_submit->m_view, m_view, sizeof(m_view) ); if (m_colorPaletteDirty > 0) @@ -3767,6 +3792,7 @@ namespace bgfx { BGFX_CHECK_HANDLE("setUniform", s_ctx->m_uniformHandle, _handle); const UniformRef& uniform = s_ctx->m_uniformRef[_handle.idx]; + BX_ASSERT(uniform.m_freq == UniformFreq::Draw, "Setting uniform per draw call, but uniform is created with different bgfx::UniformFreq::Enum!"); BX_ASSERT(isValid(_handle) && 0 < uniform.m_refCount, "Setting invalid uniform (handle %3d)!", _handle.idx); BX_ASSERT(_num == UINT16_MAX || uniform.m_num >= _num, "Truncated uniform update. %d (max: %d)", _num, uniform.m_num); BGFX_ENCODER(setUniform(uniform.m_type, _handle, _value, UINT16_MAX != _num ? _num : uniform.m_num) ); @@ -5200,7 +5226,12 @@ namespace bgfx UniformHandle createUniform(const char* _name, UniformType::Enum _type, uint16_t _num) { - return s_ctx->createUniform(_name, _type, _num); + return s_ctx->createUniform(_name, UniformFreq::Draw, _type, _num); + } + + UniformHandle createUniform(const char* _name, UniformFreq::Enum _freq, UniformType::Enum _type, uint16_t _num) + { + return s_ctx->createUniform(_name, _freq, _type, _num); } void getUniformInfo(UniformHandle _handle, UniformInfo& _info) @@ -5408,6 +5439,17 @@ namespace bgfx s_ctx->m_encoder0->setUniform(_handle, _value, _num); } + void setViewUniform(ViewId _id, UniformHandle _handle, const void* _value, uint16_t _num) + { + BX_ASSERT(checkView(_id), "Invalid view id: %d", _id); + s_ctx->setViewUniform(_id, _handle, _value, _num); + } + + void setFrameUniform(UniformHandle _handle, const void* _value, uint16_t _num) + { + s_ctx->setViewUniform(UINT16_MAX, _handle, _value, _num); + } + void setIndexBuffer(IndexBufferHandle _handle) { BGFX_CHECK_ENCODER0(); diff --git a/src/bgfx.idl.inl b/src/bgfx.idl.inl index 9c2f69b92..cab986d62 100644 --- a/src/bgfx.idl.inl +++ b/src/bgfx.idl.inl @@ -601,6 +601,13 @@ BGFX_C_API bgfx_uniform_handle_t bgfx_create_uniform(const char* _name, bgfx_uni return handle_ret.c; } +BGFX_C_API bgfx_uniform_handle_t bgfx_create_uniform_with_freq(const char* _name, bgfx_uniform_freq_t _freq, bgfx_uniform_type_t _type, uint16_t _num) +{ + union { bgfx_uniform_handle_t c; bgfx::UniformHandle cpp; } handle_ret; + handle_ret.cpp = bgfx::createUniform(_name, (bgfx::UniformFreq::Enum)_freq, (bgfx::UniformType::Enum)_type, _num); + return handle_ret.c; +} + BGFX_C_API void bgfx_get_uniform_info(bgfx_uniform_handle_t _handle, bgfx_uniform_info_t * _info) { union { bgfx_uniform_handle_t c; bgfx::UniformHandle cpp; } handle = { _handle }; @@ -781,6 +788,18 @@ BGFX_C_API void bgfx_encoder_set_uniform(bgfx_encoder_t* _this, bgfx_uniform_han This->setUniform(handle.cpp, _value, _num); } +BGFX_C_API void bgfx_set_view_uniform(bgfx_view_id_t _id, bgfx_uniform_handle_t _handle, const void* _value, uint16_t _num) +{ + union { bgfx_uniform_handle_t c; bgfx::UniformHandle cpp; } handle = { _handle }; + bgfx::setViewUniform((bgfx::ViewId)_id, handle.cpp, _value, _num); +} + +BGFX_C_API void bgfx_set_frame_uniform(bgfx_uniform_handle_t _handle, const void* _value, uint16_t _num) +{ + union { bgfx_uniform_handle_t c; bgfx::UniformHandle cpp; } handle = { _handle }; + bgfx::setFrameUniform(handle.cpp, _value, _num); +} + BGFX_C_API void bgfx_encoder_set_index_buffer(bgfx_encoder_t* _this, bgfx_index_buffer_handle_t _handle, uint32_t _firstIndex, uint32_t _numIndices) { bgfx::Encoder* This = (bgfx::Encoder*)_this; @@ -1392,6 +1411,7 @@ BGFX_C_API bgfx_interface_vtbl_t* bgfx_get_interface(uint32_t _version) bgfx_get_texture, bgfx_destroy_frame_buffer, bgfx_create_uniform, + bgfx_create_uniform_with_freq, bgfx_get_uniform_info, bgfx_destroy_uniform, bgfx_create_occlusion_query, @@ -1424,6 +1444,8 @@ BGFX_C_API bgfx_interface_vtbl_t* bgfx_get_interface(uint32_t _version) bgfx_encoder_set_transform_cached, bgfx_encoder_alloc_transform, bgfx_encoder_set_uniform, + bgfx_set_view_uniform, + bgfx_set_frame_uniform, bgfx_encoder_set_index_buffer, bgfx_encoder_set_dynamic_index_buffer, bgfx_encoder_set_transient_index_buffer, diff --git a/src/bgfx_p.h b/src/bgfx_p.h index 0cd264f21..f6edb00ed 100644 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -593,6 +593,8 @@ namespace bgfx const char* getName(ShaderHandle _handle); const char* getName(Topology::Enum _topology); + const struct UniformRef& getUniformRef(UniformHandle _handle); + template inline void release(Ty) { @@ -1313,33 +1315,43 @@ namespace bgfx }; #undef SORT_KEY_RENDER_DRAW - constexpr uint8_t kBlitKeyViewShift = 32-kSortKeyViewNumBits; - constexpr uint32_t kBlitKeyViewMask = uint32_t(BGFX_CONFIG_MAX_VIEWS-1)<> kBlitKeyItemShift); - m_view = ViewId( (_key & kBlitKeyViewMask) >> kBlitKeyViewShift); + m_item = uint16_t( (_key & kItemMask) >> kItemShift); + m_view = ViewId( (_key & kViewMask) >> kViewShift); } - static uint32_t remapView(uint32_t _key, ViewId _viewRemap[BGFX_CONFIG_MAX_VIEWS]) + static KeyT remapView(KeyT _key, ViewId _viewRemap[BGFX_CONFIG_MAX_VIEWS]) { - const ViewId oldView = ViewId( (_key & kBlitKeyViewMask) >> kBlitKeyViewShift); - const uint32_t view = uint32_t( (_viewRemap[oldView] << kBlitKeyViewShift) & kBlitKeyViewMask); - const uint32_t key = (_key & ~kBlitKeyViewMask) | view; + const ViewId oldView = ViewId( (_key & kViewMask) >> kViewShift); + const KeyT view = uint32_t( (_viewRemap[oldView] << kViewShift) & kViewMask); + const KeyT key = (_key & ~kViewMask) | view; return key; } @@ -1764,7 +1776,7 @@ namespace bgfx m_startIndirect = 0; m_numIndirect = UINT32_MAX; - m_numIndirectIndex = 0; + m_numIndirectIndex = 0; m_indirectBuffer = BGFX_INVALID_HANDLE; m_numIndirectBuffer = BGFX_INVALID_HANDLE; m_occlusionQuery = BGFX_INVALID_HANDLE; @@ -1953,6 +1965,7 @@ namespace bgfx struct UniformRef { bx::FixedString64 m_name; + UniformFreq::Enum m_freq; UniformType::Enum m_type; uint16_t m_num; int16_t m_refCount; @@ -2099,6 +2112,11 @@ namespace bgfx m_shadingRate = uint8_t(_shadingRate); } + void setUniform(UniformHandle _handle, const void* _value, uint16_t _num) + { + BX_UNUSED(_handle, _value, _num); + } + void setFrameBuffer(FrameBufferHandle _handle) { m_fbh = _handle; @@ -2135,6 +2153,149 @@ namespace bgfx uint8_t m_shadingRate; }; + struct UniformCacheKey + { + using KeyT = uint64_t; + + static constexpr uint8_t kViewShift = sizeof(KeyT)*8-kSortKeyViewNumBits; + static constexpr KeyT kViewMask = KeyT(BGFX_CONFIG_MAX_VIEWS-1)<>12)<>4)<>kSizeShift ) + 1)<<4; + constexpr uint32_t kMaxOffset = ( (kOffsetMask>>kOffsetShift) + 1)<<4; + + BX_ASSERT(true + && m_size < kMaxSize + && m_offset < kMaxOffset + , "UniformCacheKey couldn't fit size or offest (size %d max %d, offset %d max %d)!" + , m_size + , kMaxSize + , m_offset + , kMaxOffset + ); + + const KeyT view = (KeyT(m_view) << kViewShift) & kViewMask; + const KeyT handle = (KeyT(m_handle) << kHandleShift) & kHandleMask; + const KeyT offset = (KeyT(m_offset>>4) << kOffsetShift) & kOffsetMask; + const KeyT size = (KeyT(m_size>>4) << kSizeShift) & kSizeMask; + const KeyT key = view|handle|offset|size; + + return key; + } + + void decode(KeyT _key) + { + m_offset = (uint32_t( (_key & kOffsetMask) >> kOffsetShift) ) << 4; + m_handle = {uint16_t( (_key & kHandleMask) >> kHandleShift) }; + m_size = (uint16_t( (_key & kSizeMask) >> kSizeShift ) ) << 4; + m_view = ViewId( (_key & kViewMask) >> kViewShift); + } + + static KeyT remapView(KeyT _key, ViewId _viewRemap[BGFX_CONFIG_MAX_VIEWS]) + { + const ViewId oldView = ViewId( (_key & kViewMask) >> kViewShift); + const KeyT view = UINT16_MAX != oldView + ? (KeyT(_viewRemap[oldView]) << kViewShift) & kViewMask + : 0 // frame uniforms go into physical view 0. + ; + const KeyT key = (_key & ~kViewMask) | view; + return key; + } + + uint32_t m_offset; + uint16_t m_handle; + uint16_t m_size; + ViewId m_view; + }; + + struct UniformCacheEntry + { + uint32_t offset; + uint16_t size; + int16_t refCount; + }; + + struct UniformCacheFrame + { + static constexpr uint32_t kMinKeysCapacity = 256; + static constexpr uint32_t kMinDataCapacity = 16<<10; + + UniformCacheFrame() + : m_keys(NULL) + , m_data(NULL) + , m_numItems(0) + , m_keysCapacity(kMinKeysCapacity) + , m_dataCapacity(kMinDataCapacity) + { + m_keys = (UniformCacheKey::KeyT*)bx::alloc(g_allocator, m_keysCapacity*sizeof(uint64_t) ); + m_data = (uint8_t*)bx::alloc(g_allocator, m_dataCapacity); + } + + ~UniformCacheFrame() + { + bx::free(g_allocator, m_keys); + bx::free(g_allocator, m_data); + } + + void resize(uint32_t _keysCapacity, uint32_t _dataCapacity) + { + { + const uint32_t newKeysCapacity = bx::alignUp(bx::max(_keysCapacity, kMinKeysCapacity), kMinKeysCapacity); + + if (newKeysCapacity != m_keysCapacity) + { + bx::realloc(g_allocator, m_keys, newKeysCapacity*sizeof(uint64_t) ); + m_keysCapacity = newKeysCapacity; + } + } + + { + const uint32_t newDataCapacity = bx::alignUp(bx::max(_dataCapacity, kMinDataCapacity), kMinDataCapacity); + + if (newDataCapacity != m_dataCapacity) + { + bx::realloc(g_allocator, m_keys, newDataCapacity); + m_dataCapacity = newDataCapacity; + } + } + } + + void sort(ViewId* _viewRemap, uint64_t* _tempKeys) + { + for (uint32_t ii = 0, num = m_numItems; ii < num; ++ii) + { + m_keys[ii] = UniformCacheKey::remapView(m_keys[ii], _viewRemap); + } + + bx::radixSort(m_keys, _tempKeys, m_numItems); + } + + uint64_t* m_keys; + uint8_t* m_data; + uint32_t m_numItems; + uint32_t m_keysCapacity; + uint32_t m_dataCapacity; + }; + struct FrameCache { void reset() @@ -2182,7 +2343,7 @@ namespace bgfx m_perfStats.viewStats = m_viewStats; - bx::memSet(&m_renderItemBind[0], 0, sizeof(m_renderItemBind)); + bx::memSet(&m_renderItemBind[0], 0, sizeof(m_renderItemBind) ); } ~Frame() @@ -2358,6 +2519,8 @@ namespace bgfx uint32_t m_blitKeys[BGFX_CONFIG_MAX_BLIT_ITEMS+1]; BlitItem m_blitItem[BGFX_CONFIG_MAX_BLIT_ITEMS+1]; + UniformCacheFrame m_uniformCacheFrame; + FrameCache m_frameCache; UniformBuffer** m_uniformBuffer; @@ -2465,7 +2628,7 @@ namespace bgfx // will leaves bytes uninitialized. This will influence the hashing // as it reads those bytes too. To make this deterministic, we will // clear all bytes (inclusively the padding) before we start. - bx::memSet(&m_bind, 0, sizeof(m_bind)); + bx::memSet(&m_bind, 0, sizeof(m_bind) ); discard(BGFX_DISCARD_ALL); } @@ -2524,7 +2687,13 @@ namespace bgfx , _handle.idx , getName(_handle) ); -// m_uniformSet.insert(_handle.idx); + m_uniformSet.insert(_handle.idx); + + const UniformRef& uniform = getUniformRef(_handle); + BX_ASSERT(UniformFreq::Draw == uniform.m_freq + , "Setting uniform for draw call, but uniform frequency is different (frequency: %d)!" + , uniform.m_freq + ); } UniformBuffer::update(&m_frame->m_uniformBuffer[m_uniformIdx]); @@ -2960,6 +3129,7 @@ namespace bgfx static const uint64_t kInvalidBlock = UINT64_MAX; NonLocalAllocator() + : m_total(0) { } @@ -2971,6 +3141,7 @@ namespace bgfx { m_free.clear(); m_used.clear(); + m_total = 0; } void add(uint64_t _ptr, uint32_t _size) @@ -3003,6 +3174,7 @@ namespace bgfx uint64_t ptr = it->m_ptr; m_used.insert(stl::make_pair(ptr, _size) ); + m_total += _size; if (it->m_size != _size) { @@ -3027,6 +3199,8 @@ namespace bgfx UsedList::iterator it = m_used.find(_block); if (it != m_used.end() ) { + m_total -= it->second; + m_free.push_front(Free(it->first, it->second) ); m_used.erase(it); } @@ -3053,6 +3227,11 @@ namespace bgfx return 0 == m_used.size(); } + uint32_t getTotal() const + { + return m_total; + } + private: struct Free { @@ -3076,6 +3255,248 @@ namespace bgfx typedef stl::unordered_map UsedList; UsedList m_used; + + uint32_t m_total; + }; + + struct UniformCache + { + UniformCache() + { + const uint32_t size = 1<<20; + m_data = (uint8_t*)bx::alloc(g_allocator, size); + m_uniformStoreAlloc.add(0, size); + } + + ~UniformCache() + { + BX_ASSERT(true + && 0 == m_uniformKeyHashMap.size() + && 0 == m_uniformEntryMap.size() + && 0 == m_uniformStoreAlloc.getTotal() + , "UniformCache leak (keys %d, entries %d, %d bytes)!" + , m_uniformKeyHashMap.size() + , m_uniformEntryMap.size() + , m_uniformStoreAlloc.getTotal() + ); + + bx::free(g_allocator, m_data); + m_uniformKeyHashMap.clear(); + m_uniformEntryMap.clear(); + } + + void setViewUniform(ViewId _id, UniformHandle _handle, const void* _value, uint16_t _num) + { + const UniformRef& uniform = getUniformRef(_handle); + + UniformCacheKey key = + { + .m_offset = 0, + .m_handle = _handle.idx, + .m_size = 0, + .m_view = _id, + }; + + constexpr UniformCacheKey::KeyT kViewHandleMask = UniformCacheKey::kViewMask|UniformCacheKey::kHandleMask; + static_assert( ( (kViewHandleMask>>32)<<32) == kViewHandleMask, "View + handle must be in top 32 bits of 64-bit key."); + const uint32_t uniformKey = uint32_t(key.encode() >> 32); + + setUniform(uniformKey, uniform.m_type, _value, _num); + } + + void setUniform(uint32_t _uniformKey, UniformType::Enum _type, const void* _value, uint16_t _num) + { + const uint32_t typeSize = g_uniformTypeSize[_type]; + const uint32_t dataSize = _num * typeSize; + + bx::HashMurmur3 murmur; + murmur.begin(); + murmur.add(_type); + murmur.add(_num); + murmur.add(_value, dataSize); + const uint32_t hash = murmur.end(); + + UniformKeyHashMap::iterator itKey = m_uniformKeyHashMap.find(_uniformKey); + if (itKey != m_uniformKeyHashMap.end() ) + { + if (itKey->second == hash) + { + return; + } + + UniformEntryMap::iterator itOldEntry = m_uniformEntryMap.find(itKey->second); + if (itOldEntry != m_uniformEntryMap.end()) + { + if (release(itOldEntry->second) ) + { + m_uniformEntryMap.erase(itOldEntry); + } + } + + itKey->second = hash; + + UniformEntryMap::iterator itEntry = m_uniformEntryMap.find(hash); + if (itEntry != m_uniformEntryMap.end()) + { + ++itEntry->second.refCount; + + return; + } + } + else + { + m_uniformKeyHashMap.insert(stl::make_pair(_uniformKey, hash) ); + } + + UniformEntryMap::iterator itEntry = m_uniformEntryMap.find(hash); + if (itEntry != m_uniformEntryMap.end()) + { + ++itEntry->second.refCount; + } + else + { + const uint64_t offset = m_uniformStoreAlloc.alloc(dataSize); + BX_ASSERT(NonLocalAllocator::kInvalidBlock != offset, "UniformCache: Failed to allocate data!"); + + m_uniformEntryMap.insert(stl::make_pair(hash, UniformCacheEntry + { + .offset = bx::narrowCast(offset), + .size = bx::narrowCast(dataSize), + .refCount = 1 + }) ); + + bx::memCopy(&m_data[offset], _value, dataSize); + } + } + + void frame(UniformCacheFrame& _outUniformCacheFrame) + { + m_uniformStoreAlloc.compact(); + + _outUniformCacheFrame.resize( + uint32_t(m_uniformKeyHashMap.size() ) + , m_uniformStoreAlloc.getTotal() + ); + + using OffsetRemap = stl::unordered_map; + OffsetRemap offsetRemap; + + uint32_t linearOffset = 0; + uint32_t num = 0; + for (UniformKeyHashMap::const_iterator itKey = m_uniformKeyHashMap.begin(), itEnd = m_uniformKeyHashMap.end(); itKey != itEnd; ++itKey) + { + UniformEntryMap::iterator itEntry = m_uniformEntryMap.find(itKey->second); + BX_ASSERT(itEntry != m_uniformEntryMap.end() + , "Couldn't find uniform cache entry for key 0x%d, hash 0x%x!" + , itKey->first + , itKey->second + ); + + const uint32_t offset = itEntry->second.offset; + const uint16_t size = itEntry->second.size; + + UniformCacheKey key; + key.decode(uint64_t(itKey->first)<<32); + key.m_size = size; + + OffsetRemap::const_iterator itOffset = offsetRemap.find(offset); + if (itOffset != offsetRemap.end()) + { + key.m_offset = itOffset->second; + } + else + { + key.m_offset = linearOffset; + + offsetRemap.insert(stl::make_pair(offset, linearOffset) ); + bx::memCopy(&_outUniformCacheFrame.m_data[linearOffset], &m_data[offset], size); + + linearOffset += size; + } + + _outUniformCacheFrame.m_keys[num++] = key.encode(); + } + + _outUniformCacheFrame.m_numItems = num; + } + + void invalidate(ViewId _viewId) + { + for (UniformKeyHashMap::iterator itKey = m_uniformKeyHashMap.begin(), itEnd = m_uniformKeyHashMap.end(); itKey != itEnd; ++itKey) + { + UniformCacheKey key; + key.decode(uint64_t(itKey->first) << 32); + + if (key.m_view == _viewId) + { + release(itKey->second); + + UniformKeyHashMap::iterator itErase = itKey; + ++itKey; + + m_uniformKeyHashMap.erase(itErase); + } + } + } + + void invalidate(UniformHandle _handle) + { + for (UniformKeyHashMap::iterator itKey = m_uniformKeyHashMap.begin(), itEnd = m_uniformKeyHashMap.end(); itKey != itEnd;) + { + UniformCacheKey key; + key.decode(uint64_t(itKey->first) << 32); + + if (key.m_handle == _handle.idx) + { + release(itKey->second); + + UniformKeyHashMap::iterator itErase = itKey; + ++itKey; + + m_uniformKeyHashMap.erase(itErase); + } + else + { + ++itKey; + } + } + } + + bool release(UniformCacheEntry& _entry) + { + --_entry.refCount; + + if (0 == _entry.refCount) + { + const uint64_t offset = _entry.offset; + + m_uniformStoreAlloc.free(offset); + return true; + } + + return false; + } + + void release(uint32_t _hash) + { + UniformEntryMap::iterator itEntry = m_uniformEntryMap.find(_hash); + if (itEntry != m_uniformEntryMap.end()) + { + if (release(itEntry->second) ) + { + m_uniformEntryMap.erase(itEntry); + } + } + } + + using UniformKeyHashMap = stl::unordered_map; + using UniformEntryMap = stl::unordered_map; + + UniformKeyHashMap m_uniformKeyHashMap; + UniformEntryMap m_uniformEntryMap; + + NonLocalAllocator m_uniformStoreAlloc; + uint8_t* m_data; }; struct BX_NO_VTABLE RendererContextI @@ -4248,7 +4669,7 @@ namespace bgfx PredefinedUniform::Enum predefined = nameToPredefinedUniformEnum(name); if (PredefinedUniform::Count == predefined && UniformType::End != UniformType::Enum(type) ) { - uniforms[sr.m_num] = createUniform(name, UniformType::Enum(type), num); + uniforms[sr.m_num] = createUniform(name, UniformFreq::Draw, UniformType::Enum(type), num); sr.m_num++; } } @@ -4903,7 +5324,7 @@ namespace bgfx } } - BGFX_API_FUNC(UniformHandle createUniform(const char* _name, UniformType::Enum _type, uint16_t _num) ) + BGFX_API_FUNC(UniformHandle createUniform(const char* _name, UniformFreq::Enum _freq, UniformType::Enum _type, uint16_t _num) ) { BGFX_MUTEX_SCOPE(m_resourceApiLock); @@ -4930,8 +5351,10 @@ namespace bgfx , uniform.m_type ); - uint32_t oldsize = g_uniformTypeSize[uniform.m_type]; - uint32_t newsize = g_uniformTypeSize[_type]; + const uint32_t oldsize = g_uniformTypeSize[uniform.m_type]; + const uint32_t newsize = g_uniformTypeSize[_type]; + + uniform.m_freq = _freq; // Ignore shader created uniforms, and use UniformFreq when user creates uniform. if (oldsize < newsize || uniform.m_num < _num) @@ -4967,6 +5390,7 @@ namespace bgfx UniformRef& uniform = m_uniformRef[handle.idx]; uniform.m_name.set(_name); uniform.m_refCount = 1; + uniform.m_freq = _freq; uniform.m_type = _type; uniform.m_num = _num; @@ -5191,9 +5615,15 @@ namespace bgfx m_view[_id].setShadingRate(_shadingRate); } + BGFX_API_FUNC(void setViewUniform(ViewId _id, UniformHandle _handle, const void* _value, uint16_t _num) ) + { + m_uniformCache.setViewUniform(_id, _handle, _value, _num); + } + BGFX_API_FUNC(void resetView(ViewId _id) ) { m_view[_id].reset(); + m_uniformCache.invalidate(_id); } BGFX_API_FUNC(Encoder* begin(bool _forThread) ); @@ -5387,6 +5817,8 @@ namespace bgfx uint32_t m_seq[BGFX_CONFIG_MAX_VIEWS]; View m_view[BGFX_CONFIG_MAX_VIEWS]; + UniformCache m_uniformCache; + float m_clearColor[BGFX_CONFIG_MAX_COLOR_PALETTE][4]; uint8_t m_colorPaletteDirty; diff --git a/src/renderer.h b/src/renderer.h index c8971fa82..743e90d44 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -58,6 +58,49 @@ namespace bgfx uint16_t m_item; }; + struct UniformCacheItem + { + uint32_t m_offset; + uint16_t m_size; + uint16_t m_handle; + }; + + struct UniformCacheState + { + UniformCacheState(const Frame* _frame) + : m_frame(_frame) + , m_item(0) + { + m_key.decode(_frame->m_uniformCacheFrame.m_keys[0]); + } + + bool hasItem(uint16_t _view) const + { + return m_item < m_frame->m_uniformCacheFrame.m_numItems + && m_key.m_view <= _view + ; + } + + const UniformCacheItem advance() + { + UniformCacheItem item = + { + .m_offset = m_key.m_offset, + .m_size = m_key.m_size, + .m_handle = m_key.m_handle, + }; + + ++m_item; + m_key.decode(m_frame->m_uniformCacheFrame.m_keys[m_item]); + + return item; + } + + const Frame* m_frame; + UniformCacheKey m_key; + uint16_t m_item; + }; + struct ViewState { ViewState() diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 1e58a310f..661161a4d 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -2123,6 +2123,8 @@ namespace bgfx { namespace d3d11 void submitBlit(BlitState& _bs, uint16_t _view); + void submitUniformCache(UniformCacheState& _ucs, uint16_t _view); + void submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) override; void blitSetup(TextVideoMemBlitter& _blitter) override @@ -5589,6 +5591,16 @@ namespace bgfx { namespace d3d11 } } + void RendererContextD3D11::submitUniformCache(UniformCacheState& _ucs, uint16_t _view) + { + while (_ucs.hasItem(_view) ) + { + const UniformCacheItem& uci = _ucs.advance(); + + bx::memCopy(m_uniforms[uci.m_handle], &_ucs.m_frame->m_uniformCacheFrame.m_data[uci.m_offset], uci.m_size); + } + } + void RendererContextD3D11::submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) { if (m_lost) @@ -5659,6 +5671,7 @@ namespace bgfx { namespace d3d11 uint16_t view = UINT16_MAX; FrameBufferHandle fbh = { BGFX_CONFIG_MAX_FRAME_BUFFERS }; + UniformCacheState ucs(_render); BlitState bs(_render); const uint64_t primType = _render->m_debug&BGFX_DEBUG_WIREFRAME ? BGFX_STATE_PT_LINES : 0; @@ -5759,6 +5772,7 @@ namespace bgfx { namespace d3d11 prim = s_primInfo[Topology::Count]; // Force primitive type update after clear quad. } + submitUniformCache(ucs, view); submitBlit(bs, view); } diff --git a/src/renderer_d3d12.cpp b/src/renderer_d3d12.cpp index db8738a8c..a4f0166be 100644 --- a/src/renderer_d3d12.cpp +++ b/src/renderer_d3d12.cpp @@ -2269,6 +2269,8 @@ namespace bgfx { namespace d3d12 void submitBlit(BlitState& _bs, uint16_t _view); + void submitUniformCache(UniformCacheState& _ucs, uint16_t _view); + void submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) override; void blitSetup(TextVideoMemBlitter& _blitter) override @@ -6466,6 +6468,16 @@ namespace bgfx { namespace d3d12 } } + void RendererContextD3D12::submitUniformCache(UniformCacheState& _ucs, uint16_t _view) + { + while (_ucs.hasItem(_view) ) + { + const UniformCacheItem& uci = _ucs.advance(); + + bx::memCopy(m_uniforms[uci.m_handle], &_ucs.m_frame->m_uniformCacheFrame.m_data[uci.m_offset], uci.m_size); + } + } + void RendererContextD3D12::submit(Frame* _render, ClearQuad& /*_clearQuad*/, TextVideoMemBlitter& _textVideoMemBlitter) { if (m_lost @@ -6526,6 +6538,7 @@ namespace bgfx { namespace d3d12 uint16_t view = UINT16_MAX; FrameBufferHandle fbh = { BGFX_CONFIG_MAX_FRAME_BUFFERS }; + UniformCacheState ucs(_render); BlitState bs(_render); uint32_t blendFactor = 0; @@ -6690,6 +6703,7 @@ namespace bgfx { namespace d3d12 prim = s_primInfo[Topology::Count]; // Force primitive type update. + submitUniformCache(ucs, view); submitBlit(bs, view); if (m_variableRateShadingSupport) diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 029952bd7..d52269f51 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -3674,6 +3674,8 @@ namespace bgfx { namespace gl void submitBlit(BlitState& _bs, uint16_t _view); + void submitUniformCache(UniformCacheState& _ucs, uint16_t _view); + void submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) override; void blitSetup(TextVideoMemBlitter& _blitter) override @@ -7463,6 +7465,16 @@ namespace bgfx { namespace gl } } + void RendererContextGL::submitUniformCache(UniformCacheState& _ucs, uint16_t _view) + { + while (_ucs.hasItem(_view) ) + { + const UniformCacheItem& uci = _ucs.advance(); + + bx::memCopy(m_uniforms[uci.m_handle], &_ucs.m_frame->m_uniformCacheFrame.m_data[uci.m_offset], uci.m_size); + } + } + void RendererContextGL::submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) { if (_render->m_capture) @@ -7527,6 +7539,7 @@ namespace bgfx { namespace gl uint16_t view = UINT16_MAX; FrameBufferHandle fbh = { BGFX_CONFIG_MAX_FRAME_BUFFERS }; + UniformCacheState ucs(_render); BlitState bs(_render); int32_t resolutionHeight = _render->m_resolution.height; @@ -7649,6 +7662,7 @@ namespace bgfx { namespace gl GL_CHECK(glEnable(GL_CULL_FACE) ); GL_CHECK(glDisable(GL_BLEND) ); + submitUniformCache(ucs, view); submitBlit(bs, view); } diff --git a/src/renderer_mtl.mm b/src/renderer_mtl.mm index be5eb1312..c7f472b39 100644 --- a/src/renderer_mtl.mm +++ b/src/renderer_mtl.mm @@ -1338,6 +1338,8 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames void submitBlit(BlitState& _bs, uint16_t _view); + void submitUniformCache(UniformCacheState& _ucs, uint16_t _view); + void submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) override; void blitSetup(TextVideoMemBlitter& _blitter) override @@ -4137,6 +4139,16 @@ BX_PRAGMA_DIAGNOSTIC_POP(); } } + void RendererContextMtl::submitUniformCache(UniformCacheState& _ucs, uint16_t _view) + { + while (_ucs.hasItem(_view) ) + { + const UniformCacheItem& uci = _ucs.advance(); + + bx::memCopy(m_uniforms[uci.m_handle], &_ucs.m_frame->m_uniformCacheFrame.m_data[uci.m_offset], uci.m_size); + } + } + void RendererContextMtl::submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) { m_cmd.finish(false); @@ -4265,6 +4277,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); uint16_t view = UINT16_MAX; FrameBufferHandle fbh = { BGFX_CONFIG_MAX_FRAME_BUFFERS }; + UniformCacheState ucs(_render); BlitState bs(_render); const uint64_t primType = 0; @@ -4336,6 +4349,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); viewState.m_rect = _render->m_view[view].m_rect; + submitUniformCache(ucs, view); submitBlit(bs, view); if (!isCompute) diff --git a/src/renderer_vk.cpp b/src/renderer_vk.cpp index 99ecd9bc6..e90745c88 100644 --- a/src/renderer_vk.cpp +++ b/src/renderer_vk.cpp @@ -2679,6 +2679,8 @@ VK_IMPORT_DEVICE void submitBlit(BlitState& _bs, uint16_t _view); + void submitUniformCache(UniformCacheState& _ucs, uint16_t _view); + void submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) override; void blitSetup(TextVideoMemBlitter& _blitter) override @@ -8738,6 +8740,16 @@ VK_DESTROY } } + void RendererContextVK::submitUniformCache(UniformCacheState& _ucs, uint16_t _view) + { + while (_ucs.hasItem(_view) ) + { + const UniformCacheItem& uci = _ucs.advance(); + + bx::memCopy(m_uniforms[uci.m_handle], &_ucs.m_frame->m_uniformCacheFrame.m_data[uci.m_offset], uci.m_size); + } + } + void RendererContextVK::submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) { BX_UNUSED(_clearQuad); @@ -8804,6 +8816,7 @@ VK_DESTROY uint16_t view = UINT16_MAX; FrameBufferHandle fbh = { BGFX_CONFIG_MAX_FRAME_BUFFERS }; + UniformCacheState ucs(_render); BlitState bs(_render); uint64_t blendFactor = UINT64_MAX; @@ -8928,6 +8941,7 @@ VK_DESTROY beginRenderPass = false; } + submitUniformCache(ucs, view); submitBlit(bs, view); BGFX_VK_PROFILER_END();