-move app-specific stuff out of lib/ and into "hooks". see new lib/app_hooks* (note X macro goodness)
-move tex_codec stuff out of tex.cpp and into tex_codec.cpp -tex_codec: use linked list of codecs instead of array (simplifies code and removes limit) -ogl_tex: add override mechanism for s3tc/automipmapgen extension detect -tired of keeping of debug_warn text in sync with function name; now use __func__ everywhere (and emulate that with __FUNCTION__ on MSC) -add ONCE_NOT (opposite of ONCE) -fix 3!! stupid bugs in ia32_control87, its caller and the header that were canceling each other out. float exceptions now enabled except for "inexact result" (too common). (update: nicolai had already fixed 2 of these) This was SVN commit r2964.
This commit is contained in:
parent
2ef8a7b630
commit
b17fbf003d
@ -135,7 +135,7 @@ int da_free(DynArray* da)
|
||||
|
||||
if(da->prot & DA_NOT_OUR_MEM)
|
||||
{
|
||||
debug_warn("da_free: da is marked DA_NOT_OUR_MEM, must not be altered");
|
||||
debug_warn(__func__": da is marked DA_NOT_OUR_MEM, must not be altered");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -156,7 +156,7 @@ int da_set_size(DynArray* da, size_t new_size)
|
||||
|
||||
if(da->prot & DA_NOT_OUR_MEM)
|
||||
{
|
||||
debug_warn("da_set_size: da is marked DA_NOT_OUR_MEM, must not be altered");
|
||||
debug_warn(__func__": da is marked DA_NOT_OUR_MEM, must not be altered");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -191,7 +191,7 @@ int da_set_prot(DynArray* da, int prot)
|
||||
// mmap-ed, which it probably wasn't here.
|
||||
if(da->prot & DA_NOT_OUR_MEM)
|
||||
{
|
||||
debug_warn("da_set_prot: da is marked DA_NOT_OUR_MEM, must not be altered");
|
||||
debug_warn(__func__": da is marked DA_NOT_OUR_MEM, must not be altered");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -336,7 +336,7 @@ void pool_free(Pool* p, void* el)
|
||||
if(pool_contains(p, el))
|
||||
freelist_push(&p->freelist, el);
|
||||
else
|
||||
debug_warn("pool_free: invalid pointer (not in pool)");
|
||||
debug_warn(__func__": invalid pointer (not in pool)");
|
||||
}
|
||||
|
||||
|
||||
|
163
source/lib/app_hooks.cpp
Normal file
163
source/lib/app_hooks.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
// Hooks to allow application-specific behavior
|
||||
// Copyright (c) 2005 Jan Wassenberg
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "detect.h"
|
||||
#include "res/graphics/ogl_tex.h"
|
||||
#include "res/file/file.h"
|
||||
|
||||
#include "app_hooks.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// default implementations
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void override_gl_upload_caps()
|
||||
{
|
||||
if(gfx_card[0] == '\0')
|
||||
debug_warn("get_gfx_info must be called before ogl_tex_upload");
|
||||
|
||||
if(!strcmp(gfx_card, "S3 SuperSavage/IXC 1014"))
|
||||
{
|
||||
if(strstr(gfx_drv_ver, "ssicdnt.dll (2.60.115)"))
|
||||
ogl_tex_override(OGL_TEX_S3TC, OGL_TEX_DISABLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// convert contents of file <in_filename> from char to wchar_t and
|
||||
// append to <out> file.
|
||||
static void cat_atow(FILE* out, const char* in_filename)
|
||||
{
|
||||
FILE* in = fopen(in_filename, "rb");
|
||||
if(!in)
|
||||
{
|
||||
fwprintf(out, L"(unavailable)");
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t buf_size = 1024;
|
||||
char buf[buf_size+1]; // include space for trailing '\0'
|
||||
|
||||
while(!feof(in))
|
||||
{
|
||||
size_t bytes_read = fread(buf, 1, buf_size, in);
|
||||
if(!bytes_read)
|
||||
break;
|
||||
buf[bytes_read] = 0; // 0-terminate
|
||||
fwprintf(out, L"%hs", buf);
|
||||
}
|
||||
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
static void bundle_logs(FILE* f)
|
||||
{
|
||||
// for user convenience, bundle all logs into this file:
|
||||
char N_path[PATH_MAX];
|
||||
|
||||
fwprintf(f, L"System info:\n\n");
|
||||
(void)file_make_full_native_path("../logs/system_info.txt", N_path);
|
||||
cat_atow(f, N_path);
|
||||
fwprintf(f, L"\n\n====================================\n\n");
|
||||
|
||||
fwprintf(f, L"Main log:\n\n");
|
||||
(void)file_make_full_native_path("../logs/mainlog.html", N_path);
|
||||
cat_atow(f, N_path);
|
||||
fwprintf(f, L"\n\n====================================\n\n");
|
||||
}
|
||||
|
||||
|
||||
// TODO: leaks memory returned by wcsdup
|
||||
static const wchar_t* translate(const wchar_t* text)
|
||||
{
|
||||
#if HAVE_I18N
|
||||
// make sure i18n system is (already|still) initialized.
|
||||
if(g_CurrentLocale)
|
||||
{
|
||||
// be prepared for this to fail, because translation potentially
|
||||
// involves script code and the JS context might be corrupted.
|
||||
#if OS_WIN
|
||||
__try
|
||||
#endif
|
||||
{
|
||||
const wchar_t* text2 = wcsdup(I18n::translate(text).c_str());
|
||||
// only overwrite if wcsdup succeeded, i.e. not out of memory.
|
||||
if(text2)
|
||||
text = text2;
|
||||
}
|
||||
#if OS_WIN
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
static void log(const wchar_t* text)
|
||||
{
|
||||
wprintf(text);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// contains the current set of hooks. starts with the stub values and
|
||||
// may be changed via set_app_hooks.
|
||||
//
|
||||
// rationale: we don't ever need to switch "hook sets", so one global struct
|
||||
// is fine. by always having one defined, we also avoid having to check
|
||||
// if anything was registered yet.
|
||||
static AppHooks ah =
|
||||
{
|
||||
#define FUNC(ret, name, params, param_names, call_prefix) name,
|
||||
#include "app_hooks.h"
|
||||
#undef FUNC
|
||||
|
||||
// int dummy; used to terminate list, since last entry ended with ','.
|
||||
0
|
||||
};
|
||||
|
||||
// register the specified hook function pointers. any of them that
|
||||
// are non-zero override the previous function pointer value
|
||||
// (these default to the stub hooks which are functional but basic).
|
||||
void set_app_hooks(AppHooks* ah_)
|
||||
{
|
||||
debug_assert(ah_);
|
||||
ONCE_NOT(debug_warn(__func__": app hooks already set"));
|
||||
|
||||
// override members in <ah> if they are non-zero in <ah_>
|
||||
// (otherwise, we stick with the defaults set above)
|
||||
#define FUNC(ret, name, params, param_names, call_prefix) if(ah_->name) ah.name = ah_->name;
|
||||
#include "app_hooks.h"
|
||||
#undef FUNC
|
||||
}
|
||||
|
||||
// trampolines used by lib code; they call the hooks or fall back to the
|
||||
// default implementation if not set.
|
||||
#define FUNC(ret, name, params, param_names, call_prefix) inline ret ah_##name params { call_prefix ah.name param_names; }
|
||||
#include "app_hooks.h"
|
||||
#undef FUNC
|
128
source/lib/app_hooks.h
Normal file
128
source/lib/app_hooks.h
Normal file
@ -0,0 +1,128 @@
|
||||
// Hooks to allow application-specific behavior
|
||||
// Copyright (c) 2005 Jan Wassenberg
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
/*
|
||||
|
||||
Background
|
||||
----------
|
||||
|
||||
This codebase is shared between several projects, each with differing needs.
|
||||
Some of them have e.g. complicated i18n/translation facilities and require
|
||||
all text output to go through it; others strive to minimize size and
|
||||
therefore do not want to include that.
|
||||
Since commenting things out isn't an option with shared source and
|
||||
conditional compilation is ugly, we bridge the differences via "hooks".
|
||||
These are functions whose behavior is expected to differ between projects;
|
||||
they are defined by the app, registered here and called from lib code via
|
||||
our trampolines.
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This module provides a clean interface for other code to call hooks
|
||||
and allows the app to register them. It also defines default stub
|
||||
implementations.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
In the simplest case, the stubs are already acceptable. Otherwise,
|
||||
you need to implement a new version of some hooks, fill an
|
||||
AppHooks struct with pointers to those functions (zero the rest),
|
||||
and call set_app_hooks.
|
||||
|
||||
*/
|
||||
|
||||
// X macros that define the individual hooks. All function pointers,
|
||||
// struct contents, trampoline functions etc. are automatically
|
||||
// generated from them to ease maintenance.
|
||||
// When adding a new hook, you need only update this and write a
|
||||
// default (stub) implementation.
|
||||
//
|
||||
// params:
|
||||
// - ret: return value type
|
||||
// - name: function name identifier
|
||||
// - params: parameter declarations, used when declaring the function;
|
||||
// enclosed in parentheses.
|
||||
// - param_names: names of parameters, used when calling the function;
|
||||
// enclosed in parentheses.
|
||||
// - call_prefix: precedes the call to this function.
|
||||
// must be (without quotes) '(void)' if ret is void, else 'return'.
|
||||
// this is to allow generating trampoline functions with or without
|
||||
// a return value.
|
||||
#ifdef FUNC
|
||||
|
||||
// override default decision on using OpenGL extensions relating to
|
||||
// texture upload. this should call ogl_tex_override to disable/force
|
||||
// their use if the current card/driver combo respectively crashes or
|
||||
// supports it even though the extension isn't advertised.
|
||||
//
|
||||
// default implementation works but is hardwired in code and therefore
|
||||
// not expandable.
|
||||
FUNC(void, override_gl_upload_caps, (void), (), (void))
|
||||
|
||||
// gather all app-related logs/information and write it into <f>.
|
||||
// used when writing a crashlog so that all relevant info is in one file.
|
||||
//
|
||||
// default implementation gathers 0ad data but is fail-safe.
|
||||
FUNC(void, bundle_logs, (FILE* f), (f), (void))
|
||||
|
||||
// return localized version of <text> if i18n functionality is available.
|
||||
//
|
||||
// default implementation just returns the pointer unchanged.
|
||||
FUNC(const wchar_t*, translate, (const wchar_t* text), (text), return)
|
||||
|
||||
// write <text> to the app's log.
|
||||
//
|
||||
// default implementation uses stdout.
|
||||
FUNC(void, log, (const wchar_t* text), (text), (void))
|
||||
|
||||
#endif // #ifdef FUNC
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// normal header part
|
||||
|
||||
#ifndef APP_HOOKS_H__
|
||||
#define APP_HOOKS_H__
|
||||
|
||||
// holds a function pointer for each hook. passed to set_app_hooks.
|
||||
struct AppHooks
|
||||
{
|
||||
#define FUNC(ret, name, params, param_names, call_prefix) ret(*name) params;
|
||||
#include "app_hooks.h"
|
||||
#undef FUNC
|
||||
|
||||
// used to safely terminate initializer list
|
||||
int dummy;
|
||||
};
|
||||
|
||||
// register the specified hook function pointers. any of them that
|
||||
// are non-zero override the previous function pointer value
|
||||
// (these default to the stub hooks which are functional but basic).
|
||||
extern void set_app_hooks(AppHooks* ah);
|
||||
|
||||
|
||||
// trampolines used by lib code to call the hooks. they encapsulate
|
||||
// the details of how exactly to do this.
|
||||
#define FUNC(ret, name, params, param_names, call_prefix) extern ret ah_##name params;
|
||||
#include "app_hooks.h"
|
||||
#undef FUNC
|
||||
|
||||
#endif // #ifndef APP_HOOKS_H__
|
@ -28,8 +28,7 @@
|
||||
// so that our allocations don't cause infinite recursion.
|
||||
#include "nommgr.h"
|
||||
#include "self_test.h"
|
||||
// file_make_full_native_path is needed when bundling game data files.
|
||||
#include "lib/res/file/file.h"
|
||||
#include "app_hooks.h"
|
||||
|
||||
// needed when writing crashlog
|
||||
static const size_t LOG_CHARS = 16384;
|
||||
@ -60,7 +59,7 @@ void debug_wprintf_mem(const wchar_t* fmt, ...)
|
||||
va_end(args);
|
||||
if(len < 0)
|
||||
{
|
||||
debug_warn("debug_wprintf_mem: vswprintf failed");
|
||||
debug_warn(__func__": vswprintf failed");
|
||||
return;
|
||||
}
|
||||
debug_log_pos += len+2;
|
||||
@ -68,59 +67,22 @@ void debug_wprintf_mem(const wchar_t* fmt, ...)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// convert contents of file <in_filename> from char to wchar_t and
|
||||
// append to <out> file. used by debug_write_crashlog.
|
||||
static void cat_atow(FILE* out, const char* in_filename)
|
||||
{
|
||||
FILE* in = fopen(in_filename, "rb");
|
||||
if(!in)
|
||||
{
|
||||
fwprintf(out, L"(unavailable)");
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t buf_size = 1024;
|
||||
char buf[buf_size+1]; // include space for trailing '\0'
|
||||
|
||||
while(!feof(in))
|
||||
{
|
||||
size_t bytes_read = fread(buf, 1, buf_size, in);
|
||||
if(!bytes_read)
|
||||
break;
|
||||
buf[bytes_read] = 0; // 0-terminate
|
||||
fwprintf(out, L"%hs", buf);
|
||||
}
|
||||
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
|
||||
int debug_write_crashlog(const wchar_t* text)
|
||||
{
|
||||
const wchar_t divider[] = L"\n\n====================================\n\n";
|
||||
#define WRITE_DIVIDER fwprintf(f, divider);
|
||||
|
||||
FILE* f = fopen("crashlog.txt", "w");
|
||||
if(!f)
|
||||
{
|
||||
DISPLAY_ERROR(L"debug_write_crashlog: unable to open file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fputwc(0xfeff, f); // BOM
|
||||
|
||||
fwprintf(f, L"%ls\n", text);
|
||||
WRITE_DIVIDER
|
||||
fwprintf(f, L"\n\n====================================\n\n");
|
||||
|
||||
// for user convenience, bundle all logs into this file:
|
||||
char N_path[PATH_MAX];
|
||||
fwprintf(f, L"System info:\n\n");
|
||||
(void)file_make_full_native_path("../logs/system_info.txt", N_path);
|
||||
cat_atow(f, N_path);
|
||||
WRITE_DIVIDER
|
||||
fwprintf(f, L"Main log:\n\n");
|
||||
(void)file_make_full_native_path("../logs/mainlog.html", N_path);
|
||||
cat_atow(f, N_path);
|
||||
WRITE_DIVIDER
|
||||
// allow user to bundle whatever information they want
|
||||
ah_bundle_logs(f);
|
||||
|
||||
|
||||
fwprintf(f, L"Last known activity:\n\n %ls\n", debug_log);
|
||||
|
||||
|
@ -149,8 +149,8 @@ static void get_cpu_info()
|
||||
void cpu_init()
|
||||
{
|
||||
#if CPU_IA32
|
||||
// must come before any uses of ia32.asm, e.g. by get_cpu_info
|
||||
ia32_init();
|
||||
#endif
|
||||
|
||||
// no longer set 24 bit (float) precision by default: for
|
||||
// very long game uptimes (> 1 day; e.g. dedicated server),
|
||||
@ -159,19 +159,19 @@ void cpu_init()
|
||||
// we can temporarily change precision there.
|
||||
//_control87(_PC_24, _MCW_PC);
|
||||
|
||||
// disable all floating-point exceptions except zero-divide
|
||||
// Note that most exceptions are triggered by the JS engine.
|
||||
// to help catch bugs, enable as many floating-point exceptions as
|
||||
// possible. that means only zero-divide, because the JS engine is
|
||||
// triggering the rest.
|
||||
_control87(_MCW_PM|_MCW_IM|_MCW_UM|_MCW_OM|_MCW_DM, _MCW_EM);
|
||||
|
||||
// If possible, hook up capability-sensitive assembler routines
|
||||
ia32_hook_capabilities();
|
||||
#endif
|
||||
|
||||
// detects CPU clock frequency and capabilities, which are prerequisites
|
||||
// for using the TSC as a timer (desirable due to its high resolution).
|
||||
// do this before lengthy init so we can time those accurately.
|
||||
get_cpu_info();
|
||||
|
||||
#if CPU_IA32
|
||||
// If possible, hook up capability-sensitive assembler routines
|
||||
ia32_hook_capabilities();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -36,14 +36,15 @@ static int handler_stack_top = 0;
|
||||
|
||||
int in_add_handler(EventHandler handler)
|
||||
{
|
||||
if(handler_stack_top >= MAX_HANDLERS || !handler)
|
||||
debug_assert(handler);
|
||||
|
||||
if(handler_stack_top >= MAX_HANDLERS)
|
||||
{
|
||||
debug_warn("in_add_handler");
|
||||
debug_warn(__func__": increase MAX_HANDLERS");
|
||||
return -1;
|
||||
}
|
||||
|
||||
handler_stack[handler_stack_top++] = handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -62,7 +63,7 @@ void dispatch_event(const SDL_Event* event)
|
||||
continue;
|
||||
// .. invalid return value
|
||||
else
|
||||
debug_warn("dispatch_event: invalid handler return value");
|
||||
debug_warn(__func__": invalid handler return value");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,7 @@ scope
|
||||
#include "lib/types.h"
|
||||
|
||||
#include "sysdep/sysdep.h"
|
||||
#include "sysdep/cpu.h" // CAS
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
@ -78,6 +79,8 @@ scope
|
||||
// squelch the warning (unfortunately non-portable).
|
||||
#define STMT(STMT_code__) do { STMT_code__; } while(false)
|
||||
|
||||
// execute the code passed as a parameter only the first time this is
|
||||
// reached.
|
||||
// may be called at any time (in particular before main), but is not
|
||||
// thread-safe. if that's important, use pthread_once() instead.
|
||||
#define ONCE(ONCE_code__)\
|
||||
@ -90,6 +93,20 @@ STMT(\
|
||||
}\
|
||||
)
|
||||
|
||||
// execute the code passed as a parameter except the first time this is
|
||||
// reached.
|
||||
// may be called at any time (in particular before main), but is not
|
||||
// thread-safe.
|
||||
#define ONCE_NOT(ONCE_code__)\
|
||||
STMT(\
|
||||
static bool ONCE_done__ = false;\
|
||||
if(!ONCE_done__)\
|
||||
ONCE_done__ = true;\
|
||||
else\
|
||||
ONCE_code__;\
|
||||
)
|
||||
|
||||
|
||||
|
||||
// be careful here. the given expression (e.g. variable or
|
||||
// function return value) may be a Handle (=i64), so it needs to be
|
||||
|
@ -174,7 +174,7 @@ bool oglHaveVersion(const char* desired_version)
|
||||
int desired_major, desired_minor;
|
||||
if(sscanf(desired_version, "%d.%d", &desired_major, &desired_minor) != 2)
|
||||
{
|
||||
debug_warn("oglHaveVersion: invalid version string");
|
||||
debug_warn(__func__": invalid version string");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ bool oglHaveVersion(const char* desired_version)
|
||||
const char* version = (const char*)glGetString(GL_VERSION);
|
||||
if(!version || sscanf(version, "%d.%d", &major, &minor) != 2)
|
||||
{
|
||||
debug_warn("oglHaveVersion: GL_VERSION invalid");
|
||||
debug_warn(__func__": GL_VERSION invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -288,7 +288,7 @@ void oglCheck()
|
||||
}
|
||||
|
||||
if(error_enountered)
|
||||
debug_warn("oglCheck reports error(s)");
|
||||
debug_warn(__func__": OpenGL error(s) occurred");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -319,7 +319,7 @@ void oglSquelchError(GLenum err_to_ignore)
|
||||
}
|
||||
|
||||
if(error_enountered)
|
||||
debug_warn("oglSquelchError reports other error(s)");
|
||||
debug_warn(__func__": OpenGL error(s) occurred");
|
||||
}
|
||||
|
||||
|
||||
@ -360,7 +360,7 @@ void oglInit()
|
||||
// time-critical) than centralizing the 'OpenGL is ready' check.
|
||||
exts = (const char*)glGetString(GL_EXTENSIONS);
|
||||
if(!exts)
|
||||
debug_warn("oglInit called before OpenGL is ready for use");
|
||||
debug_warn(__func__": called before OpenGL is ready for use");
|
||||
have_12 = oglHaveVersion("1.2");
|
||||
have_13 = oglHaveVersion("1.3");
|
||||
have_14 = oglHaveVersion("1.4");
|
||||
|
@ -288,10 +288,10 @@ int file_set_root_dir(const char* argv0, const char* rel_path)
|
||||
}
|
||||
|
||||
fail:
|
||||
debug_warn("file_set_root_dir failed");
|
||||
debug_warn(__func__" failed");
|
||||
if(msg)
|
||||
{
|
||||
debug_printf("file_set_root_dir: %s\n", msg);
|
||||
debug_printf(__func__": %s\n", msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -781,7 +781,7 @@ int file_io_issue(File* f, off_t ofs, size_t size, void* p, FileIo* io)
|
||||
const off_t bytes_left = f->size - ofs;
|
||||
if(bytes_left < 0)
|
||||
{
|
||||
debug_warn("file_io_issue: EOF");
|
||||
debug_warn(__func__": EOF");
|
||||
return ERR_EOF;
|
||||
}
|
||||
if((off_t)size > bytes_left)
|
||||
@ -832,7 +832,7 @@ int file_io_has_completed(FileIo* io)
|
||||
if(ret == 0)
|
||||
return 1;
|
||||
|
||||
debug_warn("file_io_has_completed: unexpected aio_error return");
|
||||
debug_warn(__func__": unexpected aio_error return");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -840,7 +840,7 @@ int file_io_has_completed(FileIo* io)
|
||||
int file_io_wait(FileIo* io, void*& p, size_t& size)
|
||||
{
|
||||
#if CONFIG_PARANOIA
|
||||
debug_printf("file_io_wait: hio=%p\n", io);
|
||||
debug_printf(__func__": hio=%p\n", io);
|
||||
#endif
|
||||
|
||||
// zero output params in case something (e.g. H_DEREF) fails.
|
||||
@ -857,7 +857,7 @@ debug_printf("file_io_wait: hio=%p\n", io);
|
||||
// query number of bytes transferred (-1 if the transfer failed)
|
||||
const ssize_t bytes_transferred = aio_return(cb);
|
||||
#if CONFIG_PARANOIA
|
||||
debug_printf("file_io_wait: bytes_transferred=%d aio_nbytes=%d\n",
|
||||
debug_printf(__func__": bytes_transferred=%d aio_nbytes=%d\n",
|
||||
bytes_transferred, cb->aio_nbytes);
|
||||
#endif
|
||||
// (size was clipped to EOF in file_io => this is an actual IO error)
|
||||
@ -1004,7 +1004,7 @@ static void* block_find(u64 block_id)
|
||||
static void block_add(u64 block_id, void* block)
|
||||
{
|
||||
if(block_find(block_id))
|
||||
debug_warn("block_add: already in cache");
|
||||
debug_warn(__func__": already in cache");
|
||||
else
|
||||
block_cache[block_id] = block;
|
||||
}
|
||||
@ -1115,7 +1115,7 @@ debug_printf("file_io fd=%d size=%d ofs=%d\n", f->fd, data_size, data_ofs);
|
||||
// (not reading OR using lowio OR no callback)
|
||||
if(temp && (is_write || no_aio || !cb))
|
||||
{
|
||||
debug_warn("file_io: invalid parameter");
|
||||
debug_warn(__func__": invalid parameter");
|
||||
return ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
@ -1334,7 +1334,7 @@ int file_map(File* f, void*& p, size_t& size)
|
||||
// prevent overflow; if we have this many refs, should find out why.
|
||||
if(f->map_refs >= MAX_MAP_REFS)
|
||||
{
|
||||
debug_warn("file_map: too many references to mapping");
|
||||
debug_warn(__func__": too many references to mapping");
|
||||
return -1;
|
||||
}
|
||||
f->map_refs++;
|
||||
@ -1374,7 +1374,7 @@ int file_unmap(File* f)
|
||||
// file is not currently mapped
|
||||
if(f->map_refs == 0)
|
||||
{
|
||||
debug_warn("file_unmap: not currently mapped");
|
||||
debug_warn(__func__": not currently mapped");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,7 @@ int vfs_dir_next_ent(const Handle hd, DirEnt* ent, const char* filter)
|
||||
vd->filter_latched = 1;
|
||||
}
|
||||
if(vd->filter != filter)
|
||||
debug_warn("vfs_dir_next_ent: filter has changed for this directory. are you scanning it twice?");
|
||||
debug_warn(__func__": filter has changed for this directory. are you scanning it twice?");
|
||||
#endif
|
||||
|
||||
bool want_dir = true;
|
||||
@ -269,7 +269,7 @@ static void file_listing_add(const char* v_fn)
|
||||
// we've already shut down - complain.
|
||||
if(file_listing_enabled == -1)
|
||||
{
|
||||
debug_warn("file_listing_add: called after file_listing_shutdown atexit");
|
||||
debug_warn(__func__": called after file_listing_shutdown atexit");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -296,7 +296,7 @@ void vfs_enable_file_listing(bool want_enabled)
|
||||
// already shut down - don't allow enabling
|
||||
if(file_listing_enabled == -1 && want_enabled)
|
||||
{
|
||||
debug_warn("vfs_enable_file_listing: enabling after shutdown");
|
||||
debug_warn(__func__": enabling after shutdown");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -567,7 +567,7 @@ debug_printf("vfs_load v_fn=%s\n", v_fn);
|
||||
goto ret;
|
||||
}
|
||||
else
|
||||
debug_warn("vfs_load: invalid MEM attached to vfile (0 pointer)");
|
||||
debug_warn(__func__": invalid MEM attached to vfile (0 pointer)");
|
||||
// happens if someone frees the pointer. not an error!
|
||||
}
|
||||
/*
|
||||
|
@ -543,7 +543,7 @@ static int remount(const Mount& m)
|
||||
case MT_FILE:
|
||||
return mount_dir_tree(td, m);
|
||||
default:
|
||||
debug_warn("remount: invalid type");
|
||||
debug_warn(__func__": invalid type");
|
||||
return ERR_CORRUPTED;
|
||||
}
|
||||
}
|
||||
@ -578,7 +578,7 @@ int vfs_mount(const char* V_mount_point, const char* P_real_path, int flags, uin
|
||||
#ifndef NDEBUG
|
||||
const size_t len = strlen(V_mount_point);
|
||||
if(len && V_mount_point[len-1] != '/')
|
||||
debug_warn("vfs_mount: path doesn't end in '/'");
|
||||
debug_warn(__func__": path doesn't end in '/'");
|
||||
#endif
|
||||
|
||||
// make sure it's not already mounted, i.e. in mounts.
|
||||
@ -591,7 +591,7 @@ int vfs_mount(const char* V_mount_point, const char* P_real_path, int flags, uin
|
||||
{
|
||||
if(file_is_subpath(P_real_path, it->P_name.c_str()))
|
||||
{
|
||||
debug_warn("vfs_mount: already mounted");
|
||||
debug_warn(__func__": already mounted");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -601,7 +601,7 @@ int vfs_mount(const char* V_mount_point, const char* P_real_path, int flags, uin
|
||||
// "./" and "/." are caught by CHECK_PATH.
|
||||
if(!strcmp(P_real_path, "."))
|
||||
{
|
||||
debug_warn("vfs_mount: mounting . not allowed");
|
||||
debug_warn(__func__": mounting . not allowed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -874,7 +874,7 @@ int x_realpath(const Mount* m, const char* V_exact_path, char* P_real_path)
|
||||
P_parent_path = m->P_name.c_str();
|
||||
break;
|
||||
default:
|
||||
debug_warn("x_realpath: invalid type");
|
||||
debug_warn(__func__": invalid type");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -895,7 +895,7 @@ int x_open(const Mount* m, const char* V_exact_path, int flags, TFile* tf, XFile
|
||||
case MT_ARCHIVE:
|
||||
if(flags & FILE_WRITE)
|
||||
{
|
||||
debug_warn("requesting write access to file in archive");
|
||||
debug_warn(__func__": requesting write access to file in archive");
|
||||
return -1;
|
||||
}
|
||||
RETURN_ERR(zip_open(m->archive, V_exact_path, flags, &xf->u.zf));
|
||||
@ -905,7 +905,7 @@ int x_open(const Mount* m, const char* V_exact_path, int flags, TFile* tf, XFile
|
||||
RETURN_ERR(file_open(P_path, flags, &xf->u.f));
|
||||
break;
|
||||
default:
|
||||
debug_warn("VFile_reload: invalid type");
|
||||
debug_warn(__func__": invalid type");
|
||||
return ERR_CORRUPTED;
|
||||
}
|
||||
|
||||
@ -933,7 +933,7 @@ int x_close(XFile* xf)
|
||||
(void)file_close(&xf->u.f);
|
||||
break;
|
||||
default:
|
||||
debug_warn("x_close: invalid type");
|
||||
debug_warn(__func__": invalid type");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1022,7 +1022,7 @@ int x_io(XFile* xf, off_t ofs, size_t size, void* buf, FileIOCB cb, uintptr_t ct
|
||||
return file_io(&xf->u.f, ofs, size, buf, cb, ctx);
|
||||
|
||||
default:
|
||||
debug_warn("vfs_io: invalid file type");
|
||||
debug_warn(__func__": invalid file type");
|
||||
return ERR_CORRUPTED;
|
||||
}
|
||||
}
|
||||
@ -1037,7 +1037,7 @@ int x_map(XFile* xf, void*& p, size_t& size)
|
||||
case MT_FILE:
|
||||
return file_map(&xf->u.f, p, size);
|
||||
default:
|
||||
debug_warn("vfs_map: invalid type");
|
||||
debug_warn(__func__": invalid file type");
|
||||
return ERR_CORRUPTED;
|
||||
}
|
||||
}
|
||||
@ -1052,7 +1052,7 @@ int x_unmap(XFile* xf)
|
||||
case MT_FILE:
|
||||
return file_unmap(&xf->u.f);
|
||||
default:
|
||||
debug_warn("vfs_unmap: invalid type");
|
||||
debug_warn(__func__": invalid file type");
|
||||
return ERR_CORRUPTED;
|
||||
}
|
||||
}
|
||||
@ -1068,7 +1068,7 @@ int x_io_issue(XFile* xf, off_t ofs, size_t size, void* buf, XIo* xio)
|
||||
case MT_FILE:
|
||||
return file_io_issue(&xf->u.f, ofs, size, buf, &xio->u.fio);
|
||||
default:
|
||||
debug_warn("vfs_io_issue: invalid file type");
|
||||
debug_warn(__func__": invalid file type");
|
||||
return ERR_CORRUPTED;
|
||||
}
|
||||
}
|
||||
@ -1083,7 +1083,7 @@ int x_io_has_completed(XIo* xio)
|
||||
case MT_FILE:
|
||||
return file_io_has_completed(&xio->u.fio);
|
||||
default:
|
||||
debug_warn("vfs_io_has_completed: invalid type");
|
||||
debug_warn(__func__": invalid file type");
|
||||
return ERR_CORRUPTED;
|
||||
}
|
||||
}
|
||||
@ -1098,7 +1098,7 @@ int x_io_wait(XIo* xio, void*& p, size_t& size)
|
||||
case MT_FILE:
|
||||
return file_io_wait(&xio->u.fio, p, size);
|
||||
default:
|
||||
debug_warn("vfs_io_wait: invalid type");
|
||||
debug_warn(__func__": invalid file type");
|
||||
return ERR_CORRUPTED;
|
||||
}
|
||||
}
|
||||
@ -1113,7 +1113,7 @@ int x_io_discard(XIo* xio)
|
||||
case MT_FILE:
|
||||
return file_io_discard(&xio->u.fio);
|
||||
default:
|
||||
debug_warn("VIo_dtor: invalid type");
|
||||
debug_warn(__func__": invalid file type");
|
||||
return ERR_CORRUPTED;
|
||||
}
|
||||
}
|
||||
@ -1128,7 +1128,7 @@ int x_io_validate(const XIo* xio)
|
||||
case MT_FILE:
|
||||
return file_io_validate(&xio->u.fio);
|
||||
default:
|
||||
return -103; // invalid type
|
||||
return -100; // invalid type
|
||||
}
|
||||
UNREACHABLE;
|
||||
}
|
@ -81,8 +81,8 @@ int path_validate(const uint line, const char* path)
|
||||
// failed somewhere - err is the error code,
|
||||
// or -1 if not set specifically above.
|
||||
fail:
|
||||
debug_printf("path_validate at line %d failed: %s (error code %d)\n", line, msg, err);
|
||||
debug_warn("path_validate failed");
|
||||
debug_printf(__func__" at line %d failed: %s (error code %d)\n", line, msg, err);
|
||||
debug_warn(__func__" failed");
|
||||
return err;
|
||||
|
||||
ok:
|
||||
|
@ -106,7 +106,7 @@ TNode* node_alloc(size_t size)
|
||||
// would overflow a bucket
|
||||
if(size > BUCKET_SIZE-sizeof(u8*))
|
||||
{
|
||||
debug_warn("node_alloc: size doesn't fit in a bucket");
|
||||
debug_warn(__func__": size doesn't fit in a bucket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -458,7 +458,7 @@ int TDir::add(const char* name, TNodeType new_type, TNode** pnode)
|
||||
|
||||
if(!children.add(name, node))
|
||||
{
|
||||
debug_warn("failed to expand table");
|
||||
debug_warn(__func__": failed to expand table");
|
||||
// node will be freed by node_free_all
|
||||
return 0;
|
||||
}
|
||||
@ -816,7 +816,7 @@ int tree_dir_next_ent(TreeDirIterator* d_, DirEnt* ent)
|
||||
ent->mtime = node->u.file.mtime;
|
||||
break;
|
||||
default:
|
||||
debug_warn("invalid TNode type");
|
||||
debug_warn(__func__": invalid TNode type");
|
||||
}
|
||||
|
||||
return 0; // success
|
||||
|
@ -139,7 +139,7 @@ static const u8* z_find_id(const u8* file, size_t size, const u8* start, const c
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if(p != start)
|
||||
debug_warn("z_find_id: archive damaged, but still found next record.");
|
||||
debug_warn(__func__": archive damaged, but still found next record.");
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
@ -150,7 +150,7 @@ static const u8* z_find_id(const u8* file, size_t size, const u8* start, const c
|
||||
}
|
||||
|
||||
// passed EOF, didn't find it.
|
||||
debug_warn("z_find_id: archive corrupted, next record not found.");
|
||||
debug_warn(__func__": archive corrupted, next record not found.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -203,7 +203,7 @@ static time_t convert_dos_date(u16 fatdate, u16 fattime)
|
||||
|
||||
time_t ret = mktime(&t);
|
||||
if(ret == (time_t)-1)
|
||||
debug_warn("convert_dos_date: mktime failed");
|
||||
debug_warn(__func__": mktime failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -764,7 +764,7 @@ int inf_set_dest(uintptr_t _ctx, void* out, size_t out_size)
|
||||
|
||||
if(zs->next_out || zs->avail_out)
|
||||
{
|
||||
debug_warn("zip_set_dest: ctx already in use!");
|
||||
debug_warn(__func__": ctx already in use!");
|
||||
return -1;
|
||||
}
|
||||
zs->next_out = (Byte*)out;
|
||||
@ -804,7 +804,7 @@ double t0 = get_time();
|
||||
if(in)
|
||||
{
|
||||
if(ctx->in_buf)
|
||||
debug_warn("inf_inflate: previous input buffer not empty");
|
||||
debug_warn(__func__": previous input buffer not empty");
|
||||
zs->avail_in = (uInt)in_size;
|
||||
zs->next_in = (Byte*)in;
|
||||
|
||||
@ -1231,7 +1231,7 @@ int zip_map(ZFile* zf, void*& p, size_t& size)
|
||||
// compression algorithm is unspecified - disallow it.
|
||||
if(zfile_compressed(zf))
|
||||
{
|
||||
debug_warn("zip_map: file is compressed");
|
||||
debug_warn(__func__": file is compressed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ static GLint choose_fmt(uint bpp, uint flags)
|
||||
case 5:
|
||||
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
default:
|
||||
debug_warn("choose_fmt: invalid DXT value");
|
||||
debug_warn(__func__": invalid DXT value");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -138,7 +138,7 @@ static GLint choose_fmt(uint bpp, uint flags)
|
||||
debug_assert(alpha);
|
||||
return bgr? GL_BGRA : GL_RGBA;
|
||||
default:
|
||||
debug_warn("choose_fmt: invalid bpp");
|
||||
debug_warn(__func__": invalid bpp");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -227,7 +227,7 @@ static GLint choose_int_fmt(GLenum fmt, uint q_flags)
|
||||
return half_bpp? GL_RGBA4 : GL_RGBA8;
|
||||
|
||||
default:
|
||||
debug_warn("choose_int_fmt doesn't cover the given fmt! please add it.");
|
||||
debug_warn(__func__": given fmt isn't covered! please add it.");
|
||||
// fall back to a reasonable default
|
||||
return half_bpp? GL_RGB4 : GL_RGB8;
|
||||
}
|
||||
@ -615,7 +615,7 @@ void ogl_tex_override(OglTexOverrides what, OglTexAllow allow)
|
||||
have_auto_mipmap_gen = enable;
|
||||
break;
|
||||
default:
|
||||
debug_warn("ogl_tex_override: invalid <what>");
|
||||
debug_warn(__func__": invalid <what>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -640,15 +640,6 @@ static void detect_gl_upload_caps()
|
||||
}
|
||||
|
||||
//apphook - call back into override if app thinks anything should be disabled
|
||||
// disable features if we're on a card/driver combo on which they
|
||||
// are known to break.
|
||||
if(gfx_card[0] == '\0')
|
||||
debug_warn("ogl_tex requires get_gfx_info be called before ogl_tex_upload");
|
||||
if(!strcmp(gfx_card, "S3 SuperSavage/IXC 1014"))
|
||||
{
|
||||
if(strstr(gfx_drv_ver, "ssicdnt.dll (2.60.115)"))
|
||||
have_s3tc = false;
|
||||
}
|
||||
|
||||
// warn if more-or-less essential features are missing
|
||||
if(!have_s3tc)
|
||||
@ -871,7 +862,7 @@ int ogl_tex_get_format(Handle ht, uint* flags, GLenum* fmt)
|
||||
if(fmt)
|
||||
{
|
||||
if(!ot->is_currently_uploaded)
|
||||
debug_warn("ogl_tex_get_format: hasn't been defined yet!");
|
||||
debug_warn(__func__": hasn't been defined yet!");
|
||||
*fmt = ot->fmt;
|
||||
}
|
||||
return 0;
|
||||
|
@ -249,6 +249,8 @@ enum OglTexAllow
|
||||
OGL_TEX_ENABLE
|
||||
};
|
||||
|
||||
// override the default decision and force/disallow use of the
|
||||
// given feature. should be called from ah_override_gl_upload_caps.
|
||||
extern void ogl_tex_override(OglTexOverrides what, OglTexAllow allow);
|
||||
|
||||
// upload the texture to OpenGL.
|
||||
|
@ -331,7 +331,7 @@ static void flip_to_global_orientation(Tex* t)
|
||||
// dst_orientation (if the latter is 0, then the global_orientation).
|
||||
// (we ask for src_flags instead of src_orientation so callers don't
|
||||
// have to mask off TEX_ORIENTATION)
|
||||
static bool orientations_match(uint src_flags, uint dst_orientation)
|
||||
bool tex_orientations_match(uint src_flags, uint dst_orientation)
|
||||
{
|
||||
const uint src_orientation = src_flags & TEX_ORIENTATION;
|
||||
if(dst_orientation == 0)
|
||||
@ -344,51 +344,6 @@ static bool orientations_match(uint src_flags, uint dst_orientation)
|
||||
// util
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// allocate an array of row pointers that point into the given texture data.
|
||||
// <file_orientation> indicates whether the file format is top-down or
|
||||
// bottom-up; the row array is inverted if necessary to match global
|
||||
// orienatation. (this is more efficient than "transforming" later)
|
||||
//
|
||||
// used by PNG and JPG codecs; caller must free() rows when done.
|
||||
//
|
||||
// note: we don't allocate the data param ourselves because this function is
|
||||
// needed for encoding, too (where data is already present).
|
||||
int tex_util_alloc_rows(const u8* data, size_t h, size_t pitch,
|
||||
uint src_flags, uint dst_orientation, RowArray& rows)
|
||||
{
|
||||
const bool flip = !orientations_match(src_flags, dst_orientation);
|
||||
|
||||
rows = (RowArray)malloc(h * sizeof(RowPtr));
|
||||
if(!rows)
|
||||
return ERR_NO_MEM;
|
||||
|
||||
// determine start position and direction
|
||||
RowPtr pos = flip? data+pitch*(h-1) : data;
|
||||
const ssize_t add = flip? -(ssize_t)pitch : (ssize_t)pitch;
|
||||
const RowPtr end = flip? data-pitch : data+pitch*h;
|
||||
|
||||
for(size_t i = 0; i < h; i++)
|
||||
{
|
||||
rows[i] = pos;
|
||||
pos += add;
|
||||
}
|
||||
|
||||
debug_assert(pos == end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tex_util_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da)
|
||||
{
|
||||
RETURN_ERR(tex_transform(t, transforms));
|
||||
|
||||
void* img_data = tex_get_data(t); const size_t img_size = tex_img_size(t);
|
||||
RETURN_ERR(da_append(da, hdr, hdr_size));
|
||||
RETURN_ERR(da_append(da, img_data, img_size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void tex_util_foreach_mipmap(uint w, uint h, uint bpp, const u8* restrict data,
|
||||
int levels_to_skip, uint data_padding, MipmapCB cb, void* restrict ctx)
|
||||
{
|
||||
@ -433,109 +388,6 @@ void tex_util_foreach_mipmap(uint w, uint h, uint bpp, const u8* restrict data,
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// support routines for codecs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// should be a tight bound because we iterate this many times (for convenience)
|
||||
static const uint MAX_CODECS = 8;
|
||||
static const TexCodecVTbl* codecs[MAX_CODECS];
|
||||
|
||||
// add this vtbl to the codec list. called at NLSO init time by the
|
||||
// TEX_CODEC_REGISTER in each codec file. note that call order and therefore
|
||||
// order in the list is undefined, but since each codec only steps up if it
|
||||
// can handle the given format, this is not a problem.
|
||||
int tex_codec_register(const TexCodecVTbl* c)
|
||||
{
|
||||
debug_assert(c != 0 && "tex_codec_register(0) - why?");
|
||||
|
||||
for(uint i = 0; i < MAX_CODECS; i++)
|
||||
{
|
||||
// slot available
|
||||
if(codecs[i] == 0)
|
||||
{
|
||||
codecs[i] = c;
|
||||
return 0; // success
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find a free slot.
|
||||
debug_warn("tex_codec_register: increase MAX_CODECS");
|
||||
return 0; // failure, but caller ignores return value
|
||||
}
|
||||
|
||||
|
||||
// find codec that recognizes the desired output file extension
|
||||
int tex_codec_for_filename(const char* fn, const TexCodecVTbl** c)
|
||||
{
|
||||
const char* ext = strrchr(fn, '.');
|
||||
if(!ext)
|
||||
return ERR_UNKNOWN_FORMAT;
|
||||
ext++; // skip '.'
|
||||
|
||||
for(uint i = 0; i < MAX_CODECS; i++)
|
||||
{
|
||||
*c = codecs[i];
|
||||
// skip if 0 (e.g. if MAX_CODECS != num codecs)
|
||||
if(!*c)
|
||||
continue;
|
||||
// we found it
|
||||
if((*c)->is_ext(ext))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ERR_UNKNOWN_FORMAT;
|
||||
}
|
||||
|
||||
|
||||
// find codec that recognizes the header's magic field
|
||||
int tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl** c)
|
||||
{
|
||||
// we guarantee at least 4 bytes for is_hdr to look at
|
||||
if(file_size < 4)
|
||||
return ERR_TEX_HEADER_NOT_COMPLETE;
|
||||
for(uint i = 0; i < MAX_CODECS; i++)
|
||||
{
|
||||
*c = codecs[i];
|
||||
// skip if 0 (e.g. if MAX_CODECS != num codecs)
|
||||
if(!*c)
|
||||
continue;
|
||||
// we found it
|
||||
if((*c)->is_hdr(file))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ERR_UNKNOWN_FORMAT;
|
||||
}
|
||||
|
||||
|
||||
static int tex_codec_transform(Tex* t, uint transforms)
|
||||
{
|
||||
int ret = TEX_CODEC_CANNOT_HANDLE;
|
||||
|
||||
// find codec that understands the data, and transform
|
||||
for(int i = 0; i < MAX_CODECS; i++)
|
||||
{
|
||||
// MAX_CODECS isn't a tight bound and we have hit a 0 entry
|
||||
if(!codecs[i])
|
||||
continue;
|
||||
|
||||
int err = codecs[i]->transform(t, transforms);
|
||||
if(err == 0)
|
||||
return 0;
|
||||
else if(err == TEX_CODEC_CANNOT_HANDLE)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
ret = err;
|
||||
debug_warn("tex_codec_transform: codec indicates error");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// API
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -587,7 +439,7 @@ int tex_load(const char* fn, Tex* t)
|
||||
if(ret < 0)
|
||||
{
|
||||
(void)tex_free(t);
|
||||
debug_warn("tex_load failed");
|
||||
debug_warn(__func__" failed");
|
||||
}
|
||||
|
||||
// do not free hm! it either still holds the image data (i.e. texture
|
||||
@ -772,8 +624,8 @@ int tex_write(Tex* t, const char* fn)
|
||||
err = c->encode(t, &da);
|
||||
if(err < 0)
|
||||
{
|
||||
debug_printf("tex_write (%s): %d", c->name, err);
|
||||
debug_warn("tex_writefailed");
|
||||
debug_printf(__func__" (%s): %d", c->name, err);
|
||||
debug_warn(__func__"failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -261,6 +261,12 @@ extern int tex_write(Tex* t, const char* fn);
|
||||
// internal use only:
|
||||
extern int tex_validate(const Tex* t);
|
||||
|
||||
// indicate if the orientation specified by <src_flags> matches
|
||||
// dst_orientation (if the latter is 0, then the global_orientation).
|
||||
// (we ask for src_flags instead of src_orientation so callers don't
|
||||
// have to mask off TEX_ORIENTATION)
|
||||
extern bool tex_orientations_match(uint src_flags, uint dst_orientation);
|
||||
|
||||
typedef void(*MipmapCB)(uint level, uint level_w, uint level_h,
|
||||
const u8* level_data, size_t level_data_size, void* ctx);
|
||||
|
||||
|
@ -129,7 +129,7 @@ static int bmp_encode(Tex* restrict t, DynArray* restrict da)
|
||||
(u32)img_size, // biSizeImage
|
||||
0, 0, 0, 0 // unused (bi?PelsPerMeter, biClr*)
|
||||
};
|
||||
return tex_util_write(t, transforms, &hdr, hdr_size, da);
|
||||
return tex_codec_write(t, transforms, &hdr, hdr_size, da);
|
||||
}
|
||||
|
||||
TEX_CODEC_REGISTER(bmp);
|
||||
|
133
source/lib/res/graphics/tex_codec.cpp
Normal file
133
source/lib/res/graphics/tex_codec.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tex_codec.h"
|
||||
#include "tex.h"
|
||||
|
||||
static const TexCodecVTbl* codecs;
|
||||
|
||||
// add this vtbl to the codec list. called at NLSO init time by the
|
||||
// TEX_CODEC_REGISTER in each codec file. note that call order and therefore
|
||||
// order in the list is undefined, but since each codec only steps up if it
|
||||
// can handle the given format, this is not a problem.
|
||||
int tex_codec_register(TexCodecVTbl* c)
|
||||
{
|
||||
debug_assert(c);
|
||||
|
||||
// insert at front of list.
|
||||
c->next = codecs;
|
||||
codecs = c;
|
||||
|
||||
return 0; // (assigned to dummy variable)
|
||||
}
|
||||
|
||||
|
||||
// find codec that recognizes the desired output file extension
|
||||
int tex_codec_for_filename(const char* fn, const TexCodecVTbl** c)
|
||||
{
|
||||
const char* ext = strrchr(fn, '.');
|
||||
if(!ext)
|
||||
return ERR_UNKNOWN_FORMAT;
|
||||
ext++; // skip '.'
|
||||
|
||||
for(*c = codecs; *c; *c = (*c)->next)
|
||||
{
|
||||
// we found it
|
||||
if((*c)->is_ext(ext))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ERR_UNKNOWN_FORMAT;
|
||||
}
|
||||
|
||||
|
||||
// find codec that recognizes the header's magic field
|
||||
int tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl** c)
|
||||
{
|
||||
// we guarantee at least 4 bytes for is_hdr to look at
|
||||
if(file_size < 4)
|
||||
return ERR_TEX_HEADER_NOT_COMPLETE;
|
||||
|
||||
for(*c = codecs; *c; *c = (*c)->next)
|
||||
{
|
||||
// we found it
|
||||
if((*c)->is_hdr(file))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ERR_UNKNOWN_FORMAT;
|
||||
}
|
||||
|
||||
|
||||
int tex_codec_transform(Tex* t, uint transforms)
|
||||
{
|
||||
int ret = TEX_CODEC_CANNOT_HANDLE;
|
||||
|
||||
// find codec that understands the data, and transform
|
||||
for(const TexCodecVTbl* c = codecs; c; c = c->next)
|
||||
{
|
||||
int err = c->transform(t, transforms);
|
||||
// success
|
||||
if(err == 0)
|
||||
return 0;
|
||||
// something went wrong
|
||||
else if(err != TEX_CODEC_CANNOT_HANDLE)
|
||||
{
|
||||
ret = err;
|
||||
debug_warn(__func__": codec indicates error");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// helper functions used by codecs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// allocate an array of row pointers that point into the given texture data.
|
||||
// <file_orientation> indicates whether the file format is top-down or
|
||||
// bottom-up; the row array is inverted if necessary to match global
|
||||
// orienatation. (this is more efficient than "transforming" later)
|
||||
//
|
||||
// used by PNG and JPG codecs; caller must free() rows when done.
|
||||
//
|
||||
// note: we don't allocate the data param ourselves because this function is
|
||||
// needed for encoding, too (where data is already present).
|
||||
int tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
|
||||
uint src_flags, uint dst_orientation, RowArray& rows)
|
||||
{
|
||||
const bool flip = !tex_orientations_match(src_flags, dst_orientation);
|
||||
|
||||
rows = (RowArray)malloc(h * sizeof(RowPtr));
|
||||
if(!rows)
|
||||
return ERR_NO_MEM;
|
||||
|
||||
// determine start position and direction
|
||||
RowPtr pos = flip? data+pitch*(h-1) : data;
|
||||
const ssize_t add = flip? -(ssize_t)pitch : (ssize_t)pitch;
|
||||
const RowPtr end = flip? data-pitch : data+pitch*h;
|
||||
|
||||
for(size_t i = 0; i < h; i++)
|
||||
{
|
||||
rows[i] = pos;
|
||||
pos += add;
|
||||
}
|
||||
|
||||
debug_assert(pos == end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da)
|
||||
{
|
||||
RETURN_ERR(tex_transform(t, transforms));
|
||||
|
||||
void* img_data = tex_get_data(t); const size_t img_size = tex_img_size(t);
|
||||
RETURN_ERR(da_append(da, hdr, hdr_size));
|
||||
RETURN_ERR(da_append(da, img_data, img_size));
|
||||
return 0;
|
||||
}
|
@ -37,11 +37,15 @@ struct TexCodecVTbl
|
||||
size_t (*hdr_size)(const u8* file);
|
||||
|
||||
const char* name;
|
||||
|
||||
// intrusive linked-list of codecs: more convenient than fixed-size
|
||||
// static storage.
|
||||
const TexCodecVTbl* next;
|
||||
};
|
||||
|
||||
|
||||
#define TEX_CODEC_REGISTER(name)\
|
||||
static const TexCodecVTbl vtbl = { name##_decode, name##_encode, name##_transform, name##_is_hdr, name##_is_ext, name##_hdr_size, #name};\
|
||||
static TexCodecVTbl vtbl = { name##_decode, name##_encode, name##_transform, name##_is_hdr, name##_is_ext, name##_hdr_size, #name};\
|
||||
static int dummy = tex_codec_register(&vtbl);
|
||||
|
||||
|
||||
@ -53,7 +57,7 @@ const int TEX_CODEC_CANNOT_HANDLE = 1;
|
||||
// TEX_CODEC_REGISTER in each codec file. note that call order and therefore
|
||||
// order in the list is undefined, but since each codec only steps up if it
|
||||
// can handle the given format, this is not a problem.
|
||||
extern int tex_codec_register(const TexCodecVTbl* c);
|
||||
extern int tex_codec_register(TexCodecVTbl* c);
|
||||
|
||||
|
||||
// find codec that recognizes the desired output file extension
|
||||
@ -62,6 +66,7 @@ extern int tex_codec_for_filename(const char* fn, const TexCodecVTbl** c);
|
||||
// find codec that recognizes the header's magic field
|
||||
extern int tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl** c);
|
||||
|
||||
extern int tex_codec_transform(Tex* t, uint transforms);
|
||||
|
||||
|
||||
// allocate an array of row pointers that point into the given texture data.
|
||||
@ -75,9 +80,9 @@ extern int tex_codec_for_header(const u8* file, size_t file_size, const TexCodec
|
||||
// needed for encoding, too (where data is already present).
|
||||
typedef const u8* RowPtr;
|
||||
typedef RowPtr* RowArray;
|
||||
extern int tex_util_alloc_rows(const u8* data, size_t h, size_t pitch,
|
||||
extern int tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
|
||||
uint src_flags, uint dst_orientation, RowArray& rows);
|
||||
|
||||
extern int tex_util_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da);
|
||||
extern int tex_codec_write(Tex* t, uint transforms, const void* hdr, size_t hdr_size, DynArray* da);
|
||||
|
||||
#endif // #ifndef TEX_CODEC_H__
|
||||
|
@ -459,7 +459,7 @@ static int jpg_decode_impl(DynArray* da,
|
||||
return ERR_NO_MEM;
|
||||
|
||||
// read rows
|
||||
RETURN_ERR(tex_util_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows));
|
||||
RETURN_ERR(tex_codec_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows));
|
||||
// could use cinfo->output_scanline to keep track of progress,
|
||||
// but we need to count lines_left anyway (paranoia).
|
||||
JSAMPARRAY row = (JSAMPARRAY)rows;
|
||||
@ -520,7 +520,7 @@ static int jpg_encode_impl(Tex* t,
|
||||
|
||||
const size_t pitch = t->w * t->bpp / 8;
|
||||
u8* data = tex_get_data(t);
|
||||
RETURN_ERR(tex_util_alloc_rows(data, t->h, pitch, t->flags, TEX_TOP_DOWN, rows));
|
||||
RETURN_ERR(tex_codec_alloc_rows(data, t->h, pitch, t->flags, TEX_TOP_DOWN, rows));
|
||||
|
||||
|
||||
// could use cinfo->output_scanline to keep track of progress,
|
||||
|
@ -105,7 +105,7 @@ static int png_decode_impl(DynArray* da,
|
||||
if(!img)
|
||||
return ERR_NO_MEM;
|
||||
|
||||
RETURN_ERR(tex_util_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows));
|
||||
RETURN_ERR(tex_codec_alloc_rows(img, h, pitch, TEX_TOP_DOWN, 0, rows));
|
||||
|
||||
png_read_image(png_ptr, (png_bytepp)rows);
|
||||
png_read_end(png_ptr, info_ptr);
|
||||
@ -158,7 +158,7 @@ static int png_encode_impl(Tex* t,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
u8* data = tex_get_data(t);
|
||||
RETURN_ERR(tex_util_alloc_rows(data, h, pitch, t->flags, TEX_TOP_DOWN, rows));
|
||||
RETURN_ERR(tex_codec_alloc_rows(data, h, pitch, t->flags, TEX_TOP_DOWN, rows));
|
||||
|
||||
// PNG is native RGB.
|
||||
const int png_transforms = (t->flags & TEX_BGR)? PNG_TRANSFORM_BGR : PNG_TRANSFORM_IDENTITY;
|
||||
|
@ -146,7 +146,7 @@ static int tga_encode(Tex* restrict t, DynArray* restrict da)
|
||||
img_desc
|
||||
};
|
||||
const size_t hdr_size = sizeof(hdr);
|
||||
return tex_util_write(t, transforms, &hdr, hdr_size, da);
|
||||
return tex_codec_write(t, transforms, &hdr, hdr_size, da);
|
||||
}
|
||||
|
||||
TEX_CODEC_REGISTER(tga);
|
||||
|
@ -286,7 +286,7 @@ static int alloc_idx(i32& idx, HDATA*& hd)
|
||||
// add another
|
||||
if(last_in_use >= hdata_cap)
|
||||
{
|
||||
debug_warn("alloc_idx: too many open handles (increase IDX_BITS)");
|
||||
debug_warn(__func__": too many open handles (increase IDX_BITS)");
|
||||
return ERR_LIMIT;
|
||||
}
|
||||
idx = last_in_use+1; // just incrementing idx would start it at 1
|
||||
@ -296,7 +296,7 @@ static int alloc_idx(i32& idx, HDATA*& hd)
|
||||
// can't fail for any other reason - idx is checked above.
|
||||
{ // VC6 goto fix
|
||||
bool is_unused = !hd->tag;
|
||||
debug_assert(is_unused && "alloc_idx: invalid last_in_use");
|
||||
debug_assert(is_unused && __func__": invalid last_in_use");
|
||||
}
|
||||
|
||||
have_idx:;
|
||||
@ -491,17 +491,17 @@ static int type_validate(H_Type type)
|
||||
|
||||
if(!type)
|
||||
{
|
||||
debug_warn("h_alloc: type is 0");
|
||||
debug_warn(__func__": type is 0");
|
||||
goto fail;
|
||||
}
|
||||
if(type->user_size > HDATA_USER_SIZE)
|
||||
{
|
||||
debug_warn("h_alloc: type's user data is too large for HDATA");
|
||||
debug_warn(__func__": type's user data is too large for HDATA");
|
||||
goto fail;
|
||||
}
|
||||
if(type->name == 0)
|
||||
{
|
||||
debug_warn("h_alloc: type's name field is 0");
|
||||
debug_warn(__func__": type's name field is 0");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -539,7 +539,7 @@ static Handle reuse_existing_handle(uintptr_t key, H_Type type, uint flags)
|
||||
HDATA* hd = h_data_tag_type(h, type);
|
||||
if(hd->refs == REF_MAX)
|
||||
{
|
||||
debug_warn("reuse_existing: too many references to a handle - increase REF_BITS");
|
||||
debug_warn(__func__": too many references to a handle - increase REF_BITS");
|
||||
return ERR_LIMIT;
|
||||
}
|
||||
|
||||
@ -761,7 +761,7 @@ void* h_user_data(const Handle h, const H_Type type)
|
||||
if(!hd->refs)
|
||||
{
|
||||
// note: resetting the tag is not enough (user might pass in its value)
|
||||
debug_warn("h_user_data: no references to resource (it's cached, but someone is accessing it directly)");
|
||||
debug_warn(__func__": no references to resource (it's cached, but someone is accessing it directly)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -777,7 +777,7 @@ const char* h_filename(const Handle h)
|
||||
HDATA* hd = h_data_tag(h);
|
||||
if(!hd)
|
||||
{
|
||||
debug_warn("h_filename failed");
|
||||
debug_warn(__func__" failed");
|
||||
return 0;
|
||||
}
|
||||
return hd->fn;
|
||||
@ -789,7 +789,9 @@ int h_reload(const char* fn)
|
||||
{
|
||||
if(!fn)
|
||||
{
|
||||
debug_warn("h_reload: fn = 0");
|
||||
debug_warn(__func__": fn = 0");
|
||||
// must not continue - some resources not backed by files have
|
||||
// key = 0 and reloading those would be disastrous.
|
||||
return ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
@ -871,13 +873,13 @@ void h_add_ref(Handle h)
|
||||
HDATA* hd = h_data_tag(h);
|
||||
if(!hd)
|
||||
{
|
||||
debug_warn("h_add_ref: invalid handle");
|
||||
debug_warn(__func__": invalid handle");
|
||||
return;
|
||||
}
|
||||
|
||||
// if there are no refs, how did the caller manage to keep a Handle?!
|
||||
if(!hd->refs)
|
||||
debug_warn("h_add_ref: no refs open - resource is cached");
|
||||
debug_warn(__func__": no refs open - resource is cached");
|
||||
|
||||
hd->refs++;
|
||||
}
|
||||
@ -894,13 +896,13 @@ int h_get_refcnt(Handle h)
|
||||
HDATA* hd = h_data_tag(h);
|
||||
if(!hd)
|
||||
{
|
||||
debug_warn("h_get_refcnt: invalid handle");
|
||||
debug_warn(__func__": invalid handle");
|
||||
return ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
// if there are no refs, how did the caller manage to keep a Handle?!
|
||||
if(!hd->refs)
|
||||
debug_warn("h_get_refcnt: no refs open - resource is cached");
|
||||
debug_warn(__func__": no refs open - resource is cached");
|
||||
|
||||
return hd->refs;
|
||||
}
|
||||
@ -916,7 +918,7 @@ void h_mgr_shutdown()
|
||||
// each HDATA entry has already been allocated.
|
||||
if(!hd)
|
||||
{
|
||||
debug_warn("h_mgr_shutdown: h_data_from_idx failed - why?!");
|
||||
debug_warn(__func__": h_data_from_idx failed - why?!");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ static void remove_alloc(void* raw_p)
|
||||
{
|
||||
size_t num_removed = ptr_to_h.erase(raw_p);
|
||||
if(num_removed != 1)
|
||||
debug_warn("remove_alloc: not in map");
|
||||
debug_warn(__func__": not in map");
|
||||
}
|
||||
|
||||
|
||||
@ -118,7 +118,7 @@ static void set_alloc(void* raw_p, Handle hm)
|
||||
It it = ptr_to_h.find(raw_p);
|
||||
if(it != ptr_to_h.end())
|
||||
{
|
||||
debug_warn("set_alloc: already in map");
|
||||
debug_warn(__func__": already in map");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -360,7 +360,7 @@ void* mem_alloc(size_t size, const size_t align, uint flags, Handle* phm)
|
||||
Handle hm = mem_wrap(p, size, flags, raw_p, raw_size, dtor, ctx);
|
||||
if(!hm) // failed to allocate a handle
|
||||
{
|
||||
debug_warn("mem_alloc: mem_wrap failed");
|
||||
debug_warn(__func__": mem_wrap failed");
|
||||
dtor(p, size, ctx);
|
||||
return 0;
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ int snd_set_master_gain(float gain)
|
||||
{
|
||||
if(gain < 0)
|
||||
{
|
||||
debug_warn("snd_set_master_gain: gain < 0");
|
||||
debug_warn(__func__": gain < 0");
|
||||
return ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
@ -373,7 +373,7 @@ static void al_buf_free(ALuint al_buf)
|
||||
static void al_buf_shutdown()
|
||||
{
|
||||
if(al_bufs_outstanding != 0)
|
||||
debug_warn("al_buf_shutdown: not all buffers freed!");
|
||||
debug_warn(__func__": not all buffers freed!");
|
||||
}
|
||||
|
||||
|
||||
@ -655,9 +655,9 @@ static void* io_buf_alloc()
|
||||
if(!buf)
|
||||
{
|
||||
if(!io_bufs)
|
||||
debug_warn("io_buf_alloc: not enough memory to allocate buffer pool");
|
||||
debug_warn(__func__": not enough memory to allocate buffer pool");
|
||||
else
|
||||
debug_warn("io_buf_alloc: max #streams exceeded");
|
||||
debug_warn(__func__": max #streams exceeded");
|
||||
// can't happen (tm) because stream_open enforces MAX_STREAMS.
|
||||
return 0;
|
||||
}
|
||||
@ -766,7 +766,7 @@ static int stream_open(Stream* s, const char* fn)
|
||||
{
|
||||
if(active_streams >= MAX_STREAMS)
|
||||
{
|
||||
debug_warn("stream_open: MAX_STREAMS exceeded - why?");
|
||||
debug_warn(__func__": MAX_STREAMS exceeded - why?");
|
||||
return -1;
|
||||
// fail, because we wouldn't have enough IO buffers for all
|
||||
}
|
||||
@ -1418,7 +1418,7 @@ static void list_remove(VSrc* vs)
|
||||
return;
|
||||
}
|
||||
|
||||
debug_warn("list_remove: VSrc not found");
|
||||
debug_warn(__func__": VSrc not found");
|
||||
}
|
||||
|
||||
|
||||
@ -1832,7 +1832,7 @@ int snd_disable(bool disabled)
|
||||
if(snd_disabled)
|
||||
{
|
||||
if(al_initialized)
|
||||
debug_warn("snd_disable: already initialized => disable is pointless");
|
||||
debug_warn(__func__": already initialized => disable is pointless");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
|
@ -346,18 +346,18 @@ sym(ia32_control87):
|
||||
push eax
|
||||
fnstcw [esp]
|
||||
pop eax ; old_cw
|
||||
mov ecx, [esp+4] ; new_cw
|
||||
mov ecx, [esp+4] ; new_val
|
||||
mov edx, [esp+8] ; mask
|
||||
and ecx, edx ; new_cw & mask
|
||||
and ecx, edx ; new_val & mask
|
||||
not edx ; ~mask
|
||||
and eax, edx ; old_cw & ~mask
|
||||
or eax, ecx ; (old_cw & ~mask) | (new_cw & mask)
|
||||
push eax
|
||||
or eax, ecx ; (old_cw & ~mask) | (new_val & mask)
|
||||
push eax ; = new_cw
|
||||
fldcw [esp]
|
||||
pop eax
|
||||
xor eax, eax ; return value
|
||||
ret
|
||||
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; init
|
||||
;-------------------------------------------------------------------------------
|
||||
|
@ -39,15 +39,16 @@ extern double _ceil(double);
|
||||
extern u64 rdtsc(void);
|
||||
|
||||
|
||||
#ifndef _MCW_PC
|
||||
# define _MCW_PC 0x0300 // Precision Control
|
||||
#endif
|
||||
#ifndef _PC_24
|
||||
# define _PC_24 0x0000 // 24 bits
|
||||
#endif
|
||||
#ifndef _MCW_EM
|
||||
# define _MCW_EM 0x003f // Exception Mask
|
||||
#endif
|
||||
// these may have been defined by system headers; we redefine them to
|
||||
// the real IA-32 values for use with ia32_control87.
|
||||
#undef _MCW_PC
|
||||
#define _MCW_PC 0x0300 // Precision Control
|
||||
#undef _PC_24
|
||||
#define _PC_24 0x0000 // 24 bits
|
||||
#undef _MCW_EM
|
||||
#define _MCW_EM 0x003f // Exception Mask
|
||||
#undef _MCW_PM
|
||||
#define _MCW_PM BIT(5)
|
||||
#ifndef _MCW_IM
|
||||
# define _MCW_IM 0x0001 // Invalid Operation Mask
|
||||
#endif
|
||||
@ -72,7 +73,6 @@ extern void ia32_debug_break(void);
|
||||
extern void ia32_memcpy(void* dst, const void* src, size_t nbytes);
|
||||
|
||||
|
||||
|
||||
// CPU caps (128 bits)
|
||||
// do not change the order!
|
||||
enum CpuCap
|
||||
|
@ -46,7 +46,7 @@ extern void* alloca(size_t size);
|
||||
# define finite __finite
|
||||
#endif
|
||||
|
||||
// restrict
|
||||
// C99 restrict
|
||||
// .. for some reason, g++-3.3 claims to support C99 (according to
|
||||
// __STDC_VERSION__) but doesn't have the restrict keyword.
|
||||
// use the extension __restrict__ instead.
|
||||
@ -59,6 +59,16 @@ extern void* alloca(size_t size);
|
||||
# define restrict
|
||||
#endif
|
||||
|
||||
// C99 __func__
|
||||
// .. already available; need do nothing
|
||||
#if HAVE_C99
|
||||
// .. VC supports something similar
|
||||
#elif MSC_VERSION
|
||||
# define __func__ __FUNCTION__
|
||||
// .. unsupported; remove it from code
|
||||
#else
|
||||
# define __func__
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
|
@ -181,7 +181,7 @@ static int aio_h_set(const int fd, const HANDLE h)
|
||||
|
||||
fail:
|
||||
unlock();
|
||||
debug_warn("aio_h_set failed");
|
||||
debug_warn(__func__" failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -225,7 +225,7 @@ WIN_RESTORE_LAST_ERROR;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
debug_warn("aio_reopen failed");
|
||||
debug_warn(__func__" failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -250,7 +250,7 @@ int aio_close(int fd)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
debug_warn("aio_close failed");
|
||||
debug_warn(__func__" failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -382,7 +382,7 @@ static int aio_rw(struct aiocb* cb)
|
||||
// fail if aiocb is already in use (forbidden by SUSv3)
|
||||
if(req_find(cb))
|
||||
{
|
||||
debug_warn("aio_rw: aiocb is already in use");
|
||||
debug_warn(__func__": aiocb is already in use");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -398,14 +398,14 @@ static int aio_rw(struct aiocb* cb)
|
||||
r = req_alloc(cb);
|
||||
if(!r)
|
||||
{
|
||||
debug_warn("aio_rw: cannot allocate a Req (too many concurrent IOs)");
|
||||
debug_warn(__func__": cannot allocate a Req (too many concurrent IOs)");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
HANDLE h = aio_h_get(fd);
|
||||
if(h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
debug_warn("aio_rw: associated handle is invalid");
|
||||
debug_warn(__func__": associated handle is invalid");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
@ -531,7 +531,7 @@ int aio_error(const struct aiocb* cb)
|
||||
// must not pass 0 to req_find - we'd look for a free cb!
|
||||
if(!cb)
|
||||
{
|
||||
debug_warn("aio_error: invalid cb");
|
||||
debug_warn(__func__": invalid cb");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -557,14 +557,14 @@ ssize_t aio_return(struct aiocb* cb)
|
||||
// must not pass 0 to req_find - we'd look for a free cb!
|
||||
if(!cb)
|
||||
{
|
||||
debug_warn("aio_return: invalid cb");
|
||||
debug_warn(__func__": invalid cb");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Req* r = req_find(cb);
|
||||
if(!r)
|
||||
{
|
||||
debug_warn("aio_return: cb not found (already called aio_return?)");
|
||||
debug_warn(__func__": cb not found (already called aio_return?)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -574,7 +574,7 @@ ssize_t aio_return(struct aiocb* cb)
|
||||
DWORD bytes_transferred;
|
||||
if(!GetOverlappedResult(r->hFile, &r->ovl, &bytes_transferred, wait))
|
||||
{
|
||||
debug_warn("aio_return: GetOverlappedResult failed");
|
||||
debug_warn(__func__": GetOverlappedResult failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -26,11 +26,7 @@
|
||||
#include "sysdep/cpu.h"
|
||||
#include "wdbg.h"
|
||||
#include "byte_order.h" // FOURCC
|
||||
|
||||
// optional: enables translation of the "unhandled exception" dialog.
|
||||
#if HAVE_I18N
|
||||
#include "ps/i18n.h"
|
||||
#endif
|
||||
#include "app_hooks.h"
|
||||
|
||||
|
||||
#pragma data_seg(WIN_CALLBACK_PRE_MAIN(b))
|
||||
@ -61,44 +57,6 @@ static bool is_locked()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// return localized version of <text>, if i18n functionality is available.
|
||||
// this is used to translate the "unhandled exception" dialog strings.
|
||||
// WARNING: leaks memory returned by wcsdup, but that's ok since the
|
||||
// program will terminate soon after. fixing this is hard and senseless.
|
||||
static const wchar_t* translate(const wchar_t* text)
|
||||
{
|
||||
#if HAVE_I18N
|
||||
// make sure i18n system is (already|still) initialized.
|
||||
if(g_CurrentLocale)
|
||||
{
|
||||
// be prepared for this to fail, because translation potentially
|
||||
// involves script code and the JS context might be corrupted.
|
||||
__try
|
||||
{
|
||||
const wchar_t* text2 = wcsdup(I18n::translate(text).c_str());
|
||||
// only overwrite if wcsdup succeeded, i.e. not out of memory.
|
||||
if(text2)
|
||||
text = text2;
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
// convenience wrapper using translate.
|
||||
static void translate_and_display_msg(const wchar_t* caption, const wchar_t* text)
|
||||
{
|
||||
wdisplay_msg(translate(caption), translate(text));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@ -412,7 +370,7 @@ have_reg:
|
||||
case DBG_BREAK_DATA_WRITE:
|
||||
rw = 3; break;
|
||||
default:
|
||||
debug_warn("brk_enable_in_ctx: invalid type");
|
||||
debug_warn(__func__": invalid type");
|
||||
}
|
||||
// .. length (determine from addr's alignment).
|
||||
// note: IA-32 requires len=0 for code breakpoints.
|
||||
@ -641,13 +599,13 @@ static const wchar_t* get_SEH_exception_description(const EXCEPTION_RECORD* er)
|
||||
{
|
||||
const wchar_t* op = (ei[0])? L"writing" : L"reading";
|
||||
const wchar_t* fmt = L"Access violation %s 0x%08X";
|
||||
swprintf(description_buf, ARRAY_SIZE(description_buf), translate(fmt), translate(op), ei[1]);
|
||||
swprintf(description_buf, ARRAY_SIZE(description_buf), ah_translate(fmt), ah_translate(op), ei[1]);
|
||||
return description_buf;
|
||||
}
|
||||
|
||||
// rationale: we don't use FormatMessage because it is unclear whether
|
||||
// NTDLL's symbol table will always include English-language strings
|
||||
// (we don't want crashlogs in foreign gobbledygook).
|
||||
// (we don't want to receive crashlogs in foreign gobbledygook).
|
||||
// it also adds unwanted formatting (e.g. {EXCEPTION} and trailing .).
|
||||
|
||||
switch(code)
|
||||
|
@ -562,7 +562,7 @@ static void out(const wchar_t* fmt, ...)
|
||||
// make sure out_chars_left remains nonnegative
|
||||
if((size_t)len > out_chars_left)
|
||||
{
|
||||
debug_warn("out: apparently wrote more than out_chars_left");
|
||||
debug_warn(__func__": apparently wrote more than out_chars_left");
|
||||
len = (int)out_chars_left;
|
||||
}
|
||||
out_chars_left -= len;
|
||||
|
@ -203,7 +203,7 @@ static int dll_list_add(const char* name)
|
||||
// make sure we're allowed to be called.
|
||||
if(!dll_list_pos)
|
||||
{
|
||||
debug_warn("dll_list_add: called before dll_list_init or after failure");
|
||||
debug_warn(__func__": called before dll_list_init or after failure");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ static int dll_list_add(const char* name)
|
||||
// didn't fit; complain
|
||||
sprintf(dll_list_pos, "..."); // (room was reserved above)
|
||||
dll_list_pos = 0; // poison pill, prevent further calls
|
||||
debug_warn("dll_list_add: not enough room");
|
||||
debug_warn(__func__": not enough room");
|
||||
return ERR_BUF_SIZE;
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,7 @@ int dir_add_watch(const char* dir, intptr_t* _reqnum)
|
||||
// need it before binding dir to IOCP because it is our "key".
|
||||
if(last_reqnum == INT_MAX)
|
||||
{
|
||||
debug_warn("dir_add_watch: request numbers are no longer unique");
|
||||
debug_warn(__func__": request numbers are no longer unique");
|
||||
CloseHandle(hDir);
|
||||
goto fail;
|
||||
}
|
||||
@ -280,7 +280,7 @@ int dir_cancel_watch(const intptr_t reqnum)
|
||||
Watch* w = find_watch(reqnum);
|
||||
if(!w)
|
||||
{
|
||||
debug_warn("dir_cancel_watch: watches[reqnum] invalid");
|
||||
debug_warn(__func__": watches[reqnum] invalid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -793,12 +793,6 @@ static
|
||||
#endif
|
||||
void win_pre_main_init()
|
||||
{
|
||||
// enable FPU exceptions
|
||||
#if CPU_IA32
|
||||
const int bits = _EM_INVALID|_EM_DENORMAL|_EM_ZERODIVIDE|_EM_OVERFLOW|_EM_UNDERFLOW|_EM_INEXACT;
|
||||
_control87(bits, _MCW_EM);
|
||||
#endif
|
||||
|
||||
// enable memory tracking and leak detection;
|
||||
// no effect if !HAVE_VC_DEBUG_ALLOC.
|
||||
#if CONFIG_PARANOIA
|
||||
|
@ -278,7 +278,7 @@ static int choose_impl()
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug_warn("hrt_choose_impl: no safe timer found!");
|
||||
debug_warn(__func__": no safe timer found!");
|
||||
hrt_impl = HRT_NONE;
|
||||
hrt_nominal_freq = -1.0;
|
||||
return -1;
|
||||
@ -320,7 +320,7 @@ static i64 ticks_lk()
|
||||
|
||||
case HRT_NUM_IMPLS:
|
||||
default:
|
||||
debug_warn("ticks_lk: invalid impl");
|
||||
debug_warn(__func__": invalid impl");
|
||||
//-fallthrough
|
||||
|
||||
case HRT_NONE:
|
||||
@ -460,7 +460,7 @@ static int hrt_override_impl(HRTOverride ovr, HRTImpl impl)
|
||||
if((ovr != HRT_DISABLE && ovr != HRT_FORCE && ovr != HRT_DEFAULT) ||
|
||||
(impl != HRT_TSC && impl != HRT_QPC && impl != HRT_GTC && impl != HRT_NONE))
|
||||
{
|
||||
debug_warn("hrt_override: invalid ovr or impl param");
|
||||
debug_warn(__func__": invalid ovr or impl param");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user