bgfx/src/bgfx_p.h

5287 lines
146 KiB
C
Raw Normal View History

2012-08-06 01:51:49 +04:00
/*
2022-01-15 22:59:06 +03:00
* Copyright 2011-2022 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
2012-08-06 01:51:49 +04:00
*/
#ifndef BGFX_P_H_HEADER_GUARD
#define BGFX_P_H_HEADER_GUARD
2012-08-06 01:51:49 +04:00
#include <bx/platform.h>
#ifndef BX_CONFIG_DEBUG
# error "BX_CONFIG_DEBUG must be defined in build script!"
2021-12-31 20:43:21 +03:00
#endif // BX_CONFIG_DEBUG
2014-08-24 01:13:23 +04:00
#define BGFX_CONFIG_DEBUG BX_CONFIG_DEBUG
#if BX_CONFIG_DEBUG
# define BX_TRACE _BGFX_TRACE
# define BX_WARN _BGFX_WARN
# define BX_ASSERT _BGFX_ASSERT
#endif // BX_CONFIG_DEBUG
#include <bgfx/bgfx.h>
#include "config.h"
2012-08-06 01:51:49 +04:00
#include <inttypes.h>
2017-06-10 07:57:08 +03:00
// Check handle, cannot be bgfx::kInvalidHandle and must be valid.
2019-02-16 03:45:35 +03:00
#define BGFX_CHECK_HANDLE(_desc, _handleAlloc, _handle) \
2020-08-27 22:42:37 +03:00
BX_ASSERT(isValid(_handle) \
2019-02-16 03:45:35 +03:00
&& _handleAlloc.isValid(_handle.idx) \
, "Invalid handle. %s handle: %d (max %d)" \
, _desc \
, _handle.idx \
, _handleAlloc.getMaxHandles() \
)
2015-03-27 01:01:09 +03:00
2017-06-10 07:57:08 +03:00
// Check handle, it's ok to be bgfx::kInvalidHandle or must be valid.
2015-03-27 01:01:09 +03:00
#define BGFX_CHECK_HANDLE_INVALID_OK(_desc, _handleAlloc, _handle) \
2021-04-03 06:17:42 +03:00
BX_ASSERT(!isValid(_handle) \
2019-02-16 03:45:35 +03:00
|| _handleAlloc.isValid(_handle.idx) \
, "Invalid handle. %s handle: %d (max %d)" \
, _desc \
, _handle.idx \
, _handleAlloc.getMaxHandles() \
)
2015-03-26 09:33:35 +03:00
2017-10-29 04:43:21 +03:00
#if BGFX_CONFIG_MULTITHREADED
# define BGFX_MUTEX_SCOPE(_mutex) bx::MutexScope BX_CONCATENATE(mutexScope, __LINE__)(_mutex)
#else
# define BGFX_MUTEX_SCOPE(_mutex) BX_NOOP()
#endif // BGFX_CONFIG_MULTITHREADED
2017-10-07 04:07:40 +03:00
#if BGFX_CONFIG_PROFILER
2019-02-16 03:45:35 +03:00
# define BGFX_PROFILER_SCOPE(_name, _abgr) ProfilerScope BX_CONCATENATE(profilerScope, __LINE__)(_name, _abgr, __FILE__, uint16_t(__LINE__) )
# define BGFX_PROFILER_BEGIN(_name, _abgr) g_callback->profilerBegin(_name, _abgr, __FILE__, uint16_t(__LINE__) )
# define BGFX_PROFILER_BEGIN_LITERAL(_name, _abgr) g_callback->profilerBeginLiteral(_name, _abgr, __FILE__, uint16_t(__LINE__) )
# define BGFX_PROFILER_END() g_callback->profilerEnd()
2017-10-07 04:07:40 +03:00
# define BGFX_PROFILER_SET_CURRENT_THREAD_NAME(_name) BX_NOOP()
#else
2019-02-16 03:45:35 +03:00
# define BGFX_PROFILER_SCOPE(_name, _abgr) BX_NOOP()
# define BGFX_PROFILER_BEGIN(_name, _abgr) BX_NOOP()
# define BGFX_PROFILER_BEGIN_LITERAL(_name, _abgr) BX_NOOP()
# define BGFX_PROFILER_END() BX_NOOP()
2017-08-21 00:24:15 +03:00
# define BGFX_PROFILER_SET_CURRENT_THREAD_NAME(_name) BX_NOOP()
2015-11-10 06:18:42 +03:00
#endif // BGFX_PROFILER_SCOPE
namespace bgfx
{
#if BX_COMPILER_CLANG_ANALYZER
void __attribute__( (analyzer_noreturn) ) fatal(const char* _filePath, uint16_t _line, Fatal::Enum _code, const char* _format, ...);
2014-10-22 09:58:07 +04:00
#else
void fatal(const char* _filePath, uint16_t _line, Fatal::Enum _code, const char* _format, ...);
#endif // BX_COMPILER_CLANG_ANALYZER
2014-10-22 09:58:07 +04:00
2015-07-25 04:02:17 +03:00
void trace(const char* _filePath, uint16_t _line, const char* _format, ...);
2019-08-13 12:04:51 +03:00
inline bool operator==(const VertexLayoutHandle& _lhs, const VertexLayoutHandle& _rhs) { return _lhs.idx == _rhs.idx; }
2016-03-16 04:42:20 +03:00
inline bool operator==(const UniformHandle& _lhs, const UniformHandle& _rhs) { return _lhs.idx == _rhs.idx; }
}
2012-08-06 01:51:49 +04:00
#define _BGFX_TRACE(_format, ...) \
2021-04-03 06:17:42 +03:00
BX_MACRO_BLOCK_BEGIN \
bgfx::trace(__FILE__, uint16_t(__LINE__), "BGFX " _format "\n", ##__VA_ARGS__); \
BX_MACRO_BLOCK_END
#define _BGFX_WARN(_condition, _format, ...) \
2021-04-03 06:17:42 +03:00
BX_MACRO_BLOCK_BEGIN \
if (!BX_IGNORE_C4127(_condition) ) \
{ \
BX_TRACE("WARN " _format, ##__VA_ARGS__); \
} \
BX_MACRO_BLOCK_END
#define _BGFX_ASSERT(_condition, _format, ...) \
2021-04-03 06:17:42 +03:00
BX_MACRO_BLOCK_BEGIN \
if (!BX_IGNORE_C4127(_condition) ) \
{ \
BX_TRACE("ASSERT " _format, ##__VA_ARGS__); \
2021-04-03 06:17:42 +03:00
bgfx::fatal(__FILE__, uint16_t(__LINE__), bgfx::Fatal::DebugCheck, _format, ##__VA_ARGS__); \
} \
BX_MACRO_BLOCK_END
#define BGFX_FATAL(_condition, _err, _format, ...) \
BX_MACRO_BLOCK_BEGIN \
if (!BX_IGNORE_C4127(_condition) ) \
{ \
fatal(__FILE__, uint16_t(__LINE__), _err, _format, ##__VA_ARGS__); \
} \
BX_MACRO_BLOCK_END
2012-08-06 01:51:49 +04:00
#define BGFX_ERROR_CHECK(_condition, _err, _result, _msg, _format, ...) \
if (!BX_IGNORE_C4127(_condition) ) \
{ \
BX_ERROR_SET(_err, _result, _msg); \
BX_TRACE("%S: 0x%08x '%S' - " _format \
, &bxErrorScope.getName() \
, _err->get().code \
, &_err->getMessage() \
, ##__VA_ARGS__ \
); \
return; \
}
2017-10-27 07:41:40 +03:00
#include <bx/allocator.h>
2012-08-06 01:51:49 +04:00
#include <bx/bx.h>
2017-10-27 07:41:40 +03:00
#include <bx/cpu.h>
2012-08-06 01:51:49 +04:00
#include <bx/debug.h>
2012-07-30 00:50:23 +04:00
#include <bx/endian.h>
2021-04-17 08:13:26 +03:00
#include <bx/error.h>
2017-10-27 07:41:40 +03:00
#include <bx/float4x4_t.h>
2012-08-06 01:51:49 +04:00
#include <bx/handlealloc.h>
#include <bx/hash.h>
2017-10-27 07:41:40 +03:00
#include <bx/math.h>
2017-10-29 04:43:21 +03:00
#include <bx/mutex.h>
2017-10-27 07:41:40 +03:00
#include <bx/os.h>
#include <bx/readerwriter.h>
2017-10-27 07:41:40 +03:00
#include <bx/ringbuffer.h>
#include <bx/sort.h>
#include <bx/string.h>
2017-10-27 07:41:40 +03:00
#include <bx/thread.h>
#include <bx/timer.h>
#include <bx/uint32_t.h>
2012-08-06 01:51:49 +04:00
#include <bgfx/platform.h>
2017-04-04 08:42:27 +03:00
#include <bimg/bimg.h>
2016-03-11 08:09:32 +03:00
#include "shader.h"
2020-03-29 06:06:03 +03:00
#include "vertexlayout.h"
2020-10-06 05:45:22 +03:00
#include "version.h"
2012-08-06 01:51:49 +04:00
#define BGFX_CHUNK_MAGIC_TEX BX_MAKEFOURCC('T', 'E', 'X', 0x0)
#define BGFX_CLEAR_COLOR_USE_PALETTE UINT16_C(0x8000)
#define BGFX_CLEAR_MASK (0 \
| BGFX_CLEAR_COLOR \
| BGFX_CLEAR_DEPTH \
| BGFX_CLEAR_STENCIL \
| BGFX_CLEAR_COLOR_USE_PALETTE \
)
2014-09-01 22:24:51 +04:00
2013-08-31 09:31:40 +04:00
#if BGFX_CONFIG_USE_TINYSTL
2013-09-23 08:40:17 +04:00
namespace bgfx
2012-08-06 01:51:49 +04:00
{
2013-09-23 08:40:17 +04:00
struct TinyStlAllocator
2012-08-06 01:51:49 +04:00
{
static void* static_allocate(size_t _bytes);
static void static_deallocate(void* _ptr, size_t /*_bytes*/);
};
2013-09-23 08:40:17 +04:00
} // namespace bgfx
# define TINYSTL_ALLOCATOR bgfx::TinyStlAllocator
# include <tinystl/string.h>
# include <tinystl/unordered_map.h>
# include <tinystl/unordered_set.h>
2015-07-30 05:38:17 +03:00
# include <tinystl/vector.h>
2018-03-20 08:17:24 +03:00
namespace tinystl
{
template<typename T, typename Alloc = TINYSTL_ALLOCATOR>
class list : public vector<T, Alloc>
{
public:
2018-03-20 08:33:49 +03:00
void push_front(const T& _value)
{
this->insert(this->begin(), _value);
}
void pop_front()
{
this->erase(this->begin() );
}
void sort()
{
bx::quickSort(
2018-05-26 04:01:49 +03:00
this->begin()
2018-03-20 08:33:49 +03:00
, uint32_t(this->end() - this->begin() )
, sizeof(T)
, [](const void* _a, const void* _b) -> int32_t {
const T& lhs = *(const T*)(_a);
const T& rhs = *(const T*)(_b);
return lhs < rhs ? -1 : 1;
});
}
2018-03-20 08:17:24 +03:00
};
} // namespace tinystl
2012-08-06 01:51:49 +04:00
namespace stl = tinystl;
#else
2018-03-20 08:17:24 +03:00
# include <list>
2012-08-06 01:51:49 +04:00
# include <string>
# include <unordered_map>
2013-01-23 07:56:40 +04:00
# include <unordered_set>
2015-07-30 05:38:17 +03:00
# include <vector>
2016-11-22 20:08:21 +03:00
namespace stl = std;
2012-08-06 01:51:49 +04:00
#endif // BGFX_CONFIG_USE_TINYSTL
2013-04-19 08:16:09 +04:00
#if BX_PLATFORM_ANDROID
# include <android/native_window.h>
#endif // BX_PLATFORM_*
2018-05-26 04:01:49 +03:00
#define BGFX_MAX_COMPUTE_BINDINGS BGFX_CONFIG_MAX_TEXTURE_SAMPLERS
2014-07-21 07:27:13 +04:00
#define BGFX_SAMPLER_INTERNAL_DEFAULT UINT32_C(0x10000000)
#define BGFX_SAMPLER_INTERNAL_SHARED UINT32_C(0x20000000)
2015-11-02 04:28:23 +03:00
#define BGFX_RESET_INTERNAL_FORCE UINT32_C(0x80000000)
2015-11-02 04:28:23 +03:00
#define BGFX_STATE_INTERNAL_SCISSOR UINT64_C(0x2000000000000000)
#define BGFX_STATE_INTERNAL_OCCLUSION_QUERY UINT64_C(0x4000000000000000)
2015-11-03 00:13:57 +03:00
#define BGFX_SUBMIT_INTERNAL_NONE UINT8_C(0x00)
#define BGFX_SUBMIT_INTERNAL_INDEX32 UINT8_C(0x40)
2015-11-03 00:13:57 +03:00
#define BGFX_SUBMIT_INTERNAL_OCCLUSION_VISIBLE UINT8_C(0x80)
#define BGFX_SUBMIT_INTERNAL_RESERVED_MASK UINT8_C(0xff)
2012-08-06 01:51:49 +04:00
2021-08-25 05:35:09 +03:00
#define BGFX_RENDERER_NOOP_NAME "Noop"
#define BGFX_RENDERER_AGC_NAME "AGC"
2014-10-11 22:24:37 +04:00
#define BGFX_RENDERER_DIRECT3D9_NAME "Direct3D 9"
#define BGFX_RENDERER_DIRECT3D11_NAME "Direct3D 11"
2014-10-11 22:24:37 +04:00
#define BGFX_RENDERER_DIRECT3D12_NAME "Direct3D 12"
2019-03-13 03:01:02 +03:00
#define BGFX_RENDERER_GNM_NAME "GNM"
#define BGFX_RENDERER_METAL_NAME "Metal"
2019-03-13 03:01:02 +03:00
#define BGFX_RENDERER_NVN_NAME "NVN"
#define BGFX_RENDERER_VULKAN_NAME "Vulkan"
#define BGFX_RENDERER_WEBGPU_NAME "WebGPU"
#if BGFX_CONFIG_RENDERER_OPENGL
2014-08-27 07:56:53 +04:00
# if BGFX_CONFIG_RENDERER_OPENGL >= 31 && BGFX_CONFIG_RENDERER_OPENGL <= 33
# if BGFX_CONFIG_RENDERER_OPENGL == 31
# define BGFX_RENDERER_OPENGL_NAME "OpenGL 3.1"
# elif BGFX_CONFIG_RENDERER_OPENGL == 32
# define BGFX_RENDERER_OPENGL_NAME "OpenGL 3.2"
# else
# define BGFX_RENDERER_OPENGL_NAME "OpenGL 3.3"
# endif // 31+
2019-01-06 04:39:14 +03:00
# elif BGFX_CONFIG_RENDERER_OPENGL >= 40 && BGFX_CONFIG_RENDERER_OPENGL <= 46
2014-08-27 07:56:53 +04:00
# if BGFX_CONFIG_RENDERER_OPENGL == 40
# define BGFX_RENDERER_OPENGL_NAME "OpenGL 4.0"
# elif BGFX_CONFIG_RENDERER_OPENGL == 41
# define BGFX_RENDERER_OPENGL_NAME "OpenGL 4.1"
# elif BGFX_CONFIG_RENDERER_OPENGL == 42
# define BGFX_RENDERER_OPENGL_NAME "OpenGL 4.2"
# elif BGFX_CONFIG_RENDERER_OPENGL == 43
# define BGFX_RENDERER_OPENGL_NAME "OpenGL 4.3"
# elif BGFX_CONFIG_RENDERER_OPENGL == 44
# define BGFX_RENDERER_OPENGL_NAME "OpenGL 4.4"
2019-01-06 04:39:14 +03:00
# elif BGFX_CONFIG_RENDERER_OPENGL == 45
2014-08-27 07:56:53 +04:00
# define BGFX_RENDERER_OPENGL_NAME "OpenGL 4.5"
2019-01-06 04:39:14 +03:00
# else
# define BGFX_RENDERER_OPENGL_NAME "OpenGL 4.6"
2014-08-27 07:56:53 +04:00
# endif // 40+
2013-03-04 10:30:50 +04:00
# else
# define BGFX_RENDERER_OPENGL_NAME "OpenGL 2.1"
2013-03-04 10:30:50 +04:00
# endif // BGFX_CONFIG_RENDERER_OPENGL
#elif BGFX_CONFIG_RENDERER_OPENGLES
2014-04-01 07:08:32 +04:00
# if BGFX_CONFIG_RENDERER_OPENGLES == 30
# define BGFX_RENDERER_OPENGL_NAME "OpenGL ES 3.0"
2019-01-06 04:39:14 +03:00
# elif BGFX_CONFIG_RENDERER_OPENGLES == 31
# define BGFX_RENDERER_OPENGL_NAME "OpenGL ES 3.1"
2019-01-06 04:39:14 +03:00
# elif BGFX_CONFIG_RENDERER_OPENGLES >= 32
# define BGFX_RENDERER_OPENGL_NAME "OpenGL ES 3.2"
2014-04-01 07:08:32 +04:00
# else
# define BGFX_RENDERER_OPENGL_NAME "OpenGL ES 2.0"
2014-04-01 07:08:32 +04:00
# endif // BGFX_CONFIG_RENDERER_OPENGLES
2014-05-27 01:34:58 +04:00
#else
# define BGFX_RENDERER_OPENGL_NAME "OpenGL"
#endif //
2012-08-06 01:51:49 +04:00
namespace bgfx
{
extern InternalData g_internalData;
extern PlatformData g_platformData;
extern bool g_platformDataChangedSinceReset;
2021-04-17 08:13:26 +03:00
extern void isFrameBufferValid(uint8_t _num, const Attachment* _attachment, bx::Error* _err);
2021-10-01 03:24:36 +03:00
extern void isIdentifierValid(const bx::StringView& _name, bx::Error* _err);
2013-01-14 06:39:25 +04:00
2015-04-10 05:38:51 +03:00
#if BGFX_CONFIG_MAX_DRAW_CALLS < (64<<10)
typedef uint16_t RenderItemCount;
#else
typedef uint32_t RenderItemCount;
#endif // BGFX_CONFIG_MAX_DRAW_CALLS < (64<<10)
struct Handle
{
enum Enum
{
IndexBuffer,
Shader,
Texture,
VertexBuffer,
Count
};
uint16_t type;
uint16_t idx;
};
#define CONVERT_HANDLE(_name) \
inline Handle convert(_name##Handle _handle) \
{ \
Handle handle = { Handle::_name, _handle.idx }; \
return handle; \
}
CONVERT_HANDLE(IndexBuffer);
CONVERT_HANDLE(Shader);
CONVERT_HANDLE(Texture);
CONVERT_HANDLE(VertexBuffer);
#undef CONVERT_HANDLE
const char* getTypeName(Handle _handle);
2019-08-17 20:35:21 +03:00
inline bool isValid(const VertexLayout& _layout)
2017-10-11 19:16:59 +03:00
{
2019-08-17 20:35:21 +03:00
return 0 != _layout.m_stride;
2017-10-11 19:16:59 +03:00
}
struct Condition
{
enum Enum
{
LessEqual,
GreaterEqual,
};
};
bool windowsVersionIs(Condition::Enum _op, uint32_t _version);
constexpr bool isShaderType(uint32_t _magic, char _type)
{
return uint32_t(_type) == (_magic & BX_MAKEFOURCC(0xff, 0, 0, 0) );
}
inline bool isShaderBin(uint32_t _magic)
{
return BX_MAKEFOURCC(0, 'S', 'H', 0) == (_magic & BX_MAKEFOURCC(0, 0xff, 0xff, 0) )
&& (isShaderType(_magic, 'C') || isShaderType(_magic, 'F') || isShaderType(_magic, 'V') )
;
}
inline bool isShaderVerLess(uint32_t _magic, uint8_t _version)
{
return (_magic & BX_MAKEFOURCC(0, 0, 0, 0xff) ) < BX_MAKEFOURCC(0, 0, 0, _version);
}
const char* getShaderTypeName(uint32_t _magic);
2012-08-06 01:51:49 +04:00
struct Clear
{
void set(uint16_t _flags, uint32_t _rgba, float _depth, uint8_t _stencil)
{
m_flags = _flags;
m_index[0] = uint8_t(_rgba>>24);
m_index[1] = uint8_t(_rgba>>16);
m_index[2] = uint8_t(_rgba>> 8);
m_index[3] = uint8_t(_rgba>> 0);
m_depth = _depth;
m_stencil = _stencil;
}
void set(uint16_t _flags, float _depth, uint8_t _stencil, uint8_t _0, uint8_t _1, uint8_t _2, uint8_t _3, uint8_t _4, uint8_t _5, uint8_t _6, uint8_t _7)
{
m_flags = (_flags & ~BGFX_CLEAR_COLOR)
| (0xff != (_0&_1&_2&_3&_4&_5&_6&_7) ? BGFX_CLEAR_COLOR|BGFX_CLEAR_COLOR_USE_PALETTE : 0)
;
m_index[0] = _0;
m_index[1] = _1;
m_index[2] = _2;
m_index[3] = _3;
m_index[4] = _4;
m_index[5] = _5;
m_index[6] = _6;
m_index[7] = _7;
m_depth = _depth;
m_stencil = _stencil;
}
uint8_t m_index[8];
float m_depth;
uint8_t m_stencil;
uint16_t m_flags;
2012-08-06 01:51:49 +04:00
};
struct Rect
{
2017-02-09 05:17:59 +03:00
Rect()
{
}
Rect(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height)
: m_x(_x)
, m_y(_y)
, m_width(_width)
, m_height(_height)
{
}
2013-08-05 03:56:07 +04:00
void clear()
{
2021-04-03 06:17:42 +03:00
m_x = 0;
m_y = 0;
m_width = 0;
2013-08-05 03:56:07 +04:00
m_height = 0;
}
2013-07-15 01:32:09 +04:00
bool isZero() const
{
uint64_t ui64 = *( (uint64_t*)this);
return UINT64_C(0) == ui64;
}
2017-01-12 05:46:53 +03:00
bool isZeroArea() const
{
return 0 == m_width
|| 0 == m_height
;
}
2017-02-09 05:17:59 +03:00
void set(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height)
{
m_x = _x;
m_y = _y;
m_width = _width;
m_height = _height;
}
void setIntersect(const Rect& _a, const Rect& _b)
{
2018-06-16 18:34:06 +03:00
const uint16_t sx = bx::max<uint16_t>(_a.m_x, _b.m_x);
const uint16_t sy = bx::max<uint16_t>(_a.m_y, _b.m_y);
const uint16_t ex = bx::min<uint16_t>(_a.m_x + _a.m_width, _b.m_x + _b.m_width );
const uint16_t ey = bx::min<uint16_t>(_a.m_y + _a.m_height, _b.m_y + _b.m_height);
m_x = sx;
m_y = sy;
2018-06-16 18:34:06 +03:00
m_width = (uint16_t)bx::uint32_satsub(ex, sx);
m_height = (uint16_t)bx::uint32_satsub(ey, sy);
}
2017-02-09 05:17:59 +03:00
void intersect(const Rect& _a)
{
setIntersect(*this, _a);
}
2012-08-06 01:51:49 +04:00
uint16_t m_x;
uint16_t m_y;
uint16_t m_width;
uint16_t m_height;
};
2012-11-04 08:36:17 +04:00
struct TextureCreate
2012-08-13 08:02:11 +04:00
{
2016-01-05 08:48:01 +03:00
TextureFormat::Enum m_format;
2012-08-13 08:02:11 +04:00
uint16_t m_width;
2013-01-07 05:53:45 +04:00
uint16_t m_height;
2012-08-13 08:02:11 +04:00
uint16_t m_depth;
2016-08-20 18:10:20 +03:00
uint16_t m_numLayers;
2021-04-03 06:17:42 +03:00
uint8_t m_numMips;
bool m_cubeMap;
2012-08-13 08:02:11 +04:00
const Memory* m_mem;
};
extern const uint32_t g_uniformTypeSize[UniformType::Count+1];
2012-12-31 08:52:47 +04:00
extern CallbackI* g_callback;
2015-11-07 09:03:06 +03:00
extern bx::AllocatorI* g_allocator;
2013-10-11 05:29:57 +04:00
extern Caps g_caps;
2012-08-06 01:51:49 +04:00
typedef bx::StringT<&g_allocator> String;
2017-10-07 04:07:40 +03:00
struct ProfilerScope
{
ProfilerScope(const char* _name, uint32_t _abgr, const char* _filePath, uint16_t _line)
{
g_callback->profilerBeginLiteral(_name, _abgr, _filePath, _line);
}
~ProfilerScope()
{
g_callback->profilerEnd();
}
};
void setGraphicsDebuggerPresent(bool _present);
bool isGraphicsDebuggerPresent();
void release(const Memory* _mem);
const char* getAttribName(Attrib::Enum _attr);
2018-10-18 04:08:28 +03:00
const char* getAttribNameShort(Attrib::Enum _attr);
void getTextureSizeFromRatio(BackbufferRatio::Enum _ratio, uint16_t& _width, uint16_t& _height);
TextureFormat::Enum getViableTextureFormat(const bimg::ImageContainer& _imageContainer);
const char* getName(TextureFormat::Enum _fmt);
const char* getName(UniformHandle _handle);
const char* getName(ShaderHandle _handle);
2018-05-18 03:24:10 +03:00
const char* getName(Topology::Enum _topology);
template<typename Ty>
inline void release(Ty)
{
}
2018-03-13 04:56:27 +03:00
template<>
inline void release(Memory* _mem)
{
release( (const Memory*)_mem);
}
inline uint32_t castfu(float _value)
2012-08-06 01:51:49 +04:00
{
union { float fl; uint32_t ui; } un;
un.fl = _value;
return un.ui;
}
2012-11-11 07:59:23 +04:00
inline uint64_t packStencil(uint32_t _fstencil, uint32_t _bstencil)
{
return (uint64_t(_bstencil)<<32)|uint64_t(_fstencil);
}
inline uint32_t unpackStencil(uint8_t _0or1, uint64_t _stencil)
{
return uint32_t( (_stencil >> (32*_0or1) ) );
}
2019-03-17 07:52:44 +03:00
inline bool needBorderColor(uint64_t _flags)
2015-09-18 05:55:01 +03:00
{
return BGFX_SAMPLER_U_BORDER == (_flags & BGFX_SAMPLER_U_BORDER)
|| BGFX_SAMPLER_V_BORDER == (_flags & BGFX_SAMPLER_V_BORDER)
|| BGFX_SAMPLER_W_BORDER == (_flags & BGFX_SAMPLER_W_BORDER)
2015-09-18 05:55:01 +03:00
;
}
2015-10-14 04:28:22 +03:00
2016-08-20 07:05:37 +03:00
inline uint8_t calcNumMips(bool _hasMips, uint16_t _width, uint16_t _height, uint16_t _depth = 1)
{
2016-08-20 07:05:37 +03:00
if (_hasMips)
{
2018-02-11 02:43:26 +03:00
const uint32_t max = bx::max(_width, _height, _depth);
2019-10-26 00:58:01 +03:00
const uint32_t num = 1 + uint32_t(bx::log2<int32_t>(max) );
return uint8_t(num);
}
return 1;
}
2020-11-29 21:14:37 +03:00
/// Dump vertex layout info into debug output.
2019-08-17 20:35:21 +03:00
void dump(const VertexLayout& _layout);
2012-08-06 01:51:49 +04:00
2020-11-29 21:14:37 +03:00
/// Dump resolution and reset info into debug output.
void dump(const Resolution& _resolution);
2012-08-06 01:51:49 +04:00
struct TextVideoMem
{
TextVideoMem()
: m_mem(NULL)
, m_size(0)
, m_width(0)
, m_height(0)
, m_small(false)
{
2017-12-08 08:52:52 +03:00
resize(false, 1, 1);
2012-08-06 01:51:49 +04:00
clear();
}
2013-09-21 10:19:21 +04:00
~TextVideoMem()
2012-08-06 01:51:49 +04:00
{
2013-09-17 08:40:30 +04:00
BX_FREE(g_allocator, m_mem);
2012-08-06 01:51:49 +04:00
}
2017-12-08 08:52:52 +03:00
void resize(bool _small, uint32_t _width, uint32_t _height)
2012-08-06 01:51:49 +04:00
{
2016-10-19 03:58:42 +03:00
uint32_t width = bx::uint32_imax(1, _width/8);
uint32_t height = bx::uint32_imax(1, _height/(_small ? 8 : 16) );
2012-08-06 01:51:49 +04:00
if (NULL == m_mem
2016-10-19 03:58:42 +03:00
|| m_width != width
2012-08-06 01:51:49 +04:00
|| m_height != height
2016-10-19 03:58:42 +03:00
|| m_small != _small)
2012-08-06 01:51:49 +04:00
{
2015-04-08 03:58:14 +03:00
m_small = _small;
m_width = (uint16_t)width;
2012-08-06 01:51:49 +04:00
m_height = (uint16_t)height;
2012-08-13 08:02:11 +04:00
uint32_t size = m_size;
m_size = m_width * m_height;
2012-08-06 01:51:49 +04:00
2021-02-16 20:12:04 +03:00
m_mem = (MemSlot*)BX_REALLOC(g_allocator, m_mem, m_size * sizeof(MemSlot) );
2012-08-13 08:02:11 +04:00
if (size < m_size)
{
2021-02-16 20:12:04 +03:00
bx::memSet(&m_mem[size], 0, (m_size-size) * sizeof(MemSlot) );
2012-08-13 08:02:11 +04:00
}
2012-08-06 01:51:49 +04:00
}
}
void clear(uint8_t _attr = 0)
{
2018-02-21 20:40:47 +03:00
MemSlot* mem = m_mem;
2021-02-16 20:12:04 +03:00
bx::memSet(mem, 0, m_size * sizeof(MemSlot) );
2018-02-21 20:40:47 +03:00
if (_attr != 0)
{
for (uint32_t ii = 0, num = m_size; ii < num; ++ii)
{
mem[ii].attribute = _attr;
}
2012-08-06 01:51:49 +04:00
}
}
void printfVargs(uint16_t _x, uint16_t _y, uint8_t _attr, const char* _format, va_list _argList);
2012-08-06 01:51:49 +04:00
void printf(uint16_t _x, uint16_t _y, uint8_t _attr, const char* _format, ...)
{
va_list argList;
va_start(argList, _format);
printfVargs(_x, _y, _attr, _format, argList);
va_end(argList);
}
void image(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height, const void* _data, uint16_t _pitch)
{
if (_x < m_width && _y < m_height)
{
2018-02-21 20:40:47 +03:00
MemSlot* dst = &m_mem[_y*m_width+_x];
const uint8_t* src = (const uint8_t*)_data;
const uint32_t width = bx::min<uint32_t>(m_width, _width +_x)-_x;
2018-02-11 02:49:30 +03:00
const uint32_t height = bx::min<uint32_t>(m_height, _height+_y)-_y;
const uint32_t dstPitch = m_width;
2018-02-21 20:40:47 +03:00
for (uint32_t ii = 0; ii < height; ++ii)
{
for (uint32_t jj = 0; jj < width; ++jj)
{
dst[jj].character = src[jj*2];
dst[jj].attribute = src[jj*2+1];
}
2018-02-21 20:40:47 +03:00
src += _pitch;
dst += dstPitch;
}
}
}
2018-02-21 20:40:47 +03:00
struct MemSlot
{
uint8_t attribute;
uint8_t character;
};
2018-02-21 20:40:47 +03:00
MemSlot* m_mem;
2012-08-06 01:51:49 +04:00
uint32_t m_size;
uint16_t m_width;
uint16_t m_height;
bool m_small;
};
struct TextVideoMemBlitter
{
void init();
void shutdown();
2012-08-06 01:51:49 +04:00
TextureHandle m_texture;
TransientVertexBuffer* m_vb;
TransientIndexBuffer* m_ib;
2019-08-17 20:35:21 +03:00
VertexLayout m_layout;
2012-09-17 04:36:08 +04:00
ProgramHandle m_program;
2012-08-06 01:51:49 +04:00
};
struct RendererContextI;
extern void blit(RendererContextI* _renderCtx, TextVideoMemBlitter& _blitter, const TextVideoMem& _mem);
inline void blit(RendererContextI* _renderCtx, TextVideoMemBlitter& _blitter, const TextVideoMem* _mem)
{
blit(_renderCtx, _blitter, *_mem);
}
template <uint32_t maxKeys>
struct UpdateBatchT
{
UpdateBatchT()
: m_num(0)
{
}
void add(uint32_t _key, uint32_t _value)
{
uint32_t num = m_num++;
m_keys[num] = _key;
m_values[num] = _value;
}
bool sort()
{
if (0 < m_num)
{
uint32_t* tempKeys = (uint32_t*)alloca(sizeof(m_keys) );
uint32_t* tempValues = (uint32_t*)alloca(sizeof(m_values) );
2016-02-22 00:59:38 +03:00
bx::radixSort(m_keys, tempKeys, m_values, tempValues, m_num);
return true;
}
return false;
}
bool isFull() const
{
return m_num >= maxKeys;
}
void reset()
{
m_num = 0;
}
uint32_t m_num;
uint32_t m_keys[maxKeys];
uint32_t m_values[maxKeys];
};
2012-07-30 00:50:23 +04:00
struct ClearQuad
{
ClearQuad()
{
for (uint32_t ii = 0; ii < BX_COUNTOF(m_program); ++ii)
{
2017-06-10 07:57:08 +03:00
m_program[ii].idx = kInvalidHandle;
}
}
2012-07-30 00:50:23 +04:00
void init();
void shutdown();
2012-07-30 00:50:23 +04:00
VertexBufferHandle m_vb;
2019-08-17 20:35:21 +03:00
VertexLayout m_layout;
ProgramHandle m_program[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
2012-07-30 00:50:23 +04:00
};
2012-08-06 01:51:49 +04:00
struct PredefinedUniform
{
enum Enum
{
ViewRect,
ViewTexel,
View,
InvView,
Proj,
InvProj,
2012-08-06 01:51:49 +04:00
ViewProj,
InvViewProj,
2012-08-06 01:51:49 +04:00
Model,
2012-10-08 07:41:18 +04:00
ModelView,
2012-08-06 01:51:49 +04:00
ModelViewProj,
AlphaRef,
Count
};
uint32_t m_loc;
2012-08-06 01:51:49 +04:00
uint16_t m_count;
uint8_t m_type;
2012-08-06 01:51:49 +04:00
};
const char* getUniformTypeName(UniformType::Enum _enum);
UniformType::Enum nameToUniformTypeEnum(const char* _name);
2012-08-06 01:51:49 +04:00
const char* getPredefinedUniformName(PredefinedUniform::Enum _enum);
2021-10-01 03:24:36 +03:00
PredefinedUniform::Enum nameToPredefinedUniformEnum(const bx::StringView& _name);
2012-08-06 01:51:49 +04:00
2016-02-12 07:40:16 +03:00
class CommandBuffer
2012-08-06 01:51:49 +04:00
{
2016-02-12 07:40:16 +03:00
BX_CLASS(CommandBuffer
, NO_COPY
, NO_ASSIGNMENT
);
public:
2012-08-06 01:51:49 +04:00
CommandBuffer()
: m_buffer(NULL)
, m_pos(0)
, m_size(0)
, m_minCapacity(0)
2012-08-06 01:51:49 +04:00
{
resize();
2012-08-06 01:51:49 +04:00
finish();
}
~CommandBuffer()
{
BX_FREE(g_allocator, m_buffer);
}
void init(uint32_t _minCapacity)
{
m_minCapacity = bx::alignUp(_minCapacity, 1024);
resize();
}
2012-08-06 01:51:49 +04:00
enum Enum
{
RendererInit,
RendererShutdownBegin,
2019-08-13 12:04:51 +03:00
CreateVertexLayout,
2012-08-06 01:51:49 +04:00
CreateIndexBuffer,
CreateVertexBuffer,
CreateDynamicIndexBuffer,
UpdateDynamicIndexBuffer,
CreateDynamicVertexBuffer,
UpdateDynamicVertexBuffer,
CreateShader,
2012-09-17 04:36:08 +04:00
CreateProgram,
2012-08-06 01:51:49 +04:00
CreateTexture,
2012-08-13 08:02:11 +04:00
UpdateTexture,
ResizeTexture,
2014-02-06 11:07:11 +04:00
CreateFrameBuffer,
2012-08-06 01:51:49 +04:00
CreateUniform,
UpdateViewName,
InvalidateOcclusionQuery,
SetName,
2012-08-06 01:51:49 +04:00
End,
RendererShutdownEnd,
2019-08-13 12:04:51 +03:00
DestroyVertexLayout,
2012-08-06 01:51:49 +04:00
DestroyIndexBuffer,
DestroyVertexBuffer,
DestroyDynamicIndexBuffer,
DestroyDynamicVertexBuffer,
DestroyShader,
2012-09-17 04:36:08 +04:00
DestroyProgram,
2012-08-06 01:51:49 +04:00
DestroyTexture,
2014-02-06 11:07:11 +04:00
DestroyFrameBuffer,
2012-08-06 01:51:49 +04:00
DestroyUniform,
ReadTexture,
2012-08-06 01:51:49 +04:00
};
void resize(uint32_t _capacity = 0)
{
m_capacity = bx::alignUp(bx::max(_capacity, m_minCapacity), 1024);
m_buffer = (uint8_t*)BX_REALLOC(g_allocator, m_buffer, m_capacity);
}
2012-08-06 01:51:49 +04:00
void write(const void* _data, uint32_t _size)
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(m_size == 0, "Called write outside start/finish (m_size: %d)?", m_size);
if (m_pos + _size > m_capacity)
{
resize(m_capacity + (16<<10) );
}
2017-02-09 06:55:31 +03:00
bx::memCopy(&m_buffer[m_pos], _data, _size);
2012-08-06 01:51:49 +04:00
m_pos += _size;
}
template<typename Type>
void write(const Type& _in)
{
2014-02-06 11:07:11 +04:00
align(BX_ALIGNOF(Type) );
2012-08-06 01:51:49 +04:00
write(reinterpret_cast<const uint8_t*>(&_in), sizeof(Type) );
}
void read(void* _data, uint32_t _size)
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(m_pos + _size <= m_size
2019-06-04 07:43:21 +03:00
, "CommandBuffer::read error (pos: %d-%d, size: %d)."
, m_pos
, m_pos + _size
, m_size
);
2017-02-09 06:55:31 +03:00
bx::memCopy(_data, &m_buffer[m_pos], _size);
2012-08-06 01:51:49 +04:00
m_pos += _size;
}
template<typename Type>
void read(Type& _in)
{
2014-02-06 11:07:11 +04:00
align(BX_ALIGNOF(Type) );
2012-08-06 01:51:49 +04:00
read(reinterpret_cast<uint8_t*>(&_in), sizeof(Type) );
}
const uint8_t* skip(uint32_t _size)
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(m_pos + _size <= m_size
2019-06-04 07:43:21 +03:00
, "CommandBuffer::skip error (pos: %d-%d, size: %d)."
, m_pos
, m_pos + _size
, m_size
);
const uint8_t* result = &m_buffer[m_pos];
m_pos += _size;
return result;
}
2014-02-06 11:07:11 +04:00
template<typename Type>
void skip()
{
align(BX_ALIGNOF(Type) );
skip(sizeof(Type) );
}
void align(uint32_t _alignment)
{
const uint32_t mask = _alignment-1;
const uint32_t pos = (m_pos+mask) & (~mask);
m_pos = pos;
}
2012-08-06 01:51:49 +04:00
void reset()
{
m_pos = 0;
}
void start()
{
m_pos = 0;
m_size = 0;
}
2012-08-06 01:51:49 +04:00
void finish()
{
uint8_t cmd = End;
write(cmd);
m_size = m_pos;
2012-08-06 01:51:49 +04:00
m_pos = 0;
if (m_size < m_minCapacity
&& m_capacity != m_minCapacity)
{
resize();
}
2012-08-06 01:51:49 +04:00
}
uint8_t* m_buffer;
2012-08-06 01:51:49 +04:00
uint32_t m_pos;
uint32_t m_size;
uint32_t m_capacity;
uint32_t m_minCapacity;
2012-08-06 01:51:49 +04:00
};
2020-06-19 07:20:01 +03:00
//
2022-05-17 21:30:10 +03:00
constexpr uint8_t kSortKeyViewNumBits = uint8_t(31 - bx::uint32_cntlz(BGFX_CONFIG_MAX_VIEWS) );
2020-06-19 07:20:01 +03:00
constexpr uint8_t kSortKeyViewBitShift = 64-kSortKeyViewNumBits;
constexpr uint64_t kSortKeyViewMask = uint64_t(BGFX_CONFIG_MAX_VIEWS-1)<<kSortKeyViewBitShift;
2020-06-19 07:20:01 +03:00
constexpr uint8_t kSortKeyDrawBitShift = kSortKeyViewBitShift - 1;
constexpr uint64_t kSortKeyDrawBit = uint64_t(1)<<kSortKeyDrawBitShift;
2020-06-19 07:20:01 +03:00
//
constexpr uint8_t kSortKeyDrawTypeNumBits = 2;
constexpr uint8_t kSortKeyDrawTypeBitShift = kSortKeyDrawBitShift - kSortKeyDrawTypeNumBits;
constexpr uint64_t kSortKeyDrawTypeMask = uint64_t(3)<<kSortKeyDrawTypeBitShift;
2020-06-19 07:20:01 +03:00
constexpr uint64_t kSortKeyDrawTypeProgram = uint64_t(0)<<kSortKeyDrawTypeBitShift;
constexpr uint64_t kSortKeyDrawTypeDepth = uint64_t(1)<<kSortKeyDrawTypeBitShift;
constexpr uint64_t kSortKeyDrawTypeSequence = uint64_t(2)<<kSortKeyDrawTypeBitShift;
2017-06-15 08:29:12 +03:00
2020-06-19 07:20:01 +03:00
//
constexpr uint8_t kSortKeyTransNumBits = 2;
2017-11-28 06:38:36 +03:00
2020-06-19 07:20:01 +03:00
constexpr uint8_t kSortKeyDraw0BlendShift = kSortKeyDrawTypeBitShift - kSortKeyTransNumBits;
constexpr uint64_t kSortKeyDraw0BlendMask = uint64_t(0x3)<<kSortKeyDraw0BlendShift;
2017-06-15 08:29:12 +03:00
2020-06-19 07:20:01 +03:00
constexpr uint8_t kSortKeyDraw0ProgramShift = kSortKeyDraw0BlendShift - BGFX_CONFIG_SORT_KEY_NUM_BITS_PROGRAM;
constexpr uint64_t kSortKeyDraw0ProgramMask = uint64_t(BGFX_CONFIG_MAX_PROGRAMS-1)<<kSortKeyDraw0ProgramShift;
2017-06-15 08:29:12 +03:00
2020-06-19 07:20:01 +03:00
constexpr uint8_t kSortKeyDraw0DepthShift = kSortKeyDraw0ProgramShift - BGFX_CONFIG_SORT_KEY_NUM_BITS_DEPTH;
constexpr uint64_t kSortKeyDraw0DepthMask = ( (uint64_t(1)<<BGFX_CONFIG_SORT_KEY_NUM_BITS_DEPTH)-1)<<kSortKeyDraw0DepthShift;
2017-06-15 08:29:12 +03:00
2020-06-19 07:20:01 +03:00
//
constexpr uint8_t kSortKeyDraw1DepthShift = kSortKeyDrawTypeBitShift - BGFX_CONFIG_SORT_KEY_NUM_BITS_DEPTH;
constexpr uint64_t kSortKeyDraw1DepthMask = ( (uint64_t(1)<<BGFX_CONFIG_SORT_KEY_NUM_BITS_DEPTH)-1)<<kSortKeyDraw1DepthShift;
2017-06-15 08:29:12 +03:00
2020-06-19 07:20:01 +03:00
constexpr uint8_t kSortKeyDraw1BlendShift = kSortKeyDraw1DepthShift - kSortKeyTransNumBits;
constexpr uint64_t kSortKeyDraw1BlendMask = uint64_t(0x3)<<kSortKeyDraw1BlendShift;
2017-06-15 08:29:12 +03:00
2020-06-19 07:20:01 +03:00
constexpr uint8_t kSortKeyDraw1ProgramShift = kSortKeyDraw1BlendShift - BGFX_CONFIG_SORT_KEY_NUM_BITS_PROGRAM;
constexpr uint64_t kSortKeyDraw1ProgramMask = uint64_t(BGFX_CONFIG_MAX_PROGRAMS-1)<<kSortKeyDraw1ProgramShift;
2020-06-19 07:20:01 +03:00
//
constexpr uint8_t kSortKeyDraw2SeqShift = kSortKeyDrawTypeBitShift - BGFX_CONFIG_SORT_KEY_NUM_BITS_SEQ;
constexpr uint64_t kSortKeyDraw2SeqMask = ( (uint64_t(1)<<BGFX_CONFIG_SORT_KEY_NUM_BITS_SEQ)-1)<<kSortKeyDraw2SeqShift;
2020-06-19 07:20:01 +03:00
constexpr uint8_t kSortKeyDraw2BlendShift = kSortKeyDraw2SeqShift - kSortKeyTransNumBits;
constexpr uint64_t kSortKeyDraw2BlendMask = uint64_t(0x3)<<kSortKeyDraw2BlendShift;
2020-06-19 07:20:01 +03:00
constexpr uint8_t kSortKeyDraw2ProgramShift = kSortKeyDraw2BlendShift - BGFX_CONFIG_SORT_KEY_NUM_BITS_PROGRAM;
constexpr uint64_t kSortKeyDraw2ProgramMask = uint64_t(BGFX_CONFIG_MAX_PROGRAMS-1)<<kSortKeyDraw2ProgramShift;
2020-06-19 07:20:01 +03:00
//
constexpr uint8_t kSortKeyComputeSeqShift = kSortKeyDrawBitShift - BGFX_CONFIG_SORT_KEY_NUM_BITS_SEQ;
constexpr uint64_t kSortKeyComputeSeqMask = ( (uint64_t(1)<<BGFX_CONFIG_SORT_KEY_NUM_BITS_SEQ)-1)<<kSortKeyComputeSeqShift;
2020-06-19 07:20:01 +03:00
constexpr uint8_t kSortKeyComputeProgramShift = kSortKeyComputeSeqShift - BGFX_CONFIG_SORT_KEY_NUM_BITS_PROGRAM;
constexpr uint64_t kSortKeyComputeProgramMask = uint64_t(BGFX_CONFIG_MAX_PROGRAMS-1)<<kSortKeyComputeProgramShift;
BX_STATIC_ASSERT(BGFX_CONFIG_MAX_VIEWS <= (1<<kSortKeyViewNumBits) );
BX_STATIC_ASSERT( (BGFX_CONFIG_MAX_PROGRAMS & (BGFX_CONFIG_MAX_PROGRAMS-1) ) == 0); // Must be power of 2.
BX_STATIC_ASSERT( (0 // Render key mask shouldn't overlap.
| kSortKeyViewMask
| kSortKeyDrawBit
| kSortKeyDrawTypeMask
2020-05-16 07:58:43 +03:00
| kSortKeyDraw0BlendMask
| kSortKeyDraw0ProgramMask
| kSortKeyDraw0DepthMask
) == (0
^ kSortKeyViewMask
^ kSortKeyDrawBit
^ kSortKeyDrawTypeMask
2020-05-16 07:58:43 +03:00
^ kSortKeyDraw0BlendMask
^ kSortKeyDraw0ProgramMask
^ kSortKeyDraw0DepthMask
2017-06-15 08:29:12 +03:00
) );
BX_STATIC_ASSERT( (0 // Render key mask shouldn't overlap.
| kSortKeyViewMask
| kSortKeyDrawBit
| kSortKeyDrawTypeMask
| kSortKeyDraw1DepthMask
2020-05-16 07:58:43 +03:00
| kSortKeyDraw1BlendMask
| kSortKeyDraw1ProgramMask
2017-06-15 08:29:12 +03:00
) == (0
^ kSortKeyViewMask
^ kSortKeyDrawBit
^ kSortKeyDrawTypeMask
^ kSortKeyDraw1DepthMask
2020-05-16 07:58:43 +03:00
^ kSortKeyDraw1BlendMask
^ kSortKeyDraw1ProgramMask
) );
BX_STATIC_ASSERT( (0 // Render key mask shouldn't overlap.
| kSortKeyViewMask
| kSortKeyDrawBit
| kSortKeyDrawTypeMask
| kSortKeyDraw2SeqMask
2020-05-16 07:58:43 +03:00
| kSortKeyDraw2BlendMask
| kSortKeyDraw2ProgramMask
) == (0
^ kSortKeyViewMask
^ kSortKeyDrawBit
^ kSortKeyDrawTypeMask
^ kSortKeyDraw2SeqMask
2020-05-16 07:58:43 +03:00
^ kSortKeyDraw2BlendMask
^ kSortKeyDraw2ProgramMask
) );
BX_STATIC_ASSERT( (0 // Compute key mask shouldn't overlap.
| kSortKeyViewMask
| kSortKeyDrawBit
| kSortKeyComputeSeqShift
| kSortKeyComputeProgramMask
) == (0
^ kSortKeyViewMask
^ kSortKeyDrawBit
^ kSortKeyComputeSeqShift
^ kSortKeyComputeProgramMask
) );
2014-09-08 04:17:38 +04:00
2017-06-15 08:29:12 +03:00
// | 3 2 1 0|
// |fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210| Common
// |vvvvvvvvd |
// | ^^ |
// | || |
// | view-+| |
// | +-draw |
// |----------------------------------------------------------------| Draw Key 0 - Sort by program
// | |kkttpppppppppdddddddddddddddddddddddddddddddd |
// | | ^ ^ ^ |
// | | | | | |
2020-05-16 07:58:43 +03:00
// | | +-blend +-program depth-+ |
2017-06-15 08:29:12 +03:00
// | | |
// |----------------------------------------------------------------| Draw Key 1 - Sort by depth
// | |kkddddddddddddddddddddddddddddddddttppppppppp |
// | | ^^ ^ ^ |
// | | || +-trans | |
// | | depth-+ program-+ |
// | | |
// |----------------------------------------------------------------| Draw Key 2 - Sequential
// | |kkssssssssssssssssssssttppppppppp |
// | | ^ ^ ^ |
// | | | | | |
// | | seq-+ +-trans +-program |
2017-06-15 08:29:12 +03:00
// | | |
// |----------------------------------------------------------------| Compute Key
// | |ssssssssssssssssssssppppppppp |
// | | ^ ^ |
// | | | | |
// | | seq-+ +-program |
2017-06-15 08:29:12 +03:00
// | | |
// |--------+-------------------------------------------------------|
//
2012-08-06 01:51:49 +04:00
struct SortKey
{
enum Enum
2017-06-15 08:29:12 +03:00
{
SortProgram,
SortDepth,
SortSequence,
};
uint64_t encodeDraw(Enum _type)
{
2018-12-19 03:11:41 +03:00
switch (_type)
2017-06-15 08:29:12 +03:00
{
2018-12-19 03:11:41 +03:00
case SortProgram:
{
const uint64_t depth = (uint64_t(m_depth ) << kSortKeyDraw0DepthShift ) & kSortKeyDraw0DepthMask;
const uint64_t program = (uint64_t(m_program.idx) << kSortKeyDraw0ProgramShift) & kSortKeyDraw0ProgramMask;
2020-05-16 07:58:43 +03:00
const uint64_t blend = (uint64_t(m_blend ) << kSortKeyDraw0BlendShift ) & kSortKeyDraw0BlendMask;
const uint64_t view = (uint64_t(m_view ) << kSortKeyViewBitShift ) & kSortKeyViewMask;
2020-05-16 07:58:43 +03:00
const uint64_t key = view|kSortKeyDrawBit|kSortKeyDrawTypeProgram|blend|program|depth;
2018-12-19 03:11:41 +03:00
return key;
}
break;
2017-06-15 08:29:12 +03:00
2018-12-19 03:11:41 +03:00
case SortDepth:
{
const uint64_t depth = (uint64_t(m_depth ) << kSortKeyDraw1DepthShift ) & kSortKeyDraw1DepthMask;
const uint64_t program = (uint64_t(m_program.idx) << kSortKeyDraw1ProgramShift) & kSortKeyDraw1ProgramMask;
2020-05-16 07:58:43 +03:00
const uint64_t blend = (uint64_t(m_blend ) << kSortKeyDraw1BlendShift) & kSortKeyDraw1BlendMask;
const uint64_t view = (uint64_t(m_view ) << kSortKeyViewBitShift ) & kSortKeyViewMask;
2020-05-16 07:58:43 +03:00
const uint64_t key = view|kSortKeyDrawBit|kSortKeyDrawTypeDepth|depth|blend|program;
2018-12-19 03:11:41 +03:00
return key;
}
break;
2018-12-19 03:11:41 +03:00
case SortSequence:
{
const uint64_t seq = (uint64_t(m_seq ) << kSortKeyDraw2SeqShift ) & kSortKeyDraw2SeqMask;
const uint64_t program = (uint64_t(m_program.idx) << kSortKeyDraw2ProgramShift) & kSortKeyDraw2ProgramMask;
2020-05-16 07:58:43 +03:00
const uint64_t blend = (uint64_t(m_blend ) << kSortKeyDraw2BlendShift ) & kSortKeyDraw2BlendMask;
const uint64_t view = (uint64_t(m_view ) << kSortKeyViewBitShift ) & kSortKeyViewMask;
2020-05-16 07:58:43 +03:00
const uint64_t key = view|kSortKeyDrawBit|kSortKeyDrawTypeSequence|seq|blend|program;
2018-12-19 03:11:41 +03:00
2020-06-16 20:06:18 +03:00
BX_ASSERT(seq == (uint64_t(m_seq) << kSortKeyDraw2SeqShift)
2018-12-19 03:11:41 +03:00
, "SortKey error, sequence is truncated (m_seq: %d)."
, m_seq
);
return key;
}
break;
}
2020-06-16 20:06:18 +03:00
BX_ASSERT(false, "You should not be here.");
2018-12-19 03:11:41 +03:00
return 0;
2014-07-21 07:27:13 +04:00
}
uint64_t encodeCompute()
2012-08-06 01:51:49 +04:00
{
const uint64_t program = (uint64_t(m_program.idx) << kSortKeyComputeProgramShift) & kSortKeyComputeProgramMask;
const uint64_t seq = (uint64_t(m_seq ) << kSortKeyComputeSeqShift ) & kSortKeyComputeSeqMask;
const uint64_t view = (uint64_t(m_view ) << kSortKeyViewBitShift ) & kSortKeyViewMask;
2014-07-21 07:27:13 +04:00
const uint64_t key = program|seq|view;
2020-06-16 20:06:18 +03:00
BX_ASSERT(seq == (uint64_t(m_seq) << kSortKeyComputeSeqShift)
2017-06-15 08:29:12 +03:00
, "SortKey error, sequence is truncated (m_seq: %d)."
, m_seq
);
2012-08-06 01:51:49 +04:00
return key;
}
2016-11-20 23:50:28 +03:00
/// Returns true if item is compute command.
2017-11-28 02:57:31 +03:00
bool decode(uint64_t _key, ViewId _viewRemap[BGFX_CONFIG_MAX_VIEWS])
2012-08-06 01:51:49 +04:00
{
m_view = _viewRemap[(_key & kSortKeyViewMask) >> kSortKeyViewBitShift];
2021-04-03 06:17:42 +03:00
if (_key & kSortKeyDrawBit)
2014-07-21 07:27:13 +04:00
{
uint64_t type = _key & kSortKeyDrawTypeMask;
2021-04-03 06:17:42 +03:00
if (type == kSortKeyDrawTypeDepth)
2017-06-15 08:29:12 +03:00
{
m_program.idx = uint16_t( (_key & kSortKeyDraw1ProgramMask) >> kSortKeyDraw1ProgramShift);
2017-06-15 08:29:12 +03:00
return false;
}
2021-04-03 06:17:42 +03:00
if (type == kSortKeyDrawTypeSequence)
{
m_program.idx = uint16_t( (_key & kSortKeyDraw2ProgramMask) >> kSortKeyDraw2ProgramShift);
return false;
}
2017-06-15 08:29:12 +03:00
m_program.idx = uint16_t( (_key & kSortKeyDraw0ProgramMask) >> kSortKeyDraw0ProgramShift);
2014-07-21 07:27:13 +04:00
return false; // draw
}
m_program.idx = uint16_t( (_key & kSortKeyComputeProgramMask) >> kSortKeyComputeProgramShift);
2014-07-21 07:27:13 +04:00
return true; // compute
2012-08-06 01:51:49 +04:00
}
2017-11-28 03:34:27 +03:00
static ViewId decodeView(uint64_t _key)
2016-11-21 01:29:37 +03:00
{
return ViewId( (_key & kSortKeyViewMask) >> kSortKeyViewBitShift);
2016-11-21 01:29:37 +03:00
}
2017-11-28 00:11:57 +03:00
static uint64_t remapView(uint64_t _key, ViewId _viewRemap[BGFX_CONFIG_MAX_VIEWS])
{
2017-11-28 03:34:27 +03:00
const ViewId oldView = decodeView(_key);
const uint64_t view = uint64_t(_viewRemap[oldView]) << kSortKeyViewBitShift;
const uint64_t key = (_key & ~kSortKeyViewMask) | view;
return key;
}
2012-08-06 01:51:49 +04:00
void reset()
{
2014-04-13 08:25:38 +04:00
m_depth = 0;
m_seq = 0;
2018-12-19 03:11:41 +03:00
m_program = {0};
2014-04-13 08:25:38 +04:00
m_view = 0;
2020-05-16 07:58:43 +03:00
m_blend = 0;
2012-08-06 01:51:49 +04:00
}
2018-12-19 03:11:41 +03:00
uint32_t m_depth;
uint32_t m_seq;
ProgramHandle m_program;
ViewId m_view;
2020-05-16 07:58:43 +03:00
uint8_t m_blend;
2012-08-06 01:51:49 +04:00
};
#undef SORT_KEY_RENDER_DRAW
2012-08-06 01:51:49 +04:00
2022-05-15 07:26:20 +03:00
constexpr uint8_t kBlitKeyViewShift = 32-kSortKeyViewNumBits;
constexpr uint32_t kBlitKeyViewMask = uint32_t(BGFX_CONFIG_MAX_VIEWS-1)<<kBlitKeyViewShift;
constexpr uint8_t kBlitKeyItemShift = 0;
constexpr uint32_t kBlitKeyItemMask = UINT16_MAX;
2015-10-16 02:38:59 +03:00
struct BlitKey
{
uint32_t encode()
{
2022-05-15 07:26:20 +03:00
const uint32_t view = (uint32_t(m_view) << kBlitKeyViewShift) & kBlitKeyViewMask;
const uint32_t item = (uint32_t(m_item) << kBlitKeyItemShift) & kBlitKeyItemMask;
2022-05-17 21:30:10 +03:00
const uint32_t key = view|item;
2022-05-15 07:26:20 +03:00
return key;
2015-10-16 02:38:59 +03:00
}
void decode(uint32_t _key)
{
2022-05-15 07:26:20 +03:00
m_item = uint16_t( (_key & kBlitKeyItemMask) >> kBlitKeyItemShift);
m_view = ViewId( (_key & kBlitKeyViewMask) >> kBlitKeyViewShift);
2015-10-16 02:38:59 +03:00
}
2017-11-28 00:11:57 +03:00
static uint32_t remapView(uint32_t _key, ViewId _viewRemap[BGFX_CONFIG_MAX_VIEWS])
2015-10-16 02:38:59 +03:00
{
2022-05-15 07:26:20 +03:00
const ViewId oldView = ViewId( (_key & kBlitKeyViewMask) >> kBlitKeyViewShift);
const uint32_t view = uint32_t( (_viewRemap[oldView] << kBlitKeyViewShift) & kBlitKeyViewMask);
const uint32_t key = (_key & ~kBlitKeyViewMask) | view;
2015-10-16 02:38:59 +03:00
return key;
}
uint16_t m_item;
2017-11-28 00:11:57 +03:00
ViewId m_view;
2015-10-16 02:38:59 +03:00
};
2018-10-16 03:54:41 +03:00
BX_ALIGN_DECL_16(struct) Srt
{
float rotate[4];
float translate[3];
float pad0;
float scale[3];
float pad1;
};
2014-10-14 08:31:18 +04:00
BX_ALIGN_DECL_16(struct) Matrix4
2012-08-06 01:51:49 +04:00
{
2014-01-19 11:33:00 +04:00
union
{
float val[16];
bx::float4x4_t f4x4;
2014-01-19 11:33:00 +04:00
} un;
2012-08-06 01:51:49 +04:00
void setIdentity()
{
2017-02-09 06:55:31 +03:00
bx::memSet(un.val, 0, sizeof(un.val) );
2014-01-19 11:33:00 +04:00
un.val[0] = un.val[5] = un.val[10] = un.val[15] = 1.0f;
2012-08-06 01:51:49 +04:00
}
};
struct MatrixCache
{
MatrixCache()
: m_num(1)
{
m_cache[0].setIdentity();
}
void reset()
{
m_num = 1;
}
uint32_t reserve(uint16_t* _num)
{
2014-10-10 20:26:58 +04:00
uint32_t num = *_num;
2017-11-02 08:34:11 +03:00
uint32_t first = bx::atomicFetchAndAddsat<uint32_t>(&m_num, num, BGFX_CONFIG_MAX_MATRIX_CACHE - 1);
BX_WARN(first+num < BGFX_CONFIG_MAX_MATRIX_CACHE, "Matrix cache overflow. %d (max: %d)", first+num, BGFX_CONFIG_MAX_MATRIX_CACHE);
2018-02-11 02:49:30 +03:00
num = bx::min(num, BGFX_CONFIG_MAX_MATRIX_CACHE-1-first);
*_num = (uint16_t)num;
return first;
}
2012-08-06 01:51:49 +04:00
uint32_t add(const void* _mtx, uint16_t _num)
{
if (NULL != _mtx)
{
uint32_t first = reserve(&_num);
2017-02-09 06:55:31 +03:00
bx::memCopy(&m_cache[first], _mtx, sizeof(Matrix4)*_num);
2012-08-06 01:51:49 +04:00
return first;
}
return 0;
}
float* toPtr(uint32_t _cacheIdx)
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(_cacheIdx < BGFX_CONFIG_MAX_MATRIX_CACHE, "Matrix cache out of bounds index %d (max: %d)"
, _cacheIdx
, BGFX_CONFIG_MAX_MATRIX_CACHE
);
return m_cache[_cacheIdx].un.val;
}
uint32_t fromPtr(const void* _ptr) const
{
return uint32_t( (const Matrix4*)_ptr - m_cache);
}
2012-08-06 01:51:49 +04:00
Matrix4 m_cache[BGFX_CONFIG_MAX_MATRIX_CACHE];
uint32_t m_num;
};
struct RectCache
{
RectCache()
: m_num(0)
{
}
void reset()
{
m_num = 0;
}
uint32_t add(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height)
{
2017-11-02 08:34:11 +03:00
const uint32_t first = bx::atomicFetchAndAddsat<uint32_t>(&m_num, 1, BGFX_CONFIG_MAX_RECT_CACHE-1);
2020-06-16 20:06:18 +03:00
BX_ASSERT(first+1 < BGFX_CONFIG_MAX_RECT_CACHE, "Rect cache overflow. %d (max: %d)", first, BGFX_CONFIG_MAX_RECT_CACHE);
2017-11-02 08:34:11 +03:00
Rect& rect = m_cache[first];
rect.m_x = _x;
rect.m_y = _y;
rect.m_width = _width;
rect.m_height = _height;
return first;
}
2021-04-03 06:17:42 +03:00
Rect m_cache[BGFX_CONFIG_MAX_RECT_CACHE];
uint32_t m_num;
};
2020-06-19 07:20:01 +03:00
constexpr uint8_t kConstantOpcodeTypeShift = 27;
constexpr uint32_t kConstantOpcodeTypeMask = UINT32_C(0xf8000000);
constexpr uint8_t kConstantOpcodeLocShift = 11;
constexpr uint32_t kConstantOpcodeLocMask = UINT32_C(0x07fff800);
constexpr uint8_t kConstantOpcodeNumShift = 1;
constexpr uint32_t kConstantOpcodeNumMask = UINT32_C(0x000007fe);
constexpr uint8_t kConstantOpcodeCopyShift = 0;
constexpr uint32_t kConstantOpcodeCopyMask = UINT32_C(0x00000001);
constexpr uint8_t kUniformFragmentBit = 0x10;
constexpr uint8_t kUniformSamplerBit = 0x20;
constexpr uint8_t kUniformReadOnlyBit = 0x40;
constexpr uint8_t kUniformCompareBit = 0x80;
constexpr uint8_t kUniformMask = 0
| kUniformFragmentBit
| kUniformSamplerBit
| kUniformReadOnlyBit
| kUniformCompareBit
;
2012-08-06 01:51:49 +04:00
2015-09-15 01:53:33 +03:00
class UniformBuffer
2012-08-06 01:51:49 +04:00
{
public:
2015-09-15 01:53:33 +03:00
static UniformBuffer* create(uint32_t _size = 1<<20)
2012-08-06 01:51:49 +04:00
{
2018-01-13 07:26:23 +03:00
const uint32_t structSize = sizeof(UniformBuffer)-sizeof(UniformBuffer::m_buffer);
uint32_t size = bx::alignUp(_size, 16);
2018-01-13 07:26:23 +03:00
void* data = BX_ALLOC(g_allocator, size+structSize);
return BX_PLACEMENT_NEW(data, UniformBuffer)(size);
2012-08-06 01:51:49 +04:00
}
2015-09-15 01:53:33 +03:00
static void destroy(UniformBuffer* _uniformBuffer)
2012-08-06 01:51:49 +04:00
{
2015-09-15 01:53:33 +03:00
_uniformBuffer->~UniformBuffer();
BX_FREE(g_allocator, _uniformBuffer);
}
static void update(UniformBuffer** _uniformBuffer, uint32_t _threshold = 64<<10, uint32_t _grow = 1<<20)
2015-09-15 01:53:33 +03:00
{
2017-11-04 09:48:40 +03:00
UniformBuffer* uniformBuffer = *_uniformBuffer;
if (_threshold >= uniformBuffer->m_size - uniformBuffer->m_pos)
2015-09-15 01:53:33 +03:00
{
2018-01-13 07:26:23 +03:00
const uint32_t structSize = sizeof(UniformBuffer)-sizeof(UniformBuffer::m_buffer);
uint32_t size = bx::alignUp(uniformBuffer->m_size + _grow, 16);
2018-01-13 07:26:23 +03:00
void* data = BX_REALLOC(g_allocator, uniformBuffer, size+structSize);
2017-11-04 09:48:40 +03:00
uniformBuffer = reinterpret_cast<UniformBuffer*>(data);
uniformBuffer->m_size = size;
*_uniformBuffer = uniformBuffer;
2015-09-15 01:53:33 +03:00
}
2012-08-06 01:51:49 +04:00
}
2012-10-28 08:34:41 +04:00
static uint32_t encodeOpcode(UniformType::Enum _type, uint16_t _loc, uint16_t _num, uint16_t _copy)
2012-08-06 01:51:49 +04:00
{
2020-06-19 07:20:01 +03:00
const uint32_t type = _type << kConstantOpcodeTypeShift;
const uint32_t loc = _loc << kConstantOpcodeLocShift;
const uint32_t num = _num << kConstantOpcodeNumShift;
const uint32_t copy = _copy << kConstantOpcodeCopyShift;
return type|loc|num|copy;
2012-08-06 01:51:49 +04:00
}
2012-10-28 08:34:41 +04:00
static void decodeOpcode(uint32_t _opcode, UniformType::Enum& _type, uint16_t& _loc, uint16_t& _num, uint16_t& _copy)
2012-08-06 01:51:49 +04:00
{
2020-06-19 07:20:01 +03:00
const uint32_t type = (_opcode&kConstantOpcodeTypeMask) >> kConstantOpcodeTypeShift;
const uint32_t loc = (_opcode&kConstantOpcodeLocMask ) >> kConstantOpcodeLocShift;
const uint32_t num = (_opcode&kConstantOpcodeNumMask ) >> kConstantOpcodeNumShift;
const uint32_t copy = (_opcode&kConstantOpcodeCopyMask); // >> kConstantOpcodeCopyShift;
2012-08-06 01:51:49 +04:00
_type = (UniformType::Enum)(type);
2012-08-06 01:51:49 +04:00
_copy = (uint16_t)copy;
_num = (uint16_t)num;
_loc = (uint16_t)loc;
2012-08-06 01:51:49 +04:00
}
void write(const void* _data, uint32_t _size)
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(m_pos + _size < m_size, "Write would go out of bounds. pos %d + size %d > max size: %d).", m_pos, _size, m_size);
2012-08-06 01:51:49 +04:00
if (m_pos + _size < m_size)
{
2017-02-09 06:55:31 +03:00
bx::memCopy(&m_buffer[m_pos], _data, _size);
2012-08-06 01:51:49 +04:00
m_pos += _size;
}
}
void write(uint32_t _value)
{
write(&_value, sizeof(uint32_t) );
}
const char* read(uint32_t _size)
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(m_pos < m_size, "Out of bounds %d (size: %d).", m_pos, m_size);
2012-08-06 01:51:49 +04:00
const char* result = &m_buffer[m_pos];
m_pos += _size;
return result;
}
uint32_t read()
{
uint32_t result;
2017-02-09 06:55:31 +03:00
bx::memCopy(&result, read(sizeof(uint32_t) ), sizeof(uint32_t) );
return result;
2012-08-06 01:51:49 +04:00
}
bool isEmpty() const
{
return 0 == m_pos;
}
uint32_t getPos() const
{
return m_pos;
}
void reset(uint32_t _pos = 0)
{
m_pos = _pos;
}
void finish()
{
2012-10-28 08:34:41 +04:00
write(UniformType::End);
2012-08-06 01:51:49 +04:00
m_pos = 0;
}
2012-10-28 08:34:41 +04:00
void writeUniform(UniformType::Enum _type, uint16_t _loc, const void* _value, uint16_t _num = 1);
void writeUniformHandle(UniformType::Enum _type, uint16_t _loc, UniformHandle _handle, uint16_t _num = 1);
void writeMarker(const char* _marker);
2012-08-06 01:51:49 +04:00
private:
2015-09-15 01:53:33 +03:00
UniformBuffer(uint32_t _size)
2018-01-13 07:26:23 +03:00
: m_size(_size)
2012-08-06 01:51:49 +04:00
, m_pos(0)
{
finish();
}
2015-09-15 01:53:33 +03:00
~UniformBuffer()
2012-08-06 01:51:49 +04:00
{
}
uint32_t m_size;
uint32_t m_pos;
2021-04-03 06:17:42 +03:00
char m_buffer[256<<20];
2012-08-06 01:51:49 +04:00
};
struct UniformRegInfo
2012-08-06 01:51:49 +04:00
{
UniformHandle m_handle;
2012-08-06 01:51:49 +04:00
};
2017-03-21 10:14:48 +03:00
class UniformRegistry
{
2012-08-06 01:51:49 +04:00
public:
UniformRegistry()
{
}
~UniformRegistry()
{
}
const UniformRegInfo* find(const char* _name) const
{
2017-09-24 02:27:16 +03:00
uint16_t handle = m_uniforms.find(bx::hash<bx::HashMurmur2A>(_name) );
2017-06-10 07:57:08 +03:00
if (kInvalidHandle != handle)
2012-08-06 01:51:49 +04:00
{
return &m_info[handle];
2012-08-06 01:51:49 +04:00
}
return NULL;
}
2012-08-06 01:51:49 +04:00
2018-05-22 02:59:17 +03:00
const UniformRegInfo& add(UniformHandle _handle, const char* _name)
2012-08-06 01:51:49 +04:00
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(isValid(_handle), "Uniform handle is invalid (name: %s)!", _name);
2017-09-24 02:27:16 +03:00
const uint32_t key = bx::hash<bx::HashMurmur2A>(_name);
2016-09-09 03:00:16 +03:00
m_uniforms.removeByKey(key);
m_uniforms.insert(key, _handle.idx);
2012-08-06 01:51:49 +04:00
UniformRegInfo& info = m_info[_handle.idx];
info.m_handle = _handle;
return info;
2012-08-06 01:51:49 +04:00
}
2016-09-09 03:00:16 +03:00
void remove(UniformHandle _handle)
{
m_uniforms.removeByHandle(_handle.idx);
}
2015-01-14 09:34:48 +03:00
private:
typedef bx::HandleHashMapT<BGFX_CONFIG_MAX_UNIFORMS*2> UniformHashMap;
2015-01-14 09:34:48 +03:00
UniformHashMap m_uniforms;
UniformRegInfo m_info[BGFX_CONFIG_MAX_UNIFORMS];
2015-01-14 09:34:48 +03:00
};
2012-08-06 01:51:49 +04:00
2015-01-14 09:34:48 +03:00
struct Binding
2012-08-06 01:51:49 +04:00
{
2015-01-14 09:34:48 +03:00
enum Enum
{
Image,
IndexBuffer,
VertexBuffer,
Texture,
Count
};
uint32_t m_samplerFlags;
2014-07-21 07:27:13 +04:00
uint16_t m_idx;
2015-01-14 09:34:48 +03:00
uint8_t m_type;
uint8_t m_format;
uint8_t m_access;
uint8_t m_mip;
2014-07-21 07:27:13 +04:00
};
2012-08-06 01:51:49 +04:00
2016-09-13 05:38:29 +03:00
struct Stream
{
void clear()
{
2021-04-03 06:17:42 +03:00
m_startVertex = 0;
m_handle.idx = kInvalidHandle;
m_layoutHandle.idx = kInvalidHandle;
2016-09-13 05:38:29 +03:00
}
uint32_t m_startVertex;
VertexBufferHandle m_handle;
2021-04-03 06:17:42 +03:00
VertexLayoutHandle m_layoutHandle;
2016-09-13 05:38:29 +03:00
};
2017-11-03 08:06:39 +03:00
BX_ALIGN_DECL_CACHE_LINE(struct) RenderBind
2017-04-07 06:32:48 +03:00
{
2020-01-22 07:08:48 +03:00
void clear(uint8_t _flags = BGFX_DISCARD_ALL)
2017-04-07 06:32:48 +03:00
{
2020-04-03 05:04:13 +03:00
if (0 != (_flags & BGFX_DISCARD_BINDINGS) )
2017-04-07 06:32:48 +03:00
{
2020-01-20 21:03:12 +03:00
for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_TEXTURE_SAMPLERS; ++ii)
{
Binding& bind = m_bind[ii];
bind.m_idx = kInvalidHandle;
bind.m_type = 0;
bind.m_samplerFlags = 0;
}
2017-04-07 06:32:48 +03:00
}
};
Binding m_bind[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
};
2017-11-03 08:06:39 +03:00
BX_ALIGN_DECL_CACHE_LINE(struct) RenderDraw
2014-07-21 07:27:13 +04:00
{
2020-01-22 07:08:48 +03:00
void clear(uint8_t _flags = BGFX_DISCARD_ALL)
2012-08-06 01:51:49 +04:00
{
2020-01-22 07:08:48 +03:00
if (0 != (_flags & BGFX_DISCARD_STATE) )
2020-01-20 21:03:12 +03:00
{
2020-04-03 05:04:13 +03:00
m_uniformBegin = 0;
m_uniformEnd = 0;
m_uniformIdx = UINT8_MAX;
m_stateFlags = BGFX_STATE_DEFAULT;
m_stencil = packStencil(BGFX_STENCIL_DEFAULT, BGFX_STENCIL_DEFAULT);
m_rgba = 0;
m_scissor = UINT16_MAX;
}
if (0 != (_flags & BGFX_DISCARD_TRANSFORM) )
{
m_startMatrix = 0;
m_numMatrices = 1;
}
if (0 != (_flags & BGFX_DISCARD_INSTANCE_DATA) )
{
2020-01-20 21:03:12 +03:00
m_instanceDataOffset = 0;
m_instanceDataStride = 0;
m_numInstances = 1;
m_instanceDataBuffer.idx = kInvalidHandle;
}
2020-01-22 07:08:48 +03:00
if (0 != (_flags & BGFX_DISCARD_VERTEX_STREAMS) )
2020-01-20 21:03:12 +03:00
{
2020-04-03 05:04:13 +03:00
m_numVertices = UINT32_MAX;
m_streamMask = 0;
2020-01-20 21:03:12 +03:00
m_stream[0].clear();
}
2020-01-22 07:08:48 +03:00
if (0 != (_flags & BGFX_DISCARD_INDEX_BUFFER) )
2020-01-20 21:03:12 +03:00
{
2020-04-03 05:04:13 +03:00
m_startIndex = 0;
m_numIndices = UINT32_MAX;
2020-01-20 21:03:12 +03:00
m_indexBuffer.idx = kInvalidHandle;
2021-04-03 02:46:42 +03:00
m_submitFlags = 0;
}
else
{
m_submitFlags = isIndex16() ? 0 : BGFX_SUBMIT_INTERNAL_INDEX32;
2020-01-20 21:03:12 +03:00
}
2020-04-03 05:04:13 +03:00
m_startIndirect = 0;
m_numIndirect = UINT16_MAX;
m_numIndirectIndex = 0;
2020-04-03 05:04:13 +03:00
m_indirectBuffer.idx = kInvalidHandle;
m_numIndirectBuffer.idx = kInvalidHandle;
2020-04-03 05:04:13 +03:00
m_occlusionQuery.idx = kInvalidHandle;
2012-08-06 01:51:49 +04:00
}
2016-09-16 06:54:00 +03:00
bool setStreamBit(uint8_t _stream, VertexBufferHandle _handle)
{
const uint8_t bit = 1<<_stream;
const uint8_t mask = m_streamMask & ~bit;
const uint8_t tmp = isValid(_handle) ? bit : 0;
m_streamMask = mask | tmp;
return 0 != tmp;
}
bool isIndex16() const
{
return 0 == (m_submitFlags & BGFX_SUBMIT_INTERNAL_INDEX32);
}
2016-09-13 05:38:29 +03:00
Stream m_stream[BGFX_CONFIG_MAX_VERTEX_STREAMS];
2015-11-02 04:28:23 +03:00
uint64_t m_stateFlags;
2012-11-11 07:59:23 +04:00
uint64_t m_stencil;
uint32_t m_rgba;
2017-10-10 07:08:03 +03:00
uint32_t m_uniformBegin;
uint32_t m_uniformEnd;
2017-10-10 07:17:58 +03:00
uint32_t m_startMatrix;
2012-08-06 01:51:49 +04:00
uint32_t m_startIndex;
uint32_t m_numIndices;
uint32_t m_numVertices;
uint32_t m_instanceDataOffset;
2016-03-02 04:56:04 +03:00
uint32_t m_numInstances;
2012-08-06 01:51:49 +04:00
uint16_t m_instanceDataStride;
2015-05-02 00:54:23 +03:00
uint16_t m_startIndirect;
uint16_t m_numIndirect;
uint32_t m_numIndirectIndex;
2017-10-10 07:17:58 +03:00
uint16_t m_numMatrices;
2013-07-15 01:32:09 +04:00
uint16_t m_scissor;
2014-12-28 22:36:36 +03:00
uint8_t m_submitFlags;
2016-09-13 05:38:29 +03:00
uint8_t m_streamMask;
2017-11-02 08:34:11 +03:00
uint8_t m_uniformIdx;
2012-08-06 01:51:49 +04:00
2015-11-02 04:28:23 +03:00
IndexBufferHandle m_indexBuffer;
VertexBufferHandle m_instanceDataBuffer;
2015-05-02 00:54:23 +03:00
IndirectBufferHandle m_indirectBuffer;
IndexBufferHandle m_numIndirectBuffer;
2015-11-02 04:28:23 +03:00
OcclusionQueryHandle m_occlusionQuery;
2014-07-21 07:27:13 +04:00
};
2017-11-03 08:06:39 +03:00
BX_ALIGN_DECL_CACHE_LINE(struct) RenderCompute
2014-07-21 07:27:13 +04:00
{
2020-04-03 05:04:13 +03:00
void clear(uint8_t _flags)
2014-07-21 07:27:13 +04:00
{
2020-04-03 05:04:13 +03:00
if (0 != (_flags & BGFX_DISCARD_STATE) )
2020-01-20 21:03:12 +03:00
{
m_uniformBegin = 0;
m_uniformEnd = 0;
m_uniformIdx = UINT8_MAX;
2020-04-03 05:04:13 +03:00
}
2020-01-20 21:03:12 +03:00
2020-04-03 05:04:13 +03:00
if (0 != (_flags & BGFX_DISCARD_TRANSFORM) )
{
m_startMatrix = 0;
m_numMatrices = 0;
2020-01-20 21:03:12 +03:00
}
2020-04-03 05:04:13 +03:00
m_numX = 0;
m_numY = 0;
m_numZ = 0;
m_submitFlags = 0;
m_indirectBuffer.idx = kInvalidHandle;
m_startIndirect = 0;
m_numIndirect = UINT16_MAX;
2014-07-21 07:27:13 +04:00
}
2017-10-10 07:08:03 +03:00
uint32_t m_uniformBegin;
uint32_t m_uniformEnd;
2017-10-10 07:17:58 +03:00
uint32_t m_startMatrix;
2015-05-02 00:54:23 +03:00
IndirectBufferHandle m_indirectBuffer;
2014-07-21 07:27:13 +04:00
2017-07-28 00:57:31 +03:00
uint32_t m_numX;
uint32_t m_numY;
uint32_t m_numZ;
2015-05-02 00:54:23 +03:00
uint16_t m_startIndirect;
uint16_t m_numIndirect;
2017-10-10 07:17:58 +03:00
uint16_t m_numMatrices;
2014-12-28 22:36:36 +03:00
uint8_t m_submitFlags;
2017-11-02 08:34:11 +03:00
uint8_t m_uniformIdx;
2014-07-21 07:27:13 +04:00
};
union RenderItem
{
RenderDraw draw;
RenderCompute compute;
};
2017-11-03 08:06:39 +03:00
BX_ALIGN_DECL_CACHE_LINE(struct) BlitItem
2015-10-16 02:38:59 +03:00
{
uint16_t m_srcX;
uint16_t m_srcY;
uint16_t m_srcZ;
uint16_t m_dstX;
uint16_t m_dstY;
uint16_t m_dstZ;
uint16_t m_width;
uint16_t m_height;
uint16_t m_depth;
uint8_t m_srcMip;
uint8_t m_dstMip;
TextureHandle m_src;
TextureHandle m_dst;
};
struct IndexBuffer
{
String m_name;
uint32_t m_size;
uint16_t m_flags;
};
2014-12-10 10:16:27 +03:00
struct VertexBuffer
{
String m_name;
uint32_t m_size;
2014-12-10 10:16:27 +03:00
uint16_t m_stride;
};
2012-08-06 01:51:49 +04:00
struct DynamicIndexBuffer
{
2022-08-19 20:40:00 +03:00
void reset()
{
m_handle = BGFX_INVALID_HANDLE;
m_offset = 0;
m_size = 0;
m_startIndex = 0;
m_flags = 0;
}
2012-08-06 01:51:49 +04:00
IndexBufferHandle m_handle;
uint32_t m_offset;
uint32_t m_size;
2015-01-24 09:18:07 +03:00
uint32_t m_startIndex;
2015-05-14 21:37:32 +03:00
uint16_t m_flags;
2012-08-06 01:51:49 +04:00
};
struct DynamicVertexBuffer
{
2022-08-19 20:40:00 +03:00
void reset()
{
m_handle = BGFX_INVALID_HANDLE;
m_offset = 0;
m_size = 0;
m_startVertex = 0;
m_numVertices = 0;
m_stride = 0;
m_layoutHandle = BGFX_INVALID_HANDLE;
m_flags = 0;
}
2012-08-06 01:51:49 +04:00
VertexBufferHandle m_handle;
uint32_t m_offset;
uint32_t m_size;
uint32_t m_startVertex;
uint32_t m_numVertices;
2014-12-10 10:16:27 +03:00
uint16_t m_stride;
2019-08-17 20:35:21 +03:00
VertexLayoutHandle m_layoutHandle;
2015-05-14 21:37:32 +03:00
uint16_t m_flags;
2012-08-06 01:51:49 +04:00
};
2019-01-18 06:59:46 +03:00
struct ShaderRef
{
UniformHandle* m_uniforms;
String m_name;
uint32_t m_hashIn;
uint32_t m_hashOut;
uint16_t m_num;
int16_t m_refCount;
};
struct ProgramRef
{
ShaderHandle m_vsh;
ShaderHandle m_fsh;
int16_t m_refCount;
};
struct UniformRef
{
String m_name;
UniformType::Enum m_type;
uint16_t m_num;
int16_t m_refCount;
};
struct TextureRef
{
void init(
BackbufferRatio::Enum _ratio
, uint16_t _width
, uint16_t _height
, uint16_t _depth
2019-01-18 06:59:46 +03:00
, TextureFormat::Enum _format
, uint32_t _storageSize
, uint8_t _numMips
, uint16_t _numLayers
, bool _ptrPending
, bool _immutable
2020-10-10 06:47:50 +03:00
, bool _cubeMap
, uint64_t _flags
2019-01-18 06:59:46 +03:00
)
{
m_ptr = _ptrPending ? (void*)UINTPTR_MAX : NULL;
m_storageSize = _storageSize;
m_refCount = 1;
m_bbRatio = uint8_t(_ratio);
m_width = _width;
m_height = _height;
m_depth = _depth;
2019-01-18 06:59:46 +03:00
m_format = uint8_t(_format);
m_numSamples = 1 << bx::uint32_satsub((_flags & BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT, 1);
2019-01-18 06:59:46 +03:00
m_numMips = _numMips;
m_numLayers = _numLayers;
m_owned = false;
m_immutable = _immutable;
2020-10-10 06:47:50 +03:00
m_cubeMap = _cubeMap;
m_flags = _flags;
}
bool isRt() const
{
return 0 != (m_flags & BGFX_TEXTURE_RT_MASK);
}
bool isReadBack() const
{
return 0 != (m_flags & BGFX_TEXTURE_READ_BACK);
2019-01-18 06:59:46 +03:00
}
bool isBlitDst() const
{
return 0 != (m_flags & BGFX_TEXTURE_BLIT_DST);
}
2020-10-10 06:47:50 +03:00
bool isCubeMap() const
{
return m_cubeMap;
}
bool is3D() const
{
return 0 < m_depth;
}
2019-01-18 06:59:46 +03:00
String m_name;
void* m_ptr;
uint64_t m_flags;
2019-01-18 06:59:46 +03:00
uint32_t m_storageSize;
int16_t m_refCount;
uint8_t m_bbRatio;
uint16_t m_width;
uint16_t m_height;
uint16_t m_depth;
2019-01-18 06:59:46 +03:00
uint8_t m_format;
uint8_t m_numSamples;
2019-01-18 06:59:46 +03:00
uint8_t m_numMips;
uint16_t m_numLayers;
bool m_owned;
bool m_immutable;
2020-10-10 06:47:50 +03:00
bool m_cubeMap;
2019-01-18 06:59:46 +03:00
};
struct FrameBufferRef
{
String m_name;
uint16_t m_width;
uint16_t m_height;
2019-01-18 06:59:46 +03:00
union un
{
TextureHandle m_th[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
void* m_nwh;
} un;
bool m_window;
};
BX_ALIGN_DECL_CACHE_LINE(struct) View
{
void reset()
{
setRect(0, 0, 1, 1);
setScissor(0, 0, 0, 0);
setClear(BGFX_CLEAR_NONE, 0, 0.0f, 0);
setMode(ViewMode::Default);
setFrameBuffer(BGFX_INVALID_HANDLE);
2018-12-22 10:25:30 +03:00
setTransform(NULL, NULL);
}
void setRect(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height)
{
2018-06-16 18:34:06 +03:00
m_rect.m_x = uint16_t(bx::max<int16_t>(int16_t(_x), 0) );
m_rect.m_y = uint16_t(bx::max<int16_t>(int16_t(_y), 0) );
m_rect.m_width = bx::max<uint16_t>(_width, 1);
m_rect.m_height = bx::max<uint16_t>(_height, 1);
}
void setScissor(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height)
{
m_scissor.m_x = _x;
m_scissor.m_y = _y;
m_scissor.m_width = _width;
m_scissor.m_height = _height;
}
void setClear(uint16_t _flags, uint32_t _rgba, float _depth, uint8_t _stencil)
{
m_clear.set(_flags, _rgba, _depth, _stencil);
}
void setClear(uint16_t _flags, float _depth, uint8_t _stencil, uint8_t _0, uint8_t _1, uint8_t _2, uint8_t _3, uint8_t _4, uint8_t _5, uint8_t _6, uint8_t _7)
{
m_clear.set(_flags, _depth, _stencil, _0, _1, _2, _3, _4, _5, _6, _7);
}
void setMode(ViewMode::Enum _mode)
{
m_mode = uint8_t(_mode);
}
void setFrameBuffer(FrameBufferHandle _handle)
{
m_fbh = _handle;
}
2018-12-22 10:25:30 +03:00
void setTransform(const void* _view, const void* _proj)
{
if (NULL != _view)
{
bx::memCopy(m_view.un.val, _view, sizeof(Matrix4) );
}
else
{
m_view.setIdentity();
}
if (NULL != _proj)
{
2018-12-22 10:25:30 +03:00
bx::memCopy(m_proj.un.val, _proj, sizeof(Matrix4) );
}
else
{
2018-12-22 10:25:30 +03:00
m_proj.setIdentity();
}
}
Clear m_clear;
Rect m_rect;
Rect m_scissor;
Matrix4 m_view;
2018-12-22 10:25:30 +03:00
Matrix4 m_proj;
FrameBufferHandle m_fbh;
uint8_t m_mode;
};
struct FrameCache
{
void reset()
{
m_matrixCache.reset();
m_rectCache.reset();
}
bool isZeroArea(const Rect& _rect, uint16_t _scissor) const
{
if (UINT16_MAX != _scissor)
{
Rect scissorRect;
scissorRect.setIntersect(_rect, m_rectCache.m_cache[_scissor]);
return scissorRect.isZeroArea();
}
return false;
}
MatrixCache m_matrixCache;
RectCache m_rectCache;
};
struct ScreenShot
{
bx::FilePath filePath;
FrameBufferHandle handle;
};
2014-10-14 08:31:18 +04:00
BX_ALIGN_DECL_CACHE_LINE(struct) Frame
2012-08-06 01:51:49 +04:00
{
Frame()
2017-11-02 08:34:11 +03:00
: m_waitSubmit(0)
, m_waitRender(0)
, m_frameNum(0)
, m_capture(false)
2012-08-06 01:51:49 +04:00
{
2014-10-29 08:08:55 +03:00
SortKey term;
term.reset();
2018-12-19 03:11:41 +03:00
term.m_program = BGFX_INVALID_HANDLE;
m_sortKeys[BGFX_CONFIG_MAX_DRAW_CALLS] = term.encodeDraw(SortKey::SortProgram);
2014-10-29 08:08:55 +03:00
m_sortValues[BGFX_CONFIG_MAX_DRAW_CALLS] = BGFX_CONFIG_MAX_DRAW_CALLS;
2017-02-09 06:55:31 +03:00
bx::memSet(m_occlusion, 0xff, sizeof(m_occlusion) );
2017-11-03 08:06:39 +03:00
m_perfStats.viewStats = m_viewStats;
2012-08-06 01:51:49 +04:00
}
~Frame()
{
}
void create(uint32_t _minResourceCbSize)
2012-08-06 01:51:49 +04:00
{
m_cmdPre.init(_minResourceCbSize);
m_cmdPost.init(_minResourceCbSize);
2017-11-02 08:34:11 +03:00
{
const uint32_t num = g_caps.limits.maxEncoders;
m_uniformBuffer = (UniformBuffer**)BX_ALLOC(g_allocator, sizeof(UniformBuffer*)*num);
for (uint32_t ii = 0; ii < num; ++ii)
{
m_uniformBuffer[ii] = UniformBuffer::create();
}
2017-11-02 08:34:11 +03:00
}
2012-08-06 01:51:49 +04:00
reset();
start(0);
2013-09-21 09:13:58 +04:00
m_textVideoMem = BX_NEW(g_allocator, TextVideoMem);
2012-08-06 01:51:49 +04:00
}
void destroy()
{
for (uint32_t ii = 0, num = g_caps.limits.maxEncoders; ii < num; ++ii)
2017-11-02 08:34:11 +03:00
{
UniformBuffer::destroy(m_uniformBuffer[ii]);
}
BX_FREE(g_allocator, m_uniformBuffer);
2013-09-21 09:13:58 +04:00
BX_DELETE(g_allocator, m_textVideoMem);
2012-08-06 01:51:49 +04:00
}
void reset()
{
start(0);
finish();
resetFreeHandles();
}
void start(uint32_t frameNum)
2012-08-06 01:51:49 +04:00
{
2018-04-19 02:35:57 +03:00
m_perfStats.transientVbUsed = m_vboffset;
m_perfStats.transientIbUsed = m_iboffset;
m_frameCache.reset();
2014-07-21 07:27:13 +04:00
m_numRenderItems = 0;
2015-10-16 02:38:59 +03:00
m_numBlitItems = 0;
2012-08-06 01:51:49 +04:00
m_iboffset = 0;
m_vboffset = 0;
m_cmdPre.start();
m_cmdPost.start();
m_capture = false;
m_numScreenShots = 0;
m_frameNum = frameNum;
2012-08-06 01:51:49 +04:00
}
void finish()
{
m_cmdPre.finish();
m_cmdPost.finish();
}
void sort();
uint32_t getAvailTransientIndexBuffer(uint32_t _num, uint16_t _indexSize)
{
const uint32_t offset = bx::strideAlign(m_iboffset, _indexSize);
uint32_t iboffset = offset + _num*_indexSize;
2018-04-19 02:35:57 +03:00
iboffset = bx::min<uint32_t>(iboffset, g_caps.limits.transientIbSize);
const uint32_t num = (iboffset-offset)/_indexSize;
return num;
}
uint32_t allocTransientIndexBuffer(uint32_t& _num, uint16_t _indexSize)
{
uint32_t offset = bx::strideAlign(m_iboffset, _indexSize);
uint32_t num = getAvailTransientIndexBuffer(_num, _indexSize);
m_iboffset = offset + num*_indexSize;
_num = num;
return offset;
}
uint32_t getAvailTransientVertexBuffer(uint32_t _num, uint16_t _stride)
{
uint32_t offset = bx::strideAlign(m_vboffset, _stride);
uint32_t vboffset = offset + _num * _stride;
2018-04-19 02:35:57 +03:00
vboffset = bx::min<uint32_t>(vboffset, g_caps.limits.transientVbSize);
uint32_t num = (vboffset-offset)/_stride;
return num;
}
uint32_t allocTransientVertexBuffer(uint32_t& _num, uint16_t _stride)
{
uint32_t offset = bx::strideAlign(m_vboffset, _stride);
uint32_t num = getAvailTransientVertexBuffer(_num, _stride);
m_vboffset = offset + num * _stride;
_num = num;
return offset;
}
bool free(IndexBufferHandle _handle)
{
return m_freeIndexBuffer.queue(_handle);
}
2019-08-13 12:04:51 +03:00
bool free(VertexLayoutHandle _handle)
{
2019-08-17 20:35:21 +03:00
return m_freeVertexLayout.queue(_handle);
}
bool free(VertexBufferHandle _handle)
{
return m_freeVertexBuffer.queue(_handle);
}
bool free(ShaderHandle _handle)
{
return m_freeShader.queue(_handle);
}
bool free(ProgramHandle _handle)
{
return m_freeProgram.queue(_handle);
}
bool free(TextureHandle _handle)
{
return m_freeTexture.queue(_handle);
}
bool free(FrameBufferHandle _handle)
{
return m_freeFrameBuffer.queue(_handle);
}
bool free(UniformHandle _handle)
{
return m_freeUniform.queue(_handle);
}
void resetFreeHandles()
{
m_freeIndexBuffer.reset();
2019-08-17 20:35:21 +03:00
m_freeVertexLayout.reset();
m_freeVertexBuffer.reset();
m_freeShader.reset();
m_freeProgram.reset();
m_freeTexture.reset();
m_freeFrameBuffer.reset();
m_freeUniform.reset();
}
2017-11-28 02:57:31 +03:00
ViewId m_viewRemap[BGFX_CONFIG_MAX_VIEWS];
float m_colorPalette[BGFX_CONFIG_MAX_COLOR_PALETTE][4];
View m_view[BGFX_CONFIG_MAX_VIEWS];
int32_t m_occlusion[BGFX_CONFIG_MAX_OCCLUSION_QUERIES];
uint64_t m_sortKeys[BGFX_CONFIG_MAX_DRAW_CALLS+1];
RenderItemCount m_sortValues[BGFX_CONFIG_MAX_DRAW_CALLS+1];
RenderItem m_renderItem[BGFX_CONFIG_MAX_DRAW_CALLS+1];
RenderBind m_renderItemBind[BGFX_CONFIG_MAX_DRAW_CALLS + 1];
uint32_t m_blitKeys[BGFX_CONFIG_MAX_BLIT_ITEMS+1];
BlitItem m_blitItem[BGFX_CONFIG_MAX_BLIT_ITEMS+1];
FrameCache m_frameCache;
UniformBuffer** m_uniformBuffer;
2017-10-29 04:43:21 +03:00
uint32_t m_numRenderItems;
uint16_t m_numBlitItems;
uint32_t m_iboffset;
uint32_t m_vboffset;
TransientIndexBuffer* m_transientIb;
TransientVertexBuffer* m_transientVb;
Resolution m_resolution;
uint32_t m_debug;
ScreenShot m_screenShot[BGFX_CONFIG_MAX_SCREENSHOTS];
uint8_t m_numScreenShots;
CommandBuffer m_cmdPre;
CommandBuffer m_cmdPost;
template<typename Ty, uint32_t Max>
struct FreeHandle
{
FreeHandle()
: m_num(0)
{
}
bool isQueued(Ty _handle)
{
for (uint32_t ii = 0, num = m_num; ii < num; ++ii)
{
if (m_queue[ii].idx == _handle.idx)
{
return true;
}
}
return false;
}
bool queue(Ty _handle)
{
if (BX_ENABLED(BGFX_CONFIG_DEBUG) )
{
if (isQueued(_handle) )
{
return false;
}
}
m_queue[m_num] = _handle;
++m_num;
return true;
}
void reset()
{
m_num = 0;
}
Ty get(uint16_t _idx) const
{
return m_queue[_idx];
}
uint16_t getNumQueued() const
{
return m_num;
}
Ty m_queue[Max];
uint16_t m_num;
};
FreeHandle<IndexBufferHandle, BGFX_CONFIG_MAX_INDEX_BUFFERS> m_freeIndexBuffer;
2019-08-17 21:52:19 +03:00
FreeHandle<VertexLayoutHandle, BGFX_CONFIG_MAX_VERTEX_LAYOUTS> m_freeVertexLayout;
FreeHandle<VertexBufferHandle, BGFX_CONFIG_MAX_VERTEX_BUFFERS> m_freeVertexBuffer;
FreeHandle<ShaderHandle, BGFX_CONFIG_MAX_SHADERS> m_freeShader;
FreeHandle<ProgramHandle, BGFX_CONFIG_MAX_PROGRAMS> m_freeProgram;
FreeHandle<TextureHandle, BGFX_CONFIG_MAX_TEXTURES> m_freeTexture;
FreeHandle<FrameBufferHandle, BGFX_CONFIG_MAX_FRAME_BUFFERS> m_freeFrameBuffer;
FreeHandle<UniformHandle, BGFX_CONFIG_MAX_UNIFORMS> m_freeUniform;
TextVideoMem* m_textVideoMem;
2017-11-03 08:06:39 +03:00
Stats m_perfStats;
ViewStats m_viewStats[BGFX_CONFIG_MAX_VIEWS];
int64_t m_waitSubmit;
int64_t m_waitRender;
uint32_t m_frameNum;
bool m_capture;
};
BX_ALIGN_DECL_CACHE_LINE(struct) EncoderImpl
{
EncoderImpl()
{
2020-04-03 05:04:13 +03:00
discard(BGFX_DISCARD_ALL);
}
2017-11-28 00:11:57 +03:00
void begin(Frame* _frame, uint8_t _idx)
2017-10-29 04:43:21 +03:00
{
m_frame = _frame;
2017-11-02 08:34:11 +03:00
2017-11-03 08:06:39 +03:00
m_cpuTimeBegin = bx::getHPCounter();
2017-11-10 08:07:55 +03:00
m_uniformIdx = _idx;
2017-11-02 08:34:11 +03:00
m_uniformBegin = 0;
m_uniformEnd = 0;
2017-11-04 09:48:40 +03:00
UniformBuffer* uniformBuffer = m_frame->m_uniformBuffer[m_uniformIdx];
uniformBuffer->reset();
2017-11-02 08:34:11 +03:00
m_numSubmitted = 0;
m_numDropped = 0;
2017-10-29 04:43:21 +03:00
}
2017-11-11 07:30:16 +03:00
void end(bool _finalize)
{
2017-11-11 07:30:16 +03:00
if (_finalize)
{
UniformBuffer* uniformBuffer = m_frame->m_uniformBuffer[m_uniformIdx];
uniformBuffer->finish();
2017-11-02 08:34:11 +03:00
2017-11-11 07:30:16 +03:00
m_cpuTimeEnd = bx::getHPCounter();
}
2017-11-03 08:06:39 +03:00
if (BX_ENABLED(BGFX_CONFIG_DEBUG_OCCLUSION) )
{
m_occlusionQuerySet.clear();
}
if (BX_ENABLED(BGFX_CONFIG_DEBUG_UNIFORM) )
{
m_uniformSet.clear();
}
}
2017-10-29 04:43:21 +03:00
void setMarker(const char* _name)
{
UniformBuffer::update(&m_frame->m_uniformBuffer[m_uniformIdx]);
2017-11-04 09:48:40 +03:00
UniformBuffer* uniformBuffer = m_frame->m_uniformBuffer[m_uniformIdx];
uniformBuffer->writeMarker(_name);
}
2017-10-29 04:43:21 +03:00
void setUniform(UniformType::Enum _type, UniformHandle _handle, const void* _value, uint16_t _num)
{
if (BX_ENABLED(BGFX_CONFIG_DEBUG_UNIFORM) )
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(m_uniformSet.end() == m_uniformSet.find(_handle.idx)
, "Uniform %d (%s) was already set for this draw call."
, _handle.idx
, getName(_handle)
);
m_uniformSet.insert(_handle.idx);
}
2017-11-04 09:48:40 +03:00
UniformBuffer::update(&m_frame->m_uniformBuffer[m_uniformIdx]);
UniformBuffer* uniformBuffer = m_frame->m_uniformBuffer[m_uniformIdx];
uniformBuffer->writeUniform(_type, _handle.idx, _value, _num);
}
void setState(uint64_t _state, uint32_t _rgba)
2012-08-06 01:51:49 +04:00
{
const uint8_t blend = ( (_state&BGFX_STATE_BLEND_MASK )>>BGFX_STATE_BLEND_SHIFT )&0xff;
const uint8_t alphaRef = ( (_state&BGFX_STATE_ALPHA_REF_MASK)>>BGFX_STATE_ALPHA_REF_SHIFT)&0xff;
// Transparency sort order table:
//
// +----------------------------------------- BGFX_STATE_BLEND_ZERO
// | +-------------------------------------- BGFX_STATE_BLEND_ONE
// | | +----------------------------------- BGFX_STATE_BLEND_SRC_COLOR
// | | | +-------------------------------- BGFX_STATE_BLEND_INV_SRC_COLOR
// | | | | +----------------------------- BGFX_STATE_BLEND_SRC_ALPHA
// | | | | | +-------------------------- BGFX_STATE_BLEND_INV_SRC_ALPHA
// | | | | | | +----------------------- BGFX_STATE_BLEND_DST_ALPHA
// | | | | | | | +-------------------- BGFX_STATE_BLEND_INV_DST_ALPHA
// | | | | | | | | +----------------- BGFX_STATE_BLEND_DST_COLOR
// | | | | | | | | | +-------------- BGFX_STATE_BLEND_INV_DST_COLOR
// | | | | | | | | | | +----------- BGFX_STATE_BLEND_SRC_ALPHA_SAT
// | | | | | | | | | | | +-------- BGFX_STATE_BLEND_FACTOR
// | | | | | | | | | | | | +----- BGFX_STATE_BLEND_INV_FACTOR
// | | | | | | | | | | | | |
// x | | | | | | | | | | | | | x x x x x
2020-05-16 07:58:43 +03:00
m_key.m_blend = "\x0\x2\x2\x3\x3\x2\x3\x2\x3\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2"[( (blend)&0xf) + (!!blend)] + !!alphaRef;
2015-11-02 04:28:23 +03:00
m_draw.m_stateFlags = _state;
m_draw.m_rgba = _rgba;
2012-08-06 01:51:49 +04:00
}
2015-11-02 04:28:23 +03:00
void setCondition(OcclusionQueryHandle _handle, bool _visible)
{
m_draw.m_occlusionQuery = _handle;
2015-11-03 00:13:57 +03:00
m_draw.m_submitFlags |= _visible ? BGFX_SUBMIT_INTERNAL_OCCLUSION_VISIBLE : 0;
2015-11-02 04:28:23 +03:00
}
2012-11-11 07:59:23 +04:00
void setStencil(uint32_t _fstencil, uint32_t _bstencil)
{
2014-07-21 07:27:13 +04:00
m_draw.m_stencil = packStencil(_fstencil, _bstencil);
2012-11-11 07:59:23 +04:00
}
2017-10-29 04:43:21 +03:00
uint16_t setScissor(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height)
2013-07-15 01:32:09 +04:00
{
2017-10-29 04:43:21 +03:00
uint16_t scissor = (uint16_t)m_frame->m_frameCache.m_rectCache.add(_x, _y, _width, _height);
2014-07-21 07:27:13 +04:00
m_draw.m_scissor = scissor;
return scissor;
2013-07-15 01:32:09 +04:00
}
void setScissor(uint16_t _cache)
{
2014-07-21 07:27:13 +04:00
m_draw.m_scissor = _cache;
2013-07-15 01:32:09 +04:00
}
2017-10-29 04:43:21 +03:00
uint32_t setTransform(const void* _mtx, uint16_t _num)
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
m_draw.m_startMatrix = m_frame->m_frameCache.m_matrixCache.add(_mtx, _num);
2017-10-10 07:17:58 +03:00
m_draw.m_numMatrices = _num;
2012-08-06 01:51:49 +04:00
2017-10-10 07:17:58 +03:00
return m_draw.m_startMatrix;
2012-08-06 01:51:49 +04:00
}
2017-10-29 04:43:21 +03:00
uint32_t allocTransform(Transform* _transform, uint16_t _num)
{
2017-10-29 04:43:21 +03:00
uint32_t first = m_frame->m_frameCache.m_matrixCache.reserve(&_num);
_transform->data = m_frame->m_frameCache.m_matrixCache.toPtr(first);
_transform->num = _num;
2014-10-11 21:12:27 +04:00
return first;
}
2014-10-11 21:12:27 +04:00
void setTransform(uint32_t _cache, uint16_t _num)
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(_cache < BGFX_CONFIG_MAX_MATRIX_CACHE, "Matrix cache out of bounds index %d (max: %d)"
, _cache
, BGFX_CONFIG_MAX_MATRIX_CACHE
);
2017-10-10 07:17:58 +03:00
m_draw.m_startMatrix = _cache;
2018-02-11 02:49:30 +03:00
m_draw.m_numMatrices = uint16_t(bx::min<uint32_t>(_cache+_num, BGFX_CONFIG_MAX_MATRIX_CACHE-1) - _cache);
2012-08-06 01:51:49 +04:00
}
void setIndexBuffer(IndexBufferHandle _handle, const IndexBuffer& _ib, uint32_t _firstIndex, uint32_t _numIndices)
2012-08-06 01:51:49 +04:00
{
2020-11-02 08:28:42 +03:00
BX_ASSERT(UINT8_MAX != m_draw.m_streamMask, "bgfx::setVertexCount was already called for this draw call.");
m_draw.m_startIndex = _firstIndex;
m_draw.m_numIndices = _numIndices;
2014-07-21 07:27:13 +04:00
m_draw.m_indexBuffer = _handle;
m_draw.m_submitFlags |= 0 == (_ib.m_flags & BGFX_BUFFER_INDEX32) ? BGFX_SUBMIT_INTERNAL_NONE : BGFX_SUBMIT_INTERNAL_INDEX32;
2012-08-06 01:51:49 +04:00
}
2015-01-24 09:18:07 +03:00
void setIndexBuffer(const DynamicIndexBuffer& _dib, uint32_t _firstIndex, uint32_t _numIndices)
{
2020-11-02 08:28:42 +03:00
BX_ASSERT(UINT8_MAX != m_draw.m_streamMask, "bgfx::setVertexCount was already called for this draw call.");
2015-04-09 05:59:48 +03:00
const uint32_t indexSize = 0 == (_dib.m_flags & BGFX_BUFFER_INDEX32) ? 2 : 4;
2015-01-24 09:18:07 +03:00
m_draw.m_startIndex = _dib.m_startIndex + _firstIndex;
2018-02-11 02:49:30 +03:00
m_draw.m_numIndices = bx::min(_numIndices, _dib.m_size/indexSize);
2015-01-24 09:18:07 +03:00
m_draw.m_indexBuffer = _dib.m_handle;
m_draw.m_submitFlags |= 0 == (_dib.m_flags & BGFX_BUFFER_INDEX32) ? BGFX_SUBMIT_INTERNAL_NONE : BGFX_SUBMIT_INTERNAL_INDEX32;
2015-01-24 09:18:07 +03:00
}
2014-04-27 10:48:41 +04:00
void setIndexBuffer(const TransientIndexBuffer* _tib, uint32_t _firstIndex, uint32_t _numIndices)
2012-08-06 01:51:49 +04:00
{
2020-11-02 08:28:42 +03:00
BX_ASSERT(UINT8_MAX != m_draw.m_streamMask, "bgfx::setVertexCount was already called for this draw call.");
const uint32_t indexSize = _tib->isIndex16 ? 2 : 4;
const uint32_t numIndices = bx::min(_numIndices, _tib->size/indexSize);
2014-07-21 07:27:13 +04:00
m_draw.m_indexBuffer = _tib->handle;
2017-10-10 06:10:03 +03:00
m_draw.m_startIndex = _tib->startIndex + _firstIndex;
m_draw.m_numIndices = numIndices;
m_draw.m_submitFlags |= _tib->isIndex16 ? BGFX_SUBMIT_INTERNAL_NONE : BGFX_SUBMIT_INTERNAL_INDEX32;
m_discard = 0 == numIndices;
2012-08-06 01:51:49 +04:00
}
void setVertexBuffer(
uint8_t _stream
, VertexBufferHandle _handle
, uint32_t _startVertex
, uint32_t _numVertices
2019-08-17 20:35:21 +03:00
, VertexLayoutHandle _layoutHandle
)
2012-08-06 01:51:49 +04:00
{
2020-11-02 08:28:42 +03:00
BX_ASSERT(UINT8_MAX != m_draw.m_streamMask, "bgfx::setVertexCount was already called for this draw call.");
2020-06-16 20:06:18 +03:00
BX_ASSERT(_stream < BGFX_CONFIG_MAX_VERTEX_STREAMS, "Invalid stream %d (max %d).", _stream, BGFX_CONFIG_MAX_VERTEX_STREAMS);
2016-09-16 06:54:00 +03:00
if (m_draw.setStreamBit(_stream, _handle) )
{
Stream& stream = m_draw.m_stream[_stream];
stream.m_startVertex = _startVertex;
stream.m_handle = _handle;
2019-08-17 20:35:21 +03:00
stream.m_layoutHandle = _layoutHandle;
2016-09-16 06:54:00 +03:00
m_numVertices[_stream] = _numVertices;
}
2012-08-06 01:51:49 +04:00
}
void setVertexBuffer(
uint8_t _stream
, const DynamicVertexBuffer& _dvb
, uint32_t _startVertex
, uint32_t _numVertices
2019-08-17 20:35:21 +03:00
, VertexLayoutHandle _layoutHandle
)
2012-08-06 01:51:49 +04:00
{
2020-11-02 08:28:42 +03:00
BX_ASSERT(UINT8_MAX != m_draw.m_streamMask, "bgfx::setVertexCount was already called for this draw call.");
2020-06-16 20:06:18 +03:00
BX_ASSERT(_stream < BGFX_CONFIG_MAX_VERTEX_STREAMS, "Invalid stream %d (max %d).", _stream, BGFX_CONFIG_MAX_VERTEX_STREAMS);
2016-09-16 06:54:00 +03:00
if (m_draw.setStreamBit(_stream, _dvb.m_handle) )
{
Stream& stream = m_draw.m_stream[_stream];
stream.m_startVertex = _dvb.m_startVertex + _startVertex;
stream.m_handle = _dvb.m_handle;
2019-08-17 20:35:21 +03:00
stream.m_layoutHandle = isValid(_layoutHandle) ? _layoutHandle : _dvb.m_layoutHandle;
2016-09-16 06:54:00 +03:00
m_numVertices[_stream] =
2018-02-11 02:49:30 +03:00
bx::min(bx::uint32_imax(0, _dvb.m_numVertices - _startVertex), _numVertices)
2016-09-16 06:54:00 +03:00
;
}
2012-08-06 01:51:49 +04:00
}
void setVertexBuffer(
uint8_t _stream
, const TransientVertexBuffer* _tvb
, uint32_t _startVertex
, uint32_t _numVertices
2019-08-17 20:35:21 +03:00
, VertexLayoutHandle _layoutHandle
)
2012-08-06 01:51:49 +04:00
{
2020-11-02 08:28:42 +03:00
BX_ASSERT(UINT8_MAX != m_draw.m_streamMask, "bgfx::setVertexCount was already called for this draw call.");
2020-06-16 20:06:18 +03:00
BX_ASSERT(_stream < BGFX_CONFIG_MAX_VERTEX_STREAMS, "Invalid stream %d (max %d).", _stream, BGFX_CONFIG_MAX_VERTEX_STREAMS);
2016-09-16 06:54:00 +03:00
if (m_draw.setStreamBit(_stream, _tvb->handle) )
{
Stream& stream = m_draw.m_stream[_stream];
2017-10-10 07:41:59 +03:00
stream.m_startVertex = _tvb->startVertex + _startVertex;
stream.m_handle = _tvb->handle;
2019-08-17 20:35:21 +03:00
stream.m_layoutHandle = isValid(_layoutHandle) ? _layoutHandle : _tvb->layoutHandle;
m_numVertices[_stream] = bx::min(bx::uint32_imax(0, _tvb->size/_tvb->stride - _startVertex), _numVertices);
2016-09-16 06:54:00 +03:00
}
2012-08-06 01:51:49 +04:00
}
void setVertexCount(uint32_t _numVertices)
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(0 == m_draw.m_streamMask, "Vertex buffer already set.");
m_draw.m_streamMask = UINT8_MAX;
Stream& stream = m_draw.m_stream[0];
2019-08-17 20:35:21 +03:00
stream.m_startVertex = 0;
stream.m_handle.idx = kInvalidHandle;
stream.m_layoutHandle.idx = kInvalidHandle;
m_numVertices[0] = _numVertices;
}
void setInstanceDataBuffer(const InstanceDataBuffer* _idb, uint32_t _start, uint32_t _num)
2012-08-06 01:51:49 +04:00
{
const uint32_t start = bx::min(_start, _idb->num);
const uint32_t num = bx::min(_idb->num - start, _num);
m_draw.m_instanceDataOffset = _idb->offset + start*_idb->stride;
2014-07-21 07:27:13 +04:00
m_draw.m_instanceDataStride = _idb->stride;
m_draw.m_numInstances = num;
2014-07-21 07:27:13 +04:00
m_draw.m_instanceDataBuffer = _idb->handle;
2012-08-06 01:51:49 +04:00
}
2014-12-10 10:16:27 +03:00
void setInstanceDataBuffer(VertexBufferHandle _handle, uint32_t _startVertex, uint32_t _num, uint16_t _stride)
{
m_draw.m_instanceDataOffset = _startVertex * _stride;
m_draw.m_instanceDataStride = _stride;
2016-03-02 04:56:04 +03:00
m_draw.m_numInstances = _num;
2014-12-10 10:16:27 +03:00
m_draw.m_instanceDataBuffer = _handle;
}
2018-09-15 07:23:28 +03:00
void setInstanceCount(uint32_t _numInstances)
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(!isValid(m_draw.m_instanceDataBuffer), "Instance buffer already set.");
2018-09-15 07:23:28 +03:00
m_draw.m_numInstances = _numInstances;
}
2017-10-29 04:43:21 +03:00
void setTexture(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle, uint32_t _flags)
2012-08-06 01:51:49 +04:00
{
2017-04-07 06:32:48 +03:00
Binding& bind = m_bind.m_bind[_stage];
2015-08-29 06:34:14 +03:00
bind.m_idx = _handle.idx;
2015-08-30 18:52:53 +03:00
bind.m_type = uint8_t(Binding::Texture);
bind.m_samplerFlags = (_flags&BGFX_SAMPLER_INTERNAL_DEFAULT)
? BGFX_SAMPLER_INTERNAL_DEFAULT
2015-03-26 09:33:35 +03:00
: _flags
;
2012-08-06 01:51:49 +04:00
2015-08-29 00:48:51 +03:00
if (isValid(_sampler) )
2012-08-06 01:51:49 +04:00
{
uint32_t stage = _stage;
setUniform(UniformType::Sampler, _sampler, &stage, 1);
2012-08-06 01:51:49 +04:00
}
}
void setBuffer(uint8_t _stage, IndexBufferHandle _handle, Access::Enum _access)
2014-12-10 10:16:27 +03:00
{
2017-04-07 06:32:48 +03:00
Binding& bind = m_bind.m_bind[_stage];
2014-12-10 10:16:27 +03:00
bind.m_idx = _handle.idx;
2015-01-14 09:34:48 +03:00
bind.m_type = uint8_t(Binding::IndexBuffer);
bind.m_format = 0;
bind.m_access = uint8_t(_access);
bind.m_mip = 0;
}
void setBuffer(uint8_t _stage, VertexBufferHandle _handle, Access::Enum _access)
{
2017-04-07 06:32:48 +03:00
Binding& bind = m_bind.m_bind[_stage];
2015-01-14 09:34:48 +03:00
bind.m_idx = _handle.idx;
bind.m_type = uint8_t(Binding::VertexBuffer);
bind.m_format = 0;
bind.m_access = uint8_t(_access);
bind.m_mip = 0;
2014-12-10 10:16:27 +03:00
}
2018-01-20 04:06:58 +03:00
void setImage(uint8_t _stage, TextureHandle _handle, uint8_t _mip, Access::Enum _access, TextureFormat::Enum _format)
2014-07-21 07:27:13 +04:00
{
2017-04-07 06:32:48 +03:00
Binding& bind = m_bind.m_bind[_stage];
2015-01-14 09:34:48 +03:00
bind.m_idx = _handle.idx;
bind.m_type = uint8_t(Binding::Image);
bind.m_format = uint8_t(_format);
bind.m_access = uint8_t(_access);
bind.m_mip = _mip;
2014-07-21 07:27:13 +04:00
}
2020-04-03 05:04:13 +03:00
void discard(uint8_t _flags)
2013-07-30 06:01:29 +04:00
{
if (BX_ENABLED(BGFX_CONFIG_DEBUG_UNIFORM) )
{
m_uniformSet.clear();
}
2013-07-30 06:01:29 +04:00
m_discard = false;
2020-01-22 07:08:48 +03:00
m_draw.clear(_flags);
m_compute.clear(_flags);
m_bind.clear(_flags);
2013-07-30 06:01:29 +04:00
}
2020-04-03 05:04:13 +03:00
void submit(ViewId _id, ProgramHandle _program, OcclusionQueryHandle _occlusionQuery, uint32_t _depth, uint8_t _flags);
2015-05-02 00:54:23 +03:00
2020-04-03 05:04:13 +03:00
void submit(ViewId _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, uint16_t _start, uint16_t _num, uint32_t _depth, uint8_t _flags)
2015-05-02 00:54:23 +03:00
{
m_draw.m_startIndirect = _start;
m_draw.m_numIndirect = _num;
m_draw.m_indirectBuffer = _indirectHandle;
2015-11-02 04:28:23 +03:00
OcclusionQueryHandle handle = BGFX_INVALID_HANDLE;
2020-03-13 13:22:33 +03:00
submit(_id, _program, handle, _depth, _flags);
2015-05-02 00:54:23 +03:00
}
void submit(ViewId _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, uint16_t _start, IndexBufferHandle _numHandle, uint32_t _numIndex, uint16_t _numMax, uint32_t _depth, uint8_t _flags)
{
m_draw.m_numIndirectIndex = _numIndex;
m_draw.m_numIndirectBuffer = _numHandle;
submit(_id, _program, _indirectHandle, _start, _numMax, _depth, _flags);
}
2020-04-03 05:04:13 +03:00
void dispatch(ViewId _id, ProgramHandle _handle, uint32_t _ngx, uint32_t _ngy, uint32_t _ngz, uint8_t _flags);
2015-05-02 00:54:23 +03:00
2020-04-03 05:04:13 +03:00
void dispatch(ViewId _id, ProgramHandle _handle, IndirectBufferHandle _indirectHandle, uint16_t _start, uint16_t _num, uint8_t _flags)
2015-05-02 00:54:23 +03:00
{
m_compute.m_indirectBuffer = _indirectHandle;
m_compute.m_startIndirect = _start;
m_compute.m_numIndirect = _num;
2020-04-03 05:04:13 +03:00
dispatch(_id, _handle, 0, 0, 0, _flags);
2015-05-02 00:54:23 +03:00
}
void blit(ViewId _id, TextureHandle _dst, uint8_t _dstMip, uint16_t _dstX, uint16_t _dstY, uint16_t _dstZ, TextureHandle _src, uint8_t _srcMip, uint16_t _srcX, uint16_t _srcY, uint16_t _srcZ, uint16_t _width, uint16_t _height, uint16_t _depth);
2017-10-29 04:43:21 +03:00
Frame* m_frame;
2012-08-06 01:51:49 +04:00
SortKey m_key;
2017-04-07 06:32:48 +03:00
RenderDraw m_draw;
2014-07-21 07:27:13 +04:00
RenderCompute m_compute;
2017-04-07 06:32:48 +03:00
RenderBind m_bind;
2017-11-02 08:34:11 +03:00
uint32_t m_numSubmitted;
uint32_t m_numDropped;
uint32_t m_uniformBegin;
uint32_t m_uniformEnd;
uint32_t m_numVertices[BGFX_CONFIG_MAX_VERTEX_STREAMS];
2017-11-02 08:34:11 +03:00
uint8_t m_uniformIdx;
bool m_discard;
typedef stl::unordered_set<uint16_t> HandleSet;
HandleSet m_uniformSet;
HandleSet m_occlusionQuerySet;
2017-11-02 08:34:11 +03:00
2017-11-03 08:06:39 +03:00
int64_t m_cpuTimeBegin;
int64_t m_cpuTimeEnd;
2012-08-06 01:51:49 +04:00
};
2019-08-13 12:04:51 +03:00
struct VertexLayoutRef
2012-08-06 01:51:49 +04:00
{
2019-08-13 12:04:51 +03:00
VertexLayoutRef()
{
}
void init()
2012-08-06 01:51:49 +04:00
{
2020-10-30 21:37:05 +03:00
bx::memSet(m_refCount, 0, sizeof(m_refCount) );
2017-05-18 18:55:52 +03:00
bx::memSet(m_vertexBufferRef, 0xff, sizeof(m_vertexBufferRef) );
bx::memSet(m_dynamicVertexBufferRef, 0xff, sizeof(m_dynamicVertexBufferRef) );
2012-08-06 01:51:49 +04:00
}
2013-09-21 09:13:58 +04:00
template <uint16_t MaxHandlesT>
void shutdown(bx::HandleAllocT<MaxHandlesT>& _handleAlloc)
{
2017-03-30 07:53:09 +03:00
for (uint16_t ii = 0, num = _handleAlloc.getNumHandles(); ii < num; ++ii)
{
2019-08-13 12:04:51 +03:00
VertexLayoutHandle handle = { _handleAlloc.getHandleAt(ii) };
2020-10-30 21:37:05 +03:00
m_refCount[handle.idx] = 0;
2020-04-25 19:50:52 +03:00
m_vertexLayoutMap.removeByHandle(handle.idx);
2017-03-30 07:53:09 +03:00
_handleAlloc.free(handle.idx);
}
2020-04-25 19:50:52 +03:00
m_vertexLayoutMap.reset();
}
2019-08-13 12:04:51 +03:00
VertexLayoutHandle find(uint32_t _hash)
2012-08-06 01:51:49 +04:00
{
2020-04-25 19:50:52 +03:00
VertexLayoutHandle handle = { m_vertexLayoutMap.find(_hash) };
return handle;
2012-08-06 01:51:49 +04:00
}
2019-08-17 20:35:21 +03:00
void add(VertexLayoutHandle _layoutHandle, uint32_t _hash)
2017-03-30 03:54:38 +03:00
{
2020-10-30 21:37:05 +03:00
m_refCount[_layoutHandle.idx]++;
2020-04-25 19:50:52 +03:00
m_vertexLayoutMap.insert(_hash, _layoutHandle.idx);
2017-03-30 03:54:38 +03:00
}
2019-08-17 20:35:21 +03:00
void add(VertexBufferHandle _handle, VertexLayoutHandle _layoutHandle, uint32_t _hash)
2012-08-06 01:51:49 +04:00
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(m_vertexBufferRef[_handle.idx].idx == kInvalidHandle, "");
2019-08-17 20:35:21 +03:00
m_vertexBufferRef[_handle.idx] = _layoutHandle;
2020-10-30 21:37:05 +03:00
m_refCount[_layoutHandle.idx]++;
2020-04-25 19:50:52 +03:00
m_vertexLayoutMap.insert(_hash, _layoutHandle.idx);
2012-08-06 01:51:49 +04:00
}
2019-08-17 20:35:21 +03:00
void add(DynamicVertexBufferHandle _handle, VertexLayoutHandle _layoutHandle, uint32_t _hash)
2012-08-06 01:51:49 +04:00
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(m_dynamicVertexBufferRef[_handle.idx].idx == kInvalidHandle, "");
2019-08-17 20:35:21 +03:00
m_dynamicVertexBufferRef[_handle.idx] = _layoutHandle;
2020-10-30 21:37:05 +03:00
m_refCount[_layoutHandle.idx]++;
2020-04-25 19:50:52 +03:00
m_vertexLayoutMap.insert(_hash, _layoutHandle.idx);
2017-03-30 03:54:38 +03:00
}
2019-08-17 20:35:21 +03:00
VertexLayoutHandle release(VertexLayoutHandle _layoutHandle)
2017-03-30 03:54:38 +03:00
{
2019-08-17 20:35:21 +03:00
if (isValid(_layoutHandle) )
2012-08-06 01:51:49 +04:00
{
2020-10-30 21:37:05 +03:00
m_refCount[_layoutHandle.idx]--;
2020-10-30 21:37:05 +03:00
if (0 == m_refCount[_layoutHandle.idx])
{
2020-04-25 19:50:52 +03:00
m_vertexLayoutMap.removeByHandle(_layoutHandle.idx);
2019-08-17 20:35:21 +03:00
return _layoutHandle;
}
2012-08-06 01:51:49 +04:00
}
2018-02-17 05:26:53 +03:00
return BGFX_INVALID_HANDLE;
2017-03-30 03:54:38 +03:00
}
2019-08-13 12:04:51 +03:00
VertexLayoutHandle release(VertexBufferHandle _handle)
2017-03-30 03:54:38 +03:00
{
2019-08-17 20:35:21 +03:00
VertexLayoutHandle layoutHandle = m_vertexBufferRef[_handle.idx];
layoutHandle = release(layoutHandle);
2017-06-10 07:57:08 +03:00
m_vertexBufferRef[_handle.idx].idx = kInvalidHandle;
2017-03-30 03:54:38 +03:00
2019-08-17 20:35:21 +03:00
return layoutHandle;
2017-03-30 03:54:38 +03:00
}
2019-08-13 12:04:51 +03:00
VertexLayoutHandle release(DynamicVertexBufferHandle _handle)
2017-03-30 03:54:38 +03:00
{
2019-08-17 20:35:21 +03:00
VertexLayoutHandle layoutHandle = m_dynamicVertexBufferRef[_handle.idx];
layoutHandle = release(layoutHandle);
2017-06-10 07:57:08 +03:00
m_dynamicVertexBufferRef[_handle.idx].idx = kInvalidHandle;
2016-03-16 01:34:44 +03:00
2019-08-17 20:35:21 +03:00
return layoutHandle;
2012-08-06 01:51:49 +04:00
}
2019-08-17 20:35:21 +03:00
typedef bx::HandleHashMapT<BGFX_CONFIG_MAX_VERTEX_LAYOUTS*2> VertexLayoutMap;
2020-04-25 19:50:52 +03:00
VertexLayoutMap m_vertexLayoutMap;
2020-10-30 21:37:05 +03:00
uint16_t m_refCount[BGFX_CONFIG_MAX_VERTEX_LAYOUTS];
2019-08-13 12:04:51 +03:00
VertexLayoutHandle m_vertexBufferRef[BGFX_CONFIG_MAX_VERTEX_BUFFERS];
VertexLayoutHandle m_dynamicVertexBufferRef[BGFX_CONFIG_MAX_DYNAMIC_VERTEX_BUFFERS];
2012-08-06 01:51:49 +04:00
};
// First-fit non-local allocator.
class NonLocalAllocator
{
public:
2017-06-10 07:57:08 +03:00
static const uint64_t kInvalidBlock = UINT64_MAX;
2012-08-06 01:51:49 +04:00
NonLocalAllocator()
{
}
~NonLocalAllocator()
{
}
void reset()
{
m_free.clear();
m_used.clear();
}
void add(uint64_t _ptr, uint32_t _size)
{
m_free.push_back(Free(_ptr, _size) );
}
uint64_t remove()
{
2020-06-16 20:06:18 +03:00
BX_ASSERT(0 == m_used.size(), "");
if (0 < m_free.size() )
{
2015-04-05 05:10:35 +03:00
Free freeBlock = m_free.front();
m_free.pop_front();
2015-04-05 05:10:35 +03:00
return freeBlock.m_ptr;
}
return 0;
}
2012-08-06 01:51:49 +04:00
uint64_t alloc(uint32_t _size)
{
_size = bx::max(_size, 16u);
2012-08-06 01:51:49 +04:00
for (FreeList::iterator it = m_free.begin(), itEnd = m_free.end(); it != itEnd; ++it)
{
if (it->m_size >= _size)
{
uint64_t ptr = it->m_ptr;
m_used.insert(stl::make_pair(ptr, _size) );
if (it->m_size != _size)
{
it->m_size -= _size;
2014-12-10 10:16:27 +03:00
it->m_ptr += _size;
2012-08-06 01:51:49 +04:00
}
else
{
m_free.erase(it);
}
return ptr;
}
}
// there is no block large enough.
2017-06-10 07:57:08 +03:00
return kInvalidBlock;
2012-08-06 01:51:49 +04:00
}
void free(uint64_t _block)
{
UsedList::iterator it = m_used.find(_block);
if (it != m_used.end() )
{
m_free.push_front(Free(it->first, it->second) );
m_used.erase(it);
}
}
bool compact()
2012-08-06 01:51:49 +04:00
{
m_free.sort();
for (FreeList::iterator it = m_free.begin(), next = it, itEnd = m_free.end(); next != itEnd;)
{
if ( (it->m_ptr + it->m_size) == next->m_ptr)
{
it->m_size += next->m_size;
next = m_free.erase(next);
}
else
{
it = next;
++next;
}
}
return 0 == m_used.size();
2012-08-06 01:51:49 +04:00
}
private:
struct Free
{
Free(uint64_t _ptr, uint32_t _size)
: m_ptr(_ptr)
, m_size(_size)
{
}
bool operator<(const Free& rhs) const
{
return m_ptr < rhs.m_ptr;
}
uint64_t m_ptr;
uint32_t m_size;
};
2018-03-20 08:17:24 +03:00
typedef stl::list<Free> FreeList;
2012-08-06 01:51:49 +04:00
FreeList m_free;
typedef stl::unordered_map<uint64_t, uint32_t> UsedList;
UsedList m_used;
};
struct BX_NO_VTABLE RendererContextI
{
virtual ~RendererContextI() = 0;
virtual RendererType::Enum getRendererType() const = 0;
virtual const char* getRendererName() const = 0;
virtual bool isDeviceRemoved() = 0;
2018-07-20 06:22:21 +03:00
virtual void flip() = 0;
2018-03-13 04:56:27 +03:00
virtual void createIndexBuffer(IndexBufferHandle _handle, const Memory* _mem, uint16_t _flags) = 0;
virtual void destroyIndexBuffer(IndexBufferHandle _handle) = 0;
2019-08-17 20:35:21 +03:00
virtual void createVertexLayout(VertexLayoutHandle _handle, const VertexLayout& _layout) = 0;
2019-08-13 12:04:51 +03:00
virtual void destroyVertexLayout(VertexLayoutHandle _handle) = 0;
2019-08-17 20:35:21 +03:00
virtual void createVertexBuffer(VertexBufferHandle _handle, const Memory* _mem, VertexLayoutHandle _layoutHandle, uint16_t _flags) = 0;
virtual void destroyVertexBuffer(VertexBufferHandle _handle) = 0;
2015-05-14 21:37:32 +03:00
virtual void createDynamicIndexBuffer(IndexBufferHandle _handle, uint32_t _size, uint16_t _flags) = 0;
2018-03-13 04:56:27 +03:00
virtual void updateDynamicIndexBuffer(IndexBufferHandle _handle, uint32_t _offset, uint32_t _size, const Memory* _mem) = 0;
virtual void destroyDynamicIndexBuffer(IndexBufferHandle _handle) = 0;
2015-05-14 21:37:32 +03:00
virtual void createDynamicVertexBuffer(VertexBufferHandle _handle, uint32_t _size, uint16_t _flags) = 0;
2018-03-13 04:56:27 +03:00
virtual void updateDynamicVertexBuffer(VertexBufferHandle _handle, uint32_t _offset, uint32_t _size, const Memory* _mem) = 0;
virtual void destroyDynamicVertexBuffer(VertexBufferHandle _handle) = 0;
2018-03-13 04:56:27 +03:00
virtual void createShader(ShaderHandle _handle, const Memory* _mem) = 0;
virtual void destroyShader(ShaderHandle _handle) = 0;
virtual void createProgram(ProgramHandle _handle, ShaderHandle _vsh, ShaderHandle _fsh) = 0;
virtual void destroyProgram(ProgramHandle _handle) = 0;
virtual void* createTexture(TextureHandle _handle, const Memory* _mem, uint64_t _flags, uint8_t _skip) = 0;
virtual void updateTextureBegin(TextureHandle _handle, uint8_t _side, uint8_t _mip) = 0;
virtual void updateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem) = 0;
virtual void updateTextureEnd() = 0;
2016-10-21 18:22:05 +03:00
virtual void readTexture(TextureHandle _handle, void* _data, uint8_t _mip) = 0;
2018-09-19 03:25:05 +03:00
virtual void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height, uint8_t _numMips, uint16_t _numLayers) = 0;
2016-01-21 06:27:48 +03:00
virtual void overrideInternal(TextureHandle _handle, uintptr_t _ptr) = 0;
virtual uintptr_t getInternal(TextureHandle _handle) = 0;
virtual void destroyTexture(TextureHandle _handle) = 0;
2016-02-16 03:55:32 +03:00
virtual void createFrameBuffer(FrameBufferHandle _handle, uint8_t _num, const Attachment* _attachment) = 0;
virtual void createFrameBuffer(FrameBufferHandle _handle, void* _nwh, uint32_t _width, uint32_t _height, TextureFormat::Enum _format, TextureFormat::Enum _depthFormat) = 0;
virtual void destroyFrameBuffer(FrameBufferHandle _handle) = 0;
virtual void createUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name) = 0;
virtual void destroyUniform(UniformHandle _handle) = 0;
2017-03-03 06:29:34 +03:00
virtual void requestScreenShot(FrameBufferHandle _handle, const char* _filePath) = 0;
virtual void updateViewName(ViewId _id, const char* _name) = 0;
virtual void updateUniform(uint16_t _loc, const void* _data, uint32_t _size) = 0;
virtual void invalidateOcclusionQuery(OcclusionQueryHandle _handle) = 0;
2019-01-26 04:18:30 +03:00
virtual void setMarker(const char* _marker, uint16_t _len) = 0;
2019-01-25 07:35:09 +03:00
virtual void setName(Handle _handle, const char* _name, uint16_t _len) = 0;
virtual void submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) = 0;
virtual void blitSetup(TextVideoMemBlitter& _blitter) = 0;
virtual void blitRender(TextVideoMemBlitter& _blitter, uint32_t _numIndices) = 0;
};
inline RendererContextI::~RendererContextI()
{
}
2015-09-15 01:53:33 +03:00
void rendererUpdateUniforms(RendererContextI* _renderCtx, UniformBuffer* _uniformBuffer, uint32_t _begin, uint32_t _end);
2013-10-05 10:45:05 +04:00
#if BGFX_CONFIG_DEBUG
# define BGFX_API_FUNC(_func) BX_NO_INLINE _func
2013-10-05 10:45:05 +04:00
#else
# define BGFX_API_FUNC(_func) _func
2013-10-05 10:45:05 +04:00
#endif // BGFX_CONFIG_DEBUG
2012-08-06 01:51:49 +04:00
struct Context
{
2020-03-19 07:39:48 +03:00
static constexpr uint32_t kAlignment = 64;
2012-08-06 01:51:49 +04:00
Context()
2017-11-11 07:30:16 +03:00
: m_render(&m_frame[0])
, m_submit(&m_frame[BGFX_CONFIG_MULTITHREADED ? 1 : 0])
2013-07-13 10:28:25 +04:00
, m_numFreeDynamicIndexBufferHandles(0)
, m_numFreeDynamicVertexBufferHandles(0)
, m_numFreeOcclusionQueryHandles(0)
2015-09-18 07:17:38 +03:00
, m_colorPaletteDirty(0)
2012-08-06 01:51:49 +04:00
, m_frames(0)
, m_debug(BGFX_DEBUG_NONE)
2018-03-29 04:05:49 +03:00
, m_rtMemoryUsed(0)
, m_textureMemoryUsed(0)
, m_renderCtx(NULL)
2012-08-06 01:51:49 +04:00
, m_rendererInitialized(false)
, m_exit(false)
2015-04-15 21:49:20 +03:00
, m_flipAfterRender(false)
, m_singleThreaded(false)
2012-08-06 01:51:49 +04:00
{
}
~Context()
{
}
#if BX_CONFIG_SUPPORTS_THREADING
2017-11-05 01:18:33 +03:00
static int32_t renderThread(bx::Thread* /*_self*/, void* /*_userData*/)
{
BX_TRACE("render thread start");
2015-11-15 04:09:58 +03:00
BGFX_PROFILER_SET_CURRENT_THREAD_NAME("bgfx - Render Thread");
2015-04-07 04:22:15 +03:00
while (RenderFrame::Exiting != bgfx::renderFrame() ) {};
BX_TRACE("render thread exit");
2017-06-21 07:44:23 +03:00
return bx::kExitSuccess;
}
#endif
2012-08-06 01:51:49 +04:00
// game thread
bool init(const Init& _init);
2012-08-06 01:51:49 +04:00
void shutdown();
CommandBuffer& getCommandBuffer(CommandBuffer::Enum _cmd)
{
CommandBuffer& cmdbuf = _cmd < CommandBuffer::End ? m_submit->m_cmdPre : m_submit->m_cmdPost;
uint8_t cmd = (uint8_t)_cmd;
cmdbuf.write(cmd);
return cmdbuf;
}
BGFX_API_FUNC(void reset(uint32_t _width, uint32_t _height, uint32_t _flags, TextureFormat::Enum _format) )
2012-08-06 01:51:49 +04:00
{
2020-11-30 04:55:06 +03:00
const TextureFormat::Enum format = TextureFormat::Count != _format ? _format : m_init.resolution.format;
if (!g_platformDataChangedSinceReset
&& m_init.resolution.format == format
2020-11-30 04:55:06 +03:00
&& m_init.resolution.width == _width
&& m_init.resolution.height == _height
&& m_init.resolution.reset == _flags)
{
// Nothing changed, ignore request.
return;
}
const uint32_t maskFlags = ~(0
| (0 != (g_caps.supported & BGFX_CAPS_TRANSPARENT_BACKBUFFER) ? 0 : BGFX_RESET_TRANSPARENT_BACKBUFFER)
| (0 != (g_caps.supported & BGFX_CAPS_HDR10) ? 0 : BGFX_RESET_HDR10)
| (0 != (g_caps.supported & BGFX_CAPS_HIDPI) ? 0 : BGFX_RESET_HIDPI)
);
const uint32_t oldFlags = _flags;
_flags &= maskFlags;
#define WARN_RESET_CAPS_FLAGS(_name) \
BX_WARN( (oldFlags&(BGFX_RESET_##_name) ) == (_flags&(BGFX_RESET_##_name) ) \
, "Reset flag `BGFX_RESET_" #_name "` will be ignored, because `BGFX_CAPS_" #_name "` is not supported." \
)
WARN_RESET_CAPS_FLAGS(TRANSPARENT_BACKBUFFER);
WARN_RESET_CAPS_FLAGS(HDR10);
WARN_RESET_CAPS_FLAGS(HIDPI);
#undef WARN_RESET_CAPS_FLAGS
2022-07-19 20:36:18 +03:00
BX_UNUSED(oldFlags);
2016-12-15 10:23:05 +03:00
BX_WARN(g_caps.limits.maxTextureSize >= _width
&& g_caps.limits.maxTextureSize >= _height
2016-12-11 02:42:12 +03:00
, "Frame buffer resolution width or height can't be larger than limits.maxTextureSize %d (width %d, height %d)."
, g_caps.limits.maxTextureSize
2016-10-19 03:58:42 +03:00
, _width
, _height
);
2020-11-30 04:55:06 +03:00
m_init.resolution.format = format;
m_init.resolution.width = bx::clamp(_width, 1u, g_caps.limits.maxTextureSize);
m_init.resolution.height = bx::clamp(_height, 1u, g_caps.limits.maxTextureSize);
m_init.resolution.reset = 0
2016-05-23 03:20:27 +03:00
| _flags
| (g_platformDataChangedSinceReset ? BGFX_RESET_INTERNAL_FORCE : 0)
;
2020-11-29 21:14:37 +03:00
dump(m_init.resolution);
2016-05-23 03:20:27 +03:00
g_platformDataChangedSinceReset = false;
2012-08-06 01:51:49 +04:00
2015-04-15 21:49:20 +03:00
m_flipAfterRender = !!(_flags & BGFX_RESET_FLIP_AFTER_RENDER);
2015-04-15 06:03:05 +03:00
for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii)
{
m_view[ii].setFrameBuffer(BGFX_INVALID_HANDLE);
}
for (uint16_t ii = 0, num = m_textureHandle.getNumHandles(); ii < num; ++ii)
{
uint16_t textureIdx = m_textureHandle.getHandleAt(ii);
const TextureRef& ref = m_textureRef[textureIdx];
if (BackbufferRatio::Count != ref.m_bbRatio)
{
TextureHandle handle = { textureIdx };
2015-04-14 08:13:16 +03:00
resizeTexture(handle
, uint16_t(m_init.resolution.width)
, uint16_t(m_init.resolution.height)
, ref.m_numMips
, ref.m_numLayers
2015-04-14 08:13:16 +03:00
);
m_init.resolution.reset |= BGFX_RESET_INTERNAL_FORCE;
}
}
2012-08-06 01:51:49 +04:00
}
2013-10-05 10:45:05 +04:00
BGFX_API_FUNC(void setDebug(uint32_t _debug) )
{
m_debug = _debug;
}
BGFX_API_FUNC(void dbgTextClear(uint8_t _attr, bool _small) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
m_submit->m_textVideoMem->resize(_small, (uint16_t)m_init.resolution.width, (uint16_t)m_init.resolution.height);
2012-08-06 01:51:49 +04:00
m_submit->m_textVideoMem->clear(_attr);
}
2013-10-05 10:45:05 +04:00
BGFX_API_FUNC(void dbgTextPrintfVargs(uint16_t _x, uint16_t _y, uint8_t _attr, const char* _format, va_list _argList) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2012-08-06 01:51:49 +04:00
m_submit->m_textVideoMem->printfVargs(_x, _y, _attr, _format, _argList);
}
BGFX_API_FUNC(void dbgTextImage(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height, const void* _data, uint16_t _pitch) )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
m_submit->m_textVideoMem->image(_x, _y, _width, _height, _data, _pitch);
}
BGFX_API_FUNC(const Stats* getPerfStats() )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
Stats& stats = m_submit->m_perfStats;
const Resolution& resolution = m_submit->m_resolution;
stats.width = uint16_t(resolution.width);
stats.height = uint16_t(resolution.height);
const TextVideoMem* tvm = m_submit->m_textVideoMem;
stats.textWidth = tvm->m_width;
stats.textHeight = tvm->m_height;
2017-11-03 08:06:39 +03:00
stats.encoderStats = m_encoderStats;
2017-12-04 06:42:06 +03:00
stats.numDynamicIndexBuffers = m_dynamicIndexBufferHandle.getNumHandles();
stats.numDynamicVertexBuffers = m_dynamicVertexBufferHandle.getNumHandles();
stats.numFrameBuffers = m_frameBufferHandle.getNumHandles();
stats.numIndexBuffers = m_indexBufferHandle.getNumHandles();
stats.numOcclusionQueries = m_occlusionQueryHandle.getNumHandles();
stats.numPrograms = m_programHandle.getNumHandles();
stats.numShaders = m_shaderHandle.getNumHandles();
stats.numTextures = m_textureHandle.getNumHandles();
stats.numUniforms = m_uniformHandle.getNumHandles();
stats.numVertexBuffers = m_vertexBufferHandle.getNumHandles();
2019-08-17 20:35:21 +03:00
stats.numVertexLayouts = m_layoutHandle.getNumHandles();
2017-12-04 06:42:06 +03:00
2018-03-29 04:05:49 +03:00
stats.textureMemoryUsed = m_textureMemoryUsed;
stats.rtMemoryUsed = m_rtMemoryUsed;
return &stats;
}
2015-05-14 21:37:32 +03:00
BGFX_API_FUNC(IndexBufferHandle createIndexBuffer(const Memory* _mem, uint16_t _flags) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2012-08-06 01:51:49 +04:00
IndexBufferHandle handle = { m_indexBufferHandle.alloc() };
BX_WARN(isValid(handle), "Failed to allocate index buffer handle.");
if (isValid(handle) )
{
IndexBuffer& ib = m_indexBuffers[handle.idx];
ib.m_size = _mem->size;
ib.m_flags = _flags;
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateIndexBuffer);
cmdbuf.write(handle);
cmdbuf.write(_mem);
cmdbuf.write(_flags);
setDebugName(convert(handle) );
}
else
{
release(_mem);
}
2012-08-06 01:51:49 +04:00
return handle;
}
BGFX_API_FUNC(void setName(IndexBufferHandle _handle, const bx::StringView& _name) )
{
BGFX_MUTEX_SCOPE(m_resourceApiLock);
BGFX_CHECK_HANDLE("setName", m_indexBufferHandle, _handle);
IndexBuffer& ref = m_indexBuffers[_handle.idx];
ref.m_name.set(_name);
setName(convert(_handle), _name);
}
2013-10-05 10:45:05 +04:00
BGFX_API_FUNC(void destroyIndexBuffer(IndexBufferHandle _handle) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-03-26 09:33:35 +03:00
BGFX_CHECK_HANDLE("destroyIndexBuffer", m_indexBufferHandle, _handle);
2016-11-04 02:52:34 +03:00
bool ok = m_submit->free(_handle); BX_UNUSED(ok);
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Index buffer handle %d is already destroyed!", _handle.idx);
2015-03-26 09:33:35 +03:00
IndexBuffer& ref = m_indexBuffers[_handle.idx];
ref.m_name.clear();
2012-08-06 01:51:49 +04:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyIndexBuffer);
cmdbuf.write(_handle);
}
VertexLayoutHandle findOrCreateVertexLayout(const VertexLayout& _layout, bool _refCountOnCreation = false)
2012-08-06 01:51:49 +04:00
{
2019-08-17 20:35:21 +03:00
VertexLayoutHandle layoutHandle = m_vertexLayoutRef.find(_layout.m_hash);
2012-08-06 01:51:49 +04:00
if (isValid(layoutHandle) )
{
return layoutHandle;
}
layoutHandle = { m_layoutHandle.alloc() };
2019-08-17 20:35:21 +03:00
if (!isValid(layoutHandle) )
2012-08-06 01:51:49 +04:00
{
BX_TRACE("WARNING: Failed to allocate vertex layout handle (BGFX_CONFIG_MAX_VERTEX_LAYOUTS, max: %d).", BGFX_CONFIG_MAX_VERTEX_LAYOUTS);
return BGFX_INVALID_HANDLE;
}
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateVertexLayout);
cmdbuf.write(layoutHandle);
cmdbuf.write(_layout);
if (_refCountOnCreation)
{
m_vertexLayoutRef.add(layoutHandle, _layout.m_hash);
2012-08-06 01:51:49 +04:00
}
2019-08-17 20:35:21 +03:00
return layoutHandle;
2012-08-06 01:51:49 +04:00
}
2019-08-17 20:35:21 +03:00
BGFX_API_FUNC(VertexLayoutHandle createVertexLayout(const VertexLayout& _layout) )
{
BGFX_MUTEX_SCOPE(m_resourceApiLock);
VertexLayoutHandle handle = findOrCreateVertexLayout(_layout);
if (!isValid(handle) )
{
return BGFX_INVALID_HANDLE;
}
2019-08-17 20:35:21 +03:00
m_vertexLayoutRef.add(handle, _layout.m_hash);
return handle;
}
2019-08-13 12:04:51 +03:00
BGFX_API_FUNC(void destroyVertexLayout(VertexLayoutHandle _handle) )
{
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2020-10-30 21:37:05 +03:00
if (isValid(m_vertexLayoutRef.release(_handle) ) )
{
m_submit->free(_handle);
}
}
2019-08-17 20:35:21 +03:00
BGFX_API_FUNC(VertexBufferHandle createVertexBuffer(const Memory* _mem, const VertexLayout& _layout, uint16_t _flags) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2017-09-07 05:04:04 +03:00
VertexBufferHandle handle = { m_vertexBufferHandle.alloc() };
2012-08-06 01:51:49 +04:00
if (isValid(handle) )
{
VertexLayoutHandle layoutHandle = findOrCreateVertexLayout(_layout);
2019-08-17 20:35:21 +03:00
if (!isValid(layoutHandle) )
{
2019-08-17 20:35:21 +03:00
BX_TRACE("WARNING: Failed to allocate vertex layout handle (BGFX_CONFIG_MAX_VERTEX_LAYOUTS, max: %d).", BGFX_CONFIG_MAX_VERTEX_LAYOUTS);
m_vertexBufferHandle.free(handle.idx);
return BGFX_INVALID_HANDLE;
}
2019-08-17 20:35:21 +03:00
m_vertexLayoutRef.add(handle, layoutHandle, _layout.m_hash);
VertexBuffer& vb = m_vertexBuffers[handle.idx];
vb.m_size = _mem->size;
2019-08-17 20:35:21 +03:00
vb.m_stride = _layout.m_stride;
2014-12-10 10:16:27 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateVertexBuffer);
cmdbuf.write(handle);
cmdbuf.write(_mem);
2019-08-17 20:35:21 +03:00
cmdbuf.write(layoutHandle);
2015-05-14 21:37:32 +03:00
cmdbuf.write(_flags);
setDebugName(convert(handle) );
return handle;
}
2012-08-06 01:51:49 +04:00
BX_TRACE("WARNING: Failed to allocate vertex buffer handle (BGFX_CONFIG_MAX_VERTEX_BUFFERS, max: %d).", BGFX_CONFIG_MAX_VERTEX_BUFFERS);
release(_mem);
return BGFX_INVALID_HANDLE;
2012-08-06 01:51:49 +04:00
}
BGFX_API_FUNC(void setName(VertexBufferHandle _handle, const bx::StringView& _name) )
{
BGFX_MUTEX_SCOPE(m_resourceApiLock);
BGFX_CHECK_HANDLE("setName", m_vertexBufferHandle, _handle);
VertexBuffer& ref = m_vertexBuffers[_handle.idx];
ref.m_name.set(_name);
setName(convert(_handle), _name);
}
2013-10-05 10:45:05 +04:00
BGFX_API_FUNC(void destroyVertexBuffer(VertexBufferHandle _handle) )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-03-26 09:33:35 +03:00
BGFX_CHECK_HANDLE("destroyVertexBuffer", m_vertexBufferHandle, _handle);
2016-11-04 02:52:34 +03:00
bool ok = m_submit->free(_handle); BX_UNUSED(ok);
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Vertex buffer handle %d is already destroyed!", _handle.idx);
2015-03-26 09:33:35 +03:00
VertexBuffer& ref = m_vertexBuffers[_handle.idx];
ref.m_name.clear();
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyVertexBuffer);
cmdbuf.write(_handle);
}
void destroyVertexBufferInternal(VertexBufferHandle _handle)
2012-08-06 01:51:49 +04:00
{
2019-08-17 20:35:21 +03:00
VertexLayoutHandle layoutHandle = m_vertexLayoutRef.release(_handle);
if (isValid(layoutHandle) )
2012-08-06 01:51:49 +04:00
{
2019-08-13 12:04:51 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyVertexLayout);
2019-08-17 20:35:21 +03:00
cmdbuf.write(layoutHandle);
m_render->free(layoutHandle);
2012-08-06 01:51:49 +04:00
}
m_vertexBufferHandle.free(_handle.idx);
2012-08-06 01:51:49 +04:00
}
2015-05-14 21:37:32 +03:00
uint64_t allocDynamicIndexBuffer(uint32_t _size, uint16_t _flags)
2015-01-29 04:56:29 +03:00
{
uint64_t ptr = m_dynIndexBufferAllocator.alloc(_size);
2017-06-10 07:57:08 +03:00
if (ptr == NonLocalAllocator::kInvalidBlock)
2015-01-29 04:56:29 +03:00
{
IndexBufferHandle indexBufferHandle = { m_indexBufferHandle.alloc() };
2015-07-17 06:28:43 +03:00
if (!isValid(indexBufferHandle) )
2015-01-29 04:56:29 +03:00
{
BX_TRACE("Failed to allocate index buffer handle.");
return NonLocalAllocator::kInvalidBlock;
2015-01-29 04:56:29 +03:00
}
const uint32_t allocSize = bx::max<uint32_t>(BGFX_CONFIG_DYNAMIC_INDEX_BUFFER_SIZE, bx::alignUp(_size, 1<<20) );
IndexBuffer& ib = m_indexBuffers[indexBufferHandle.idx];
ib.m_size = allocSize;
2015-01-29 04:56:29 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateDynamicIndexBuffer);
cmdbuf.write(indexBufferHandle);
cmdbuf.write(allocSize);
2015-01-29 04:56:29 +03:00
cmdbuf.write(_flags);
m_dynIndexBufferAllocator.add(uint64_t(indexBufferHandle.idx) << 32, allocSize);
2015-01-29 04:56:29 +03:00
ptr = m_dynIndexBufferAllocator.alloc(_size);
}
return ptr;
}
uint64_t allocIndexBuffer(uint32_t _size, uint16_t _flags)
{
IndexBufferHandle indexBufferHandle = { m_indexBufferHandle.alloc() };
if (!isValid(indexBufferHandle) )
{
BX_TRACE("Failed to allocate index buffer handle.");
return NonLocalAllocator::kInvalidBlock;
}
IndexBuffer& ib = m_indexBuffers[indexBufferHandle.idx];
ib.m_size = _size;
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateDynamicIndexBuffer);
cmdbuf.write(indexBufferHandle);
cmdbuf.write(_size);
cmdbuf.write(_flags);
setDebugName(convert(indexBufferHandle), "Dynamic Index Buffer");
return uint64_t(indexBufferHandle.idx) << 32;
}
2015-05-14 21:37:32 +03:00
BGFX_API_FUNC(DynamicIndexBufferHandle createDynamicIndexBuffer(uint32_t _num, uint16_t _flags) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2018-07-03 02:33:11 +03:00
DynamicIndexBufferHandle handle = { m_dynamicIndexBufferHandle.alloc() };
if (!isValid(handle) )
{
BX_TRACE("Failed to allocate dynamic index buffer handle.");
2018-07-03 02:33:11 +03:00
return handle;
}
2015-04-09 05:59:48 +03:00
const uint32_t indexSize = 0 == (_flags & BGFX_BUFFER_INDEX32) ? 2 : 4;
const uint32_t size = bx::alignUp(_num*indexSize, 16);
2021-02-16 20:12:04 +03:00
const uint64_t ptr = (0 != (_flags & BGFX_BUFFER_COMPUTE_READ_WRITE) )
? allocIndexBuffer(size, _flags)
: allocDynamicIndexBuffer(size, _flags)
;
if (ptr == NonLocalAllocator::kInvalidBlock)
{
m_dynamicIndexBufferHandle.free(handle.idx);
return BGFX_INVALID_HANDLE;
2012-08-06 01:51:49 +04:00
}
DynamicIndexBuffer& dib = m_dynamicIndexBuffers[handle.idx];
dib.m_handle.idx = uint16_t(ptr>>32);
2015-01-24 09:18:07 +03:00
dib.m_offset = uint32_t(ptr);
dib.m_size = _num * indexSize;
dib.m_startIndex = bx::strideAlign(dib.m_offset, indexSize)/indexSize;
2015-01-29 04:56:29 +03:00
dib.m_flags = _flags;
2012-08-06 01:51:49 +04:00
return handle;
}
2015-05-14 21:37:32 +03:00
BGFX_API_FUNC(DynamicIndexBufferHandle createDynamicIndexBuffer(const Memory* _mem, uint16_t _flags) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2020-06-16 20:06:18 +03:00
BX_ASSERT(0 == (_flags & BGFX_BUFFER_COMPUTE_READ_WRITE), "Cannot initialize compute buffer from CPU.");
2015-04-09 05:59:48 +03:00
const uint32_t indexSize = 0 == (_flags & BGFX_BUFFER_INDEX32) ? 2 : 4;
DynamicIndexBufferHandle handle = createDynamicIndexBuffer(_mem->size/indexSize, _flags);
2018-07-03 02:33:11 +03:00
if (!isValid(handle) )
{
release(_mem);
2018-07-03 02:33:11 +03:00
return BGFX_INVALID_HANDLE;
}
2018-07-03 02:33:11 +03:00
update(handle, 0, _mem);
2012-08-06 01:51:49 +04:00
return handle;
}
BGFX_API_FUNC(void update(DynamicIndexBufferHandle _handle, uint32_t _startIndex, const Memory* _mem) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-03-26 09:33:35 +03:00
BGFX_CHECK_HANDLE("updateDynamicIndexBuffer", m_dynamicIndexBufferHandle, _handle);
2012-08-06 01:51:49 +04:00
DynamicIndexBuffer& dib = m_dynamicIndexBuffers[_handle.idx];
2020-06-16 20:06:18 +03:00
BX_ASSERT(0 == (dib.m_flags & BGFX_BUFFER_COMPUTE_WRITE), "Can't update GPU buffer from CPU.");
2015-04-09 05:59:48 +03:00
const uint32_t indexSize = 0 == (dib.m_flags & BGFX_BUFFER_INDEX32) ? 2 : 4;
2015-01-29 04:56:29 +03:00
if (dib.m_size < _mem->size
&& 0 != (dib.m_flags & BGFX_BUFFER_ALLOW_RESIZE) )
{
destroy(dib);
2021-02-16 20:12:04 +03:00
const uint64_t ptr = (0 != (dib.m_flags & BGFX_BUFFER_COMPUTE_READ) )
? allocIndexBuffer(_mem->size, dib.m_flags)
: allocDynamicIndexBuffer(_mem->size, dib.m_flags)
;
2015-01-29 04:56:29 +03:00
dib.m_handle.idx = uint16_t(ptr>>32);
dib.m_offset = uint32_t(ptr);
dib.m_size = _mem->size;
dib.m_startIndex = bx::strideAlign(dib.m_offset, indexSize)/indexSize;
2015-01-29 04:56:29 +03:00
}
2018-02-11 02:49:30 +03:00
const uint32_t offset = (dib.m_startIndex + _startIndex)*indexSize;
const uint32_t size = bx::min<uint32_t>(offset
+ bx::min(bx::uint32_satsub(dib.m_size, _startIndex*indexSize), _mem->size)
, m_indexBuffers[dib.m_handle.idx].m_size) - offset
2016-04-19 19:12:04 +03:00
;
2020-06-16 20:06:18 +03:00
BX_ASSERT(_mem->size <= size, "Truncating dynamic index buffer update (size %d, mem size %d)."
2015-01-29 04:56:29 +03:00
, size
, _mem->size
);
2012-08-06 01:51:49 +04:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::UpdateDynamicIndexBuffer);
cmdbuf.write(dib.m_handle);
2015-01-29 04:56:29 +03:00
cmdbuf.write(offset);
cmdbuf.write(size);
2012-08-06 01:51:49 +04:00
cmdbuf.write(_mem);
}
2013-10-05 10:45:05 +04:00
BGFX_API_FUNC(void destroyDynamicIndexBuffer(DynamicIndexBufferHandle _handle) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-03-26 09:33:35 +03:00
BGFX_CHECK_HANDLE("destroyDynamicIndexBuffer", m_dynamicIndexBufferHandle, _handle);
2012-08-06 01:51:49 +04:00
m_freeDynamicIndexBufferHandle[m_numFreeDynamicIndexBufferHandles++] = _handle;
}
void destroy(const DynamicIndexBuffer& _dib)
2012-08-06 01:51:49 +04:00
{
if (0 != (_dib.m_flags & BGFX_BUFFER_COMPUTE_READ_WRITE))
2015-01-29 04:56:29 +03:00
{
destroyIndexBuffer(_dib.m_handle);
2015-01-29 04:56:29 +03:00
}
else
{
m_dynIndexBufferAllocator.free(uint64_t(_dib.m_handle.idx) << 32 | _dib.m_offset);
if (m_dynIndexBufferAllocator.compact())
{
for (uint64_t ptr = m_dynIndexBufferAllocator.remove(); 0 != ptr; ptr = m_dynIndexBufferAllocator.remove())
{
IndexBufferHandle handle = { uint16_t(ptr >> 32) };
destroyIndexBuffer(handle);
}
}
2015-01-29 04:56:29 +03:00
}
}
2015-01-29 04:56:29 +03:00
void destroyDynamicIndexBufferInternal(DynamicIndexBufferHandle _handle)
{
DynamicIndexBuffer& dib = m_dynamicIndexBuffers[_handle.idx];
destroy(dib);
2022-08-19 20:40:00 +03:00
dib.reset();
2012-08-06 01:51:49 +04:00
m_dynamicIndexBufferHandle.free(_handle.idx);
}
2015-05-14 21:37:32 +03:00
uint64_t allocDynamicVertexBuffer(uint32_t _size, uint16_t _flags)
2015-01-29 04:56:29 +03:00
{
uint64_t ptr = m_dynVertexBufferAllocator.alloc(_size);
2017-06-10 07:57:08 +03:00
if (ptr == NonLocalAllocator::kInvalidBlock)
2015-01-29 04:56:29 +03:00
{
VertexBufferHandle vertexBufferHandle = { m_vertexBufferHandle.alloc() };
if (!isValid(vertexBufferHandle) )
{
BX_TRACE("Failed to allocate dynamic vertex buffer handle.");
2017-06-10 07:57:08 +03:00
return NonLocalAllocator::kInvalidBlock;
2015-01-29 04:56:29 +03:00
}
const uint32_t allocSize = bx::max<uint32_t>(BGFX_CONFIG_DYNAMIC_VERTEX_BUFFER_SIZE, bx::alignUp(_size, 1<<20) );
VertexBuffer& vb = m_vertexBuffers[vertexBufferHandle.idx];
vb.m_size = allocSize;
vb.m_stride = 0;
2015-01-29 04:56:29 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateDynamicVertexBuffer);
cmdbuf.write(vertexBufferHandle);
cmdbuf.write(allocSize);
2015-01-29 04:56:29 +03:00
cmdbuf.write(_flags);
m_dynVertexBufferAllocator.add(uint64_t(vertexBufferHandle.idx) << 32, allocSize);
2015-01-29 04:56:29 +03:00
ptr = m_dynVertexBufferAllocator.alloc(_size);
}
return ptr;
}
uint64_t allocVertexBuffer(uint32_t _size, uint16_t _flags)
{
VertexBufferHandle vertexBufferHandle = { m_vertexBufferHandle.alloc() };
if (!isValid(vertexBufferHandle) )
{
BX_TRACE("WARNING: Failed to allocate vertex buffer handle (BGFX_CONFIG_MAX_VERTEX_BUFFERS, max: %d).", BGFX_CONFIG_MAX_VERTEX_BUFFERS);
return NonLocalAllocator::kInvalidBlock;
}
VertexBuffer& vb = m_vertexBuffers[vertexBufferHandle.idx];
vb.m_size = _size;
vb.m_stride = 0;
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateDynamicVertexBuffer);
cmdbuf.write(vertexBufferHandle);
cmdbuf.write(_size);
cmdbuf.write(_flags);
setDebugName(convert(vertexBufferHandle), "Dynamic Vertex Buffer");
return uint64_t(vertexBufferHandle.idx)<<32;
}
2019-08-17 20:35:21 +03:00
BGFX_API_FUNC(DynamicVertexBufferHandle createDynamicVertexBuffer(uint32_t _num, const VertexLayout& _layout, uint16_t _flags) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
VertexLayoutHandle layoutHandle = findOrCreateVertexLayout(_layout);
2019-08-17 20:35:21 +03:00
if (!isValid(layoutHandle) )
2018-07-03 02:33:11 +03:00
{
2019-08-17 20:35:21 +03:00
BX_TRACE("WARNING: Failed to allocate vertex layout handle (BGFX_CONFIG_MAX_VERTEX_LAYOUTS, max: %d).", BGFX_CONFIG_MAX_VERTEX_LAYOUTS);
2018-07-03 02:33:11 +03:00
return BGFX_INVALID_HANDLE;
}
DynamicVertexBufferHandle handle = { m_dynamicVertexBufferHandle.alloc() };
if (!isValid(handle) )
{
BX_TRACE("WARNING: Failed to allocate dynamic vertex buffer handle (BGFX_CONFIG_MAX_DYNAMIC_VERTEX_BUFFERS, max: %d).", BGFX_CONFIG_MAX_DYNAMIC_VERTEX_BUFFERS);
return BGFX_INVALID_HANDLE;
}
2019-08-17 20:35:21 +03:00
const uint32_t size = bx::strideAlign<16>(_num*_layout.m_stride, _layout.m_stride)+_layout.m_stride;
2012-08-06 01:51:49 +04:00
2021-02-16 20:12:04 +03:00
const uint64_t ptr = (0 != (_flags & BGFX_BUFFER_COMPUTE_READ_WRITE) )
? allocVertexBuffer(size, _flags)
: allocDynamicVertexBuffer(size, _flags)
;
2014-12-10 10:16:27 +03:00
if (ptr == NonLocalAllocator::kInvalidBlock)
2014-12-10 10:16:27 +03:00
{
m_dynamicVertexBufferHandle.free(handle.idx);
return BGFX_INVALID_HANDLE;
2012-08-06 01:51:49 +04:00
}
DynamicVertexBuffer& dvb = m_dynamicVertexBuffers[handle.idx];
2019-08-17 20:35:21 +03:00
dvb.m_handle.idx = uint16_t(ptr>>32);
dvb.m_offset = uint32_t(ptr);
dvb.m_size = _num * _layout.m_stride;
dvb.m_startVertex = bx::strideAlign(dvb.m_offset, _layout.m_stride)/_layout.m_stride;
dvb.m_numVertices = _num;
dvb.m_stride = _layout.m_stride;
dvb.m_layoutHandle = layoutHandle;
dvb.m_flags = _flags;
m_vertexLayoutRef.add(handle, layoutHandle, _layout.m_hash);
2012-08-06 01:51:49 +04:00
return handle;
}
2019-08-17 20:35:21 +03:00
BGFX_API_FUNC(DynamicVertexBufferHandle createDynamicVertexBuffer(const Memory* _mem, const VertexLayout& _layout, uint16_t _flags) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2019-08-17 20:35:21 +03:00
uint32_t numVertices = _mem->size/_layout.m_stride;
DynamicVertexBufferHandle handle = createDynamicVertexBuffer(numVertices, _layout, _flags);
2018-07-03 02:33:11 +03:00
if (!isValid(handle) )
{
release(_mem);
2018-07-03 02:33:11 +03:00
return BGFX_INVALID_HANDLE;
}
2018-07-03 02:33:11 +03:00
update(handle, 0, _mem);
2012-08-06 01:51:49 +04:00
return handle;
}
BGFX_API_FUNC(void update(DynamicVertexBufferHandle _handle, uint32_t _startVertex, const Memory* _mem) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-03-26 09:33:35 +03:00
BGFX_CHECK_HANDLE("updateDynamicVertexBuffer", m_dynamicVertexBufferHandle, _handle);
2012-08-06 01:51:49 +04:00
DynamicVertexBuffer& dvb = m_dynamicVertexBuffers[_handle.idx];
2020-06-16 20:06:18 +03:00
BX_ASSERT(0 == (dvb.m_flags & BGFX_BUFFER_COMPUTE_WRITE), "Can't update GPU write buffer from CPU.");
2015-01-29 04:56:29 +03:00
if (dvb.m_size < _mem->size
&& 0 != (dvb.m_flags & BGFX_BUFFER_ALLOW_RESIZE) )
{
destroy(dvb);
2015-01-29 04:56:29 +03:00
const uint32_t size = bx::strideAlign<16>(_mem->size, dvb.m_stride)+dvb.m_stride;
2021-02-16 20:12:04 +03:00
const uint64_t ptr = (0 != (dvb.m_flags & BGFX_BUFFER_COMPUTE_READ) )
? allocVertexBuffer(size, dvb.m_flags)
: allocDynamicVertexBuffer(size, dvb.m_flags)
;
2015-01-29 04:56:29 +03:00
dvb.m_handle.idx = uint16_t(ptr>>32);
dvb.m_offset = uint32_t(ptr);
dvb.m_size = size;
dvb.m_numVertices = _mem->size / dvb.m_stride;
dvb.m_startVertex = bx::strideAlign(dvb.m_offset, dvb.m_stride)/dvb.m_stride;
2015-01-29 04:56:29 +03:00
}
2018-02-11 02:49:30 +03:00
const uint32_t offset = (dvb.m_startVertex + _startVertex)*dvb.m_stride;
const uint32_t size = bx::min<uint32_t>(offset
+ bx::min(bx::uint32_satsub(dvb.m_size, _startVertex*dvb.m_stride), _mem->size)
, m_vertexBuffers[dvb.m_handle.idx].m_size) - offset
;
2020-06-16 20:06:18 +03:00
BX_ASSERT(_mem->size <= size, "Truncating dynamic vertex buffer update (size %d, mem size %d)."
2016-04-19 19:12:04 +03:00
, size
2015-01-29 04:56:29 +03:00
, _mem->size
);
2012-08-06 01:51:49 +04:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::UpdateDynamicVertexBuffer);
cmdbuf.write(dvb.m_handle);
2015-01-29 04:56:29 +03:00
cmdbuf.write(offset);
cmdbuf.write(size);
2012-08-06 01:51:49 +04:00
cmdbuf.write(_mem);
}
2013-10-05 10:45:05 +04:00
BGFX_API_FUNC(void destroyDynamicVertexBuffer(DynamicVertexBufferHandle _handle) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-03-26 09:33:35 +03:00
BGFX_CHECK_HANDLE("destroyDynamicVertexBuffer", m_dynamicVertexBufferHandle, _handle);
2012-08-06 01:51:49 +04:00
m_freeDynamicVertexBufferHandle[m_numFreeDynamicVertexBufferHandles++] = _handle;
}
void destroy(const DynamicVertexBuffer& _dvb)
{
if (0 != (_dvb.m_flags & BGFX_BUFFER_COMPUTE_READ_WRITE))
{
destroyVertexBuffer(_dvb.m_handle);
}
else
{
m_dynVertexBufferAllocator.free(uint64_t(_dvb.m_handle.idx) << 32 | _dvb.m_offset);
if (m_dynVertexBufferAllocator.compact())
{
for (uint64_t ptr = m_dynVertexBufferAllocator.remove(); 0 != ptr; ptr = m_dynVertexBufferAllocator.remove())
{
VertexBufferHandle handle = { uint16_t(ptr >> 32) };
destroyVertexBuffer(handle);
}
}
}
}
2012-08-06 01:51:49 +04:00
void destroyDynamicVertexBufferInternal(DynamicVertexBufferHandle _handle)
{
2019-08-17 20:35:21 +03:00
VertexLayoutHandle layoutHandle = m_vertexLayoutRef.release(_handle);
BGFX_CHECK_HANDLE_INVALID_OK("destroyDynamicVertexBufferInternal", m_layoutHandle, layoutHandle);
2012-08-06 01:51:49 +04:00
2019-08-17 20:35:21 +03:00
if (isValid(layoutHandle) )
2012-08-06 01:51:49 +04:00
{
2019-08-13 12:04:51 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyVertexLayout);
2019-08-17 20:35:21 +03:00
cmdbuf.write(layoutHandle);
m_render->free(layoutHandle);
2012-08-06 01:51:49 +04:00
}
2017-03-30 03:54:38 +03:00
DynamicVertexBuffer& dvb = m_dynamicVertexBuffers[_handle.idx];
destroy(dvb);
2022-08-19 20:40:00 +03:00
dvb.reset();
2012-08-06 01:51:49 +04:00
m_dynamicVertexBufferHandle.free(_handle.idx);
}
BGFX_API_FUNC(uint32_t getAvailTransientIndexBuffer(uint32_t _num, bool _index32) )
2013-10-05 10:45:05 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
const bool isIndex16 = !_index32;
2021-06-07 00:51:39 +03:00
const uint16_t indexSize = isIndex16 ? 2 : 4;
return m_submit->getAvailTransientIndexBuffer(_num, indexSize);
2013-10-05 10:45:05 +04:00
}
2017-10-29 04:43:21 +03:00
BGFX_API_FUNC(uint32_t getAvailTransientVertexBuffer(uint32_t _num, uint16_t _stride) )
2013-10-05 10:45:05 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
return m_submit->getAvailTransientVertexBuffer(_num, _stride);
2013-10-05 10:45:05 +04:00
}
2012-08-06 01:51:49 +04:00
TransientIndexBuffer* createTransientIndexBuffer(uint32_t _size)
{
2015-01-30 06:54:23 +03:00
TransientIndexBuffer* tib = NULL;
2012-08-06 01:51:49 +04:00
IndexBufferHandle handle = { m_indexBufferHandle.alloc() };
BX_WARN(isValid(handle), "Failed to allocate transient index buffer handle.");
if (isValid(handle) )
{
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateDynamicIndexBuffer);
cmdbuf.write(handle);
cmdbuf.write(_size);
2015-05-14 21:37:32 +03:00
uint16_t flags = BGFX_BUFFER_NONE;
cmdbuf.write(flags);
2012-08-06 01:51:49 +04:00
const uint32_t size = 0
2020-05-31 21:09:30 +03:00
+ bx::alignUp<uint32_t>(sizeof(TransientIndexBuffer), 16)
+ bx::alignUp(_size, 16)
;
tib = (TransientIndexBuffer*)BX_ALIGNED_ALLOC(g_allocator, size, 16);
tib->data = (uint8_t *)tib + bx::alignUp(sizeof(TransientIndexBuffer), 16);
2015-01-30 06:54:23 +03:00
tib->size = _size;
tib->handle = handle;
setDebugName(convert(handle), "Transient Index Buffer");
}
2012-08-06 01:51:49 +04:00
2015-01-30 06:54:23 +03:00
return tib;
2012-08-06 01:51:49 +04:00
}
2015-01-30 06:54:23 +03:00
void destroyTransientIndexBuffer(TransientIndexBuffer* _tib)
2012-08-06 01:51:49 +04:00
{
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyDynamicIndexBuffer);
2015-01-30 06:54:23 +03:00
cmdbuf.write(_tib->handle);
2012-08-06 01:51:49 +04:00
2015-01-30 06:54:23 +03:00
m_submit->free(_tib->handle);
2016-06-28 05:31:54 +03:00
BX_ALIGNED_FREE(g_allocator, _tib, 16);
2012-08-06 01:51:49 +04:00
}
BGFX_API_FUNC(void allocTransientIndexBuffer(TransientIndexBuffer* _tib, uint32_t _num, bool _index32) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
const bool isIndex16 = !_index32;
2021-06-07 00:51:39 +03:00
const uint16_t indexSize = isIndex16 ? 2 : 4;
const uint32_t offset = m_submit->allocTransientIndexBuffer(_num, indexSize);
2012-08-06 01:51:49 +04:00
2015-04-09 05:59:48 +03:00
TransientIndexBuffer& tib = *m_submit->m_transientIb;
2012-08-06 01:51:49 +04:00
2015-04-09 05:59:48 +03:00
_tib->data = &tib.data[offset];
_tib->size = _num * indexSize;
2015-04-09 05:59:48 +03:00
_tib->handle = tib.handle;
_tib->startIndex = bx::strideAlign(offset, indexSize) / indexSize;
_tib->isIndex16 = isIndex16;
2012-08-06 01:51:49 +04:00
}
2019-08-17 20:35:21 +03:00
TransientVertexBuffer* createTransientVertexBuffer(uint32_t _size, const VertexLayout* _layout = NULL)
2012-08-06 01:51:49 +04:00
{
2015-01-30 06:54:23 +03:00
TransientVertexBuffer* tvb = NULL;
2012-08-06 01:51:49 +04:00
VertexBufferHandle handle = { m_vertexBufferHandle.alloc() };
2012-08-06 01:51:49 +04:00
BX_WARN(isValid(handle), "Failed to allocate transient vertex buffer handle.");
if (isValid(handle) )
2012-08-06 01:51:49 +04:00
{
uint16_t stride = 0;
2019-08-17 20:35:21 +03:00
VertexLayoutHandle layoutHandle = BGFX_INVALID_HANDLE;
2012-08-06 01:51:49 +04:00
2019-08-17 20:35:21 +03:00
if (NULL != _layout)
{
layoutHandle = findOrCreateVertexLayout(*_layout);
2019-08-17 20:35:21 +03:00
m_vertexLayoutRef.add(handle, layoutHandle, _layout->m_hash);
2012-08-06 01:51:49 +04:00
2019-08-17 20:35:21 +03:00
stride = _layout->m_stride;
}
2012-08-06 01:51:49 +04:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateDynamicVertexBuffer);
cmdbuf.write(handle);
cmdbuf.write(_size);
2015-05-14 21:37:32 +03:00
uint16_t flags = BGFX_BUFFER_NONE;
cmdbuf.write(flags);
const uint32_t size = 0
2020-05-31 21:09:30 +03:00
+ bx::alignUp<uint32_t>(sizeof(TransientVertexBuffer), 16)
+ bx::alignUp(_size, 16)
;
tvb = (TransientVertexBuffer*)BX_ALIGNED_ALLOC(g_allocator, size, 16);
tvb->data = (uint8_t *)tvb + bx::alignUp(sizeof(TransientVertexBuffer), 16);
2015-01-30 06:54:23 +03:00
tvb->size = _size;
tvb->startVertex = 0;
tvb->stride = stride;
tvb->handle = handle;
2019-08-17 20:35:21 +03:00
tvb->layoutHandle = layoutHandle;
setDebugName(convert(handle), "Transient Vertex Buffer");
}
2012-08-06 01:51:49 +04:00
2015-01-30 06:54:23 +03:00
return tvb;
2012-08-06 01:51:49 +04:00
}
2015-01-30 06:54:23 +03:00
void destroyTransientVertexBuffer(TransientVertexBuffer* _tvb)
2012-08-06 01:51:49 +04:00
{
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyDynamicVertexBuffer);
2015-01-30 06:54:23 +03:00
cmdbuf.write(_tvb->handle);
2012-08-06 01:51:49 +04:00
2015-01-30 06:54:23 +03:00
m_submit->free(_tvb->handle);
2016-06-28 05:31:54 +03:00
BX_ALIGNED_FREE(g_allocator, _tvb, 16);
2012-08-06 01:51:49 +04:00
}
BGFX_API_FUNC(void allocTransientVertexBuffer(TransientVertexBuffer* _tvb, uint32_t _num, VertexLayoutHandle _layoutHandle, uint16_t _stride) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
const uint32_t offset = m_submit->allocTransientVertexBuffer(_num, _stride);
const TransientVertexBuffer& dvb = *m_submit->m_transientVb;
2012-08-06 01:51:49 +04:00
_tvb->data = &dvb.data[offset];
_tvb->size = _num * _stride;
_tvb->startVertex = bx::strideAlign(offset, _stride)/_stride;
_tvb->stride = _stride;
_tvb->handle = dvb.handle;
_tvb->layoutHandle = _layoutHandle;
2012-08-06 01:51:49 +04:00
}
2017-10-07 07:50:38 +03:00
BGFX_API_FUNC(void allocInstanceDataBuffer(InstanceDataBuffer* _idb, uint32_t _num, uint16_t _stride) )
2012-08-06 01:51:49 +04:00
{
BGFX_MUTEX_SCOPE(m_resourceApiLock);
const uint16_t stride = bx::alignUp(_stride, 16);
const uint32_t offset = m_submit->allocTransientVertexBuffer(_num, stride);
2012-08-06 01:51:49 +04:00
TransientVertexBuffer& dvb = *m_submit->m_transientVb;
2017-10-07 07:50:38 +03:00
_idb->data = &dvb.data[offset];
_idb->size = _num * stride;
_idb->offset = offset;
_idb->num = _num;
_idb->stride = stride;
_idb->handle = dvb.handle;
2012-08-06 01:51:49 +04:00
}
2015-05-02 00:54:23 +03:00
IndirectBufferHandle createIndirectBuffer(uint32_t _num)
2015-04-30 03:18:51 +03:00
{
BX_UNUSED(_num);
2015-05-02 00:54:23 +03:00
IndirectBufferHandle handle = { m_vertexBufferHandle.alloc() };
2015-04-30 03:18:51 +03:00
BX_WARN(isValid(handle), "Failed to allocate draw indirect buffer handle.");
if (isValid(handle) )
{
2015-05-14 21:37:32 +03:00
uint32_t size = _num * BGFX_CONFIG_DRAW_INDIRECT_STRIDE;
uint16_t flags = BGFX_BUFFER_DRAW_INDIRECT;
2015-04-30 03:18:51 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateDynamicVertexBuffer);
cmdbuf.write(handle);
cmdbuf.write(size);
cmdbuf.write(flags);
}
return handle;
}
2015-05-02 00:54:23 +03:00
void destroyIndirectBuffer(IndirectBufferHandle _handle)
2015-04-30 03:18:51 +03:00
{
VertexBufferHandle handle = { _handle.idx };
BGFX_CHECK_HANDLE("destroyDrawIndirectBuffer", m_vertexBufferHandle, handle);
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyDynamicVertexBuffer);
cmdbuf.write(handle);
m_submit->free(handle);
}
BGFX_API_FUNC(ShaderHandle createShader(const Memory* _mem) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
bx::MemoryReader reader(_mem->data, _mem->size);
2016-10-06 06:41:25 +03:00
bx::Error err;
uint32_t magic;
2016-10-06 06:41:25 +03:00
bx::read(&reader, magic, &err);
if (!err.isOk() )
{
2018-02-08 05:09:39 +03:00
BX_TRACE("Couldn't read shader signature!");
release(_mem);
2018-02-08 05:09:39 +03:00
return BGFX_INVALID_HANDLE;
2016-10-06 06:41:25 +03:00
}
if (!isShaderBin(magic) )
{
BX_TRACE("Invalid shader signature! %c%c%c%d."
2014-11-13 09:16:19 +03:00
, ( (uint8_t*)&magic)[0]
, ( (uint8_t*)&magic)[1]
, ( (uint8_t*)&magic)[2]
, ( (uint8_t*)&magic)[3]
);
release(_mem);
2018-02-08 05:09:39 +03:00
return BGFX_INVALID_HANDLE;
}
if (isShaderType(magic, 'C')
&& 0 == (g_caps.supported & BGFX_CAPS_COMPUTE) )
{
BX_TRACE("Creating compute shader but compute is not supported!");
release(_mem);
return BGFX_INVALID_HANDLE;
}
if ( (isShaderType(magic, 'C') && isShaderVerLess(magic, 3) )
|| (isShaderType(magic, 'F') && isShaderVerLess(magic, 5) )
|| (isShaderType(magic, 'V') && isShaderVerLess(magic, 5) ) )
{
BX_TRACE("Unsupported shader binary version.");
release(_mem);
return BGFX_INVALID_HANDLE;
}
2017-09-24 02:27:16 +03:00
const uint32_t shaderHash = bx::hash<bx::HashMurmur2A>(_mem->data, _mem->size);
2017-07-29 05:50:33 +03:00
const uint16_t idx = m_shaderHashMap.find(shaderHash);
if (kInvalidHandle != idx)
{
ShaderHandle handle = { idx };
shaderIncRef(handle);
2017-07-29 02:43:16 +03:00
release(_mem);
return handle;
}
uint32_t hashIn;
bx::read(&reader, hashIn, &err);
uint32_t hashOut;
if (isShaderVerLess(magic, 6) )
{
hashOut = hashIn;
}
else
{
bx::read(&reader, hashOut, &err);
}
2018-02-08 05:09:39 +03:00
uint16_t count;
bx::read(&reader, count, &err);
if (!err.isOk() )
{
2018-02-08 05:09:39 +03:00
BX_TRACE("Corrupted shader binary!");
release(_mem);
return BGFX_INVALID_HANDLE;
}
2018-02-08 05:09:39 +03:00
ShaderHandle handle = { m_shaderHandle.alloc() };
2018-02-08 05:09:39 +03:00
if (!isValid(handle) )
{
BX_TRACE("Failed to allocate shader handle.");
release(_mem);
return BGFX_INVALID_HANDLE;
}
2018-02-08 05:09:39 +03:00
bool ok = m_shaderHashMap.insert(shaderHash, handle.idx);
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Shader already exists!"); BX_UNUSED(ok);
2018-02-08 05:09:39 +03:00
ShaderRef& sr = m_shaderRef[handle.idx];
sr.m_refCount = 1;
sr.m_hashIn = hashIn;
sr.m_hashOut = hashOut;
2018-02-08 05:09:39 +03:00
sr.m_num = 0;
sr.m_uniforms = NULL;
2018-02-08 05:09:39 +03:00
UniformHandle* uniforms = (UniformHandle*)alloca(count*sizeof(UniformHandle) );
2018-02-08 05:09:39 +03:00
for (uint32_t ii = 0; ii < count; ++ii)
{
uint8_t nameSize = 0;
bx::read(&reader, nameSize, &err);
2018-02-08 05:09:39 +03:00
char name[256];
bx::read(&reader, &name, nameSize, &err);
name[nameSize] = '\0';
2018-02-08 05:09:39 +03:00
uint8_t type = 0;
bx::read(&reader, type, &err);
2020-06-19 07:20:01 +03:00
type &= ~kUniformMask;
2018-02-08 05:09:39 +03:00
uint8_t num;
bx::read(&reader, num, &err);
2018-02-08 05:09:39 +03:00
uint16_t regIndex;
bx::read(&reader, regIndex, &err);
2018-02-08 05:09:39 +03:00
uint16_t regCount;
bx::read(&reader, regCount, &err);
2021-02-16 20:12:04 +03:00
if (!isShaderVerLess(magic, 8) )
{
uint16_t texInfo;
bx::read(&reader, texInfo, &err);
}
if (!isShaderVerLess(magic, 10) )
{
uint16_t texFormat = 0;
bx::read(&reader, texFormat, &err);
}
2018-02-08 05:09:39 +03:00
PredefinedUniform::Enum predefined = nameToPredefinedUniformEnum(name);
2021-02-16 20:12:04 +03:00
if (PredefinedUniform::Count == predefined && UniformType::End != UniformType::Enum(type) )
{
uniforms[sr.m_num] = createUniform(name, UniformType::Enum(type), num);
2018-02-08 05:09:39 +03:00
sr.m_num++;
}
}
2018-02-08 05:09:39 +03:00
if (0 != sr.m_num)
{
2018-02-08 05:09:39 +03:00
uint32_t size = sr.m_num*sizeof(UniformHandle);
sr.m_uniforms = (UniformHandle*)BX_ALLOC(g_allocator, size);
bx::memCopy(sr.m_uniforms, uniforms, size);
}
2018-02-08 05:09:39 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateShader);
cmdbuf.write(handle);
cmdbuf.write(_mem);
setDebugName(convert(handle) );
2012-08-06 01:51:49 +04:00
return handle;
}
BGFX_API_FUNC(uint16_t getShaderUniforms(ShaderHandle _handle, UniformHandle* _uniforms, uint16_t _max) )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
if (!isValid(_handle) )
{
BX_WARN(false, "Passing invalid shader handle to bgfx::getShaderUniforms.");
return 0;
}
ShaderRef& sr = m_shaderRef[_handle.idx];
if (NULL != _uniforms)
{
2018-06-16 18:34:06 +03:00
bx::memCopy(_uniforms, sr.m_uniforms, bx::min<uint16_t>(_max, sr.m_num)*sizeof(UniformHandle) );
}
return sr.m_num;
}
void setName(Handle _handle, const bx::StringView& _name)
{
char tmp[1024];
uint16_t len = 1+(uint16_t)bx::snprintf(tmp, BX_COUNTOF(tmp)
, "%sH %d: %S"
, getTypeName(_handle)
, _handle.idx
, &_name
);
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::SetName);
cmdbuf.write(_handle);
cmdbuf.write(len);
cmdbuf.write(tmp, len);
}
void setDebugName(Handle _handle, const bx::StringView& _name = "")
{
if (BX_ENABLED(BGFX_CONFIG_DEBUG) )
{
setName(_handle, _name);
}
}
BGFX_API_FUNC(void setName(ShaderHandle _handle, const bx::StringView& _name) )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
BGFX_CHECK_HANDLE("setName", m_shaderHandle, _handle);
ShaderRef& sr = m_shaderRef[_handle.idx];
sr.m_name.set(_name);
setName(convert(_handle), _name);
}
BGFX_API_FUNC(void destroyShader(ShaderHandle _handle) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-03-26 09:33:35 +03:00
BGFX_CHECK_HANDLE("destroyShader", m_shaderHandle, _handle);
if (!isValid(_handle) )
{
BX_WARN(false, "Passing invalid shader handle to bgfx::destroyShader.");
return;
}
shaderDecRef(_handle);
}
void shaderTakeOwnership(ShaderHandle _handle)
{
2017-07-29 02:43:16 +03:00
shaderDecRef(_handle);
}
void shaderIncRef(ShaderHandle _handle)
{
ShaderRef& sr = m_shaderRef[_handle.idx];
++sr.m_refCount;
}
void shaderDecRef(ShaderHandle _handle)
{
ShaderRef& sr = m_shaderRef[_handle.idx];
int32_t refs = --sr.m_refCount;
if (0 == refs)
{
2016-11-04 02:52:34 +03:00
bool ok = m_submit->free(_handle); BX_UNUSED(ok);
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Shader handle %d is already destroyed!", _handle.idx);
2016-11-04 02:52:34 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyShader);
cmdbuf.write(_handle);
if (0 != sr.m_num)
{
for (uint32_t ii = 0, num = sr.m_num; ii < num; ++ii)
{
destroyUniform(sr.m_uniforms[ii]);
}
BX_FREE(g_allocator, sr.m_uniforms);
sr.m_uniforms = NULL;
sr.m_num = 0;
}
m_shaderHashMap.removeByHandle(_handle.idx);
}
2012-08-06 01:51:49 +04:00
}
BGFX_API_FUNC(ProgramHandle createProgram(ShaderHandle _vsh, ShaderHandle _fsh, bool _destroyShaders) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
if (!isValid(_vsh)
|| !isValid(_fsh) )
{
2016-10-20 04:11:47 +03:00
BX_TRACE("Vertex/fragment shader is invalid (vsh %d, fsh %d).", _vsh.idx, _fsh.idx);
2018-02-17 05:26:53 +03:00
return BGFX_INVALID_HANDLE;
}
2017-09-19 04:25:08 +03:00
ProgramHandle handle = { m_programHashMap.find(uint32_t(_fsh.idx<<16)|_vsh.idx) };
if (isValid(handle) )
2015-08-25 00:52:21 +03:00
{
ProgramRef& pr = m_programRef[handle.idx];
++pr.m_refCount;
2017-07-29 02:43:16 +03:00
shaderIncRef(pr.m_vsh);
shaderIncRef(pr.m_fsh);
2015-08-25 00:52:21 +03:00
}
2017-09-19 04:25:08 +03:00
else
{
2017-09-19 04:25:08 +03:00
const ShaderRef& vsr = m_shaderRef[_vsh.idx];
const ShaderRef& fsr = m_shaderRef[_fsh.idx];
if (vsr.m_hashOut != fsr.m_hashIn)
2017-09-19 04:25:08 +03:00
{
BX_TRACE("Vertex shader output doesn't match fragment shader input.");
2018-02-17 05:26:53 +03:00
return BGFX_INVALID_HANDLE;
2017-09-19 04:25:08 +03:00
}
2015-08-25 00:52:21 +03:00
2017-09-19 04:25:08 +03:00
handle.idx = m_programHandle.alloc();
2017-09-19 04:25:08 +03:00
BX_WARN(isValid(handle), "Failed to allocate program handle.");
if (isValid(handle) )
{
shaderIncRef(_vsh);
shaderIncRef(_fsh);
ProgramRef& pr = m_programRef[handle.idx];
pr.m_vsh = _vsh;
pr.m_fsh = _fsh;
pr.m_refCount = 1;
const uint32_t key = uint32_t(_fsh.idx<<16)|_vsh.idx;
bool ok = m_programHashMap.insert(key, handle.idx);
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Program already exists (key: %x, handle: %3d)!", key, handle.idx); BX_UNUSED(ok);
2017-09-19 04:25:08 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateProgram);
cmdbuf.write(handle);
cmdbuf.write(_vsh);
cmdbuf.write(_fsh);
}
}
2012-08-06 01:51:49 +04:00
if (_destroyShaders)
{
shaderTakeOwnership(_vsh);
shaderTakeOwnership(_fsh);
}
2012-08-06 01:51:49 +04:00
return handle;
}
BGFX_API_FUNC(ProgramHandle createProgram(ShaderHandle _vsh, bool _destroyShader) )
2014-07-21 07:27:13 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2014-07-21 07:27:13 +04:00
if (!isValid(_vsh) )
{
2016-11-04 02:52:34 +03:00
BX_WARN(false, "Compute shader is invalid (vsh %d).", _vsh.idx);
2018-02-17 05:26:53 +03:00
return BGFX_INVALID_HANDLE;
2014-07-21 07:27:13 +04:00
}
2017-10-28 03:57:48 +03:00
ProgramHandle handle = { m_programHashMap.find(_vsh.idx) };
if (isValid(handle) )
2015-08-25 00:52:21 +03:00
{
ProgramRef& pr = m_programRef[handle.idx];
++pr.m_refCount;
shaderIncRef(pr.m_vsh);
2015-08-25 00:52:21 +03:00
}
2017-10-28 03:57:48 +03:00
else
2014-07-21 07:27:13 +04:00
{
2017-10-28 03:57:48 +03:00
handle.idx = m_programHandle.alloc();
2014-07-21 07:27:13 +04:00
2017-10-28 03:57:48 +03:00
BX_WARN(isValid(handle), "Failed to allocate program handle.");
if (isValid(handle) )
{
shaderIncRef(_vsh);
ProgramRef& pr = m_programRef[handle.idx];
pr.m_vsh = _vsh;
ShaderHandle fsh = BGFX_INVALID_HANDLE;
pr.m_fsh = fsh;
pr.m_refCount = 1;
2015-08-25 01:40:11 +03:00
2017-10-28 03:57:48 +03:00
const uint32_t key = uint32_t(_vsh.idx);
bool ok = m_programHashMap.insert(key, handle.idx);
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Program already exists (key: %x, handle: %3d)!", key, handle.idx); BX_UNUSED(ok);
2017-10-28 03:57:48 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateProgram);
cmdbuf.write(handle);
cmdbuf.write(_vsh);
cmdbuf.write(fsh);
}
2014-07-21 07:27:13 +04:00
}
if (_destroyShader)
{
shaderTakeOwnership(_vsh);
}
2014-07-21 07:27:13 +04:00
return handle;
}
2013-10-05 10:45:05 +04:00
BGFX_API_FUNC(void destroyProgram(ProgramHandle _handle) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-03-26 09:33:35 +03:00
BGFX_CHECK_HANDLE("destroyProgram", m_programHandle, _handle);
2015-08-25 00:52:21 +03:00
ProgramRef& pr = m_programRef[_handle.idx];
2017-08-08 03:41:08 +03:00
shaderDecRef(pr.m_vsh);
if (isValid(pr.m_fsh) )
{
shaderDecRef(pr.m_fsh);
}
2015-08-25 00:52:21 +03:00
int32_t refs = --pr.m_refCount;
if (0 == refs)
{
2016-11-04 02:52:34 +03:00
bool ok = m_submit->free(_handle); BX_UNUSED(ok);
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Program handle %d is already destroyed!", _handle.idx);
2016-11-04 02:52:34 +03:00
2015-08-25 00:52:21 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyProgram);
cmdbuf.write(_handle);
2016-09-09 03:00:16 +03:00
m_programHashMap.removeByHandle(_handle.idx);
2014-12-17 07:12:09 +03:00
}
2012-08-06 01:51:49 +04:00
}
BGFX_API_FUNC(TextureHandle createTexture(const Memory* _mem, uint64_t _flags, uint8_t _skip, TextureInfo* _info, BackbufferRatio::Enum _ratio, bool _immutable) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
TextureInfo ti;
if (NULL == _info)
2012-08-06 01:51:49 +04:00
{
_info = &ti;
}
2017-04-04 08:42:27 +03:00
bimg::ImageContainer imageContainer;
if (bimg::imageParse(imageContainer, _mem->data, _mem->size) )
{
calcTextureSize(*_info
, (uint16_t)imageContainer.m_width
, (uint16_t)imageContainer.m_height
, (uint16_t)imageContainer.m_depth
, imageContainer.m_cubeMap
2016-08-20 07:05:37 +03:00
, imageContainer.m_numMips > 1
2016-08-24 08:06:50 +03:00
, imageContainer.m_numLayers
, TextureFormat::Enum(imageContainer.m_format)
);
}
else
{
_info->format = TextureFormat::Unknown;
_info->storageSize = 0;
_info->width = 0;
_info->height = 0;
_info->depth = 0;
_info->numMips = 0;
_info->bitsPerPixel = 0;
_info->cubeMap = false;
2018-07-03 02:33:11 +03:00
return BGFX_INVALID_HANDLE;
2012-08-06 01:51:49 +04:00
}
2020-03-04 06:25:11 +03:00
_flags |= imageContainer.m_srgb ? BGFX_TEXTURE_SRGB : 0;
2012-08-06 01:51:49 +04:00
TextureHandle handle = { m_textureHandle.alloc() };
BX_WARN(isValid(handle), "Failed to allocate texture handle.");
2018-07-03 02:33:11 +03:00
if (!isValid(handle) )
{
2018-07-03 02:33:11 +03:00
release(_mem);
return BGFX_INVALID_HANDLE;
}
2014-02-06 11:07:11 +04:00
2018-07-03 02:33:11 +03:00
TextureRef& ref = m_textureRef[handle.idx];
ref.init(
_ratio
2020-10-10 06:47:50 +03:00
, uint16_t(imageContainer.m_width)
, uint16_t(imageContainer.m_height)
, uint16_t(imageContainer.m_depth)
2018-07-03 02:33:11 +03:00
, _info->format
, _info->storageSize
, imageContainer.m_numMips
2018-09-19 03:25:05 +03:00
, imageContainer.m_numLayers
2018-07-03 02:33:11 +03:00
, 0 != (g_caps.supported & BGFX_CAPS_TEXTURE_DIRECT_ACCESS)
, _immutable
2020-10-10 06:47:50 +03:00
, imageContainer.m_cubeMap
, _flags
2018-07-03 02:33:11 +03:00
);
2018-03-29 04:05:49 +03:00
if (ref.isRt() )
2018-07-03 02:33:11 +03:00
{
m_rtMemoryUsed += int64_t(ref.m_storageSize);
}
else
{
2018-07-03 02:33:11 +03:00
m_textureMemoryUsed += int64_t(ref.m_storageSize);
}
2018-07-03 02:33:11 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateTexture);
cmdbuf.write(handle);
cmdbuf.write(_mem);
cmdbuf.write(_flags);
cmdbuf.write(_skip);
setDebugName(convert(handle) );
2012-08-06 01:51:49 +04:00
return handle;
}
BGFX_API_FUNC(void setName(TextureHandle _handle, const bx::StringView& _name) )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
BGFX_CHECK_HANDLE("setName", m_textureHandle, _handle);
TextureRef& ref = m_textureRef[_handle.idx];
ref.m_name.set(_name);
setName(convert(_handle), _name);
}
void setDirectAccessPtr(TextureHandle _handle, void* _ptr)
{
TextureRef& ref = m_textureRef[_handle.idx];
ref.m_ptr = _ptr;
}
BGFX_API_FUNC(void* getDirectAccessPtr(TextureHandle _handle) )
{
BGFX_MUTEX_SCOPE(m_resourceApiLock);
BGFX_CHECK_HANDLE("getDirectAccessPtr", m_textureHandle, _handle);
TextureRef& ref = m_textureRef[_handle.idx];
return ref.m_ptr;
}
2013-10-05 10:45:05 +04:00
BGFX_API_FUNC(void destroyTexture(TextureHandle _handle) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-03-26 09:33:35 +03:00
BGFX_CHECK_HANDLE("destroyTexture", m_textureHandle, _handle);
2014-02-06 11:07:11 +04:00
if (!isValid(_handle) )
{
BX_WARN(false, "Passing invalid texture handle to bgfx::destroyTexture");
return;
}
textureDecRef(_handle);
}
2016-10-21 18:22:05 +03:00
BGFX_API_FUNC(uint32_t readTexture(TextureHandle _handle, void* _data, uint8_t _mip) )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2016-10-24 20:58:24 +03:00
BGFX_CHECK_HANDLE("readTexture", m_textureHandle, _handle);
const TextureRef& ref = m_textureRef[_handle.idx];
BX_ASSERT(ref.isReadBack(), "Can't read from texture which was not created with BGFX_TEXTURE_READ_BACK.");
BX_ASSERT(_mip < ref.m_numMips, "Invalid mip: %d num mips:", _mip, ref.m_numMips);
BX_UNUSED(ref);
2016-10-24 20:58:24 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::ReadTexture);
cmdbuf.write(_handle);
cmdbuf.write(_data);
2016-10-21 18:22:05 +03:00
cmdbuf.write(_mip);
return m_submit->m_frameNum + 2;
}
2018-09-19 03:25:05 +03:00
void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height, uint8_t _numMips, uint16_t _numLayers)
{
const TextureRef& ref = m_textureRef[_handle.idx];
BX_ASSERT(BackbufferRatio::Count != ref.m_bbRatio, "");
getTextureSizeFromRatio(BackbufferRatio::Enum(ref.m_bbRatio), _width, _height);
2016-08-23 00:17:08 +03:00
_numMips = calcNumMips(1 < _numMips, _width, _height);
BX_TRACE("Resize %3d: %4dx%d %s"
, _handle.idx
, _width
, _height
, bimg::getName(bimg::TextureFormat::Enum(ref.m_format) )
);
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::ResizeTexture);
cmdbuf.write(_handle);
cmdbuf.write(_width);
cmdbuf.write(_height);
cmdbuf.write(_numMips);
2018-09-19 03:25:05 +03:00
cmdbuf.write(_numLayers);
}
void textureTakeOwnership(TextureHandle _handle)
{
TextureRef& ref = m_textureRef[_handle.idx];
if (!ref.m_owned)
{
ref.m_owned = true;
textureDecRef(_handle);
}
}
2014-02-06 11:07:11 +04:00
void textureIncRef(TextureHandle _handle)
{
TextureRef& ref = m_textureRef[_handle.idx];
++ref.m_refCount;
}
void textureDecRef(TextureHandle _handle)
{
TextureRef& ref = m_textureRef[_handle.idx];
int32_t refs = --ref.m_refCount;
if (0 == refs)
{
ref.m_name.clear();
if (ref.isRt() )
2018-03-29 04:05:49 +03:00
{
m_rtMemoryUsed -= int64_t(ref.m_storageSize);
}
else
{
m_textureMemoryUsed -= int64_t(ref.m_storageSize);
}
2016-11-04 02:52:34 +03:00
bool ok = m_submit->free(_handle); BX_UNUSED(ok);
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Texture handle %d is already destroyed!", _handle.idx);
2016-11-04 02:52:34 +03:00
2014-02-06 11:07:11 +04:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyTexture);
cmdbuf.write(_handle);
}
2012-08-06 01:51:49 +04:00
}
2016-08-22 00:03:16 +03:00
BGFX_API_FUNC(void updateTexture(
TextureHandle _handle
, uint8_t _side
, uint8_t _mip
, uint16_t _x
, uint16_t _y
, uint16_t _z
, uint16_t _width
, uint16_t _height
, uint16_t _depth
, uint16_t _pitch
, const Memory* _mem
) )
2012-08-13 08:02:11 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
const TextureRef& ref = m_textureRef[_handle.idx];
if (ref.m_immutable)
{
BX_WARN(false, "Can't update immutable texture.");
release(_mem);
return;
}
2012-08-13 08:02:11 +04:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::UpdateTexture);
cmdbuf.write(_handle);
2012-08-20 05:50:23 +04:00
cmdbuf.write(_side);
2012-08-13 08:02:11 +04:00
cmdbuf.write(_mip);
Rect rect;
rect.m_x = _x;
rect.m_y = _y;
2016-08-22 00:03:16 +03:00
rect.m_width = _width;
2012-08-13 08:02:11 +04:00
rect.m_height = _height;
cmdbuf.write(rect);
2012-08-20 05:50:23 +04:00
cmdbuf.write(_z);
cmdbuf.write(_depth);
cmdbuf.write(_pitch);
2012-08-13 08:02:11 +04:00
cmdbuf.write(_mem);
}
2015-10-23 22:57:04 +03:00
2016-02-16 03:55:32 +03:00
BGFX_API_FUNC(FrameBufferHandle createFrameBuffer(uint8_t _num, const Attachment* _attachment, bool _destroyTextures) )
2015-10-23 22:57:04 +03:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
bx::ErrorAssert err;
2021-04-17 08:13:26 +03:00
isFrameBufferValid(_num, _attachment, &err);
if (!err.isOk() )
{
return BGFX_INVALID_HANDLE;
}
2015-10-23 22:57:04 +03:00
2014-02-06 11:07:11 +04:00
FrameBufferHandle handle = { m_frameBufferHandle.alloc() };
2014-09-08 04:17:38 +04:00
BX_WARN(isValid(handle), "Failed to allocate frame buffer handle.");
if (isValid(handle) )
{
2014-02-06 11:07:11 +04:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateFrameBuffer);
cmdbuf.write(handle);
2014-09-08 04:17:38 +04:00
cmdbuf.write(false);
2014-02-06 11:07:11 +04:00
cmdbuf.write(_num);
const TextureRef& firstTexture = m_textureRef[_attachment[0].handle.idx];
const BackbufferRatio::Enum bbRatio = BackbufferRatio::Enum(firstTexture.m_bbRatio);
2021-04-02 06:09:16 +03:00
FrameBufferRef& fbr = m_frameBufferRef[handle.idx];
if (BackbufferRatio::Count == bbRatio)
{
2021-04-02 06:09:16 +03:00
fbr.m_width = bx::max<uint16_t>(firstTexture.m_width >> _attachment[0].mip, 1);
fbr.m_height = bx::max<uint16_t>(firstTexture.m_height >> _attachment[0].mip, 1);
}
2021-04-02 06:09:16 +03:00
fbr.m_window = false;
bx::memSet(fbr.un.m_th, 0xff, sizeof(fbr.un.m_th) );
2014-02-06 11:07:11 +04:00
for (uint32_t ii = 0; ii < _num; ++ii)
{
2016-02-16 03:55:32 +03:00
TextureHandle texHandle = _attachment[ii].handle;
2021-04-02 06:09:16 +03:00
fbr.un.m_th[ii] = texHandle;
textureIncRef(texHandle);
2014-02-06 11:07:11 +04:00
}
2016-02-16 03:55:32 +03:00
cmdbuf.write(_attachment, sizeof(Attachment) * _num);
}
2012-08-06 01:51:49 +04:00
if (_destroyTextures)
{
for (uint32_t ii = 0; ii < _num; ++ii)
{
2016-02-16 03:55:32 +03:00
textureTakeOwnership(_attachment[ii].handle);
}
}
2012-08-06 01:51:49 +04:00
return handle;
}
BGFX_API_FUNC(FrameBufferHandle createFrameBuffer(void* _nwh, uint16_t _width, uint16_t _height, TextureFormat::Enum _format, TextureFormat::Enum _depthFormat) )
2014-09-08 04:17:38 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2014-09-08 04:17:38 +04:00
FrameBufferHandle handle = { m_frameBufferHandle.alloc() };
BX_WARN(isValid(handle), "Failed to allocate frame buffer handle.");
if (isValid(handle) )
{
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateFrameBuffer);
cmdbuf.write(handle);
cmdbuf.write(true);
cmdbuf.write(_nwh);
cmdbuf.write(_width);
cmdbuf.write(_height);
cmdbuf.write(_format);
2014-09-08 04:17:38 +04:00
cmdbuf.write(_depthFormat);
2021-04-02 06:09:16 +03:00
FrameBufferRef& fbr = m_frameBufferRef[handle.idx];
fbr.m_width = _width;
fbr.m_height = _height;
fbr.m_window = true;
fbr.un.m_nwh = _nwh;
2014-09-08 04:17:38 +04:00
}
return handle;
}
BGFX_API_FUNC(void setName(FrameBufferHandle _handle, const bx::StringView& _name) )
{
BGFX_MUTEX_SCOPE(m_resourceApiLock);
BGFX_CHECK_HANDLE("setName", m_frameBufferHandle, _handle);
2021-04-02 06:09:16 +03:00
FrameBufferRef& fbr = m_frameBufferRef[_handle.idx];
fbr.m_name.set(_name);
// setName(convert(_handle), _name);
}
BGFX_API_FUNC(TextureHandle getTexture(FrameBufferHandle _handle, uint8_t _attachment) )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
BGFX_CHECK_HANDLE("getTexture", m_frameBufferHandle, _handle);
2021-04-02 06:09:16 +03:00
const FrameBufferRef& fbr = m_frameBufferRef[_handle.idx];
if (!fbr.m_window)
{
2018-02-11 02:49:30 +03:00
const uint32_t attachment = bx::min<uint32_t>(_attachment, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS);
2021-04-02 06:09:16 +03:00
return fbr.un.m_th[attachment];
}
2018-02-17 05:26:53 +03:00
return BGFX_INVALID_HANDLE;
}
2014-02-06 11:07:11 +04:00
BGFX_API_FUNC(void destroyFrameBuffer(FrameBufferHandle _handle) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-03-26 09:33:35 +03:00
BGFX_CHECK_HANDLE("destroyFrameBuffer", m_frameBufferHandle, _handle);
2016-11-04 02:52:34 +03:00
bool ok = m_submit->free(_handle); BX_UNUSED(ok);
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Frame buffer handle %d is already destroyed!", _handle.idx);
2015-03-26 09:33:35 +03:00
2014-02-06 11:07:11 +04:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyFrameBuffer);
2012-08-06 01:51:49 +04:00
cmdbuf.write(_handle);
2014-02-06 11:07:11 +04:00
2021-04-02 06:09:16 +03:00
FrameBufferRef& fbr = m_frameBufferRef[_handle.idx];
fbr.m_name.clear();
2021-04-02 06:09:16 +03:00
if (!fbr.m_window)
2014-02-06 11:07:11 +04:00
{
2021-04-02 06:09:16 +03:00
for (uint32_t ii = 0; ii < BX_COUNTOF(fbr.un.m_th); ++ii)
2014-02-06 11:07:11 +04:00
{
2021-04-02 06:09:16 +03:00
TextureHandle th = fbr.un.m_th[ii];
2014-09-08 04:17:38 +04:00
if (isValid(th) )
{
textureDecRef(th);
}
2014-02-06 11:07:11 +04:00
}
}
2012-08-06 01:51:49 +04:00
}
2013-10-05 10:45:05 +04:00
BGFX_API_FUNC(UniformHandle createUniform(const char* _name, UniformType::Enum _type, uint16_t _num) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
{
bx::ErrorAssert err;
2021-10-01 03:24:36 +03:00
isIdentifierValid(_name, &err);
if (!err.isOk() )
{
return BGFX_INVALID_HANDLE;
}
}
2012-08-06 01:51:49 +04:00
2018-06-16 18:34:06 +03:00
_num = bx::max<uint16_t>(1, _num);
2017-03-28 05:27:52 +03:00
2017-09-24 02:27:16 +03:00
uint16_t idx = m_uniformHashMap.find(bx::hash<bx::HashMurmur2A>(_name) );
2017-06-10 07:57:08 +03:00
if (kInvalidHandle != idx)
{
UniformHandle handle = { idx };
UniformRef& uniform = m_uniformRef[handle.idx];
2020-06-16 20:06:18 +03:00
BX_ASSERT(uniform.m_type == _type
2016-10-26 06:16:00 +03:00
, "Uniform type mismatch (type: %d, expected %d)."
, _type
, uniform.m_type
);
uint32_t oldsize = g_uniformTypeSize[uniform.m_type];
uint32_t newsize = g_uniformTypeSize[_type];
if (oldsize < newsize
|| uniform.m_num < _num)
{
uniform.m_type = oldsize < newsize ? _type : uniform.m_type;
2018-06-16 18:34:06 +03:00
uniform.m_num = bx::max<uint16_t>(uniform.m_num, _num);
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateUniform);
cmdbuf.write(handle);
cmdbuf.write(uniform.m_type);
cmdbuf.write(uniform.m_num);
2017-04-17 07:56:17 +03:00
uint8_t len = (uint8_t)bx::strLen(_name)+1;
cmdbuf.write(len);
cmdbuf.write(_name, len);
}
++uniform.m_refCount;
return handle;
}
2012-08-06 01:51:49 +04:00
UniformHandle handle = { m_uniformHandle.alloc() };
2018-07-03 02:33:11 +03:00
if (!isValid(handle) )
{
2018-07-03 02:33:11 +03:00
BX_TRACE("Failed to allocate uniform handle.");
return BGFX_INVALID_HANDLE;
}
2014-08-23 21:37:25 +04:00
2018-07-03 02:33:11 +03:00
BX_TRACE("Creating uniform (handle %3d) %s", handle.idx, _name);
2018-07-03 02:33:11 +03:00
UniformRef& uniform = m_uniformRef[handle.idx];
uniform.m_name.set(_name);
uniform.m_refCount = 1;
uniform.m_type = _type;
uniform.m_num = _num;
2018-07-03 02:33:11 +03:00
bool ok = m_uniformHashMap.insert(bx::hash<bx::HashMurmur2A>(_name), handle.idx);
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Uniform already exists (name: %s)!", _name); BX_UNUSED(ok);
2018-07-03 02:33:11 +03:00
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateUniform);
cmdbuf.write(handle);
cmdbuf.write(_type);
cmdbuf.write(_num);
uint8_t len = (uint8_t)bx::strLen(_name)+1;
cmdbuf.write(len);
cmdbuf.write(_name, len);
2012-08-06 01:51:49 +04:00
return handle;
}
BGFX_API_FUNC(void getUniformInfo(UniformHandle _handle, UniformInfo& _info) )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
BGFX_CHECK_HANDLE("getUniformInfo", m_uniformHandle, _handle);
UniformRef& uniform = m_uniformRef[_handle.idx];
2017-04-17 07:56:17 +03:00
bx::strCopy(_info.name, sizeof(_info.name), uniform.m_name.getPtr() );
_info.type = uniform.m_type;
_info.num = uniform.m_num;
}
2013-10-05 10:45:05 +04:00
BGFX_API_FUNC(void destroyUniform(UniformHandle _handle) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-03-26 09:33:35 +03:00
BGFX_CHECK_HANDLE("destroyUniform", m_uniformHandle, _handle);
UniformRef& uniform = m_uniformRef[_handle.idx];
2020-06-16 20:06:18 +03:00
BX_ASSERT(uniform.m_refCount > 0, "Destroying already destroyed uniform %d.", _handle.idx);
int32_t refs = --uniform.m_refCount;
if (0 == refs)
{
2016-11-04 02:52:34 +03:00
bool ok = m_submit->free(_handle); BX_UNUSED(ok);
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Uniform handle %d is already destroyed!", _handle.idx);
2016-11-04 02:52:34 +03:00
uniform.m_name.clear();
m_uniformHashMap.removeByHandle(_handle.idx);
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyUniform);
cmdbuf.write(_handle);
}
2012-08-06 01:51:49 +04:00
}
2015-11-02 04:28:23 +03:00
BGFX_API_FUNC(OcclusionQueryHandle createOcclusionQuery() )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-11-02 04:28:23 +03:00
OcclusionQueryHandle handle = { m_occlusionQueryHandle.alloc() };
if (isValid(handle) )
{
2017-03-07 04:23:22 +03:00
m_submit->m_occlusion[handle.idx] = INT32_MIN;
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::InvalidateOcclusionQuery);
cmdbuf.write(handle);
}
2015-11-02 04:28:23 +03:00
return handle;
}
2017-03-07 04:23:22 +03:00
BGFX_API_FUNC(OcclusionQueryResult::Enum getResult(OcclusionQueryHandle _handle, int32_t* _result) )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2017-02-04 05:25:35 +03:00
BGFX_CHECK_HANDLE("getResult", m_occlusionQueryHandle, _handle);
switch (m_submit->m_occlusion[_handle.idx])
{
case 0: return OcclusionQueryResult::Invisible;
2017-03-07 04:23:22 +03:00
case INT32_MIN: return OcclusionQueryResult::NoResult;
default: break;
}
if (NULL != _result)
{
*_result = m_submit->m_occlusion[_handle.idx];
}
return OcclusionQueryResult::Visible;
}
2015-11-02 04:28:23 +03:00
BGFX_API_FUNC(void destroyOcclusionQuery(OcclusionQueryHandle _handle) )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2015-11-02 04:28:23 +03:00
BGFX_CHECK_HANDLE("destroyOcclusionQuery", m_occlusionQueryHandle, _handle);
m_freeOcclusionQueryHandle[m_numFreeOcclusionQueryHandles++] = _handle;
2015-11-02 04:28:23 +03:00
}
2017-03-03 06:29:34 +03:00
BGFX_API_FUNC(void requestScreenShot(FrameBufferHandle _handle, const char* _filePath) )
2012-08-06 01:51:49 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2017-03-03 06:29:34 +03:00
BGFX_CHECK_HANDLE_INVALID_OK("requestScreenShot", m_frameBufferHandle, _handle);
if (isValid(_handle) )
{
2021-04-02 06:09:16 +03:00
const FrameBufferRef& fbr = m_frameBufferRef[_handle.idx];
if (!fbr.m_window)
{
BX_TRACE("requestScreenShot can be done only for window frame buffer handles (handle: %d).", _handle.idx);
return;
}
}
if (m_submit->m_numScreenShots >= BGFX_CONFIG_MAX_SCREENSHOTS)
{
BX_TRACE("Only %d screenshots can be requested.", BGFX_CONFIG_MAX_SCREENSHOTS);
return;
}
2020-11-11 04:14:54 +03:00
for (uint8_t ii = 0, num = m_submit->m_numScreenShots; ii < num; ++ii)
{
const ScreenShot& screenShot = m_submit->m_screenShot[ii];
if (screenShot.handle.idx == _handle.idx)
{
BX_TRACE("Already requested screenshot on handle %d.", _handle.idx);
return;
}
}
ScreenShot& screenShot = m_submit->m_screenShot[m_submit->m_numScreenShots++];
screenShot.handle = _handle;
screenShot.filePath.set(_filePath);
2012-08-06 01:51:49 +04:00
}
2015-09-17 03:21:28 +03:00
BGFX_API_FUNC(void setPaletteColor(uint8_t _index, const float _rgba[4]) )
2014-09-01 22:24:51 +04:00
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
2020-06-16 20:06:18 +03:00
BX_ASSERT(_index < BGFX_CONFIG_MAX_COLOR_PALETTE, "Color palette index out of bounds %d (max: %d)."
2014-09-01 22:24:51 +04:00
, _index
2015-09-17 03:21:28 +03:00
, BGFX_CONFIG_MAX_COLOR_PALETTE
2014-09-01 22:24:51 +04:00
);
2017-02-09 06:55:31 +03:00
bx::memCopy(&m_clearColor[_index][0], _rgba, 16);
2015-09-18 07:17:38 +03:00
m_colorPaletteDirty = 2;
2014-09-01 22:24:51 +04:00
}
BGFX_API_FUNC(void setViewName(ViewId _id, const char* _name) )
{
2017-10-29 04:43:21 +03:00
BGFX_MUTEX_SCOPE(m_resourceApiLock);
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::UpdateViewName);
cmdbuf.write(_id);
2017-04-17 07:56:17 +03:00
uint16_t len = (uint16_t)bx::strLen(_name)+1;
cmdbuf.write(len);
cmdbuf.write(_name, len);
}
BGFX_API_FUNC(void setViewRect(ViewId _id, uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height) )
2012-08-06 01:51:49 +04:00
{
m_view[_id].setRect(_x, _y, _width, _height);
2012-08-06 01:51:49 +04:00
}
BGFX_API_FUNC(void setViewScissor(ViewId _id, uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height) )
2013-07-15 01:32:09 +04:00
{
m_view[_id].setScissor(_x, _y, _width, _height);
2013-07-15 01:32:09 +04:00
}
BGFX_API_FUNC(void setViewClear(ViewId _id, uint16_t _flags, uint32_t _rgba, float _depth, uint8_t _stencil) )
2012-08-06 01:51:49 +04:00
{
2021-10-14 05:54:27 +03:00
BX_ASSERT(bx::isEqual(_depth, bx::clamp(_depth, 0.0f, 1.0f), 0.0001f)
, "Clear depth value must be between 0.0 and 1.0 (_depth %f)."
, _depth
);
m_view[_id].setClear(_flags, _rgba, _depth, _stencil);
2014-09-01 22:24:51 +04:00
}
BGFX_API_FUNC(void setViewClear(ViewId _id, uint16_t _flags, float _depth, uint8_t _stencil, uint8_t _0, uint8_t _1, uint8_t _2, uint8_t _3, uint8_t _4, uint8_t _5, uint8_t _6, uint8_t _7) )
2014-09-01 22:24:51 +04:00
{
2021-10-14 05:54:27 +03:00
BX_ASSERT(bx::isEqual(_depth, bx::clamp(_depth, 0.0f, 1.0f), 0.0001f)
, "Clear depth value must be between 0.0 and 1.0 (_depth %f)."
, _depth
);
m_view[_id].setClear(_flags, _depth, _stencil, _0, _1, _2, _3, _4, _5, _6, _7);
2012-08-06 01:51:49 +04:00
}
BGFX_API_FUNC(void setViewMode(ViewId _id, ViewMode::Enum _mode) )
2012-08-06 01:51:49 +04:00
{
m_view[_id].setMode(_mode);
2012-08-06 01:51:49 +04:00
}
BGFX_API_FUNC(void setViewFrameBuffer(ViewId _id, FrameBufferHandle _handle) )
2012-08-06 01:51:49 +04:00
{
2015-03-27 01:01:09 +03:00
BGFX_CHECK_HANDLE_INVALID_OK("setViewFrameBuffer", m_frameBufferHandle, _handle);
m_view[_id].setFrameBuffer(_handle);
2012-08-06 01:51:49 +04:00
}
2018-12-22 10:25:30 +03:00
BGFX_API_FUNC(void setViewTransform(ViewId _id, const void* _view, const void* _proj) )
{
2018-12-22 10:25:30 +03:00
m_view[_id].setTransform(_view, _proj);
}
BGFX_API_FUNC(void resetView(ViewId _id) )
2015-10-28 01:14:48 +03:00
{
m_view[_id].reset();
2015-10-28 01:14:48 +03:00
}
2017-11-27 20:06:57 +03:00
BGFX_API_FUNC(void setViewOrder(ViewId _id, uint16_t _num, const ViewId* _order) )
{
2018-02-11 02:49:30 +03:00
const uint32_t num = bx::min(_id + _num, BGFX_CONFIG_MAX_VIEWS) - _id;
if (NULL == _order)
{
for (uint32_t ii = 0; ii < num; ++ii)
{
2017-11-27 20:06:57 +03:00
ViewId id = ViewId(ii+_id);
m_viewRemap[id] = id;
}
}
else
{
2017-11-28 03:34:27 +03:00
bx::memCopy(&m_viewRemap[_id], _order, num*sizeof(ViewId) );
}
}
BGFX_API_FUNC(Encoder* begin(bool _forThread) );
2017-10-29 04:43:21 +03:00
BGFX_API_FUNC(void end(Encoder* _encoder) );
BGFX_API_FUNC(uint32_t frame(bool _capture = false) );
uint32_t getSeqIncr(ViewId _id)
2017-10-08 07:19:47 +03:00
{
return bx::atomicFetchAndAdd<uint32_t>(&m_seq[_id], 1);
2017-10-08 07:19:47 +03:00
}
void dumpViewStats();
void freeDynamicBuffers();
void freeAllHandles(Frame* _frame);
void frameNoRenderWait();
void swap();
2012-08-06 01:51:49 +04:00
2013-10-06 06:46:57 +04:00
// render thread
void flip();
RenderFrame::Enum renderFrame(int32_t _msecs = -1);
void flushTextureUpdateBatch(CommandBuffer& _cmdbuf);
void rendererExecCommands(CommandBuffer& _cmdbuf);
2012-08-06 01:51:49 +04:00
#if BGFX_CONFIG_MULTITHREADED
2016-11-23 04:55:45 +03:00
void apiSemPost()
2012-08-06 01:51:49 +04:00
{
if (!m_singleThreaded)
{
m_apiSem.post();
}
2012-08-06 01:51:49 +04:00
}
bool apiSemWait(int32_t _msecs = -1)
2012-08-06 01:51:49 +04:00
{
if (m_singleThreaded)
{
return true;
}
2017-10-07 04:07:40 +03:00
BGFX_PROFILER_SCOPE("bgfx/API thread wait", 0xff2040ff);
int64_t start = bx::getHPCounter();
bool ok = m_apiSem.wait(_msecs);
if (ok)
{
m_render->m_waitSubmit = bx::getHPCounter()-start;
2016-05-15 18:27:13 +03:00
m_submit->m_perfStats.waitSubmit = m_submit->m_waitSubmit;
return true;
}
return false;
2012-08-06 01:51:49 +04:00
}
void renderSemPost()
{
if (!m_singleThreaded)
{
m_renderSem.post();
}
2012-08-06 01:51:49 +04:00
}
void renderSemWait()
{
if (!m_singleThreaded)
{
2017-10-07 04:07:40 +03:00
BGFX_PROFILER_SCOPE("bgfx/Render thread wait", 0xff2040ff);
int64_t start = bx::getHPCounter();
bool ok = m_renderSem.wait();
2020-06-16 20:06:18 +03:00
BX_ASSERT(ok, "Semaphore wait failed."); BX_UNUSED(ok);
m_submit->m_waitRender = bx::getHPCounter() - start;
2016-05-15 18:27:13 +03:00
m_submit->m_perfStats.waitRender = m_submit->m_waitRender;
}
2012-08-06 01:51:49 +04:00
}
2017-11-10 07:21:56 +03:00
void encoderApiWait()
2017-10-29 04:43:21 +03:00
{
uint16_t numEncoders = m_encoderHandle->getNumHandles();
2017-11-11 07:30:16 +03:00
for (uint16_t ii = 1; ii < numEncoders; ++ii)
2017-10-29 04:43:21 +03:00
{
2017-11-11 07:30:16 +03:00
m_encoderEndSem.wait();
2017-11-10 07:21:56 +03:00
}
2017-11-03 08:06:39 +03:00
2017-11-11 07:30:16 +03:00
for (uint16_t ii = 0; ii < numEncoders; ++ii)
2017-11-10 07:21:56 +03:00
{
uint16_t idx = m_encoderHandle->getHandleAt(ii);
2017-11-11 07:30:16 +03:00
m_encoderStats[ii].cpuTimeBegin = m_encoder[idx].m_cpuTimeBegin;
m_encoderStats[ii].cpuTimeEnd = m_encoder[idx].m_cpuTimeEnd;
2017-10-29 04:43:21 +03:00
}
2017-11-11 07:30:16 +03:00
m_submit->m_perfStats.numEncoders = uint8_t(numEncoders);
m_encoderHandle->reset();
uint16_t idx = m_encoderHandle->alloc();
2020-06-16 20:06:18 +03:00
BX_ASSERT(0 == idx, "Internal encoder handle is not 0 (idx %d).", idx); BX_UNUSED(idx);
2017-10-29 04:43:21 +03:00
}
2013-08-04 09:15:13 +04:00
bx::Semaphore m_renderSem;
bx::Semaphore m_apiSem;
2017-11-11 07:30:16 +03:00
bx::Semaphore m_encoderEndSem;
2017-10-29 04:43:21 +03:00
bx::Mutex m_encoderApiLock;
bx::Mutex m_resourceApiLock;
2017-11-11 07:30:16 +03:00
bx::Thread m_thread;
2012-08-06 01:51:49 +04:00
#else
2016-11-23 04:55:45 +03:00
void apiSemPost()
2012-08-06 01:51:49 +04:00
{
}
2016-10-14 05:17:41 +03:00
bool apiSemWait(int32_t _msecs = -1)
2012-08-06 01:51:49 +04:00
{
2016-10-14 05:17:41 +03:00
BX_UNUSED(_msecs);
return true;
2012-08-06 01:51:49 +04:00
}
void renderSemPost()
{
}
void renderSemWait()
{
}
2017-10-29 04:43:21 +03:00
void encoderApiWait()
{
2017-11-04 20:32:31 +03:00
m_encoderStats[0].cpuTimeBegin = m_encoder[0].m_cpuTimeBegin;
m_encoderStats[0].cpuTimeEnd = m_encoder[0].m_cpuTimeEnd;
m_submit->m_perfStats.numEncoders = 1;
2017-10-29 04:43:21 +03:00
}
2012-08-06 01:51:49 +04:00
#endif // BGFX_CONFIG_MULTITHREADED
EncoderStats* m_encoderStats;
Encoder* m_encoder0;
EncoderImpl* m_encoder;
2017-10-29 04:43:21 +03:00
uint32_t m_numEncoders;
bx::HandleAlloc* m_encoderHandle;
2017-11-03 08:06:39 +03:00
Frame m_frame[1+(BGFX_CONFIG_MULTITHREADED ? 1 : 0)];
2012-08-06 01:51:49 +04:00
Frame* m_render;
Frame* m_submit;
uint64_t m_tempKeys[BGFX_CONFIG_MAX_DRAW_CALLS];
2015-04-10 05:38:51 +03:00
RenderItemCount m_tempValues[BGFX_CONFIG_MAX_DRAW_CALLS];
2012-08-06 01:51:49 +04:00
IndexBuffer m_indexBuffers[BGFX_CONFIG_MAX_INDEX_BUFFERS];
2014-12-10 10:16:27 +03:00
VertexBuffer m_vertexBuffers[BGFX_CONFIG_MAX_VERTEX_BUFFERS];
2015-01-24 09:18:07 +03:00
DynamicIndexBuffer m_dynamicIndexBuffers[BGFX_CONFIG_MAX_DYNAMIC_INDEX_BUFFERS];
2012-08-06 01:51:49 +04:00
DynamicVertexBuffer m_dynamicVertexBuffers[BGFX_CONFIG_MAX_DYNAMIC_VERTEX_BUFFERS];
uint16_t m_numFreeDynamicIndexBufferHandles;
uint16_t m_numFreeDynamicVertexBufferHandles;
uint16_t m_numFreeOcclusionQueryHandles;
DynamicIndexBufferHandle m_freeDynamicIndexBufferHandle[BGFX_CONFIG_MAX_DYNAMIC_INDEX_BUFFERS];
2012-08-06 01:51:49 +04:00
DynamicVertexBufferHandle m_freeDynamicVertexBufferHandle[BGFX_CONFIG_MAX_DYNAMIC_VERTEX_BUFFERS];
OcclusionQueryHandle m_freeOcclusionQueryHandle[BGFX_CONFIG_MAX_OCCLUSION_QUERIES];
2012-08-06 01:51:49 +04:00
NonLocalAllocator m_dynIndexBufferAllocator;
2013-09-21 09:13:58 +04:00
bx::HandleAllocT<BGFX_CONFIG_MAX_DYNAMIC_INDEX_BUFFERS> m_dynamicIndexBufferHandle;
NonLocalAllocator m_dynVertexBufferAllocator;
2013-09-21 09:13:58 +04:00
bx::HandleAllocT<BGFX_CONFIG_MAX_DYNAMIC_VERTEX_BUFFERS> m_dynamicVertexBufferHandle;
bx::HandleAllocT<BGFX_CONFIG_MAX_INDEX_BUFFERS> m_indexBufferHandle;
2019-08-17 20:35:21 +03:00
bx::HandleAllocT<BGFX_CONFIG_MAX_VERTEX_LAYOUTS > m_layoutHandle;
2013-09-21 09:13:58 +04:00
bx::HandleAllocT<BGFX_CONFIG_MAX_VERTEX_BUFFERS> m_vertexBufferHandle;
bx::HandleAllocT<BGFX_CONFIG_MAX_SHADERS> m_shaderHandle;
2013-09-21 09:13:58 +04:00
bx::HandleAllocT<BGFX_CONFIG_MAX_PROGRAMS> m_programHandle;
bx::HandleAllocT<BGFX_CONFIG_MAX_TEXTURES> m_textureHandle;
2014-02-06 11:07:11 +04:00
bx::HandleAllocT<BGFX_CONFIG_MAX_FRAME_BUFFERS> m_frameBufferHandle;
2013-09-21 09:13:58 +04:00
bx::HandleAllocT<BGFX_CONFIG_MAX_UNIFORMS> m_uniformHandle;
2017-02-04 05:25:35 +03:00
bx::HandleAllocT<BGFX_CONFIG_MAX_OCCLUSION_QUERIES> m_occlusionQueryHandle;
2012-08-06 01:51:49 +04:00
typedef bx::HandleHashMapT<BGFX_CONFIG_MAX_UNIFORMS*2> UniformHashMap;
UniformHashMap m_uniformHashMap;
UniformRef m_uniformRef[BGFX_CONFIG_MAX_UNIFORMS];
2015-08-25 00:52:21 +03:00
typedef bx::HandleHashMapT<BGFX_CONFIG_MAX_SHADERS*2> ShaderHashMap;
ShaderHashMap m_shaderHashMap;
ShaderRef m_shaderRef[BGFX_CONFIG_MAX_SHADERS];
2015-08-25 00:52:21 +03:00
typedef bx::HandleHashMapT<BGFX_CONFIG_MAX_PROGRAMS*2> ProgramHashMap;
2015-08-25 00:52:21 +03:00
ProgramHashMap m_programHashMap;
ProgramRef m_programRef[BGFX_CONFIG_MAX_PROGRAMS];
2015-08-25 00:52:21 +03:00
2021-04-02 06:09:16 +03:00
TextureRef m_textureRef[BGFX_CONFIG_MAX_TEXTURES];
FrameBufferRef m_frameBufferRef[BGFX_CONFIG_MAX_FRAME_BUFFERS];
VertexLayoutRef m_vertexLayoutRef;
2012-08-06 01:51:49 +04:00
2017-11-28 00:11:57 +03:00
ViewId m_viewRemap[BGFX_CONFIG_MAX_VIEWS];
uint32_t m_seq[BGFX_CONFIG_MAX_VIEWS];
View m_view[BGFX_CONFIG_MAX_VIEWS];
2014-09-01 22:24:51 +04:00
2015-09-17 03:21:28 +03:00
float m_clearColor[BGFX_CONFIG_MAX_COLOR_PALETTE][4];
2012-08-06 01:51:49 +04:00
2015-09-18 07:17:38 +03:00
uint8_t m_colorPaletteDirty;
2014-09-01 22:24:51 +04:00
Init m_init;
2017-09-23 07:39:16 +03:00
int64_t m_frameTimeLast;
2012-08-06 01:51:49 +04:00
uint32_t m_frames;
uint32_t m_debug;
2018-03-29 04:05:49 +03:00
int64_t m_rtMemoryUsed;
int64_t m_textureMemoryUsed;
2012-08-06 01:51:49 +04:00
TextVideoMemBlitter m_textVideoMemBlitter;
ClearQuad m_clearQuad;
RendererContextI* m_renderCtx;
2012-08-06 01:51:49 +04:00
bool m_rendererInitialized;
bool m_exit;
2015-04-15 21:49:20 +03:00
bool m_flipAfterRender;
bool m_singleThreaded;
2016-11-09 05:01:26 +03:00
bool m_flipped;
typedef UpdateBatchT<256> TextureUpdateBatch;
2014-10-14 08:31:18 +04:00
BX_ALIGN_DECL_CACHE_LINE(TextureUpdateBatch m_textureUpdateBatch);
2012-08-06 01:51:49 +04:00
};
2013-10-05 10:45:05 +04:00
#undef BGFX_API_FUNC
2012-08-06 01:51:49 +04:00
} // namespace bgfx
#endif // BGFX_P_H_HEADER_GUARD