1
0
forked from 0ad/0ad

inlined bits and bit_mask for efficiency (as suggested by philip - thanks!)

add sanity check for struct Tex

This was SVN commit r2755.
This commit is contained in:
janwas 2005-09-19 23:40:33 +00:00
parent 13501cf58b
commit 2a8953452d
6 changed files with 94 additions and 41 deletions

View File

@ -213,23 +213,6 @@ int ilog2(const float x)
uint bit_mask(uint num_bits)
{
return (1u << num_bits)-1;
}
uint bits(uint num, uint lo_idx, uint hi_idx)
{
const uint count = (hi_idx - lo_idx)+1; // # bits to return
uint result = num >> lo_idx;
result &= bit_mask(count);
return result;
}
// multiple must be a power of two.
uintptr_t round_up(const uintptr_t n, const uintptr_t multiple)
{

View File

@ -349,10 +349,24 @@ const size_t GiB = 1ul << 30;
#define BIT(n) (1ul << (n))
extern uint bit_mask(uint num_bits);
extern uint bits(uint x, uint lo_idx, uint hi_idx);
// these are declared in the header and inlined to aid compiler optimizations
// (they can easily end up being time-critical).
inline uint bit_mask(uint num_bits)
{
return (1u << num_bits)-1;
}
inline uint bits(uint num, uint lo_idx, uint hi_idx)
{
const uint count = (hi_idx - lo_idx)+1; // # bits to return
uint result = num >> lo_idx;
result &= bit_mask(count);
return result;
}
// FNV1-A hash - good for strings.
// if len = 0 (default), treat buf as a C-string;

View File

@ -207,7 +207,7 @@ static void OglTex_init(OglTex* ot, va_list args)
static void OglTex_dtor(OglTex* ot)
{
tex_free(&ot->t);
(void)tex_free(&ot->t);
glDeleteTextures(1, &ot->id);
ot->id = 0;
@ -343,17 +343,11 @@ static int ogl_tex_validate(const uint line, const OglTex* ot)
const char* msg = 0;
int err = -1;
// pointer to texture data
size_t tex_file_size;
void* tex_file = mem_get_ptr(ot->t.hm, &tex_file_size);
if(!tex_file)
msg = "texture file not loaded";
// possible causes: texture file header is invalid,
// or file wasn't loaded completely.
if(ot->t.ofs > tex_file_size)
msg = "offset to texture data exceeds file size";
RETURN_ERR(tex_validate(line, &ot->t));
// width, height
// (note: this is done here because tex.cpp doesn't impose any
// restrictions on dimensions, while OpenGL does).
GLsizei w = (GLsizei)ot->t.w;
GLsizei h = (GLsizei)ot->t.h;
// if w or h is 0, texture file probably not loaded successfully.
@ -377,13 +371,6 @@ static int ogl_tex_validate(const uint line, const OglTex* ot)
// may define their own. not necessary anyway - if non-0, assume
// loader knows what it's doing, and that the format is valid.
// bits per pixel
u32 bpp = ot->t.bpp;
// half-hearted sanity check: must be divisible by 4.
// don't bother checking all values.
if(bpp % 4 || bpp > 32)
msg = "invalid bpp? should be one of {4,8,16,24,32}";
// upload parameters, set by ogl_tex_upload(Handle), or 0
GLint filter = ot->filter;
if(filter != 0 && !filter_is_known(filter))
@ -395,8 +382,8 @@ static int ogl_tex_validate(const uint line, const OglTex* ot)
if(msg)
{
debug_printf("tex_validate at line %d failed: %s (error code %d)\n", line, msg, err);
debug_warn("tex_validate failed");
debug_printf("ogl_tex_validate at line %d failed: %s (error code %d)\n", line, msg, err);
debug_warn("ogl_tex_validate failed");
return err;
}

View File

@ -32,6 +32,53 @@
#define ERR_TOO_SHORT -4
// be careful not to use other tex_* APIs here because they call us.
int tex_validate(const uint line, const Tex* t)
{
const char* msg = 0;
int err = -1;
// texture data
size_t tex_file_size;
void* tex_file = mem_get_ptr(t->hm, &tex_file_size);
// .. only check validity if the image is still in memory.
// (e.g. ogl_tex frees the data after uploading to GL)
if(tex_file)
{
// possible causes: texture file header is invalid,
// or file wasn't loaded completely.
if(tex_file_size < t->ofs + t->w*t->h*t->bpp/8)
msg = "file size smaller than header+texels";
}
// bits per pixel
// (we don't bother checking all values; a sanity check is enough)
if(t->bpp % 4 || t->bpp > 32)
msg = "invalid bpp? should be one of {4,8,16,24,32}";
// flags
// .. DXT
const uint dxt = t->flags & TEX_DXT;
if(dxt != 0 && dxt != 1 && dxt != DXT1A && dxt != 3 && dxt != 5)
msg = "invalid DXT in flags";
// .. orientation
const uint orientation = t->flags & TEX_ORIENTATION;
if(orientation == (TEX_BOTTOM_UP|TEX_TOP_DOWN))
msg = "invalid orientation in flags";
if(msg)
{
debug_printf("tex_validate at line %d failed: %s (error code %d)\n", line, msg, err);
debug_warn("tex_validate failed");
return err;
}
return 0;
}
#define CHECK_TEX(t) CHECK_ERR(tex_validate(__LINE__, t))
// rationale for default: see tex_set_global_orientation
static int global_orientation = TEX_TOP_DOWN;
@ -79,6 +126,8 @@ static int validate_format(uint bpp, uint flags)
// somewhat optimized (loops are hoisted, cache associativity accounted for)
static int plain_transform(Tex* t, uint transforms)
{
CHECK_TEX(t);
// extract texture info
const uint w = t->w, h = t->h, bpp = t->bpp, flags = t->flags;
u8* const img = tex_get_data(t);
@ -285,6 +334,8 @@ int tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
int tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da)
{
CHECK_TEX(t);
RETURN_ERR(tex_transform(t, transforms));
void* img_data = tex_get_data(t); const size_t img_size = tex_img_size(t);
@ -319,6 +370,9 @@ void tex_set_global_orientation(int o)
u8* tex_get_data(const Tex* t)
{
if(tex_validate(__LINE__, t) < 0)
return 0;
u8* p = (u8*)mem_get_ptr(t->hm);
if(!p)
return 0;
@ -327,6 +381,9 @@ u8* tex_get_data(const Tex* t)
size_t tex_img_size(const Tex* t)
{
if(tex_validate(__LINE__, t) < 0)
return 0;
return t->w * t->h * t->bpp/8;
}
@ -386,6 +443,7 @@ int tex_load_mem(Handle hm, Tex* t)
WARN_ERR(plain_transform(t, transforms));
}
CHECK_TEX(t);
return 0;
}
@ -401,12 +459,15 @@ int tex_load(const char* fn, Tex* t)
// wasn't compressed) or was replaced by a new buffer for the image data.
if(ret < 0)
memset(t, 0, sizeof(Tex));
// <t> has already been validated.
return ret;
}
int tex_free(Tex* t)
{
CHECK_TEX(t);
mem_free_h(t->hm);
return 0;
}
@ -414,6 +475,8 @@ int tex_free(Tex* t)
int tex_transform(Tex* t, uint transforms)
{
CHECK_TEX(t);
// find codec that understands the data, and transform
for(int i = 0; i < MAX_CODECS; i++)
{
@ -441,8 +504,11 @@ int tex_wrap(uint w, uint h, uint bpp, uint flags, void* img, Tex* t)
t->bpp = bpp;
t->flags = flags;
const size_t img_size = tex_img_size(t);
// note: we can't use tex_img_size because that requires all
// Tex fields to be valid, but this calculation must be done first.
const size_t img_size = w*h*bpp/8;
t->hm = mem_assign(img, img_size, 0, 0, 0, 0, 0);
RETURN_ERR(t->hm);
// the exact value of img is lost, since the handle references the
// allocation and disregards the offset within it given by <img>.
@ -450,7 +516,7 @@ int tex_wrap(uint w, uint h, uint bpp, uint flags, void* img, Tex* t)
void* reported_ptr = mem_get_ptr(t->hm);
t->ofs = (u8*)img - (u8*)reported_ptr;
RETURN_ERR(t->hm);
CHECK_TEX(t);
return 0;
}

View File

@ -91,4 +91,7 @@ extern int tex_write(const char* fn, uint w, uint h, uint bpp, uint flags, void*
extern void tex_set_global_orientation(int orientation);
// internal use only:
extern int tex_validate(uint line, const Tex* t);
#endif // __TEX_H__

View File

@ -88,7 +88,7 @@ static inline uint access_bit_tbl64(u64 tbl, uint idx, uint bit_width)
// MS bits - see http://www.mindcontrol.org/~hplus/graphics/expand-bits.html ;
// this is also the algorithm used by graphics cards when decompressing S3TC).
// used to convert 565 to 32bpp RGB.
static uint unpack_to_8(u16 c, uint bits_below, uint num_bits)
static inline uint unpack_to_8(u16 c, uint bits_below, uint num_bits)
{
const uint num_filler_bits = 8-num_bits;
const uint field = bits(c, bits_below, bits_below+num_bits-1);