Fast buffer copy from string

Before I go and write one (because Im very lazy)… has anyone written a little native copy function to effectively do the below:

local buff = buffer.create(v.res.width * v.res.height, { 
    {    name=hash(v.res.type), type=buffer.VALUE_TYPE_UINT8, count=rgbcount } 
})
local stm = buffer.get_stream(buff, hash(v.res.type))
for idx = 1, v.res.width * v.res.height * rgbcount do 
    stm[idx] = string.byte(v.res.buffer, idx )
end

The for loop is what I will be looking to move out.

[[ UPDATE ]]
So… to answer my own question I quickly made one. Beware NO CHECKING!! But it works :slight_smile:
Texture load times are now fine.

static int SetBufferBytes(lua_State* L)
{
    DM_LUA_STACK_CHECK(L, 0);
    dmScript::LuaHBuffer *buffer = dmScript::CheckBuffer(L, 1);
    const char *streamname = luaL_checkstring(L, 2);
    const char *bufferstring = luaL_checkstring(L, 3);
    
    uint8_t* bytes = 0x0;
    uint32_t size = 0;
    uint32_t count = 0;
    uint32_t components = 0;
    uint32_t stride = 0;
    dmBuffer::Result r = dmBuffer::GetStream(buffer->m_Buffer, dmHashString64(streamname), (void**)&bytes, &count, &components, &stride);

    size_t idx = 0;
    if (r == dmBuffer::RESULT_OK) {
        for (int i = 0; i < count; ++i)
        {
            for (int c = 0; c < components; ++c)
            {
                bytes[c] = bufferstring[idx++];
            }
            bytes += stride;
        }
    } else {
        // handle error
    }
        
    r = dmBuffer::ValidateBuffer(buffer->m_Buffer);
    return 0;
}

This is all for a gltf loader Im working on - mostly Lua. Theres now a native function being used :slight_smile: … and one ffi call that will be replaced by the above native function (I hope).

8 Likes

A little related, this is a helper method for copying a string into a table as a list of unsigned shorts. It takes two bytes and merges into a single unsigned short (vertex index buffers are like this).

static int SetBufferIntsFromTable(lua_State* L)
{
    DM_LUA_STACK_CHECK(L, 0);
    size_t offset = luaL_checknumber(L, 1);
    size_t length = luaL_checknumber(L, 2);
    const unsigned char *data = (unsigned char *)luaL_checkstring(L, 3);
    luaL_checktype(L, 4, LUA_TTABLE);

    
    // Now we have the data, cast it to the union and write back out.
    int idx = 1;
    for( int i=0; i<length; i+=sizeof(unsigned short))
    {
        unsigned int val = ((unsigned int)data[i+1+offset] << 8) | ((unsigned int)data[i+offset]);
        //printf("%d\n", val);
        lua_pushnumber(L, val);  /* value */
        lua_rawseti(L, 4, idx++);  /* set table at key `i' */
    }

    return 0;
}

And a complementary function for doing the same for floats: converting 4 bytes into a single float from a string buffer array.

static int SetBufferFloatsFromTable(lua_State* L)
{
    DM_LUA_STACK_CHECK(L, 0);
    size_t offset = luaL_checknumber(L, 1);
    size_t length = luaL_checknumber(L, 2);
    const char *data = luaL_checkstring(L, 3);
    luaL_checktype(L, 4, LUA_TTABLE);
    
    // Now we have the data, cast it to the union and write back out.
    int idx = 1;
    for( int i=0; i<length; i+= sizeof(float))
    {
        float val = *(float *)(data + i + offset);
        //printf("%f\n", val);
        lua_pushnumber(L, val);  /* value */
        lua_rawseti(L, 4, idx++);  /* set table at key `i' */
    }

    return 0;
}
4 Likes

Very nice! Thank you for sharing. I’m excited to see the stuff you are working on!

3 Likes