Merge MSVC support into master.

This commit is contained in:
Pavel Krajcevski 2013-01-28 11:48:41 -05:00
commit cdbf72b6c0
30 changed files with 714 additions and 113 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "Windows"]
path = Windows
url = git@github.com:Mokosha/FasTC-MSVCLibs.git

View File

@ -1526,12 +1526,11 @@ namespace BC7C
// implementation has an 4:1 compression ratio.
void CompressImageBC7(const unsigned char *inBuf, unsigned char *outBuf, unsigned int width, unsigned int height)
{
uint32 block[16];
BC7CompressionMode::MaxAnnealingIterations = min(BC7CompressionMode::kMaxAnnealingIterations, GetQualityLevel());
for(int j = 0; j < height; j += 4)
for(uint32 j = 0; j < height; j += 4)
{
for(int i = 0; i < width; i += 4)
for(uint32 i = 0; i < width; i += 4)
{
// ExtractBlock(inBuf + i * 4, width, block);
CompressBC7Block((const uint32 *)inBuf, outBuf);
@ -1569,12 +1568,11 @@ namespace BC7C
unsigned int height,
BlockStatManager &statManager
) {
uint32 block[16];
BC7CompressionMode::MaxAnnealingIterations = min(BC7CompressionMode::kMaxAnnealingIterations, GetQualityLevel());
for(int j = 0; j < height; j += 4)
for(uint32 j = 0; j < height; j += 4)
{
for(int i = 0; i < width; i += 4)
for(uint32 i = 0; i < width; i += 4)
{
// ExtractBlock(inBuf + i * 4, width, block);
CompressBC7Block((const uint32 *)inBuf, outBuf, statManager);
@ -2387,7 +2385,7 @@ namespace BC7C
assert(idxMode < 2);
assert(rotMode < 4);
assert(shapeIdx < ((mode == 0)? 16 : 64));
assert(shapeIdx < uint32((mode == 0)? 16 : 64));
uint32 cp = attrs->colorChannelPrecision;
const uint32 shift = 8 - cp;

View File

@ -505,7 +505,7 @@ static uint32 PowerIteration(const RGBAMatrix &mat, RGBADir &eigVec, double &eig
for(int nTries = 0; nTries < 3; nTries++) {
// !SPEED! Find eigenvectors by using the power method. This is good because the
// matrix is only 4x4, which allows us to use SIMD...
RGBAVector b = RGBAVector(rand());
RGBAVector b = RGBAVector(float(rand()));
assert(b.Length() > 0);
b /= b.Length();
@ -528,7 +528,7 @@ static uint32 PowerIteration(const RGBAMatrix &mat, RGBADir &eigVec, double &eig
}
eigVal = newB.Length();
newB /= eigVal;
newB /= float(eigVal);
if(fabs(1.0f - (b * newB)) < 1e-5)
fixed = true;

View File

@ -54,6 +54,12 @@ ADD_EXECUTABLE(
${SOURCES}
)
# Make sure that if we're using boost libraries for threading then we add this linker path.
# Personally, I believe this is a bug in CMAKE but I'm not exactly sure.
#IF( THREAD_API MATCHES "Boost" )
# SET_TARGET_PROPERTIES(tc PROPERTIES LINK_FLAGS "/LIBPATH:\"${Boost_LIBRARY_DIRS}\"")
#ENDIF()
TARGET_LINK_LIBRARIES( tc BPTCEncoder )
TARGET_LINK_LIBRARIES( tc TexCompIO )
TARGET_LINK_LIBRARIES( tc TexCompCore )

View File

@ -40,6 +40,187 @@
*
* <http://gamma.cs.unc.edu/FasTC/>
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <SDKDDKVer.h>
#include <Windows.h>
int main(int argc, char **argv) {
#include "BlockStats.h"
#include "TexComp.h"
#include "ImageFile.h"
#include "Image.h"
void PrintUsage() {
fprintf(stderr, "Usage: tc [-l] [-q <quality>] [-n <num>] [-simd] [-t <threads> [-j <jobs>]] <imagefile>\n");
}
void ExtractBasename(const char *filename, char *buf, uint32 bufSz) {
size_t len = strlen(filename);
const char *end = filename + len;
while(--end != filename) {
if(*end == '.')
{
uint32 numChars = int32(end - filename + 1);
uint32 toCopy = (numChars > bufSz)? bufSz : numChars;
memcpy(buf, filename, toCopy);
buf[toCopy - 1] = '\0';
return;
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int fileArg = 1;
if(fileArg == argc) {
PrintUsage();
exit(1);
}
int numJobs = 0;
int quality = 50;
int numThreads = 1;
int numCompressions = 1;
bool bUseSIMD = false;
bool bSaveLog = false;
bool knowArg = false;
do {
knowArg = false;
if(strcmp(argv[fileArg], "-n") == 0) {
fileArg++;
if(fileArg == argc || (numCompressions = atoi(argv[fileArg])) < 0) {
PrintUsage();
exit(1);
}
fileArg++;
knowArg = true;
continue;
}
if(strcmp(argv[fileArg], "-l") == 0) {
fileArg++;
bSaveLog = true;
knowArg = true;
continue;
}
if(strcmp(argv[fileArg], "-simd") == 0) {
fileArg++;
bUseSIMD = true;
knowArg = true;
continue;
}
if(strcmp(argv[fileArg], "-t") == 0) {
fileArg++;
if(fileArg == argc || (numThreads = atoi(argv[fileArg])) < 1) {
PrintUsage();
exit(1);
}
fileArg++;
knowArg = true;
continue;
}
if(strcmp(argv[fileArg], "-q") == 0) {
fileArg++;
if(fileArg == argc || (quality = atoi(argv[fileArg])) < 0) {
PrintUsage();
exit(1);
}
fileArg++;
knowArg = true;
continue;
}
if(strcmp(argv[fileArg], "-j") == 0) {
fileArg++;
if(fileArg == argc || (numJobs = atoi(argv[fileArg])) < 0) {
PrintUsage();
exit(1);
}
fileArg++;
knowArg = true;
continue;
}
} while(knowArg && fileArg < argc);
if(numThreads > 1 && bSaveLog) {
bSaveLog = false;
fprintf(stderr, "WARNING: Will not save log because implementation is not thread safe.\n"
"If you'd like, send a complaint to pavel@cs.unc.edu to get this done faster.\n");
}
if(fileArg == argc) {
PrintUsage();
exit(1);
}
char basename[256];
ExtractBasename(argv[fileArg], basename, 256);
ImageFile file (argv[fileArg]);
if(!file.Load()) {
fprintf(stderr, "Error loading file: %s\n", argv[fileArg]);
return 1;
}
const Image *img = file.GetImage();
int numBlocks = (img->GetWidth() * img->GetHeight())/16;
BlockStatManager *statManager = NULL;
if(bSaveLog) {
statManager = new BlockStatManager(numBlocks);
}
SCompressionSettings settings;
settings.bUseSIMD = bUseSIMD;
settings.iNumThreads = numThreads;
settings.iQuality = quality;
settings.iNumCompressions = numCompressions;
settings.iJobSize = numJobs;
settings.pStatManager = statManager;
CompressedImage *ci = img->Compress(settings);
if(NULL == ci) {
fprintf(stderr, "Error compressing image!\n");
return 1;
}
double PSNR = img->ComputePSNR(*ci);
if(PSNR > 0.0) {
fprintf(stdout, "PSNR: %.3f\n", PSNR);
}
else {
fprintf(stderr, "Error computing PSNR\n");
}
if(bSaveLog) {
strcat_s(basename, ".log");
statManager->ToFile(basename);
basename[strlen(basename) - 4] = '\0';
}
strcat_s(basename, "-bc7.png");
Image cImg (*ci);
ImageFile cImgFile (basename, eFileFormat_PNG, cImg);
cImgFile.Write();
// Cleanup
delete ci;
if(statManager)
delete statManager;
return 0;
}

View File

@ -43,6 +43,31 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(TexC)
IF(MSVC)
SET(MSVC_INSTALL_PATH "${PROJECT_SOURCE_DIR}/Windows")
SET(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};${MSVC_INSTALL_PATH}")
IF(MSVC10)
SET(MSVC_VERSION_STRING vc100)
ELSEIF(MSVC11)
SET(MSVC_VERSION_STRING vc110)
ELSEIF(MSVC90)
SET(MSVC_VERSION_STRING vc90)
ELSEIF(MSVC80)
SET(MSVC_VERSION_STRING vc80)
ENDIF()
# !FIXME! Actually detect compiler architecture version....
IF( CMAKE_SIZEOF_VOID_P EQUAL 8 )
SET(MSVC_ARCHITECTURE_STRING x64)
ELSE()
SET(MSVC_ARCHITECTURE_STRING x86)
ENDIF()
SET(MSVC_LIB_DIR "${MSVC_INSTALL_PATH}/lib/${MSVC_ARCHITECTURE_STRING}/${MSVC_VERSION_STRING}")
SET(CMAKE_LIBRARY_PATH "${CMAKE_LIBRARY_PATH};${MSVC_LIB_DIR}")
ENDIF(MSVC)
ADD_SUBDIRECTORY(BPTCEncoder)
ADD_SUBDIRECTORY(IO)
ADD_SUBDIRECTORY(Core)

View File

@ -80,7 +80,15 @@ INCLUDE_DIRECTORIES( ${TexC_SOURCE_DIR}/Core/include )
SET( THREAD_API )
SET( THREAD_APIS_AVAILABLE "None" )
FIND_PACKAGE( Boost COMPONENTS thread system )
###### Find Boost...
IF( MSVC )
SET(ENV{BOOSTLIBDIR} "${MSVC_LIB_DIR}")
SET(ENV{BOOSTINCLUDEDIR} "${MSVC_INSTALL_PATH}/include")
ENDIF( MSVC )
SET( Boost_USE_STATIC_LIBS ON )
FIND_PACKAGE( Boost COMPONENTS thread system date_time chrono )
IF( Boost_FOUND )
SET( THREAD_APIS_AVAILABLE "Boost" ${THREAD_APIS_AVAILABLE} )
@ -90,6 +98,8 @@ IF( Boost_FOUND )
ENDIF()
###### Find PThreads....
FIND_PACKAGE( Threads )
IF( CMAKE_USE_PTHREADS_INIT )
@ -111,7 +121,7 @@ SET_PROPERTY( CACHE THREAD_API PROPERTY STRINGS ${THREAD_APIS_AVAILABLE} )
IF( THREAD_API MATCHES "Boost")
INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} )
SET( SOURCES ${SOURCES} "src/ThreadBoost.cpp" )
LINK_DIRECTORIES( ${Boost_LIBRARY_DIR} )
LINK_DIRECTORIES( ${Boost_LIBRARY_DIRS} )
ENDIF()
IF( THREAD_API MATCHES "PThread" )
@ -125,7 +135,7 @@ ELSE()
SET( SOURCES ${SOURCES} "src/ThreadGroup.cpp" )
SET( SOURCES ${SOURCES} "src/WorkerQueue.cpp" )
SET( HEADERS ${HEADERS} "include/Thread.h" )
SET( HEADERS ${HEADERS} "src/Thread.h" )
SET( HEADERS ${HEADERS} "src/ThreadGroup.h" )
SET( HEADERS ${HEADERS} "src/WorkerQueue.h" )
ENDIF()

View File

@ -46,7 +46,19 @@
#include "TexCompTypes.h"
#include "ReferenceCounter.h"
#include "Thread.h"
///////////////////////////////////////////////////////////////////////////////
//
// Forward declarations
//
///////////////////////////////////////////////////////////////////////////////
class TCMutex;
///////////////////////////////////////////////////////////////////////////////
//
// class BlockStat
//
///////////////////////////////////////////////////////////////////////////////
struct BlockStat {
friend class BlockStatManager;
@ -57,7 +69,7 @@ public:
BlockStat(const BlockStat &);
BlockStat &operator=(const BlockStat &);
void ToString(char *buf, int bufSz) const;
void ToString(CHAR *buf, int bufSz) const;
private:
const enum Type {
@ -79,6 +91,8 @@ class BlockStatManager {
public:
BlockStatManager(int nBlocks);
BlockStatManager(const BlockStatManager &);
BlockStatManager &operator=(const BlockStatManager &);
~BlockStatManager();
uint32 BeginBlock();
@ -90,6 +104,7 @@ class BlockStatManager {
class BlockStatList {
public:
BlockStatList();
BlockStatList(const BlockStatList &other);
~BlockStatList();
void AddStat(const BlockStat &stat);
@ -106,9 +121,12 @@ class BlockStatManager {
} *m_BlockStatList;
uint32 m_BlockStatListSz;
TCMutex m_Mutex;
TCMutex *m_Mutex;
uint32 m_NextBlock;
ReferenceCounter m_Counter;
// Note: we probably shouldn't call this...
void Copy(const BlockStatManager &);
};
#endif // __BLOCK_STATS_H__

View File

@ -52,16 +52,17 @@
#ifdef _MSC_VER
typedef __int16 int16;
typedef __uint16 uint16;
typedef unsigned __int16 uint16;
typedef __int32 int32;
typedef __uint32 uint32;
typedef unsigned __int32 uint32;
typedef __int8 int8;
typedef __uint8 uint8;
typedef unsigned __int8 uint8;
typedef __uint64 uint64;
typedef unsigned __int64 uint64;
typedef __int64 int64;
typedef __int32_ptr int32_ptr;
#include <tchar.h>
typedef TCHAR CHAR;
// If not, assume GCC, or at least standard defines...
#else
@ -78,7 +79,6 @@ typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uintptr_t int32_ptr;
typedef char CHAR;
#endif // _MSC_VER

View File

@ -49,6 +49,7 @@
#include <assert.h>
#include "FileStream.h"
#include "Thread.h"
template <typename T>
static T max(const T &a, const T &b) {
@ -65,14 +66,22 @@ BlockStat::BlockStat(const CHAR *statName, int stat)
: m_IntStat(stat)
, m_Type(eType_Int)
{
#ifdef _MSC_VER
strncpy_s(m_StatName, statName, kStatNameSz);
#else
strncpy(m_StatName, statName, kStatNameSz);
#endif
}
BlockStat::BlockStat(const CHAR *statName, double stat)
: m_FloatStat(stat)
, m_Type(eType_Float)
{
#ifdef _MSC_VER
strncpy_s(m_StatName, statName, kStatNameSz);
#else
strncpy(m_StatName, statName, kStatNameSz);
#endif
}
BlockStat::BlockStat(const BlockStat &other) : m_Type(other.m_Type) {
@ -81,16 +90,25 @@ BlockStat::BlockStat(const BlockStat &other) : m_Type(other.m_Type) {
BlockStat &BlockStat::operator=(const BlockStat &other) {
memcpy(this, &other, sizeof(*this));
return *this;
}
void BlockStat::ToString(char *buf, int bufSz) const {
void BlockStat::ToString(CHAR *buf, int bufSz) const {
switch(m_Type) {
case BlockStat::eType_Float:
#ifdef _MSC_VER
_sntprintf_s(buf, bufSz, _TRUNCATE, "%s,%f", m_StatName, m_FloatStat);
#else
snprintf(buf, bufSz, "%s,%f", m_StatName, m_FloatStat);
#endif
break;
case BlockStat::eType_Int:
#ifdef _MSC_VER
_sntprintf_s(buf, bufSz, _TRUNCATE, "%s,%llu", m_StatName, m_IntStat);
#else
snprintf(buf, bufSz, "%s,%llu", m_StatName, m_IntStat);
#endif
break;
default:
@ -105,9 +123,36 @@ void BlockStat::ToString(char *buf, int bufSz) const {
//
////////////////////////////////////////////////////////////////////////////////
void BlockStatManager::Copy(const BlockStatManager &other) {
// This is a bug. If we copy the manager then all of the lists and pointers
// become shared and can cause dereferencing issues. Check to see where you're
// copying this class and make sure to actually create a new instance.
assert(!"We shouldn't be copying these in this manner!");
m_BlockStatList = new BlockStatList(*other.m_BlockStatList);
m_BlockStatListSz = other.m_BlockStatListSz;
m_NextBlock = other.m_NextBlock;
// If we do copy them, then make sure that we are actually using the exact same
// pointers for our synchronization primitives... otherwise we could run into
// deadlock issues.
m_Mutex = other.m_Mutex;
}
BlockStatManager::BlockStatManager(const BlockStatManager &other) {
Copy(other);
}
BlockStatManager &BlockStatManager::operator=(const BlockStatManager &other) {
m_Counter = other.m_Counter;
Copy(other);
return *this;
}
BlockStatManager::BlockStatManager(int nBlocks)
: m_BlockStatListSz(max(nBlocks, 0))
, m_NextBlock(0)
, m_Mutex(new TCMutex)
{
m_BlockStatList = new BlockStatList[m_BlockStatListSz];
if(!m_BlockStatList) {
@ -121,6 +166,12 @@ BlockStatManager::~BlockStatManager() {
if(m_Counter.GetRefCount() == 0) {
delete [] m_BlockStatList;
}
if(m_Mutex)
{
delete m_Mutex;
m_Mutex = 0;
}
}
uint32 BlockStatManager::BeginBlock() {
@ -130,7 +181,7 @@ uint32 BlockStatManager::BeginBlock() {
return m_NextBlock-1;
}
TCLock lock (m_Mutex);
TCLock lock (*m_Mutex);
return m_NextBlock++;
}
@ -141,7 +192,7 @@ void BlockStatManager::AddStat(uint32 blockIdx, const BlockStat &stat) {
return;
}
TCLock lock (m_Mutex);
TCLock lock (*m_Mutex);
m_BlockStatList[blockIdx].AddStat(stat);
}
@ -149,7 +200,7 @@ void BlockStatManager::ToFile(const CHAR *filename) {
FileStream fstr (filename, eFileMode_Write);
for(int i = 0; i < m_BlockStatListSz; i++) {
for(uint32 i = 0; i < m_BlockStatListSz; i++) {
const BlockStatList *head = &(m_BlockStatList[i]);
while(head) {
BlockStat s = head->GetStat();
@ -158,12 +209,16 @@ void BlockStatManager::ToFile(const CHAR *filename) {
s.ToString(statStr, 256);
CHAR str[256];
#ifdef _MSC_VER
_sntprintf_s(str, 256, _TRUNCATE, "%d,%s\n", i, statStr);
#else
snprintf(str, 256, "%d,%s\n", i, statStr);
#endif
int strLen = strlen(str);
uint32 strLen = uint32(strlen(str));
if(strLen > 255) {
str[255] = '\n';
strLen = 256;
str[255] = '\n';
strLen = 256;
}
fstr.Write((uint8 *)str, strLen);
@ -179,7 +234,7 @@ void BlockStatManager::ToFile(const CHAR *filename) {
//
////////////////////////////////////////////////////////////////////////////////
static const CHAR *kNullBlockString = "NULL_BLOCK_STAT";
static const uint32 kNullBlockStringLength = strlen(kNullBlockString);
static const uint32 kNullBlockStringLength = uint32(strlen(kNullBlockString));
BlockStatManager::BlockStatList::BlockStatList()
: m_Tail(0)
@ -190,8 +245,14 @@ BlockStatManager::BlockStatList::BlockStatList(const BlockStat &stat)
: m_Tail(0)
, m_Stat(stat)
{
assert(!"If you're copying a block stat list then you're probably not using them properly.");
}
BlockStatManager::BlockStatList::BlockStatList(const BlockStatList &other)
: m_Tail(new BlockStatList(*other.m_Tail))
, m_Stat(other.m_Stat)
{}
BlockStatManager::BlockStatList::~BlockStatList() {
if(m_Counter.GetRefCount() == 0 && m_Tail) {
delete m_Tail;

View File

@ -48,6 +48,7 @@
#include <stdio.h>
#include <assert.h>
#include "TexCompTypes.h"
#include "BC7Compressor.h"
CompressedImage::CompressedImage()
@ -109,7 +110,7 @@ CompressedImage::~CompressedImage() {
bool CompressedImage::DecompressImage(unsigned char *outBuf, unsigned int outBufSz) const {
// First make sure that we have enough data
int dataSz = 0;
uint32 dataSz = 0;
switch(m_Format) {
case eCompressionFormat_DXT1: dataSz = m_DataSz * 8; break;
case eCompressionFormat_DXT5: dataSz = m_DataSz * 4; break;

View File

@ -118,7 +118,7 @@ double Image::ComputePSNR(const CompressedImage &ci) const {
const double wb = 1.0;
double MSE = 0.0;
for(int i = 0; i < imageSz; i+=4) {
for(uint32 i = 0; i < imageSz; i+=4) {
const unsigned char *pixelDataRaw = m_PixelData + i;
const unsigned char *pixelDataUncomp = unCompData + i;

View File

@ -67,12 +67,14 @@
#include "TexCompTypes.h"
#include <cassert>
#include <Windows.h>
class StopWatchImpl {
public:
uint64 frequency;
uint64 start;
uint64 stop;
uintptr affinityMask;
uintptr_t affinityMask;
StopWatchImpl() :
start(0), stop(0), affinityMask(0)
@ -85,6 +87,8 @@ class StopWatchImpl {
}
};
StopWatch::StopWatch() : impl(new StopWatchImpl) { }
StopWatch::StopWatch(const StopWatch &other) {
impl = new StopWatchImpl();
memcpy(impl, other.impl, sizeof(StopWatchImpl));
@ -96,6 +100,7 @@ StopWatch &StopWatch::operator=(const StopWatch &other) {
}
impl = new StopWatchImpl();
memcpy(impl, other.impl, sizeof(StopWatchImpl));
return *this;
}
StopWatch::~StopWatch() {
@ -156,7 +161,7 @@ double StopWatch::TimeInSeconds() const
{
// Return the elapsed time in seconds.
assert((impl->stop - impl->start) > 0);
return double(impl->stop - impl->start) / double(frequency);
return double(impl->stop - impl->start) / double(impl->frequency);
}
// Get the elapsed time in milliseconds.
@ -164,7 +169,7 @@ double StopWatch::TimeInMilliseconds() const
{
// Return the elapsed time in milliseconds.
assert((impl->stop - impl->start) > 0);
return double(impl->stop - impl->start) / double(frequency) * 1000.0;
return double(impl->stop - impl->start) / double(impl->frequency) * 1000.0;
}
// Get the elapsed time in microseconds.

View File

@ -268,7 +268,7 @@ bool CompressImageData(
}
// Allocate data based on the compression method
int cmpDataSzNeeded = 0;
uint32 cmpDataSzNeeded = 0;
switch(settings.format) {
case eCompressionFormat_DXT1: cmpDataSzNeeded = dataSz / 8;
case eCompressionFormat_DXT5: cmpDataSzNeeded = dataSz / 4;

View File

@ -77,6 +77,8 @@ TCThreadBase &TCThreadBase::operator=(const TCThreadBase &other) {
// Our implementation is now the same as the other.
m_Impl = other.m_Impl;
m_Impl->IncreaseReferenceCount();
return *this;
}
TCThreadBase::~TCThreadBase() {

View File

@ -46,6 +46,11 @@
#include "TexCompTypes.h"
//!HACK! Apparently MSVC has issues with Yield()...????
#ifdef _MSC_VER
#undef Yield
#endif
////////////////////////////////////////////////////////////////////////////////
//
// Base implementation
@ -111,9 +116,9 @@ class TCThread : public TCThreadBase {
public:
TCThread(TCCallable &);
void Join();
static void Yield();
void Join();
};
////////////////////////////////////////////////////////////////////////////////

View File

@ -286,6 +286,8 @@ bool ThreadGroup::CleanUpThreads() {
// Reset active number of threads...
m_ActiveThreads = 0;
m_ExitFlag = false;
return true;
}
void ThreadGroup::Join() {

View File

@ -191,7 +191,7 @@ void WorkerQueue::Run() {
// Spawn a bunch of threads...
TCLock lock(m_Mutex);
for(int i = 0; i < m_NumThreads; i++) {
for(uint32 i = 0; i < m_NumThreads; i++) {
m_Workers[i] = new WorkerThread(this, i);
m_ThreadHandles[m_ActiveThreads] = new TCThread(*m_Workers[i]);
m_ActiveThreads++;
@ -211,7 +211,7 @@ void WorkerQueue::Run() {
m_StopWatch.Stop();
// Join them all together..
for(int i = 0; i < m_NumThreads; i++) {
for(uint32 i = 0; i < m_NumThreads; i++) {
m_ThreadHandles[i]->Join();
delete m_ThreadHandles[i];
delete m_Workers[i];
@ -274,7 +274,7 @@ WorkerThread::EAction WorkerQueue::AcceptThreadData(uint32 threadIdx) {
const uint8 *WorkerQueue::GetSrcForThread(const int threadIdx) const {
assert(m_Offsets[threadIdx] >= 0);
assert(threadIdx >= 0);
assert(threadIdx < m_NumThreads);
assert(threadIdx < int(m_NumThreads));
const uint32 inBufBlockSz = 16 * 4;
return m_InBuf + m_Offsets[threadIdx] * inBufBlockSz;
@ -283,7 +283,7 @@ const uint8 *WorkerQueue::GetSrcForThread(const int threadIdx) const {
uint8 *WorkerQueue::GetDstForThread(const int threadIdx) const {
assert(m_Offsets[threadIdx] >= 0);
assert(threadIdx >= 0);
assert(threadIdx < m_NumThreads);
assert(threadIdx < int(m_NumThreads));
const uint32 outBufBlockSz = 16;
return m_OutBuf + m_Offsets[threadIdx] * outBufBlockSz;
@ -292,7 +292,7 @@ uint8 *WorkerQueue::GetDstForThread(const int threadIdx) const {
uint32 WorkerQueue::GetNumBlocksForThread(const int threadIdx) const {
assert(m_Offsets[threadIdx] >= 0);
assert(threadIdx >= 0);
assert(threadIdx < m_NumThreads);
assert(threadIdx < int(m_NumThreads));
return m_NumBlocks[threadIdx];
}

View File

@ -53,7 +53,7 @@ class WorkerQueue;
#include "Thread.h"
#include "StopWatch.h"
struct WorkerThread : public TCCallable {
class WorkerThread : public TCCallable {
friend class WorkerQueue;
public:

View File

@ -43,7 +43,6 @@
SET( SOURCES
"src/ImageWriter.cpp"
"src/ImageLoader.cpp"
"src/FileStream.cpp"
"src/ImageFile.cpp"
)
@ -54,6 +53,15 @@ SET( HEADERS
"include/FileStream.h"
)
IF( WIN32 )
SET( SOURCES ${SOURCES} "src/FileStreamWin32.cpp" )
ELSE()
SET( SOURCES ${SOURCES} "src/FileStreamUnix.cpp" )
# Assume compiler is GCC
SET( LINK_FLAGS -lrt ${LINK_FLAGS} )
ENDIF()
FIND_PACKAGE( PNG )
IF( PNG_FOUND )
INCLUDE_DIRECTORIES( ${PNG_INCLUDE_DIR} )

View File

@ -82,7 +82,7 @@ public:
const EImageFileFormat m_FileFormat;
static unsigned char *ReadFileData(const CHAR *filename);
static bool WriteImageDataToFile(const uint8 *data, const uint32 dataSz, const CHAR *filename);
static bool WriteImageDataToFile(const uint8 *data, const uint32 dataSz, const CHAR *filename);
static EImageFileFormat DetectFileFormat(const CHAR *filename);
Image *LoadImage(const unsigned char *rawImageData) const;

View File

@ -139,6 +139,8 @@ FileStream &FileStream::operator=(const FileStream &other) {
m_Mode = other.m_Mode;
strncpy(m_Filename, other.m_Filename, kMaxFilenameSz);
return *this;
}
FileStream::~FileStream() {

253
IO/src/FileStreamWin32.cpp Executable file
View File

@ -0,0 +1,253 @@
#include "FileStream.h"
#include <Windows.h>
#include <stdio.h>
#include <assert.h>
class FileStreamImpl {
private:
// Track the number of references to this filestream so
// that we know whether or not we need to close it when
// the object gets destroyed.
uint32 m_ReferenceCount;
HANDLE m_Handle;
public:
FileStreamImpl(const CHAR *filename, EFileMode mode)
: m_ReferenceCount(1)
{
DWORD dwDesiredAccess = GENERIC_READ;
DWORD dwShareMode = 0;
switch(mode) {
default:
case eFileMode_ReadBinary:
case eFileMode_Read:
// Do nothing.
break;
case eFileMode_Write:
case eFileMode_WriteBinary:
dwDesiredAccess = GENERIC_WRITE;
break;
case eFileMode_WriteAppend:
case eFileMode_WriteBinaryAppend:
dwDesiredAccess = FILE_APPEND_DATA;
break;
}
m_Handle = CreateFile(filename, dwDesiredAccess, dwShareMode, NULL, 0, FILE_ATTRIBUTE_NORMAL, NULL);
assert(m_Handle != INVALID_HANDLE_VALUE);
}
~FileStreamImpl() {
CloseHandle(m_Handle);
}
void IncreaseReferenceCount() { m_ReferenceCount++; }
void DecreaseReferenceCount() { m_ReferenceCount--; }
uint32 GetReferenceCount() { return m_ReferenceCount; }
HANDLE GetFileHandle() const { return m_Handle; }
};
FileStream::FileStream(const CHAR *filename, EFileMode mode)
: m_Impl(new FileStreamImpl(filename, mode))
, m_Mode(mode)
{
strncpy_s(m_Filename, filename, kMaxFilenameSz);
m_Filename[kMaxFilenameSz - 1] = CHAR('\0');
}
FileStream::FileStream(const FileStream &other)
: m_Impl(other.m_Impl)
, m_Mode(other.m_Mode)
{
m_Impl->IncreaseReferenceCount();
strncpy_s(m_Filename, other.m_Filename, kMaxFilenameSz);
}
FileStream &FileStream::operator=(const FileStream &other) {
// We no longer reference this implementation.
m_Impl->DecreaseReferenceCount();
// If we're the last ones to reference it, then it should be destroyed.
if(m_Impl->GetReferenceCount() <= 0) {
assert(m_Impl->GetReferenceCount() == 0);
delete m_Impl;
m_Impl = 0;
}
m_Impl = other.m_Impl;
m_Impl->IncreaseReferenceCount();
m_Mode = other.m_Mode;
strncpy_s(m_Filename, other.m_Filename, kMaxFilenameSz);
return *this;
}
FileStream::~FileStream() {
// We no longer reference this implementation.
m_Impl->DecreaseReferenceCount();
// If we're the last ones to reference it, then it should be destroyed.
if(m_Impl->GetReferenceCount() <= 0) {
assert(m_Impl->GetReferenceCount() == 0);
delete m_Impl;
m_Impl = 0;
}
}
int32 FileStream::Read(uint8 *buf, uint32 bufSz) {
if(
m_Mode == eFileMode_Write ||
m_Mode == eFileMode_WriteBinary ||
m_Mode == eFileMode_WriteAppend ||
m_Mode == eFileMode_WriteBinaryAppend
) {
CHAR errStr[256];
_sntprintf_s(errStr, 256, "Cannot read from file '%s': File opened for reading.", m_Filename);
OutputDebugString(errStr);
return -2;
}
HANDLE fp = m_Impl->GetFileHandle();
if(INVALID_HANDLE_VALUE == fp)
return -1;
DWORD oldPosition = SetFilePointer(fp, 0, NULL, FILE_CURRENT);
if(INVALID_SET_FILE_POINTER == oldPosition) {
CHAR errStr[256];
_sntprintf_s(errStr, 256, "Error querying the file position before reading from file '%s'(0x%x).", m_Filename, GetLastError());
OutputDebugString(errStr);
return -1;
}
DWORD amtRead;
BOOL success = ReadFile(fp, buf, bufSz, &amtRead, NULL);
if(!success) {
CHAR errStr[256];
_sntprintf_s(errStr, 256, "Error reading from file '%s'.", m_Filename);
OutputDebugString(errStr);
return -1;
}
DWORD newPosition = SetFilePointer(fp, 0, NULL, FILE_CURRENT);
if(INVALID_SET_FILE_POINTER == newPosition) {
CHAR errStr[256];
_sntprintf_s(errStr, 256, "Error querying the file position after reading from file '%s'(0x%x).", m_Filename, GetLastError());
OutputDebugString(errStr);
return -1;
}
return newPosition - oldPosition;
}
int32 FileStream::Write(const uint8 *buf, uint32 bufSz) {
if(
m_Mode == eFileMode_Read ||
m_Mode == eFileMode_ReadBinary
) {
CHAR errStr[256];
_sntprintf_s(errStr, 256, "Cannot write to file '%s': File opened for writing.", m_Filename);
OutputDebugString(errStr);
return -2;
}
HANDLE fp = m_Impl->GetFileHandle();
if(NULL == fp)
return -1;
DWORD dwPos;
if(m_Mode == eFileMode_WriteBinaryAppend || m_Mode == eFileMode_WriteAppend) {
dwPos = SetFilePointer(fp, 0, NULL, FILE_END);
}
else {
dwPos = SetFilePointer(fp, 0, NULL, FILE_CURRENT);
}
if(INVALID_SET_FILE_POINTER == dwPos) {
CHAR errStr[256];
_sntprintf_s(errStr, 256, "Error querying the file position before reading to file '%s'(0x%x).", m_Filename, GetLastError());
OutputDebugString(errStr);
return -1;
}
while(!LockFile(fp, dwPos, 0, bufSz, 0)) Sleep(1);
DWORD amtWritten;
BOOL success = WriteFile(fp, buf, bufSz, &amtWritten, NULL);
UnlockFile(fp, dwPos, 0, bufSz, 0);
if(!success) {
CHAR errStr[256];
_sntprintf_s(errStr, 256, "Error writing to file '%s'.", m_Filename);
OutputDebugString(errStr);
return -1;
}
return amtWritten;
}
int64 FileStream::Tell() {
HANDLE fp = m_Impl->GetFileHandle();
if(NULL == fp) {
return -1;
}
DWORD pos = SetFilePointer(fp, 0, NULL, FILE_CURRENT);
if(INVALID_SET_FILE_POINTER == pos) {
CHAR errStr[256];
_sntprintf_s(errStr, 256, "Error querying the file position before reading to file '%s'(0x%x).", m_Filename, GetLastError());
OutputDebugString(errStr);
return -1;
}
return pos;
}
bool FileStream::Seek(uint32 offset, ESeekPosition pos) {
// We cannot seek in append mode.
if(m_Mode == eFileMode_WriteAppend || m_Mode == eFileMode_WriteBinaryAppend)
return false;
HANDLE fp = m_Impl->GetFileHandle();
if(NULL == fp) return false;
DWORD origin = FILE_BEGIN;
switch(pos) {
default:
case eSeekPosition_Beginning:
// Do nothing
break;
case eSeekPosition_Current:
origin = FILE_CURRENT;
break;
case eSeekPosition_End:
origin = FILE_END;
break;
}
if(SetFilePointer(fp, offset, NULL, origin) == INVALID_SET_FILE_POINTER)
return false;
return true;
}
void FileStream::Flush() {
HANDLE fp = m_Impl->GetFileHandle();
if(NULL == fp) return;
FlushFileBuffers(fp);
}

View File

@ -48,6 +48,7 @@
#include <stdio.h>
#include <limits.h>
#include <assert.h>
#include <algorithm>
#include "ImageWriter.h"
#include "ImageLoader.h"
@ -75,10 +76,10 @@ static inline T abs(const T &a) {
return a > 0? a : -a;
}
template <typename T>
static inline T min(const T &a, const T &b) {
return (a < b)? a : b;
}
//!HACK!
#ifdef _MSC_VER
#define strncpy strncpy_s
#endif
//////////////////////////////////////////////////////////////////////////////////////////
//
@ -156,7 +157,7 @@ bool ImageFile::Write() {
return false;
}
WriteImageDataToFile(writer->GetRawFileData(), writer->GetRawFileDataSz(), m_Filename);
WriteImageDataToFile(writer->GetRawFileData(), uint32(writer->GetRawFileDataSz()), m_Filename);
delete writer;
return true;
@ -197,13 +198,13 @@ Image *ImageFile::LoadImage(const unsigned char *rawImageData) const {
EImageFileFormat ImageFile::DetectFileFormat(const CHAR *filename) {
int len = strlen(filename);
size_t len = strlen(filename);
if(len >= 256) {
// !FIXME! Report Error...
return kNumImageFileFormats;
}
int dotPos = len - 1;
size_t dotPos = len - 1;
while(dotPos >= 0 && filename[dotPos--] != '.');
@ -242,8 +243,16 @@ unsigned char *ImageFile::ReadFileData(const CHAR *filename) {
assert(fstr.Tell() == 0);
// Read all of the data
int32 bytesRead = fstr.Read(rawData, fileSize);
if(bytesRead != fileSize) {
uint64 totalBytesRead = 0;
uint64 totalBytesLeft = fileSize;
uint32 bytesToRead = uint32(std::min(totalBytesLeft, uint64(1 << 31)));
int32 bytesRead;
while((bytesRead = fstr.Read(rawData, uint32(fileSize))) > 0) {
totalBytesRead += bytesRead;
totalBytesLeft -= bytesRead;
}
if(totalBytesRead != fileSize) {
assert(!"We didn't read as much data as we thought we had!");
fprintf(stderr, "Internal error: Incorrect file size assumption\n");
return 0;

View File

@ -48,6 +48,12 @@
#include <limits.h>
#include <assert.h>
///////////////////////////////////////////////////////////////////////////////
//
// Static helper functions
//
///////////////////////////////////////////////////////////////////////////////
template <typename T>
static inline T min(const T &a, const T &b) {
return (a > b)? b : a;
@ -58,6 +64,11 @@ static inline T abs(const T &a) {
return (a > 0)? a : -a;
}
template <typename T>
static inline T sad(const T &a, const T &b) {
return (a > b)? a - b : b - a;
}
void ReportError(const char *str) {
fprintf(stderr, "ImageLoader.cpp -- ERROR: %s\n", str);
}
@ -102,8 +113,8 @@ unsigned int ImageLoader::GetChannelForPixel(uint32 x, uint32 y, uint32 ch) {
const uint32 val = data[pixelIdx];
if(prec < 8) {
uint32 ret = 0;
for(uint32 precLeft = 8; precLeft > 0; precLeft -= min(prec, abs(prec - precLeft))) {
int32 ret = 0;
for(uint32 precLeft = 8; precLeft > 0; precLeft -= min(prec, sad(prec, precLeft))) {
if(prec > precLeft) {
const int toShift = prec - precLeft;
@ -120,7 +131,7 @@ unsigned int ImageLoader::GetChannelForPixel(uint32 x, uint32 y, uint32 ch) {
return ret;
}
else if(prec > 8) {
const int toShift = prec - 8;
const int32 toShift = prec - 8;
return val >> toShift;
}
@ -156,59 +167,59 @@ bool ImageLoader::LoadImage() {
#endif
int byteIdx = 0;
for(int i = 0; i < ah; i+=4) {
for(int j = 0; j < aw; j+= 4) {
for(uint32 i = 0; i < ah; i+=4) {
for(uint32 j = 0; j < aw; j+= 4) {
// For each block, visit the pixels in sequential order
for(int y = i; y < i+4; y++) {
for(int x = j; x < j+4; x++) {
for(uint32 y = i; y < i+4; y++) {
for(uint32 x = j; x < j+4; x++) {
if(y >= m_Height || x >= m_Width) {
m_PixelData[byteIdx++] = 0; // r
m_PixelData[byteIdx++] = 0; // g
m_PixelData[byteIdx++] = 0; // b
m_PixelData[byteIdx++] = 0; // a
continue;
}
if(y >= m_Height || x >= m_Width) {
m_PixelData[byteIdx++] = 0; // r
m_PixelData[byteIdx++] = 0; // g
m_PixelData[byteIdx++] = 0; // b
m_PixelData[byteIdx++] = 0; // a
continue;
}
unsigned int redVal = GetChannelForPixel(x, y, 0);
if(redVal == INT_MAX)
return false;
unsigned int redVal = GetChannelForPixel(x, y, 0);
if(redVal == INT_MAX)
return false;
unsigned int greenVal = redVal;
unsigned int blueVal = redVal;
unsigned int greenVal = redVal;
unsigned int blueVal = redVal;
if(GetGreenChannelPrecision() > 0) {
greenVal = GetChannelForPixel(x, y, 1);
if(greenVal == INT_MAX)
return false;
}
if(GetGreenChannelPrecision() > 0) {
greenVal = GetChannelForPixel(x, y, 1);
if(greenVal == INT_MAX)
return false;
}
if(GetBlueChannelPrecision() > 0) {
blueVal = GetChannelForPixel(x, y, 2);
if(blueVal == INT_MAX)
return false;
}
if(GetBlueChannelPrecision() > 0) {
blueVal = GetChannelForPixel(x, y, 2);
if(blueVal == INT_MAX)
return false;
}
unsigned int alphaVal = 0xFF;
if(GetAlphaChannelPrecision() > 0) {
alphaVal = GetChannelForPixel(x, y, 3);
if(alphaVal == INT_MAX)
return false;
}
unsigned int alphaVal = 0xFF;
if(GetAlphaChannelPrecision() > 0) {
alphaVal = GetChannelForPixel(x, y, 3);
if(alphaVal == INT_MAX)
return false;
}
// Red channel
m_PixelData[byteIdx++] = redVal & 0xFF;
// Red channel
m_PixelData[byteIdx++] = redVal & 0xFF;
// Green channel
m_PixelData[byteIdx++] = greenVal & 0xFF;
// Green channel
m_PixelData[byteIdx++] = greenVal & 0xFF;
// Blue channel
m_PixelData[byteIdx++] = blueVal & 0xFF;
// Blue channel
m_PixelData[byteIdx++] = blueVal & 0xFF;
// Alpha channel
m_PixelData[byteIdx++] = alphaVal & 0xFF;
}
// Alpha channel
m_PixelData[byteIdx++] = alphaVal & 0xFF;
}
}
}
}

View File

@ -150,14 +150,14 @@ bool ImageLoaderPNG::ReadData() {
m_RedChannelPrecision = bitDepth;
m_RedData = new unsigned char[numPixels];
for(int i = 0; i < m_Height; i++) {
for(uint32 i = 0; i < m_Height; i++) {
png_read_row(png_ptr, rowData, NULL);
unsigned int rowOffset = i * m_Width;
unsigned int byteIdx = 0;
for(int j = 0; j < m_Width; j++) {
for(uint32 j = 0; j < m_Width; j++) {
m_RedData[rowOffset + j] = rowData[byteIdx++];
}
@ -174,14 +174,14 @@ bool ImageLoaderPNG::ReadData() {
m_BlueChannelPrecision = bitDepth;
m_BlueData = new unsigned char[numPixels];
for(int i = 0; i < m_Height; i++) {
for(uint32 i = 0; i < m_Height; i++) {
png_read_row(png_ptr, rowData, NULL);
unsigned int rowOffset = i * m_Width;
unsigned int byteIdx = 0;
for(int j = 0; j < m_Width; j++) {
for(uint32 j = 0; j < m_Width; j++) {
m_RedData[rowOffset + j] = rowData[byteIdx++];
m_GreenData[rowOffset + j] = rowData[byteIdx++];
m_BlueData[rowOffset + j] = rowData[byteIdx++];
@ -201,14 +201,14 @@ bool ImageLoaderPNG::ReadData() {
m_AlphaChannelPrecision = bitDepth;
m_AlphaData = new unsigned char[numPixels];
for(int i = 0; i < m_Height; i++) {
for(uint32 i = 0; i < m_Height; i++) {
png_read_row(png_ptr, rowData, NULL);
unsigned int rowOffset = i * m_Width;
unsigned int byteIdx = 0;
for(int j = 0; j < m_Width; j++) {
for(uint32 j = 0; j < m_Width; j++) {
m_RedData[rowOffset + j] = rowData[byteIdx++];
m_GreenData[rowOffset + j] = rowData[byteIdx++];
m_BlueData[rowOffset + j] = rowData[byteIdx++];
@ -225,14 +225,14 @@ bool ImageLoaderPNG::ReadData() {
m_AlphaChannelPrecision = bitDepth;
m_AlphaData = new unsigned char[numPixels];
for(int i = 0; i < m_Height; i++) {
for(uint32 i = 0; i < m_Height; i++) {
png_read_row(png_ptr, rowData, NULL);
unsigned int rowOffset = i * m_Width;
unsigned int byteIdx = 0;
for(int j = 0; j < m_Width; j++) {
for(uint32 j = 0; j < m_Width; j++) {
m_RedData[rowOffset + j] = rowData[byteIdx++];
m_AlphaData[rowOffset + j] = rowData[byteIdx++];
}

View File

@ -54,7 +54,7 @@ class ImageLoaderPNG : public ImageLoader {
virtual bool ReadData();
private:
unsigned int m_StreamPosition;
uint64 m_StreamPosition;
friend class PNGStreamReader;
};

View File

@ -125,13 +125,13 @@ bool ImageWriterPNG::WriteImage() {
/* Initialize rows of PNG. */
row_pointers = (png_byte **)png_malloc (png_ptr, m_Height * sizeof (png_byte *));
for (int y = 0; y < m_Height; ++y) {
for (uint32 y = 0; y < m_Height; ++y) {
png_byte *row = (png_byte *)png_malloc (png_ptr, sizeof (uint8) * m_Width * pixel_size);
row_pointers[y] = row;
for (int x = 0; x < m_Width; ++x) {
for(int ch = 0; ch < 4; ch++) {
for (uint32 x = 0; x < m_Width; ++x) {
for(uint32 ch = 0; ch < 4; ch++) {
*row++ = GetChannelForPixel(x, y, ch);
}
}
@ -141,7 +141,7 @@ bool ImageWriterPNG::WriteImage() {
png_set_rows (png_ptr, info_ptr, row_pointers);
png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
for (int y = 0; y < m_Height; y++) {
for (uint32 y = 0; y < m_Height; y++) {
png_free (png_ptr, row_pointers[y]);
}
png_free (png_ptr, row_pointers);

View File

@ -55,7 +55,7 @@ class ImageWriterPNG : public ImageWriter {
virtual bool WriteImage();
private:
uint32 m_StreamPosition;
uint64 m_StreamPosition;
uint32 m_TotalBytesWritten;
friend class PNGStreamWriter;
};

1
Windows Submodule

@ -0,0 +1 @@
Subproject commit 1fad7ec01fd8b3cc88d5346231b5c6a92cfd0325