libgui/source/gui/GuiImageAsync.cpp

177 lines
5.6 KiB
C++
Raw Normal View History

2017-10-29 10:28:14 +01:00
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* 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 3 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <unistd.h>
2018-06-21 20:44:58 +02:00
#include <gui/GuiImageAsync.h>
#include "../fs/CFile.hpp"
2017-10-29 10:28:14 +01:00
std::vector<GuiImageAsync *> GuiImageAsync::imageQueue;
CThread * GuiImageAsync::pThread = NULL;
std::recursive_mutex * GuiImageAsync::pMutex = NULL;
2018-06-21 20:44:58 +02:00
uint32_t GuiImageAsync::threadRefCounter = 0;
2017-10-29 10:28:14 +01:00
bool GuiImageAsync::bExitRequested = false;
GuiImageAsync * GuiImageAsync::pInUse = NULL;
2018-06-21 20:44:58 +02:00
GuiImageAsync::GuiImageAsync(const uint8_t *imageBuffer, const uint32_t & imageBufferSize, GuiImageData * preloadImg)
2017-10-29 10:28:14 +01:00
: GuiImage(preloadImg)
2018-06-21 20:44:58 +02:00
, imgData(NULL)
, imgBuffer(imageBuffer)
, imgBufferSize(imageBufferSize) {
threadInit();
threadAddImage(this);
2017-10-29 10:28:14 +01:00
}
GuiImageAsync::GuiImageAsync(const std::string & file, GuiImageData * preloadImg)
: GuiImage(preloadImg)
2018-06-21 20:44:58 +02:00
, imgData(NULL)
, filename(file)
, imgBuffer(NULL)
, imgBufferSize(0) {
threadInit();
threadAddImage(this);
2017-10-29 10:28:14 +01:00
}
2018-06-21 20:44:58 +02:00
GuiImageAsync::~GuiImageAsync() {
threadRemoveImage(this);
while(pInUse == this)
OSSleepTicks(OSMicrosecondsToTicks(1000));
2017-10-29 10:28:14 +01:00
2018-06-21 20:44:58 +02:00
if (imgData)
2017-10-29 10:28:14 +01:00
delete imgData;
//threadExit();
}
2018-06-21 20:44:58 +02:00
void GuiImageAsync::threadAddImage(GuiImageAsync *Image) {
2017-10-29 10:28:14 +01:00
pMutex->lock();
2018-06-21 20:44:58 +02:00
imageQueue.push_back(Image);
2017-10-29 10:28:14 +01:00
pMutex->unlock();
2018-06-21 20:44:58 +02:00
pThread->resumeThread();
2017-10-29 10:28:14 +01:00
}
2018-06-21 20:44:58 +02:00
void GuiImageAsync::threadRemoveImage(GuiImageAsync *image) {
2017-10-29 10:28:14 +01:00
pMutex->lock();
2018-06-21 20:44:58 +02:00
for(uint32_t i = 0; i < imageQueue.size(); ++i) {
if(imageQueue[i] == image) {
imageQueue.erase(imageQueue.begin() + i);
break;
}
}
2017-10-29 10:28:14 +01:00
pMutex->unlock();
}
2018-06-21 20:44:58 +02:00
void GuiImageAsync::clearQueue() {
2017-10-29 10:28:14 +01:00
pMutex->lock();
2018-06-21 20:44:58 +02:00
imageQueue.clear();
2017-10-29 10:28:14 +01:00
pMutex->unlock();
}
2018-06-21 20:44:58 +02:00
void GuiImageAsync::guiImageAsyncThread(CThread *thread, void *arg) {
while(!bExitRequested) {
2017-10-29 10:28:14 +01:00
if(imageQueue.empty() && !bExitRequested)
pThread->suspendThread();
2018-06-21 20:44:58 +02:00
if(!imageQueue.empty() && !bExitRequested) {
2017-10-29 10:28:14 +01:00
pMutex->lock();
2018-06-21 20:44:58 +02:00
pInUse = imageQueue.front();
imageQueue.erase(imageQueue.begin());
2017-10-29 10:28:14 +01:00
pMutex->unlock();
2018-06-21 20:44:58 +02:00
if (!pInUse)
continue;
2017-10-29 10:28:14 +01:00
2018-06-21 20:44:58 +02:00
if(pInUse->imgBuffer && pInUse->imgBufferSize) {
2017-10-29 10:28:14 +01:00
pInUse->imgData = new GuiImageData(pInUse->imgBuffer, pInUse->imgBufferSize);
2018-06-21 20:44:58 +02:00
} else {
uint8_t *buffer = NULL;
uint64_t bufferSize = 0;
CFile file(pInUse->filename, CFile::ReadOnly);
if(file.isOpen()) {
uint64_t filesize = file.size();
buffer = (uint8_t *) malloc(filesize);
if (buffer != NULL) {
uint32_t blocksize = 0x4000;
uint32_t done = 0;
int32_t readBytes = 0;
while(done < filesize) {
if(done + blocksize > filesize) {
blocksize = filesize - done;
}
readBytes = file.read(buffer + done, blocksize);
if(readBytes <= 0)
break;
done += readBytes;
}
if(done == filesize){
bufferSize = filesize;
}else{
free(buffer);
}
}
file.close();
}
2017-10-29 10:28:14 +01:00
if(buffer != NULL && bufferSize > 0) {
2018-06-21 20:44:58 +02:00
pInUse->imgData = new GuiImageData(buffer, bufferSize, GX2_TEX_CLAMP_MODE_MIRROR);
2017-10-29 10:28:14 +01:00
//! free original image buffer which is converted to texture now and not needed anymore
free(buffer);
}
}
2018-06-21 20:44:58 +02:00
if(pInUse->imgData) {
if(pInUse->imgData->getTexture()) {
2017-10-29 10:28:14 +01:00
pInUse->width = pInUse->imgData->getWidth();
pInUse->height = pInUse->imgData->getHeight();
pInUse->imageData = pInUse->imgData;
2018-06-21 20:44:58 +02:00
} else {
2017-10-29 10:28:14 +01:00
delete pInUse->imgData;
pInUse->imgData = NULL;
}
}
pInUse->imageLoaded(pInUse);
2018-06-21 20:44:58 +02:00
pInUse = NULL;
}
}
2017-10-29 10:28:14 +01:00
}
2018-06-21 20:44:58 +02:00
void GuiImageAsync::threadInit() {
if (pThread == NULL) {
2017-10-29 10:28:14 +01:00
bExitRequested = false;
pMutex = new std::recursive_mutex();
2018-06-21 20:44:58 +02:00
pThread = CThread::create(GuiImageAsync::guiImageAsyncThread, NULL, CThread::eAttributeAffCore1 | CThread::eAttributePinnedAff, 10);
pThread->resumeThread();
2017-10-29 10:28:14 +01:00
}
++threadRefCounter;
}
2018-06-21 20:44:58 +02:00
void GuiImageAsync::threadExit() {
if(threadRefCounter) {
2017-10-29 10:28:14 +01:00
--threadRefCounter;
}
2018-06-21 20:44:58 +02:00
if(/*(threadRefCounter == 0) &&*/ (pThread != NULL)) {
bExitRequested = true;
2017-10-29 10:28:14 +01:00
delete pThread;
delete pMutex;
pThread = NULL;
pMutex = NULL;
2018-06-21 20:44:58 +02:00
}
2017-10-29 10:28:14 +01:00
}