Bugfix and Enhancement for Clut, Issue 2584, Kudos to Fl?ssie
This commit is contained in:
@@ -739,6 +739,8 @@ PREFERENCES_CIEART;CIECAM02 optimization
|
||||
PREFERENCES_CIEART_LABEL;Use float precision instead of double
|
||||
PREFERENCES_CIEART_TOOLTIP;If enabled, CIECAM02 calculations are performed in the single-precision floating-point format instead of the double-precision one. This provides a small increase in speed at the expense of a negligible loss of quality.
|
||||
PREFERENCES_CLIPPINGIND;Clipping Indication
|
||||
PREFERENCES_CLUTSCACHE;HaldCLUT cache
|
||||
PREFERENCES_CLUTSCACHE_LABEL;Max number of cached Cluts
|
||||
PREFERENCES_CLUTSDIR;HaldCLUT directory
|
||||
PREFERENCES_CMETRICINTENT;Colorimetric intent
|
||||
PREFERENCES_CUSTPROFBUILDHINT;Executable (or script) file called when a new initial processing profile should be generated for an image.\n\nThe path of the communication file (*.ini style, a.k.a. "Keyfile") is added as a command line parameter. It contains various parameters required for the scripts and image Exif to allow a rules-based processing profile generation.\n\n<b>WARNING:</b> You are responsible for using double quotes where necessary if you're using paths containing spaces.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "rt_math.h"
|
||||
#include "stdimagesource.h"
|
||||
#include "safegtk.h"
|
||||
#include "../rtgui/options.h"
|
||||
|
||||
rtengine::CLUTStore clutStore;
|
||||
|
||||
@@ -10,49 +11,67 @@ using namespace rtengine;
|
||||
const float MAXVAL8 = 255.;
|
||||
|
||||
CLUTStore::CLUTStore()
|
||||
: m_refCount( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
CLUT* CLUTStore::getClut( Glib::ustring filename )
|
||||
CLUT* CLUTStore::getClut( const Glib::ustring& filename )
|
||||
{
|
||||
//MyMutex::MyLock lock(m_mutex); // copypasted from iccstore
|
||||
CLUT *result = 0;
|
||||
if ( !m_lastHaldClut.isValid() || m_lastFilename != filename )
|
||||
{
|
||||
takeUpClut();
|
||||
m_lastHaldClut.load( filename );
|
||||
m_mutex.lock();
|
||||
Cluts::iterator cluts_it = m_cluts.find(filename);
|
||||
if (cluts_it == m_cluts.end()) {
|
||||
if (m_cluts.size() >= options.clutCacheSize) {
|
||||
// Evict a "random" entry from cache
|
||||
Cluts::iterator victim_it = m_cluts.begin();
|
||||
if (--victim_it->second.first == -1) {
|
||||
delete victim_it->second.second;
|
||||
m_cluts.erase(victim_it);
|
||||
}
|
||||
if ( m_lastHaldClut.isValid() )
|
||||
{
|
||||
result = &m_lastHaldClut;
|
||||
m_lastFilename = filename;
|
||||
++m_refCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
cluts_it = m_cluts.insert(std::make_pair(filename, std::make_pair(0, new HaldCLUT))).first;
|
||||
cluts_it->second.second->load( filename );
|
||||
}
|
||||
if (cluts_it->second.second->isValid()) {
|
||||
result = cluts_it->second.second;
|
||||
++cluts_it->second.first;
|
||||
} else {
|
||||
delete cluts_it->second.second;
|
||||
m_cluts.erase(cluts_it);
|
||||
}
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CLUTStore::takeUpClut()
|
||||
void CLUTStore::releaseClut( const CLUT* clut )
|
||||
{
|
||||
m_mutex.lock();
|
||||
for (Cluts::iterator cluts_it = m_cluts.begin(); cluts_it != m_cluts.end(); ++cluts_it) {
|
||||
if (cluts_it->second.second == clut) {
|
||||
if (--cluts_it->second.first == -1) {
|
||||
delete cluts_it->second.second;
|
||||
m_cluts.erase(cluts_it);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CLUTStore::releaseClut( CLUT *clut )
|
||||
{
|
||||
if ( clut && --m_refCount == 0 )
|
||||
{
|
||||
m_mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void CLUTStore::clearCache()
|
||||
{
|
||||
m_lastHaldClut.clear();
|
||||
m_lastFilename.clear();
|
||||
m_mutex.lock();
|
||||
for (Cluts::iterator cluts_it = m_cluts.begin(); cluts_it != m_cluts.end();) {
|
||||
if (--cluts_it->second.first == -1) {
|
||||
delete cluts_it->second.second;
|
||||
Cluts::iterator tmp = cluts_it;
|
||||
++cluts_it;
|
||||
m_cluts.erase(tmp);
|
||||
} else {
|
||||
++cluts_it;
|
||||
}
|
||||
}
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void rtengine::splitClutFilename( Glib::ustring filename, Glib::ustring &name, Glib::ustring &extension, Glib::ustring &profileName )
|
||||
@@ -61,26 +80,21 @@ void rtengine::splitClutFilename( Glib::ustring filename, Glib::ustring &name, G
|
||||
name = filename;
|
||||
//remove dirs
|
||||
size_t lastSlashPos = filename.find_last_of( "/" );
|
||||
if ( lastSlashPos == Glib::ustring::npos )
|
||||
{
|
||||
if ( lastSlashPos == Glib::ustring::npos ) {
|
||||
lastSlashPos = filename.find_last_of( "\\" );
|
||||
}
|
||||
|
||||
size_t lastDotPos = filename.find_last_of( '.' );
|
||||
if ( lastDotPos != Glib::ustring::npos )
|
||||
{
|
||||
if ( lastDotPos != Glib::ustring::npos ) {
|
||||
name = filename.substr( 0, lastDotPos );
|
||||
extension = filename.substr( lastDotPos + 1, Glib::ustring::npos );
|
||||
}
|
||||
|
||||
profileName = "sRGB"; // sRGB by default
|
||||
static std::vector<Glib::ustring> workingProfiles = rtengine::getWorkingProfiles();
|
||||
for ( std::vector<Glib::ustring>::iterator it = workingProfiles.begin();
|
||||
it != workingProfiles.end();
|
||||
++it )
|
||||
{
|
||||
for ( std::vector<Glib::ustring>::iterator it = workingProfiles.begin(); it != workingProfiles.end(); ++it ) {
|
||||
Glib::ustring ¤tProfile = *it;
|
||||
if ( std::search( name.rbegin(), name.rend(), currentProfile.rbegin(), currentProfile.rend() ) == name.rbegin() )
|
||||
{
|
||||
if ( std::search( name.rbegin(), name.rend(), currentProfile.rbegin(), currentProfile.rend() ) == name.rbegin() ) {
|
||||
profileName = currentProfile;
|
||||
name = name.substr( 0, name.size() - currentProfile.size() );
|
||||
break;
|
||||
@@ -94,36 +108,26 @@ HaldCLUT::HaldCLUT()
|
||||
: m_clutImage( 0 ),
|
||||
m_level (0),
|
||||
m_profile( "sRGB" )
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
HaldCLUT::~HaldCLUT()
|
||||
{
|
||||
}
|
||||
|
||||
void HaldCLUT::clear()
|
||||
{
|
||||
if ( m_clutImage )
|
||||
{
|
||||
if ( m_clutImage ) {
|
||||
m_clutImage->free();
|
||||
m_clutImage = 0;
|
||||
}
|
||||
m_filename.clear();
|
||||
}
|
||||
|
||||
void HaldCLUT::load( Glib::ustring filename )
|
||||
{
|
||||
if ( m_filename != filename )
|
||||
{
|
||||
clear();
|
||||
m_clutImage = loadFile( filename, "", m_level );
|
||||
Glib::ustring name, ext;
|
||||
splitClutFilename( filename, name, ext, m_profile );
|
||||
if ( m_clutImage )
|
||||
{
|
||||
if ( m_clutImage ) {
|
||||
m_filename = filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Glib::ustring HaldCLUT::profile() const
|
||||
{
|
||||
@@ -134,8 +138,7 @@ Imagefloat* HaldCLUT::loadFile( Glib::ustring filename, Glib::ustring workingCol
|
||||
{
|
||||
Imagefloat *result = 0;
|
||||
StdImageSource imgSrc;
|
||||
if ( !safe_file_test( filename, Glib::FILE_TEST_EXISTS ) || imgSrc.load(filename) )
|
||||
{
|
||||
if ( !safe_file_test( filename, Glib::FILE_TEST_EXISTS ) || imgSrc.load(filename) ) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -144,18 +147,15 @@ Imagefloat* HaldCLUT::loadFile( Glib::ustring filename, Glib::ustring workingCol
|
||||
|
||||
bool valid = false;
|
||||
//test on Hald format, copypasted from http://www.quelsolaar.com/technology/clut.html
|
||||
if ( fw == fh )
|
||||
{
|
||||
if ( fw == fh ) {
|
||||
outLevel = 1;
|
||||
for(; outLevel * outLevel * outLevel < fw; outLevel++);
|
||||
if( !( outLevel * outLevel * outLevel > fw ) )
|
||||
{
|
||||
if( !( outLevel * outLevel * outLevel > fw ) ) {
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( valid )
|
||||
{
|
||||
if ( valid ) {
|
||||
ColorTemp currWB = imgSrc.getWB();
|
||||
Imagefloat* baseImg = new Imagefloat (fw, fh);
|
||||
PreviewProps pp (0, 0, fw, fh, 1);
|
||||
@@ -164,8 +164,7 @@ Imagefloat* HaldCLUT::loadFile( Glib::ustring filename, Glib::ustring workingCol
|
||||
icm.working = workingColorSpace;
|
||||
|
||||
imgSrc.getImage (currWB, TR_NONE, baseImg, pp, procparams::ToneCurveParams(), icm, procparams::RAWParams());
|
||||
if ( !workingColorSpace.empty() )
|
||||
{
|
||||
if ( !workingColorSpace.empty() ) {
|
||||
imgSrc.convertColorSpace(baseImg, icm, currWB, procparams::RAWParams());
|
||||
}
|
||||
result = baseImg;
|
||||
@@ -181,10 +180,8 @@ void HaldCLUT::loadClut( Imagefloat *img, RawClut &outClut )
|
||||
outClut.resize( x_size * y_size * 3 );
|
||||
int clutIdx = 0;
|
||||
//int level = m_level * m_level; (unused)
|
||||
for(int y = 0; y < y_size; y++)
|
||||
{
|
||||
for(int x = 0; x < x_size; x++)
|
||||
{
|
||||
for(int y = 0; y < y_size; y++) {
|
||||
for(int x = 0; x < x_size; x++) {
|
||||
outClut[ clutIdx * 3 ] = img->r( y, x ) * MAXVAL8;
|
||||
outClut[ clutIdx * 3 + 1 ] = img->g( y, x ) * MAXVAL8;
|
||||
outClut[ clutIdx * 3 + 2 ] = img->b( y, x ) * MAXVAL8;
|
||||
@@ -202,12 +199,9 @@ Imagefloat* HaldCLUT::generateIdentImage( int level )
|
||||
int cubeSideSize = level * level;
|
||||
float step = MAXVALF / (cubeSideSize - 1);
|
||||
int pos = 0;
|
||||
for( int b = 0; b < cubeSideSize; ++b )
|
||||
{
|
||||
for ( int g = 0; g < cubeSideSize; ++g )
|
||||
{
|
||||
for ( int r = 0; r < cubeSideSize; ++r )
|
||||
{
|
||||
for( int b = 0; b < cubeSideSize; ++b ) {
|
||||
for ( int g = 0; g < cubeSideSize; ++g ) {
|
||||
for ( int r = 0; r < cubeSideSize; ++r ) {
|
||||
int x = pos / imageWidth;
|
||||
int y = pos % imageWidth;
|
||||
resultImg->r( x, y ) = step * r;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "../rtgui/threadutils.h"
|
||||
#include "imagefloat.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace rtengine {
|
||||
|
||||
@@ -25,7 +26,6 @@ public:
|
||||
~HaldCLUT();
|
||||
void load( Glib::ustring filename );
|
||||
bool isValid() const;
|
||||
void clear();
|
||||
|
||||
void getRGB( float r, float g, float b, float &outR, float &outG, float &outB ) const;
|
||||
Glib::ustring profile() const;
|
||||
@@ -51,17 +51,17 @@ class CLUTStore
|
||||
{
|
||||
public:
|
||||
CLUTStore();
|
||||
CLUT* getClut( Glib::ustring filename );
|
||||
void takeUpClut();
|
||||
void releaseClut( CLUT *clut );
|
||||
|
||||
CLUT* getClut( const Glib::ustring& filename );
|
||||
void releaseClut( const CLUT* clut );
|
||||
|
||||
void clearCache();
|
||||
|
||||
private:
|
||||
int m_refCount;
|
||||
MyMutex m_mutex;
|
||||
typedef std::map<Glib::ustring, std::pair<int, HaldCLUT*> > Cluts;
|
||||
|
||||
HaldCLUT m_lastHaldClut;
|
||||
Glib::ustring m_lastFilename;
|
||||
Cluts m_cluts;
|
||||
MyMutex m_mutex;
|
||||
};
|
||||
|
||||
void splitClutFilename( Glib::ustring filename, Glib::ustring &name, Glib::ustring &extension, Glib::ustring &profileName );
|
||||
@@ -79,12 +79,12 @@ public:
|
||||
ClutPtr() : m_point( 0 ) {}
|
||||
explicit ClutPtr(CLUT *p) : m_point( p ) {}
|
||||
~ClutPtr() { clutStore.releaseClut( m_point ); }
|
||||
CLUT* operator-> () const { return m_point; }
|
||||
const CLUT* operator-> () const { return m_point; }
|
||||
operator bool() const { return m_point != 0; }
|
||||
void set( CLUT *p ) { m_point = p; }
|
||||
|
||||
private:
|
||||
ClutPtr& operator=(ClutPtr const& cp ) { /*only for clean warning messages*/return *this; }
|
||||
ClutPtr& operator=(ClutPtr const& cp );
|
||||
CLUT *m_point;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "improcfun.h"
|
||||
#include "curves.h"
|
||||
#include "iccstore.h"
|
||||
#include "clutstore.h"
|
||||
#include "processingjob.h"
|
||||
#include <glibmm.h>
|
||||
#include "../rtgui/options.h"
|
||||
@@ -678,6 +679,10 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
|
||||
if (settings->verbose)
|
||||
printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob);
|
||||
|
||||
// if clut was used and size of clut cache == 1 we free the memory used by the clutstore (default clut cache size = 1 for 32 bit OS)
|
||||
if ( params.filmSimulation.enabled && !params.filmSimulation.clutFilename.empty() && options.clutCacheSize == 1)
|
||||
clutStore.clearCache();
|
||||
|
||||
// freeing up some memory
|
||||
customToneCurve1.Reset();
|
||||
customToneCurve2.Reset();
|
||||
|
||||
@@ -114,6 +114,7 @@ void FilmSimulation::read( const rtengine::procparams::ProcParams* pp, const Par
|
||||
}
|
||||
if ( !m_enabled->get_inconsistent() && !pp->filmSimulation.enabled )
|
||||
{
|
||||
if (options.clutCacheSize == 1)
|
||||
clutStore.clearCache();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@
|
||||
#include "../rtengine/safegtk.h"
|
||||
#include "version.h"
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
// for GCC32
|
||||
@@ -354,7 +359,11 @@ void Options::setDefaults () {
|
||||
histogramFullMode = false;
|
||||
|
||||
rgbDenoiseThreadLimit = 0;
|
||||
|
||||
#if defined( _OPENMP ) && defined( __x86_64__ )
|
||||
clutCacheSize = omp_get_num_procs();
|
||||
#else
|
||||
clutCacheSize = 1;
|
||||
#endif
|
||||
filledProfile = false;
|
||||
|
||||
showProfileSelector = true;
|
||||
@@ -736,8 +745,7 @@ if (keyFile.has_group ("Performance")) {
|
||||
if (keyFile.has_key ("Performance", "LevNRAUT")) rtSettings.leveldnaut = keyFile.get_integer("Performance", "LevNRAUT");
|
||||
if (keyFile.has_key ("Performance", "LevNRLISS")) rtSettings.leveldnliss = keyFile.get_integer("Performance", "LevNRLISS");
|
||||
if (keyFile.has_key ("Performance", "SIMPLNRAUT")) rtSettings.leveldnautsimpl = keyFile.get_integer("Performance", "SIMPLNRAUT");
|
||||
|
||||
|
||||
if (keyFile.has_key ("Performance", "ClutCacheSize")) clutCacheSize = keyFile.get_integer ("Performance", "ClutCacheSize");
|
||||
}
|
||||
|
||||
if (keyFile.has_group ("GUI")) {
|
||||
@@ -1019,6 +1027,7 @@ int Options::saveToFile (Glib::ustring fname) {
|
||||
keyFile.set_integer ("Performance", "LevNRAUT", rtSettings.leveldnaut);
|
||||
keyFile.set_integer ("Performance", "LevNRLISS", rtSettings.leveldnliss);
|
||||
keyFile.set_integer ("Performance", "SIMPLNRAUT", rtSettings.leveldnautsimpl);
|
||||
keyFile.set_integer ("Performance", "ClutCacheSize", clutCacheSize);
|
||||
|
||||
keyFile.set_string ("Output", "Format", saveFormat.format);
|
||||
keyFile.set_integer ("Output", "JpegQuality", saveFormat.jpegQuality);
|
||||
|
||||
@@ -219,7 +219,7 @@ class Options {
|
||||
|
||||
// Performance options
|
||||
int rgbDenoiseThreadLimit; // maximum number of threads for the denoising tool ; 0 = use the maximum available
|
||||
|
||||
int clutCacheSize;
|
||||
bool filledProfile; // Used as reminder for the ProfilePanel "mode"
|
||||
|
||||
bool menuGroupRank;
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#include <sstream>
|
||||
#include "../rtengine/safegtk.h"
|
||||
#include "rtimage.h"
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
extern Options options;
|
||||
extern Glib::ustring argv0;
|
||||
@@ -595,6 +598,32 @@ Gtk::Widget* Preferences::getPerformancePanel () {
|
||||
fdenoise->add (*mainContainer);
|
||||
mvbsd->pack_start (*fdenoise, Gtk::PACK_SHRINK, 4);
|
||||
|
||||
|
||||
Gtk::Frame* fclut = Gtk::manage( new Gtk::Frame (M("PREFERENCES_CLUTSCACHE")) );
|
||||
|
||||
Gtk::HBox* clutCacheSizeHB = Gtk::manage( new Gtk::HBox () );
|
||||
clutCacheSizeHB->set_border_width(4);
|
||||
clutCacheSizeHB->set_spacing(4);
|
||||
// clutCacheSizeHB->set_tooltip_text(M("PREFERENCES_CLUTCACHESIZE_TOOLTIP"));
|
||||
Gtk::Label* CLUTLl = Gtk::manage( new Gtk::Label (M("PREFERENCES_CLUTSCACHE_LABEL") + ":", Gtk::ALIGN_LEFT));
|
||||
clutCacheSizeSB = Gtk::manage( new Gtk::SpinButton () );
|
||||
clutCacheSizeSB->set_digits (0);
|
||||
clutCacheSizeSB->set_increments (1, 5);
|
||||
clutCacheSizeSB->set_max_length(2); // Will this be sufficient? :)
|
||||
|
||||
#ifdef _OPENMP
|
||||
clutCacheSizeSB->set_range (1, 2*omp_get_num_procs());
|
||||
#else
|
||||
clutCacheSizeSB->set_range (1, 8);
|
||||
#endif
|
||||
|
||||
clutCacheSizeHB->pack_start (*CLUTLl, Gtk::PACK_SHRINK, 0);
|
||||
clutCacheSizeHB->pack_end (*clutCacheSizeSB, Gtk::PACK_SHRINK, 0);
|
||||
fclut->add (*clutCacheSizeHB);
|
||||
|
||||
|
||||
mvbsd->pack_start (*fclut, Gtk::PACK_SHRINK, 4);
|
||||
|
||||
// return mainContainer;
|
||||
return mvbsd;
|
||||
|
||||
@@ -1377,6 +1406,7 @@ void Preferences::storePreferences () {
|
||||
moptions.UseIconNoText = ckbUseIconNoText->get_active();
|
||||
|
||||
moptions.rgbDenoiseThreadLimit = rgbDenoiseTreadLimitSB->get_value_as_int();
|
||||
moptions.clutCacheSize = clutCacheSizeSB->get_value_as_int();
|
||||
|
||||
// Sounds only on Windows and Linux
|
||||
#if defined(WIN32) || defined(__linux__)
|
||||
@@ -1522,7 +1552,7 @@ void Preferences::fillPreferences () {
|
||||
ckbUseIconNoText->set_active(moptions.UseIconNoText);
|
||||
|
||||
rgbDenoiseTreadLimitSB->set_value(moptions.rgbDenoiseThreadLimit);
|
||||
|
||||
clutCacheSizeSB->set_value(moptions.clutCacheSize);
|
||||
//darkFrameDir->set_filename( moptions.rtSettings.darkFramesPath );
|
||||
//updateDFinfos();
|
||||
darkFrameDir->set_current_folder( moptions.rtSettings.darkFramesPath );
|
||||
|
||||
@@ -124,6 +124,7 @@ class Preferences : public Gtk::Dialog, public ProfileStoreListener {
|
||||
Gtk::CheckButton* sameThumbSize;
|
||||
|
||||
Gtk::SpinButton* rgbDenoiseTreadLimitSB;
|
||||
Gtk::SpinButton* clutCacheSizeSB;
|
||||
|
||||
Gtk::CheckButton* ckbmenuGroupRank;
|
||||
Gtk::CheckButton* ckbmenuGroupLabel;
|
||||
|
||||
Reference in New Issue
Block a user