/* * Copyright 2011-2016 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 ViewState { ViewState() { } ViewState(Frame* _render, bool _hmdEnabled) { reset(_render, _hmdEnabled); } void reset(Frame* _render, bool _hmdEnabled) { m_alphaRef = 0.0f; m_invViewCached = UINT16_MAX; m_invProjCached = UINT16_MAX; m_invViewProjCached = UINT16_MAX; m_view[0] = _render->m_view; m_view[1] = m_viewTmp[1]; if (_hmdEnabled) { HMD& hmd = _render->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 == (_render->m_viewFlags[ii] & BGFX_VIEW_STEREO) ) { bx::float4x4_mul(&m_view[eye][ii].un.f4x4 , &_render->m_view[ii].un.f4x4 , &viewAdjust.un.f4x4 ); } else { memcpy(&m_view[0][ii].un.f4x4, &_render->m_view[ii].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 , &_render->m_proj[eye][ii].un.f4x4 ); } } } template void setPredefined(RendererContext* _renderer, uint16_t view, uint8_t eye, Program& _program, Frame* _render, const Draw& _draw) { for (uint32_t ii = 0, num = _program.m_numPredefined; ii < num; ++ii) { 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 , _render->m_proj[eye][view].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 , &_render->m_proj[eye][view].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 = _render->m_matrixCache.m_cache[_draw.m_matrix]; _renderer->setShaderUniform4x4f(flags , predefined.m_loc , model.un.val , bx::uint32_min(_draw.m_num*mtxRegs, predefined.m_count) ); } break; case PredefinedUniform::ModelView: { Matrix4 modelView; const Matrix4& model = _render->m_matrixCache.m_cache[_draw.m_matrix]; 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 = _render->m_matrixCache.m_cache[_draw.m_matrix]; 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 inline void release(Ty) { } template class StateCacheLru { public: void add(uint64_t _key, 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) ); } 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 HashMap; HashMap m_hashMap; bx::HandleAllocLruT m_alloc; struct Data { uint64_t m_hash; Ty m_value; uint16_t m_parent; }; Data m_data[MaxHandleT]; }; } // namespace bgfx #endif // BGFX_RENDERER_H_HEADER_GUARD