Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/graphics/TextureConverter.cpp
/* Copyright (C) 2015 Wildfire Games. | /* Copyright (C) 2019 Wildfire Games. | ||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
▲ Show 20 Lines • Show All 277 Lines • ▼ Show 20 Lines | #endif | ||||
// Set up the worker thread: | // Set up the worker thread: | ||||
int ret; | int ret; | ||||
// Use SDL semaphores since OS X doesn't implement sem_init | // Use SDL semaphores since OS X doesn't implement sem_init | ||||
m_WorkerSem = SDL_CreateSemaphore(0); | m_WorkerSem = SDL_CreateSemaphore(0); | ||||
ENSURE(m_WorkerSem); | ENSURE(m_WorkerSem); | ||||
ret = pthread_mutex_init(&m_WorkerMutex, NULL); | m_WorkerThread = std::thread(RunThread, this); | ||||
ENSURE(ret == 0); | |||||
ret = pthread_create(&m_WorkerThread, NULL, &RunThread, this); | |||||
ENSURE(ret == 0); | |||||
// Maybe we should share some centralised pool of worker threads? | // Maybe we should share some centralised pool of worker threads? | ||||
// For now we'll just stick with a single thread for this specific use. | // For now we'll just stick with a single thread for this specific use. | ||||
} | } | ||||
CTextureConverter::~CTextureConverter() | CTextureConverter::~CTextureConverter() | ||||
{ | { | ||||
// Tell the thread to shut down | // Tell the thread to shut down | ||||
pthread_mutex_lock(&m_WorkerMutex); | { | ||||
std::lock_guard<std::mutex> lock(m_WorkerMutex); | |||||
m_Shutdown = true; | m_Shutdown = true; | ||||
pthread_mutex_unlock(&m_WorkerMutex); | } | ||||
// Wake it up so it sees the notification | // Wake it up so it sees the notification | ||||
SDL_SemPost(m_WorkerSem); | SDL_SemPost(m_WorkerSem); | ||||
// Wait for it to shut down cleanly | // Wait for it to shut down cleanly | ||||
pthread_join(m_WorkerThread, NULL); | m_WorkerThread.join(); | ||||
// Clean up resources | // Clean up resources | ||||
SDL_DestroySemaphore(m_WorkerSem); | SDL_DestroySemaphore(m_WorkerSem); | ||||
pthread_mutex_destroy(&m_WorkerMutex); | |||||
} | } | ||||
bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath& src, const VfsPath& dest, const Settings& settings) | bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath& src, const VfsPath& dest, const Settings& settings) | ||||
{ | { | ||||
shared_ptr<u8> file; | shared_ptr<u8> file; | ||||
size_t fileSize; | size_t fileSize; | ||||
if (m_VFS->LoadFile(src, file, fileSize) < 0) | if (m_VFS->LoadFile(src, file, fileSize) < 0) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | else // bpp == 8 | ||||
{ | { | ||||
p[0] = p[1] = p[2] = p[3] = *input++; | p[0] = p[1] = p[2] = p[3] = *input++; | ||||
p += 4; | p += 4; | ||||
} | } | ||||
request->inputOptions.setMipmapData(rgba, tex.m_Width, tex.m_Height); | request->inputOptions.setMipmapData(rgba, tex.m_Width, tex.m_Height); | ||||
delete[] rgba; | delete[] rgba; | ||||
} | } | ||||
pthread_mutex_lock(&m_WorkerMutex); | { | ||||
std::lock_guard<std::mutex> lock(m_WorkerMutex); | |||||
m_RequestQueue.push_back(request); | m_RequestQueue.push_back(request); | ||||
pthread_mutex_unlock(&m_WorkerMutex); | } | ||||
// Wake up the worker thread | // Wake up the worker thread | ||||
SDL_SemPost(m_WorkerSem); | SDL_SemPost(m_WorkerSem); | ||||
return true; | return true; | ||||
#else | #else | ||||
LOGERROR("Failed to convert texture \"%s\" (NVTT not available)", src.string8()); | LOGERROR("Failed to convert texture \"%s\" (NVTT not available)", src.string8()); | ||||
return false; | return false; | ||||
#endif | #endif | ||||
} | } | ||||
bool CTextureConverter::Poll(CTexturePtr& texture, VfsPath& dest, bool& ok) | bool CTextureConverter::Poll(CTexturePtr& texture, VfsPath& dest, bool& ok) | ||||
{ | { | ||||
#if CONFIG2_NVTT | #if CONFIG2_NVTT | ||||
shared_ptr<ConversionResult> result; | shared_ptr<ConversionResult> result; | ||||
// Grab the first result (if any) | // Grab the first result (if any) | ||||
pthread_mutex_lock(&m_WorkerMutex); | { | ||||
std::lock_guard<std::mutex> lock(m_WorkerMutex); | |||||
if (!m_ResultQueue.empty()) | if (!m_ResultQueue.empty()) | ||||
{ | { | ||||
result = m_ResultQueue.front(); | result = m_ResultQueue.front(); | ||||
m_ResultQueue.pop_front(); | m_ResultQueue.pop_front(); | ||||
} | } | ||||
pthread_mutex_unlock(&m_WorkerMutex); | } | ||||
if (!result) | if (!result) | ||||
{ | { | ||||
// no work to do | // no work to do | ||||
return false; | return false; | ||||
} | } | ||||
if (!result->ret) | if (!result->ret) | ||||
Show All 23 Lines | |||||
#else // #if CONFIG2_NVTT | #else // #if CONFIG2_NVTT | ||||
return false; | return false; | ||||
#endif | #endif | ||||
} | } | ||||
bool CTextureConverter::IsBusy() | bool CTextureConverter::IsBusy() | ||||
{ | { | ||||
pthread_mutex_lock(&m_WorkerMutex); | std::lock_guard<std::mutex> lock(m_WorkerMutex); | ||||
bool busy = !m_RequestQueue.empty(); | bool busy = !m_RequestQueue.empty(); | ||||
pthread_mutex_unlock(&m_WorkerMutex); | |||||
return busy; | return busy; | ||||
} | } | ||||
void* CTextureConverter::RunThread(void* data) | void CTextureConverter::RunThread(CTextureConverter* textureConverter) | ||||
{ | { | ||||
debug_SetThreadName("TextureConverter"); | debug_SetThreadName("TextureConverter"); | ||||
g_Profiler2.RegisterCurrentThread("texconv"); | g_Profiler2.RegisterCurrentThread("texconv"); | ||||
CTextureConverter* textureConverter = static_cast<CTextureConverter*>(data); | |||||
#if CONFIG2_NVTT | #if CONFIG2_NVTT | ||||
// Wait until the main thread wakes us up | // Wait until the main thread wakes us up | ||||
while (SDL_SemWait(textureConverter->m_WorkerSem) == 0) | while (SDL_SemWait(textureConverter->m_WorkerSem) == 0) | ||||
{ | { | ||||
g_Profiler2.RecordSyncMarker(); | g_Profiler2.RecordSyncMarker(); | ||||
PROFILE2_EVENT("wakeup"); | PROFILE2_EVENT("wakeup"); | ||||
pthread_mutex_lock(&textureConverter->m_WorkerMutex); | shared_ptr<ConversionRequest> request; | ||||
if (textureConverter->m_Shutdown) | |||||
{ | { | ||||
pthread_mutex_unlock(&textureConverter->m_WorkerMutex); | std::lock_guard<std::mutex> lock(textureConverter->m_WorkerMutex); | ||||
if (textureConverter->m_Shutdown) | |||||
break; | break; | ||||
} | |||||
// If we weren't woken up for shutdown, we must have been woken up for | // If we weren't woken up for shutdown, we must have been woken up for | ||||
// a new request, so grab it from the queue | // a new request, so grab it from the queue | ||||
shared_ptr<ConversionRequest> request = textureConverter->m_RequestQueue.front(); | request = textureConverter->m_RequestQueue.front(); | ||||
textureConverter->m_RequestQueue.pop_front(); | textureConverter->m_RequestQueue.pop_front(); | ||||
pthread_mutex_unlock(&textureConverter->m_WorkerMutex); | } | ||||
// Set up the result object | // Set up the result object | ||||
shared_ptr<ConversionResult> result(new ConversionResult()); | shared_ptr<ConversionResult> result(new ConversionResult()); | ||||
result->dest = request->dest; | result->dest = request->dest; | ||||
result->texture = request->texture; | result->texture = request->texture; | ||||
request->outputOptions.setOutputHandler(&result->output); | request->outputOptions.setOutputHandler(&result->output); | ||||
Show All 16 Lines | // TIMER(L"TextureConverter compress"); | ||||
if (request->isDXT1a && result->ret && result->output.buffer.size() > 80) | if (request->isDXT1a && result->ret && result->output.buffer.size() > 80) | ||||
result->output.buffer[80] |= 1; // DDPF_ALPHAPIXELS in DDS_PIXELFORMAT.dwFlags | result->output.buffer[80] |= 1; // DDPF_ALPHAPIXELS in DDS_PIXELFORMAT.dwFlags | ||||
// Ugly hack: NVTT always sets DDPF_RGB, even if we're trying to output 8-bit | // Ugly hack: NVTT always sets DDPF_RGB, even if we're trying to output 8-bit | ||||
// alpha-only DDS with no RGB components. Unset that flag. | // alpha-only DDS with no RGB components. Unset that flag. | ||||
if (request->is8bpp) | if (request->is8bpp) | ||||
result->output.buffer[80] &= ~0x40; // DDPF_RGB in DDS_PIXELFORMAT.dwFlags | result->output.buffer[80] &= ~0x40; // DDPF_RGB in DDS_PIXELFORMAT.dwFlags | ||||
// Push the result onto the queue | // Push the result onto the queue | ||||
pthread_mutex_lock(&textureConverter->m_WorkerMutex); | std::lock_guard<std::mutex> lock(textureConverter->m_WorkerMutex); | ||||
textureConverter->m_ResultQueue.push_back(result); | textureConverter->m_ResultQueue.push_back(result); | ||||
pthread_mutex_unlock(&textureConverter->m_WorkerMutex); | |||||
} | } | ||||
#endif | #endif | ||||
return NULL; | |||||
} | } |
Wildfire Games · Phabricator