Added texture update batching. Added rect packing.

This commit is contained in:
bkaradzic 2013-03-02 21:35:09 -08:00
parent c3cef2bb5b
commit 435b83f1ac
8 changed files with 466 additions and 71 deletions

View file

@ -11,9 +11,11 @@
#include "../common/dbg.h"
#include "../common/math.h"
#include "../common/processevents.h"
#include "../common/packrect.h"
#include <stdio.h>
#include <string.h>
#include <list>
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<PackCube> 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 };

177
examples/common/packrect.h Normal file
View file

@ -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 <bx/uint32_t.h>
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 <uint16_t numBlocks>
class RectPackCubeT;
template <uint16_t numBlocks>
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)<<width)-1;
for (uint16_t starty = 0; starty <= numy; ++starty)
{
uint64_t mem = m_mem[starty];
uint16_t ntz = (uint16_t)bx::uint64_cnttz(mem);
uint64_t mask = scan<<ntz;
for (uint16_t xx = ntz; xx <= numx; ++xx, mask <<= 1)
{
uint16_t yy = starty;
if ( (mem&mask) == mask)
{
uint16_t endy = starty + height;
while (yy < endy && (m_mem[yy]&mask) == mask)
{
++yy;
}
if (yy == endy)
{
uint64_t cmask = ~mask;
for (yy = starty; yy < endy; ++yy)
{
m_mem[yy] &= cmask;
}
_pack.m_x = xx * m_bw;
_pack.m_y = starty * m_bh;
_pack.m_width = width * m_bw;
_pack.m_height = height * m_bh;
return true;
}
}
}
}
return false;
}
void clear(const Pack2D& _pack)
{
uint16_t startx = bx::uint16_min(63, _pack.m_x / m_bw);
uint16_t starty = bx::uint16_min(numBlocks-1, _pack.m_y / m_bh);
uint16_t endx = bx::uint16_min(64, (_pack.m_width + m_bw - 1) / m_bw + startx);
uint16_t endy = bx::uint16_min(numBlocks, (_pack.m_height + m_bh - 1) / m_bh + starty);
uint16_t width = endx - startx;
const uint64_t mask = (width == 64 ? UINT64_MAX : (UINT64_C(1)<<width)-1 )<<startx;
for (uint16_t yy = starty; yy < endy; ++yy)
{
m_mem[yy] |= mask;
}
}
private:
friend class RectPackCubeT<numBlocks>;
RectPack2DT()
{
}
uint64_t m_mem[numBlocks];
uint16_t m_bw;
uint16_t m_bh;
};
template <uint16_t numBlocks>
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<numBlocks> m_ra[6];
uint8_t m_mru[6];
};
#endif // __RECTPACK_H__

View file

@ -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 <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) );
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<uint8_t*>(&_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

View file

@ -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();

View file

@ -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)

View file

@ -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

View file

@ -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();

View file

@ -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*/)
{
}