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:
parent
13501cf58b
commit
2a8953452d
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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__
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user