diff --git a/examples/08-update/update.cpp b/examples/08-update/update.cpp index 80adfd869..e952a1e7e 100644 --- a/examples/08-update/update.cpp +++ b/examples/08-update/update.cpp @@ -11,9 +11,11 @@ #include "../common/dbg.h" #include "../common/math.h" #include "../common/processevents.h" +#include "../common/packrect.h" #include #include +#include struct PosColorVertex { @@ -205,11 +207,7 @@ int _main_(int _argc, char** _argv) bgfx::destroyFragmentShader(fsh); uint32_t blockSide = 0; - uint32_t blockX = 0; - uint32_t blockY = 0; - const uint32_t blockWidth = 8; - const uint32_t blockHeight = 8; - const uint32_t textureSide = 256; + const uint32_t textureSide = 2048; bgfx::TextureHandle textureCube = bgfx::createTextureCube(6 @@ -219,15 +217,18 @@ int _main_(int _argc, char** _argv) , BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT ); - bgfx::TextureInfo ti; - bgfx::calcTextureSize(ti, blockWidth, blockHeight, 1, 1, bgfx::TextureFormat::BGRA8); - uint8_t rr = rand()%255; uint8_t gg = rand()%255; uint8_t bb = rand()%255; int64_t updateTime = 0; + RectPackCubeT<256> cube(textureSide); + + uint32_t hit = 0; + uint32_t miss = 0; + std::list quads; + while (!processEvents(width, height, debug, reset) ) { // Set view 0 default viewport. @@ -252,43 +253,53 @@ int _main_(int _argc, char** _argv) if (now > updateTime) { -// updateTime = now + freq/10; - const bgfx::Memory* mem = bgfx::alloc(ti.storageSize); - uint8_t* data = (uint8_t*)mem->data; - for (uint32_t ii = 0, num = ti.storageSize*8/ti.bitsPerPixel; ii < num; ++ii) + PackCube face; + + uint32_t bw = bx::uint16_max(1, rand()%(textureSide/4) ); + uint32_t bh = bx::uint16_max(1, rand()%(textureSide/4) ); + + if (cube.find(bw, bh, face) ) { - data[0] = bb; - data[1] = rr; - data[2] = gg; - data[3] = 0xff; - data += 4; - } + quads.push_back(face); - bgfx::updateTextureCube(textureCube, blockSide, 0, blockX, blockY, blockWidth, blockHeight, mem); + ++hit; + bgfx::TextureInfo ti; + const Pack2D& rect = face.m_rect; + bgfx::calcTextureSize(ti, rect.m_width, rect.m_height, 1, 1, bgfx::TextureFormat::BGRA8); - blockX += 8; - if (blockX >= textureSide) - { - blockX = 0; - blockY += 8; - - if (blockY >= textureSide) +// updateTime = now + freq/10; + const bgfx::Memory* mem = bgfx::alloc(ti.storageSize); + uint8_t* data = (uint8_t*)mem->data; + for (uint32_t ii = 0, num = ti.storageSize*8/ti.bitsPerPixel; ii < num; ++ii) { - rr = rand()%255; - gg = rand()%255; - bb = rand()%255; + data[0] = bb; + data[1] = rr; + data[2] = gg; + data[3] = 0xff; + data += 4; + } - blockY = 0; - ++blockSide; + bgfx::updateTextureCube(textureCube, face.m_side, 0, rect.m_x, rect.m_y, rect.m_width, rect.m_height, mem); - if (blockSide > 5) - { - blockSide = 0; - } + rr = rand()%255; + gg = rand()%255; + bb = rand()%255; + } + else + { + ++miss; + + for (uint32_t ii = 0, num = bx::uint32_min(10, (uint32_t)quads.size() ); ii < num; ++ii) + { + const PackCube& face = quads.front(); + cube.clear(face); + quads.pop_front(); } } } + bgfx::dbgTextPrintf(0, 4, 0x0f, "hit: %d, miss %d", hit, miss); + float at[3] = { 0.0f, 0.0f, 0.0f }; float eye[3] = { 0.0f, 0.0f, -5.0f }; diff --git a/examples/common/packrect.h b/examples/common/packrect.h new file mode 100644 index 000000000..b3248409d --- /dev/null +++ b/examples/common/packrect.h @@ -0,0 +1,177 @@ +/* + * Copyright 2011-2013 Branimir Karadzic. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#ifndef __RECTPACK_H__ +#define __RECTPACK_H__ + +#include + +struct Pack2D +{ + uint16_t m_x; + uint16_t m_y; + uint16_t m_width; + uint16_t m_height; +}; + +struct PackCube +{ + Pack2D m_rect; + uint8_t m_side; +}; + +template +class RectPackCubeT; + +template +class RectPack2DT +{ +public: + RectPack2DT(uint16_t _width, uint16_t _height) + { + reset(_width, _height); + } + + void reset(uint16_t _width, uint16_t _height) + { + m_bw = _width/64; + m_bh = _height/numBlocks; + memset(m_mem, 0xff, sizeof(m_mem) ); + } + + bool find(uint16_t _width, uint16_t _height, Pack2D& _pack) + { + uint16_t width = bx::uint16_min(64, (_width + m_bw - 1) / m_bw); + uint16_t height = bx::uint16_min(numBlocks, (_height + m_bh - 1) / m_bh); + uint16_t numx = 64-width; + uint16_t numy = numBlocks-height; + + const uint64_t scan = width == 64 ? UINT64_MAX : (UINT64_C(1)<; + + RectPack2DT() + { + } + + uint64_t m_mem[numBlocks]; + uint16_t m_bw; + uint16_t m_bh; +}; + +template +class RectPackCubeT +{ +public: + RectPackCubeT(uint16_t _side) + { + reset(_side); + } + + void reset(uint16_t _side) + { + for (uint32_t ii = 0; ii < 6; ++ii) + { + m_mru[ii] = ii; + m_ra[ii].reset(_side, _side); + } + } + + bool find(uint16_t _width, uint16_t _height, PackCube& _pack) + { + bool found = false; + for (uint32_t ii = 0; ii < 6; ++ii) + { + uint8_t side = m_mru[ii]; + found = m_ra[side].find(_width, _height, _pack.m_rect); + + if (found) + { + _pack.m_side = side; + m_mru[ii] = m_mru[0]; + m_mru[0] = side; + return true; + } + } + + return false; + } + + void clear(const PackCube& _pack) + { + uint8_t side = _pack.m_side; + + uint32_t ii = 0; + for (; ii < 6 && m_mru[ii] != side; ++ii); + + m_mru[ii] = m_mru[0]; + m_mru[0] = side; + + m_ra[side].clear(_pack.m_rect); + } + +private: + RectPackCubeT(); + + RectPack2DT m_ra[6]; + uint8_t m_mru[6]; +}; + +#endif // __RECTPACK_H__ diff --git a/src/bgfx_p.h b/src/bgfx_p.h index e4bd57d92..a94905b5c 100755 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -194,16 +194,6 @@ namespace bgfx const char* getAttribName(Attrib::Enum _attr); bool renderFrame(); - inline uint16_t uint16_min(uint16_t _a, uint16_t _b) - { - return _a > _b ? _b : _a; - } - - inline uint16_t uint16_max(uint16_t _a, uint16_t _b) - { - return _a < _b ? _b : _a; - } - inline uint32_t gcd(uint32_t _a, uint32_t _b) { do @@ -374,6 +364,49 @@ namespace bgfx bool m_init; }; + template + 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) ); + bx::radixSort32(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]; + }; + struct ClearQuad { void init(); @@ -480,6 +513,12 @@ namespace bgfx read(reinterpret_cast(&_in), sizeof(Type) ); } + void skip(uint32_t _size) + { + BX_CHECK(m_pos < m_size, ""); + m_pos += _size; + } + void reset() { m_pos = 0; @@ -2369,7 +2408,9 @@ namespace bgfx void rendererCreateProgram(ProgramHandle _handle, VertexShaderHandle _vsh, FragmentShaderHandle _fsh); void rendererDestroyProgram(FragmentShaderHandle _handle); void rendererCreateTexture(TextureHandle _handle, Memory* _mem, uint32_t _flags); + void rendererUpdateTextureBegin(TextureHandle _handle, uint8_t _side, uint8_t _mip); void rendererUpdateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, const Memory* _mem); + void rendererUpdateTextureEnd(); void rendererDestroyTexture(TextureHandle _handle); void rendererCreateRenderTarget(RenderTargetHandle _handle, uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags); void rendererDestroyRenderTarget(RenderTargetHandle _handle); @@ -2403,6 +2444,66 @@ namespace bgfx } } + void flushTextureUpdateBatch(CommandBuffer& _cmdbuf) + { + if (m_textureUpdateBatch.sort() ) + { + const uint32_t pos = _cmdbuf.m_pos; + + uint32_t currentKey = UINT32_MAX; + + for (uint32_t ii = 0, num = m_textureUpdateBatch.m_num; ii < num; ++ii) + { + _cmdbuf.m_pos = m_textureUpdateBatch.m_values[ii]; + + TextureHandle handle; + _cmdbuf.read(handle); + + uint8_t side; + _cmdbuf.read(side); + + uint8_t mip; + _cmdbuf.read(mip); + + Rect rect; + _cmdbuf.read(rect); + + uint16_t zz; + _cmdbuf.read(zz); + + uint16_t depth; + _cmdbuf.read(depth); + + Memory* mem; + _cmdbuf.read(mem); + + uint32_t key = m_textureUpdateBatch.m_keys[ii]; + if (key != currentKey) + { + if (currentKey != UINT32_MAX) + { + rendererUpdateTextureEnd(); + } + currentKey = key; + rendererUpdateTextureBegin(handle, side, mip); + } + + rendererUpdateTexture(handle, side, mip, rect, zz, depth, mem); + + release(mem); + } + + if (currentKey != UINT32_MAX) + { + rendererUpdateTextureEnd(); + } + + m_textureUpdateBatch.reset(); + + _cmdbuf.m_pos = pos; + } + } + void rendererExecCommands(CommandBuffer& _cmdbuf) { _cmdbuf.reset(); @@ -2677,6 +2778,13 @@ namespace bgfx case CommandBuffer::UpdateTexture: { + if (m_textureUpdateBatch.isFull() ) + { + flushTextureUpdateBatch(_cmdbuf); + } + + uint32_t value = _cmdbuf.m_pos; + TextureHandle handle; _cmdbuf.read(handle); @@ -2686,21 +2794,14 @@ namespace bgfx uint8_t mip; _cmdbuf.read(mip); - Rect rect; - _cmdbuf.read(rect); + _cmdbuf.skip(sizeof(Rect)+sizeof(uint16_t)+sizeof(uint16_t)+sizeof(Memory*) ); + + uint32_t key = (handle.idx<<16) + | (side<<8) + | mip + ; - uint16_t zz; - _cmdbuf.read(zz); - - uint16_t depth; - _cmdbuf.read(depth); - - Memory* mem; - _cmdbuf.read(mem); - - rendererUpdateTexture(handle, side, mip, rect, zz, depth, mem); - - release(mem); + m_textureUpdateBatch.add(key, value); } break; @@ -2794,6 +2895,8 @@ namespace bgfx break; } } while (!end); + + flushTextureUpdateBatch(_cmdbuf); } void rendererSubmit(); @@ -2915,6 +3018,10 @@ namespace bgfx bool m_rendererInitialized; bool m_exit; + + BX_CACHE_LINE_ALIGN_MARKER(); + typedef UpdateBatchT<256> TextureUpdateBatch; + TextureUpdateBatch m_textureUpdateBatch; }; } // namespace bgfx diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 6ebcac063..7eefc5062 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -1799,7 +1799,7 @@ namespace bgfx , ... ); #else - deviceCtx->UpdateSubresource(m_ptr, subres, &box, _mem->data, _rect.m_width*4, 0); + deviceCtx->UpdateSubresource(m_ptr, subres, &box, _mem->data, _rect.m_width*4, 0); #endif // 0 } @@ -2011,11 +2011,19 @@ namespace bgfx s_renderCtx.m_textures[_handle.idx].create(_mem, _flags); } + void Context::rendererUpdateTextureBegin(TextureHandle /*_handle*/, uint8_t /*_side*/, uint8_t /*_mip*/) + { + } + void Context::rendererUpdateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, const Memory* _mem) { s_renderCtx.m_textures[_handle.idx].update(_side, _mip, _rect, _z, _depth, _mem); } + void Context::rendererUpdateTextureEnd() + { + } + void Context::rendererDestroyTexture(TextureHandle _handle) { s_renderCtx.m_textures[_handle.idx].destroy(); diff --git a/src/renderer_d3d9.cpp b/src/renderer_d3d9.cpp index 12f92932c..8da29a019 100644 --- a/src/renderer_d3d9.cpp +++ b/src/renderer_d3d9.cpp @@ -881,6 +881,12 @@ namespace bgfx UniformRegistry m_uniformReg; void* m_uniforms[BGFX_CONFIG_MAX_UNIFORMS]; + Texture* m_updateTexture; + uint8_t* m_updateTextureBits; + uint32_t m_updateTexturePitch; + uint8_t m_updateTextureSide; + uint8_t m_updateTextureMip; + TextVideoMem m_textVideoMem; RenderTargetHandle m_rt; bool m_rtMsaa; @@ -1346,6 +1352,42 @@ namespace bgfx BX_CHECK(false, "You should not be here."); } + void Texture::dirty(uint8_t _side, const Rect& _rect) + { + switch (m_type) + { + case Texture2D: + { + RECT rect; + rect.left = _rect.m_x; + rect.top = _rect.m_y; + rect.right = rect.left + _rect.m_width; + rect.bottom = rect.top + _rect.m_height; + DX_CHECK(m_texture2d->AddDirtyRect(&rect) ); + } + return; + + case Texture3D: + { +// DX_CHECK(m_texture3d->AddDirtyRect(_box) ); + } + return; + + case TextureCube: + { + RECT rect; + rect.left = _rect.m_x; + rect.top = _rect.m_y; + rect.right = rect.left + _rect.m_width; + rect.bottom = rect.top + _rect.m_height; + DX_CHECK(m_textureCube->AddDirtyRect(D3DCUBEMAP_FACES(_side), &rect) ); + } + return; + } + + BX_CHECK(false, "You should not be here."); + } + void Texture::create(const Memory* _mem, uint32_t _flags) { m_tau = s_textureAddress[(_flags&BGFX_TEXTURE_U_MASK)>>BGFX_TEXTURE_U_SHIFT]; @@ -1548,22 +1590,41 @@ namespace bgfx } } + void Texture::updateBegin(uint8_t _side, uint8_t _mip) + { + uint32_t slicePitch; + s_renderCtx.m_updateTextureSide = _side; + s_renderCtx.m_updateTextureMip = _mip; + s_renderCtx.m_updateTextureBits = lock(_side, _mip, s_renderCtx.m_updateTexturePitch, slicePitch); + } + void Texture::update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, const Memory* _mem) { - uint32_t pitch; - uint32_t slicePitch; - uint8_t* bits = lock(_side, _mip, pitch, slicePitch, &_rect); + uint32_t bpp = s_textureFormat[m_format].m_bpp; + uint32_t srcpitch = _rect.m_width*bpp/8; + uint32_t dstpitch = s_renderCtx.m_updateTexturePitch; + uint8_t* bits = s_renderCtx.m_updateTextureBits + _rect.m_y*dstpitch + _rect.m_x*bpp/8; - uint32_t srcpitch = _rect.m_width*s_textureFormat[m_format].m_bpp/8; - uint32_t dstpitch = pitch; - for (uint32_t yy = 0, height = _rect.m_height; yy < height; ++yy) + if (srcpitch == dstpitch) { - uint8_t* src = &_mem->data[yy*srcpitch]; - uint8_t* dst = &bits[yy*dstpitch]; - memcpy(dst, src, srcpitch); + memcpy(bits, _mem->data, srcpitch*_rect.m_height); + } + else + { + for (uint32_t yy = 0, height = _rect.m_height; yy < height; ++yy) + { + uint8_t* src = &_mem->data[yy*srcpitch]; + uint8_t* dst = &bits[yy*dstpitch]; + memcpy(dst, src, srcpitch); + } } - unlock(_side, _mip); + dirty(_side, _rect); + } + + void Texture::updateEnd() + { + unlock(s_renderCtx.m_updateTextureSide, s_renderCtx.m_updateTextureMip); } void Texture::commit(uint8_t _stage) @@ -1990,9 +2051,21 @@ namespace bgfx s_renderCtx.m_textures[_handle.idx].create(_mem, _flags); } + void Context::rendererUpdateTextureBegin(TextureHandle _handle, uint8_t _side, uint8_t _mip) + { + s_renderCtx.m_updateTexture = &s_renderCtx.m_textures[_handle.idx]; + s_renderCtx.m_updateTexture->updateBegin(_side, _mip); + } + void Context::rendererUpdateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, const Memory* _mem) { - s_renderCtx.m_textures[_handle.idx].update(_side, _mip, _rect, _z, _depth, _mem); + s_renderCtx.m_updateTexture->update(_side, _mip, _rect, _z, _depth, _mem); + } + + void Context::rendererUpdateTextureEnd() + { + s_renderCtx.m_updateTexture->updateEnd(); + s_renderCtx.m_updateTexture = NULL; } void Context::rendererDestroyTexture(TextureHandle _handle) diff --git a/src/renderer_d3d9.h b/src/renderer_d3d9.h index 9b9e6bb45..d9c412830 100644 --- a/src/renderer_d3d9.h +++ b/src/renderer_d3d9.h @@ -320,6 +320,7 @@ namespace bgfx uint8_t* lock(uint8_t _side, uint8_t _lod, uint32_t& _pitch, uint32_t& _slicePitch, const Rect* _rect = NULL); void unlock(uint8_t _side, uint8_t _lod); + void dirty(uint8_t _side, const Rect& _rect); void create(const Memory* _mem, uint32_t _flags); @@ -328,7 +329,9 @@ namespace bgfx DX_RELEASE(m_ptr, 0); } + void updateBegin(uint8_t _side, uint8_t _mip); void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, const Memory* _mem); + void updateEnd(); void commit(uint8_t _stage); union diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 645de1ff5..20f6c3362 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -2187,11 +2187,19 @@ namespace bgfx s_renderCtx.m_textures[_handle.idx].create(_mem, _flags); } + void Context::rendererUpdateTextureBegin(TextureHandle _handle, uint8_t _side, uint8_t _mip) + { + } + void Context::rendererUpdateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, const Memory* _mem) { s_renderCtx.m_textures[_handle.idx].update(_side, _mip, _rect, _z, _depth, _mem); } + void Context::rendererUpdateTextureEnd() + { + } + void Context::rendererDestroyTexture(TextureHandle _handle) { s_renderCtx.m_textures[_handle.idx].destroy(); diff --git a/src/renderer_null.cpp b/src/renderer_null.cpp index 0f710bd72..da61080a9 100644 --- a/src/renderer_null.cpp +++ b/src/renderer_null.cpp @@ -124,10 +124,18 @@ namespace bgfx } } + void Context::rendererUpdateTextureBegin(TextureHandle /*_handle*/, uint8_t /*_side*/, uint8_t /*_mip*/) + { + } + void Context::rendererUpdateTexture(TextureHandle /*_handle*/, uint8_t /*_side*/, uint8_t /*_mip*/, const Rect& /*_rect*/, uint16_t /*_z*/, uint16_t /*_depth*/, const Memory* /*_mem*/) { } + void Context::rendererUpdateTextureEnd() + { + } + void Context::rendererDestroyTexture(TextureHandle /*_handle*/) { }