mirror of
https://github.com/holub/mame
synced 2025-06-12 15:45:52 +03:00
571 lines
13 KiB
C++
571 lines
13 KiB
C++
/*
|
|
* Copyright 2011-2017 Branimir Karadzic. All rights reserved.
|
|
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
|
|
*/
|
|
|
|
#ifndef BGFX_RENDERER_H_HEADER_GUARD
|
|
#define BGFX_RENDERER_H_HEADER_GUARD
|
|
|
|
#include "bgfx_p.h"
|
|
|
|
namespace bgfx
|
|
{
|
|
struct BlitState
|
|
{
|
|
BlitState(const Frame* _frame)
|
|
: m_frame(_frame)
|
|
, m_item(0)
|
|
{
|
|
m_key.decode(_frame->m_blitKeys[0]);
|
|
}
|
|
|
|
bool hasItem(uint16_t _view) const
|
|
{
|
|
return m_item < m_frame->m_numBlitItems
|
|
&& m_key.m_view <= _view
|
|
;
|
|
}
|
|
|
|
const BlitItem& advance()
|
|
{
|
|
const BlitItem& bi = m_frame->m_blitItem[m_key.m_item];
|
|
|
|
++m_item;
|
|
m_key.decode(m_frame->m_blitKeys[m_item]);
|
|
|
|
return bi;
|
|
}
|
|
|
|
const Frame* m_frame;
|
|
BlitKey m_key;
|
|
uint16_t m_item;
|
|
};
|
|
|
|
struct ViewState
|
|
{
|
|
ViewState()
|
|
{
|
|
}
|
|
|
|
ViewState(Frame* _frame, bool _hmdEnabled)
|
|
{
|
|
reset(_frame, _hmdEnabled);
|
|
}
|
|
|
|
void reset(Frame* _frame, bool _hmdEnabled)
|
|
{
|
|
m_alphaRef = 0.0f;
|
|
m_invViewCached = UINT16_MAX;
|
|
m_invProjCached = UINT16_MAX;
|
|
m_invViewProjCached = UINT16_MAX;
|
|
|
|
m_view[0] = m_viewTmp[0];
|
|
m_view[1] = m_viewTmp[1];
|
|
|
|
if (_hmdEnabled)
|
|
{
|
|
HMD& hmd = _frame->m_hmd;
|
|
|
|
m_view[0] = m_viewTmp[0];
|
|
Matrix4 viewAdjust;
|
|
bx::mtxIdentity(viewAdjust.un.val);
|
|
|
|
for (uint32_t eye = 0; eye < 2; ++eye)
|
|
{
|
|
const HMD::Eye& hmdEye = hmd.eye[eye];
|
|
viewAdjust.un.val[12] = hmdEye.viewOffset[0];
|
|
viewAdjust.un.val[13] = hmdEye.viewOffset[1];
|
|
viewAdjust.un.val[14] = hmdEye.viewOffset[2];
|
|
|
|
for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii)
|
|
{
|
|
if (BGFX_VIEW_STEREO == (_frame->m_view[ii].m_flags & BGFX_VIEW_STEREO) )
|
|
{
|
|
bx::float4x4_mul(&m_view[eye][ii].un.f4x4
|
|
, &_frame->m_view[ii].m_view.un.f4x4
|
|
, &viewAdjust.un.f4x4
|
|
);
|
|
}
|
|
else
|
|
{
|
|
bx::memCopy(&m_view[0][ii].un.f4x4, &_frame->m_view[ii].m_view.un.f4x4, sizeof(Matrix4) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii)
|
|
{
|
|
bx::memCopy(&m_view[0][ii].un.f4x4, &_frame->m_view[ii].m_view.un.f4x4, sizeof(Matrix4) );
|
|
}
|
|
}
|
|
|
|
for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii)
|
|
{
|
|
for (uint32_t eye = 0; eye < uint32_t(_hmdEnabled)+1; ++eye)
|
|
{
|
|
bx::float4x4_mul(&m_viewProj[eye][ii].un.f4x4
|
|
, &m_view[eye][ii].un.f4x4
|
|
, &_frame->m_view[ii].m_proj[eye].un.f4x4
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<uint16_t mtxRegs, typename RendererContext, typename Program, typename Draw>
|
|
void setPredefined(RendererContext* _renderer, uint16_t _view, uint8_t _eye, const Program& _program, const Frame* _frame, const Draw& _draw)
|
|
{
|
|
const FrameCache& frameCache = _frame->m_frameCache;
|
|
|
|
for (uint32_t ii = 0, num = _program.m_numPredefined; ii < num; ++ii)
|
|
{
|
|
const PredefinedUniform& predefined = _program.m_predefined[ii];
|
|
uint8_t flags = predefined.m_type&BGFX_UNIFORM_FRAGMENTBIT;
|
|
switch (predefined.m_type&(~BGFX_UNIFORM_FRAGMENTBIT) )
|
|
{
|
|
case PredefinedUniform::ViewRect:
|
|
{
|
|
float frect[4];
|
|
frect[0] = m_rect.m_x;
|
|
frect[1] = m_rect.m_y;
|
|
frect[2] = m_rect.m_width;
|
|
frect[3] = m_rect.m_height;
|
|
|
|
_renderer->setShaderUniform4f(flags
|
|
, predefined.m_loc
|
|
, &frect[0]
|
|
, 1
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PredefinedUniform::ViewTexel:
|
|
{
|
|
float frect[4];
|
|
frect[0] = 1.0f/float(m_rect.m_width);
|
|
frect[1] = 1.0f/float(m_rect.m_height);
|
|
|
|
_renderer->setShaderUniform4f(flags
|
|
, predefined.m_loc
|
|
, &frect[0]
|
|
, 1
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PredefinedUniform::View:
|
|
{
|
|
_renderer->setShaderUniform4x4f(flags
|
|
, predefined.m_loc
|
|
, m_view[_eye][_view].un.val
|
|
, bx::uint32_min(mtxRegs, predefined.m_count)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PredefinedUniform::InvView:
|
|
{
|
|
uint16_t viewEye = (_view << 1) | _eye;
|
|
if (viewEye != m_invViewCached)
|
|
{
|
|
m_invViewCached = viewEye;
|
|
bx::float4x4_inverse(&m_invView.un.f4x4
|
|
, &m_view[_eye][_view].un.f4x4
|
|
);
|
|
}
|
|
|
|
_renderer->setShaderUniform4x4f(flags
|
|
, predefined.m_loc
|
|
, m_invView.un.val
|
|
, bx::uint32_min(mtxRegs, predefined.m_count)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PredefinedUniform::Proj:
|
|
{
|
|
_renderer->setShaderUniform4x4f(flags
|
|
, predefined.m_loc
|
|
, _frame->m_view[_view].m_proj[_eye].un.val
|
|
, bx::uint32_min(mtxRegs, predefined.m_count)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PredefinedUniform::InvProj:
|
|
{
|
|
uint16_t viewEye = (_view << 1) | _eye;
|
|
if (viewEye != m_invProjCached)
|
|
{
|
|
m_invProjCached = viewEye;
|
|
bx::float4x4_inverse(&m_invProj.un.f4x4
|
|
, &_frame->m_view[_view].m_proj[_eye].un.f4x4
|
|
);
|
|
}
|
|
|
|
_renderer->setShaderUniform4x4f(flags
|
|
, predefined.m_loc
|
|
, m_invProj.un.val
|
|
, bx::uint32_min(mtxRegs, predefined.m_count)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PredefinedUniform::ViewProj:
|
|
{
|
|
_renderer->setShaderUniform4x4f(flags
|
|
, predefined.m_loc
|
|
, m_viewProj[_eye][_view].un.val
|
|
, bx::uint32_min(mtxRegs, predefined.m_count)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PredefinedUniform::InvViewProj:
|
|
{
|
|
uint16_t viewEye = (_view << 1) | _eye;
|
|
if (viewEye != m_invViewProjCached)
|
|
{
|
|
m_invViewProjCached = viewEye;
|
|
bx::float4x4_inverse(&m_invViewProj.un.f4x4
|
|
, &m_viewProj[_eye][_view].un.f4x4
|
|
);
|
|
}
|
|
|
|
_renderer->setShaderUniform4x4f(flags
|
|
, predefined.m_loc
|
|
, m_invViewProj.un.val
|
|
, bx::uint32_min(mtxRegs, predefined.m_count)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PredefinedUniform::Model:
|
|
{
|
|
const Matrix4& model = frameCache.m_matrixCache.m_cache[_draw.m_startMatrix];
|
|
_renderer->setShaderUniform4x4f(flags
|
|
, predefined.m_loc
|
|
, model.un.val
|
|
, bx::uint32_min(_draw.m_numMatrices*mtxRegs, predefined.m_count)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PredefinedUniform::ModelView:
|
|
{
|
|
Matrix4 modelView;
|
|
const Matrix4& model = frameCache.m_matrixCache.m_cache[_draw.m_startMatrix];
|
|
bx::float4x4_mul(&modelView.un.f4x4
|
|
, &model.un.f4x4
|
|
, &m_view[_eye][_view].un.f4x4
|
|
);
|
|
_renderer->setShaderUniform4x4f(flags
|
|
, predefined.m_loc
|
|
, modelView.un.val
|
|
, bx::uint32_min(mtxRegs, predefined.m_count)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PredefinedUniform::ModelViewProj:
|
|
{
|
|
Matrix4 modelViewProj;
|
|
const Matrix4& model = frameCache.m_matrixCache.m_cache[_draw.m_startMatrix];
|
|
bx::float4x4_mul(&modelViewProj.un.f4x4
|
|
, &model.un.f4x4
|
|
, &m_viewProj[_eye][_view].un.f4x4
|
|
);
|
|
_renderer->setShaderUniform4x4f(flags
|
|
, predefined.m_loc
|
|
, modelViewProj.un.val
|
|
, bx::uint32_min(mtxRegs, predefined.m_count)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PredefinedUniform::AlphaRef:
|
|
{
|
|
_renderer->setShaderUniform4f(flags
|
|
, predefined.m_loc
|
|
, &m_alphaRef
|
|
, 1
|
|
);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
BX_CHECK(false, "predefined %d not handled", predefined.m_type);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Matrix4 m_viewTmp[2][BGFX_CONFIG_MAX_VIEWS];
|
|
Matrix4 m_viewProj[2][BGFX_CONFIG_MAX_VIEWS];
|
|
Matrix4* m_view[2];
|
|
Rect m_rect;
|
|
Matrix4 m_invView;
|
|
Matrix4 m_invProj;
|
|
Matrix4 m_invViewProj;
|
|
float m_alphaRef;
|
|
uint16_t m_invViewCached;
|
|
uint16_t m_invProjCached;
|
|
uint16_t m_invViewProjCached;
|
|
};
|
|
|
|
template<typename Ty>
|
|
inline void release(Ty)
|
|
{
|
|
}
|
|
|
|
template <typename Ty, uint16_t MaxHandleT>
|
|
class StateCacheLru
|
|
{
|
|
public:
|
|
Ty* add(uint64_t _key, const Ty& _value, uint16_t _parent)
|
|
{
|
|
uint16_t handle = m_alloc.alloc();
|
|
if (UINT16_MAX == handle)
|
|
{
|
|
uint16_t back = m_alloc.getBack();
|
|
invalidate(back);
|
|
handle = m_alloc.alloc();
|
|
}
|
|
|
|
BX_CHECK(UINT16_MAX != handle, "Failed to find handle.");
|
|
|
|
Data& data = m_data[handle];
|
|
data.m_hash = _key;
|
|
data.m_value = _value;
|
|
data.m_parent = _parent;
|
|
m_hashMap.insert(stl::make_pair(_key, handle) );
|
|
|
|
return &m_data[handle].m_value;
|
|
}
|
|
|
|
Ty* find(uint64_t _key)
|
|
{
|
|
HashMap::iterator it = m_hashMap.find(_key);
|
|
if (it != m_hashMap.end() )
|
|
{
|
|
uint16_t handle = it->second;
|
|
m_alloc.touch(handle);
|
|
return &m_data[handle].m_value;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void invalidate(uint64_t _key)
|
|
{
|
|
HashMap::iterator it = m_hashMap.find(_key);
|
|
if (it != m_hashMap.end() )
|
|
{
|
|
uint16_t handle = it->second;
|
|
m_alloc.free(handle);
|
|
m_hashMap.erase(it);
|
|
release(m_data[handle].m_value);
|
|
}
|
|
}
|
|
|
|
void invalidate(uint16_t _handle)
|
|
{
|
|
if (m_alloc.isValid(_handle) )
|
|
{
|
|
m_alloc.free(_handle);
|
|
Data& data = m_data[_handle];
|
|
m_hashMap.erase(m_hashMap.find(data.m_hash) );
|
|
release(data.m_value);
|
|
}
|
|
}
|
|
|
|
void invalidateWithParent(uint16_t _parent)
|
|
{
|
|
for (uint16_t ii = 0; ii < m_alloc.getNumHandles();)
|
|
{
|
|
uint16_t handle = m_alloc.getHandleAt(ii);
|
|
Data& data = m_data[handle];
|
|
|
|
if (data.m_parent == _parent)
|
|
{
|
|
m_alloc.free(handle);
|
|
m_hashMap.erase(m_hashMap.find(data.m_hash) );
|
|
release(data.m_value);
|
|
}
|
|
else
|
|
{
|
|
++ii;
|
|
}
|
|
}
|
|
}
|
|
|
|
void invalidate()
|
|
{
|
|
for (uint16_t ii = 0, num = m_alloc.getNumHandles(); ii < num; ++ii)
|
|
{
|
|
uint16_t handle = m_alloc.getHandleAt(ii);
|
|
Data& data = m_data[handle];
|
|
release(data.m_value);
|
|
}
|
|
|
|
m_hashMap.clear();
|
|
m_alloc.reset();
|
|
}
|
|
|
|
uint32_t getCount() const
|
|
{
|
|
return uint32_t(m_hashMap.size() );
|
|
}
|
|
|
|
private:
|
|
typedef stl::unordered_map<uint64_t, uint16_t> HashMap;
|
|
HashMap m_hashMap;
|
|
bx::HandleAllocLruT<MaxHandleT> m_alloc;
|
|
struct Data
|
|
{
|
|
uint64_t m_hash;
|
|
Ty m_value;
|
|
uint16_t m_parent;
|
|
};
|
|
|
|
Data m_data[MaxHandleT];
|
|
};
|
|
|
|
class StateCache
|
|
{
|
|
public:
|
|
void add(uint64_t _key, uint16_t _value)
|
|
{
|
|
invalidate(_key);
|
|
m_hashMap.insert(stl::make_pair(_key, _value) );
|
|
}
|
|
|
|
uint16_t find(uint64_t _key)
|
|
{
|
|
HashMap::iterator it = m_hashMap.find(_key);
|
|
if (it != m_hashMap.end() )
|
|
{
|
|
return it->second;
|
|
}
|
|
|
|
return UINT16_MAX;
|
|
}
|
|
|
|
void invalidate(uint64_t _key)
|
|
{
|
|
HashMap::iterator it = m_hashMap.find(_key);
|
|
if (it != m_hashMap.end() )
|
|
{
|
|
m_hashMap.erase(it);
|
|
}
|
|
}
|
|
|
|
void invalidate()
|
|
{
|
|
m_hashMap.clear();
|
|
}
|
|
|
|
uint32_t getCount() const
|
|
{
|
|
return uint32_t(m_hashMap.size() );
|
|
}
|
|
|
|
private:
|
|
typedef stl::unordered_map<uint64_t, uint16_t> HashMap;
|
|
HashMap m_hashMap;
|
|
};
|
|
|
|
inline bool hasVertexStreamChanged(const RenderDraw& _current, const RenderDraw& _new)
|
|
{
|
|
if (_current.m_streamMask != _new.m_streamMask
|
|
|| _current.m_instanceDataBuffer.idx != _new.m_instanceDataBuffer.idx
|
|
|| _current.m_instanceDataOffset != _new.m_instanceDataOffset
|
|
|| _current.m_instanceDataStride != _new.m_instanceDataStride)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
for (uint32_t idx = 0, streamMask = _new.m_streamMask, ntz = bx::uint32_cnttz(streamMask)
|
|
; 0 != streamMask
|
|
; streamMask >>= 1, idx += 1, ntz = bx::uint32_cnttz(streamMask)
|
|
)
|
|
{
|
|
streamMask >>= ntz;
|
|
idx += ntz;
|
|
|
|
if (_current.m_stream[idx].m_handle.idx != _new.m_stream[idx].m_handle.idx
|
|
|| _current.m_stream[idx].m_startVertex != _new.m_stream[idx].m_startVertex)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
template<typename Ty>
|
|
struct Profiler
|
|
{
|
|
Profiler(Frame* _frame, Ty& _gpuTimer, const char (*_viewName)[BGFX_CONFIG_MAX_VIEW_NAME], bool _enabled = true)
|
|
: m_viewName(_viewName)
|
|
, m_frame(_frame)
|
|
, m_gpuTimer(_gpuTimer)
|
|
, m_queryIdx(UINT32_MAX)
|
|
, m_numViews(0)
|
|
, m_enabled(_enabled && 0 != (_frame->m_debug & BGFX_DEBUG_PROFILER) )
|
|
{
|
|
}
|
|
|
|
~Profiler()
|
|
{
|
|
m_frame->m_perfStats.numViews = m_numViews;
|
|
}
|
|
|
|
void begin(uint16_t _view)
|
|
{
|
|
if (m_enabled)
|
|
{
|
|
ViewStats& viewStats = m_frame->m_perfStats.viewStats[m_numViews];
|
|
viewStats.cpuTimeElapsed = -bx::getHPCounter();
|
|
|
|
m_queryIdx = m_gpuTimer.begin(_view);
|
|
|
|
viewStats.view = ViewId(_view);
|
|
bx::strCopy(viewStats.name
|
|
, BGFX_CONFIG_MAX_VIEW_NAME
|
|
, &m_viewName[_view][BGFX_CONFIG_MAX_VIEW_NAME_RESERVED]
|
|
);
|
|
}
|
|
}
|
|
|
|
void end()
|
|
{
|
|
if (m_enabled
|
|
&& UINT32_MAX != m_queryIdx)
|
|
{
|
|
m_gpuTimer.end(m_queryIdx);
|
|
|
|
ViewStats& viewStats = m_frame->m_perfStats.viewStats[m_numViews];
|
|
const typename Ty::Result& result = m_gpuTimer.m_result[viewStats.view];
|
|
|
|
viewStats.cpuTimeElapsed += bx::getHPCounter();
|
|
viewStats.gpuTimeElapsed = result.m_end - result.m_begin;
|
|
|
|
++m_numViews;
|
|
m_queryIdx = UINT32_MAX;
|
|
}
|
|
}
|
|
|
|
const char (*m_viewName)[BGFX_CONFIG_MAX_VIEW_NAME];
|
|
Frame* m_frame;
|
|
Ty& m_gpuTimer;
|
|
uint32_t m_queryIdx;
|
|
uint16_t m_numViews;
|
|
bool m_enabled;
|
|
};
|
|
|
|
} // namespace bgfx
|
|
|
|
#endif // BGFX_RENDERER_H_HEADER_GUARD
|