mirror of
				https://github.com/yuzu-emu/FasTC.git
				synced 2025-11-04 12:04:56 +00:00 
			
		
		
		
	Add files for implementing a worker queue threading scheme
This commit is contained in:
		
							parent
							
								
									2c22889533
								
							
						
					
					
						commit
						62ca4ffee0
					
				| 
						 | 
				
			
			@ -38,8 +38,11 @@ FIND_PACKAGE( Boost COMPONENTS thread system )
 | 
			
		|||
IF( Boost_FOUND )
 | 
			
		||||
	INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} )
 | 
			
		||||
 | 
			
		||||
	SET( SOURCES ${SOURCES} "src/ThreadGroup.cpp")
 | 
			
		||||
	SET( HEADERS ${HEADERS} "src/ThreadGroup.h")
 | 
			
		||||
	SET( SOURCES ${SOURCES} "src/ThreadGroup.cpp" )
 | 
			
		||||
	SET( SOURCES ${SOURCES} "src/WorkerQueue.cpp" )
 | 
			
		||||
 | 
			
		||||
	SET( HEADERS ${HEADERS} "src/ThreadGroup.h" )
 | 
			
		||||
	SET( HEADERS ${HEADERS} "src/WorkerQueue.h" )
 | 
			
		||||
 | 
			
		||||
	LINK_DIRECTORIES( ${Boost_LIBRARY_DIR} )
 | 
			
		||||
ENDIF()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,13 @@ public:
 | 
			
		|||
 | 
			
		||||
class ThreadGroup {
 | 
			
		||||
 public:
 | 
			
		||||
  ThreadGroup( int numThreads, const unsigned char *inBuf, unsigned int inBufSz, CompressionFunc func, unsigned char *outBuf );
 | 
			
		||||
  ThreadGroup( 
 | 
			
		||||
    int numThreads, 
 | 
			
		||||
    const unsigned char *inBuf, 
 | 
			
		||||
    unsigned int inBufSz, 
 | 
			
		||||
    CompressionFunc func, 
 | 
			
		||||
    unsigned char *outBuf
 | 
			
		||||
  );
 | 
			
		||||
  ~ThreadGroup();
 | 
			
		||||
 | 
			
		||||
  bool PrepareThreads();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										186
									
								
								Core/src/WorkerQueue.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								Core/src/WorkerQueue.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,186 @@
 | 
			
		|||
#include "WorkerQueue.h"
 | 
			
		||||
 | 
			
		||||
#include "BC7Compressor.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#include <boost/thread/thread.hpp>
 | 
			
		||||
#include <boost/thread/barrier.hpp>
 | 
			
		||||
#include <boost/thread/mutex.hpp>
 | 
			
		||||
#include <boost/thread/condition_variable.hpp>
 | 
			
		||||
 | 
			
		||||
WorkerThread::WorkerThread(WorkerQueue * parent, uint32 idx) 
 | 
			
		||||
  : m_ThreadIdx(idx)
 | 
			
		||||
  , m_Parent(parent)
 | 
			
		||||
{ }
 | 
			
		||||
 | 
			
		||||
void WorkerThread::operator()() {
 | 
			
		||||
 | 
			
		||||
  if(!m_Parent) {
 | 
			
		||||
    fprintf(stderr, "%s\n", "Illegal worker thread initialization -- parent is NULL.");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  CompressionFunc f = m_Parent->GetCompressionFunc();
 | 
			
		||||
  if(!f) {
 | 
			
		||||
    fprintf(stderr, "%s\n", "Illegal worker queue initialization -- compression func is NULL.");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
ThreadGroup::ThreadGroup( int numThreads, const unsigned char *inBuf, unsigned int inBufSz, CompressionFunc func, unsigned char *outBuf )
 | 
			
		||||
  : m_StartBarrier(new boost::barrier(numThreads + 1))
 | 
			
		||||
  , m_FinishMutex(new boost::mutex())
 | 
			
		||||
  , m_FinishCV(new boost::condition_variable())
 | 
			
		||||
  , m_NumThreads(numThreads)
 | 
			
		||||
  , m_ActiveThreads(0)
 | 
			
		||||
  , m_Func(func)
 | 
			
		||||
  , m_ImageDataSz(inBufSz)
 | 
			
		||||
  , m_ImageData(inBuf)
 | 
			
		||||
  , m_OutBuf(outBuf)
 | 
			
		||||
  , m_ThreadState(eThreadState_Done)
 | 
			
		||||
  , m_ExitFlag(false)
 | 
			
		||||
{ 
 | 
			
		||||
  for(int i = 0; i < kMaxNumThreads; i++) {
 | 
			
		||||
    // Thread synchronization primitives
 | 
			
		||||
    m_Threads[i].m_ParentCounterLock = m_FinishMutex;
 | 
			
		||||
    m_Threads[i].m_FinishCV = m_FinishCV;
 | 
			
		||||
    m_Threads[i].m_ParentCounter = &m_ThreadsFinished;
 | 
			
		||||
    m_Threads[i].m_StartBarrier = m_StartBarrier;
 | 
			
		||||
    m_Threads[i].m_ParentExitFlag = &m_ExitFlag;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ThreadGroup::~ThreadGroup() {
 | 
			
		||||
  delete m_StartBarrier;
 | 
			
		||||
  delete m_FinishMutex;
 | 
			
		||||
  delete m_FinishCV;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int ThreadGroup::GetCompressedBlockSize() {
 | 
			
		||||
  if(m_Func == BC7C::CompressImageBC7) return 16;
 | 
			
		||||
#ifdef HAS_SSE_41
 | 
			
		||||
  if(m_Func == BC7C::CompressImageBC7SIMD) return 16;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int ThreadGroup::GetUncompressedBlockSize() {
 | 
			
		||||
  if(m_Func == BC7C::CompressImageBC7) return 64;
 | 
			
		||||
#ifdef HAS_SSE_41
 | 
			
		||||
  if(m_Func == BC7C::CompressImageBC7SIMD) return 64;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ThreadGroup::PrepareThreads() {
 | 
			
		||||
 | 
			
		||||
  // Make sure that threads aren't running.
 | 
			
		||||
  if(m_ThreadState != eThreadState_Done) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Have we already activated the thread group?
 | 
			
		||||
  if(m_ActiveThreads > 0) {
 | 
			
		||||
    m_ThreadState = eThreadState_Waiting;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // We can assume that the image data is in block stream order
 | 
			
		||||
  // so, the size of the data given to each thread will be (nb*4)x4
 | 
			
		||||
  int numBlocks = m_ImageDataSz / 64;
 | 
			
		||||
 | 
			
		||||
  int blocksProcessed = 0;
 | 
			
		||||
  int blocksPerThread = (numBlocks/m_NumThreads) + ((numBlocks % m_NumThreads)? 1 : 0);
 | 
			
		||||
 | 
			
		||||
  // Currently no threads are finished...
 | 
			
		||||
  m_ThreadsFinished = 0;
 | 
			
		||||
  for(int i = 0; i < m_NumThreads; i++) {
 | 
			
		||||
 | 
			
		||||
    if(m_ActiveThreads >= kMaxNumThreads)
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    int numBlocksThisThread = blocksPerThread;
 | 
			
		||||
    if(blocksProcessed + numBlocksThisThread > numBlocks) {
 | 
			
		||||
      numBlocksThisThread = numBlocks - blocksProcessed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CmpThread &t = m_Threads[m_ActiveThreads];
 | 
			
		||||
    t.m_Height = 4;
 | 
			
		||||
    t.m_Width = numBlocksThisThread * 4;
 | 
			
		||||
    t.m_CmpFunc = m_Func;
 | 
			
		||||
    t.m_OutBuf = m_OutBuf + (blocksProcessed * GetCompressedBlockSize());
 | 
			
		||||
    t.m_InBuf = m_ImageData + (blocksProcessed * GetUncompressedBlockSize());
 | 
			
		||||
 | 
			
		||||
    blocksProcessed += numBlocksThisThread;
 | 
			
		||||
    
 | 
			
		||||
    m_ThreadHandles[m_ActiveThreads] = new boost::thread(t);
 | 
			
		||||
 | 
			
		||||
    m_ActiveThreads++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  m_ThreadState = eThreadState_Waiting;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ThreadGroup::Start() {
 | 
			
		||||
 | 
			
		||||
  if(m_ActiveThreads <= 0) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(m_ThreadState != eThreadState_Waiting) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  m_StopWatch.Reset();
 | 
			
		||||
  m_StopWatch.Start();
 | 
			
		||||
 | 
			
		||||
  // Last thread to activate the barrier is this one.
 | 
			
		||||
  m_ThreadState = eThreadState_Running;
 | 
			
		||||
  m_StartBarrier->wait();
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ThreadGroup::CleanUpThreads() {
 | 
			
		||||
 | 
			
		||||
  // Are the threads currently running?
 | 
			
		||||
  if(m_ThreadState == eThreadState_Running) {
 | 
			
		||||
    // ... if so, wait for them to finish
 | 
			
		||||
    Join();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  assert(m_ThreadState == eThreadState_Done || m_ThreadState == eThreadState_Waiting);
 | 
			
		||||
  
 | 
			
		||||
  // Mark all threads for exit
 | 
			
		||||
  m_ExitFlag = true;
 | 
			
		||||
 | 
			
		||||
  // Hit the barrier to signal them to go.
 | 
			
		||||
  m_StartBarrier->wait();
 | 
			
		||||
 | 
			
		||||
  // Clean up.
 | 
			
		||||
  for(int i = 0; i < m_ActiveThreads; i++) {
 | 
			
		||||
    m_ThreadHandles[i]->join();
 | 
			
		||||
    delete m_ThreadHandles[i];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Reset active number of threads...
 | 
			
		||||
  m_ActiveThreads = 0;
 | 
			
		||||
  m_ExitFlag = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadGroup::Join() {
 | 
			
		||||
 | 
			
		||||
  boost::unique_lock<boost::mutex> lock(*m_FinishMutex);
 | 
			
		||||
  while(m_ThreadsFinished != m_ActiveThreads) {
 | 
			
		||||
    m_FinishCV->wait(lock);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  m_StopWatch.Stop();
 | 
			
		||||
  m_ThreadState = eThreadState_Done;
 | 
			
		||||
  m_ThreadsFinished = 0;
 | 
			
		||||
}
 | 
			
		||||
#endif 
 | 
			
		||||
							
								
								
									
										59
									
								
								Core/src/WorkerQueue.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								Core/src/WorkerQueue.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
#ifndef __TEXCOMP_WORKDER_QUEUE_H__
 | 
			
		||||
#define __TEXCOMP_WORKDER_QUEUE_H__
 | 
			
		||||
 | 
			
		||||
#include "TexCompTypes.h"
 | 
			
		||||
#include "TexComp.h"
 | 
			
		||||
 | 
			
		||||
// Forward declare...
 | 
			
		||||
class WorkerQueue;
 | 
			
		||||
namespace boost {
 | 
			
		||||
  class thread;
 | 
			
		||||
  class mutex;
 | 
			
		||||
  class barrier;
 | 
			
		||||
  class condition_variable;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct WorkerThread {
 | 
			
		||||
  friend class WorkerQueue;
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  WorkerThread(WorkerQueue *, uint32 idx);
 | 
			
		||||
  void operator ()();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  uint32 m_ThreadIdx;
 | 
			
		||||
  WorkerQueue *const m_Parent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class WorkerQueue {
 | 
			
		||||
  friend class WorkerThread;
 | 
			
		||||
 public:
 | 
			
		||||
  WorkerQueue(
 | 
			
		||||
    uint32 numThreads, 
 | 
			
		||||
    uint32 jobSize,
 | 
			
		||||
    const uint8 *inBuf, 
 | 
			
		||||
    uint32 inBufSz, 
 | 
			
		||||
    CompressionFunc func, 
 | 
			
		||||
    uint8 *outBuf
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  ~WorkerQueue() { }
 | 
			
		||||
 | 
			
		||||
  // Runs the 
 | 
			
		||||
  void Run();
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
 | 
			
		||||
  static const int kMaxNumWorkerThreads = 256;
 | 
			
		||||
  int m_Offsets[kMaxNumWorkerThreads];
 | 
			
		||||
 | 
			
		||||
  int GetOffsetForThread(const int threadIdx) const;
 | 
			
		||||
  
 | 
			
		||||
  const CompressionFunc m_CompressionFunc;
 | 
			
		||||
  CompressionFunc GetCompressionFunc() const { return m_CompressionFunc; }
 | 
			
		||||
 | 
			
		||||
  void SignalThreadReady(int threadIdx);
 | 
			
		||||
  bool AcceptThreadData(int threadIdx) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif //__TEXCOMP_WORKDER_QUEUE_H__
 | 
			
		||||
		Loading…
	
		Reference in a new issue