Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions IccConnect/IccLibConnect/IccConnect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,12 @@ CIccNamedColorCmm* CIccConnectCmm::GetNamedCmm() const

CIccCmmSearch* CIccConnectCmm::GetSearchCmm() const
{
return dynamic_cast<CIccCmmSearch*>(m_pCmm);
CIccCmmSearch* search = dynamic_cast<CIccCmmSearch*>(m_pCmm);
if (search)
return search;

CIccThreadedCmm* threaded = GetThreadedCmm();
return threaded ? dynamic_cast<CIccCmmSearch*>(threaded->GetBaseCmm()) : nullptr;
}

CIccThreadedCmm* CIccConnectCmm::GetThreadedCmm() const
Expand Down Expand Up @@ -462,10 +467,25 @@ CIccConnectCmm* CIccConnectCmm::CreateStandard(const CIccCfgProfileSequence& pro

CIccConnectCmm* CIccConnectCmm::CreateSearch(const CIccCfgSearchApply& searchApply,
std::string* pErrorMsg)
{
return CreateSearch(searchApply, pErrorMsg, 1);
}

CIccConnectCmm* CIccConnectCmm::CreateSearch(const CIccCfgSearchApply& searchApply,
std::string* pErrorMsg,
int nThreads)
{
std::string localErr;
std::string& sErrorMsg = pErrorMsg ? *pErrorMsg : localErr;

if (nThreads < 0 || nThreads > CIccThreadedCmm::GetMaxThreads()) {
std::ostringstream oss;
oss << "invalid thread count " << nThreads << " (maximum "
<< CIccThreadedCmm::GetMaxThreads() << ")";
sErrorMsg = oss.str();
return nullptr;
}

IccProfilePtrList pccList;
auto pCmm = std::unique_ptr<CIccCmmSearch>(new (std::nothrow) CIccCmmSearch());
if (!pCmm) {
Expand Down Expand Up @@ -633,7 +653,11 @@ CIccConnectCmm* CIccConnectCmm::CreateSearch(const CIccCfgSearchApply& searchApp
}

ReleasePccList(pccList);
return Attach(pCmm.release());
std::unique_ptr<CIccCmm> baseCmm(pCmm.release());
CIccConnectCmm* pConnect = AttachStandardCmm(baseCmm, nThreads);
if (!pConnect)
sErrorMsg = "failed to attach search CMM";
return pConnect;
}

#ifdef USEICCDEVNAMESPACE
Expand Down
3 changes: 3 additions & 0 deletions IccConnect/IccLibConnect/IccConnect.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ class CIccConnectCmm
// description of the first failure encountered. Callers print it.
static CIccConnectCmm* CreateSearch(const CIccCfgSearchApply& searchApply,
std::string* pErrorMsg = nullptr);
static CIccConnectCmm* CreateSearch(const CIccCfgSearchApply& searchApply,
std::string* pErrorMsg,
int nThreads);

// Wraps an already-initialized CMM (takes ownership).
static CIccConnectCmm* Attach(CIccCmm* pCmm);
Expand Down
104 changes: 97 additions & 7 deletions IccProfLib/IccCmmSearch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,17 @@
#include "IccCmmSearch.h"

#include <cmath>
#include <memory>
#include <utility>


CIccApplyCmmSearch::CIccApplyCmmSearch(CIccCmm* pBaseCmm) : CIccApplyCmm(pBaseCmm)
{
CIccCmmSearch* pCmm = (CIccCmmSearch*)pBaseCmm;

m_bReady = false;
m_pMidToDstApply = nullptr;

m_nApply = pCmm->m_pcc.size();
if (!m_nApply)
m_nApply = 1;
Expand Down Expand Up @@ -113,10 +118,50 @@ CIccApplyCmmSearch::CIccApplyCmmSearch(CIccCmm* pBaseCmm) : CIccApplyCmm(pBaseCm
m_maxBounds = pCmm->m_maxBounds;

m_bNeedPcsToLab = pCmm->m_bNeedPcsToLab;

icStatusCMM status = icCmmStatOk;
std::unique_ptr<CIccApplyCmm> mid_to_dst_apply(
pCmm->m_mid_to_dst->GetNewApplyCmm(status));
if (!mid_to_dst_apply || status != icCmmStatOk)
return;

std::vector<std::unique_ptr<CIccApplyCmm>> src_to_mid_apply;
src_to_mid_apply.reserve(pCmm->m_src_to_mid.size());
for (const auto& cmm : pCmm->m_src_to_mid) {
std::unique_ptr<CIccApplyCmm> apply(cmm->GetNewApplyCmm(status));
if (!apply || status != icCmmStatOk) {
return;
}
src_to_mid_apply.push_back(std::move(apply));
}

std::vector<std::unique_ptr<CIccApplyCmm>> dst_to_mid_apply;
dst_to_mid_apply.reserve(pCmm->m_dst_to_mid.size());
for (const auto& cmm : pCmm->m_dst_to_mid) {
std::unique_ptr<CIccApplyCmm> apply(cmm->GetNewApplyCmm(status));
if (!apply || status != icCmmStatOk) {
return;
}
dst_to_mid_apply.push_back(std::move(apply));
}

m_srcToMidApply.reserve(src_to_mid_apply.size());
m_dstToMidApply.reserve(dst_to_mid_apply.size());
m_pMidToDstApply = mid_to_dst_apply.release();
for (auto& apply : src_to_mid_apply)
m_srcToMidApply.push_back(apply.release());
for (auto& apply : dst_to_mid_apply)
m_dstToMidApply.push_back(apply.release());
m_bReady = true;
}

CIccApplyCmmSearch::~CIccApplyCmmSearch()
{
delete m_pMidToDstApply;
for (CIccApplyCmm* apply : m_srcToMidApply)
delete apply;
for (CIccApplyCmm* apply : m_dstToMidApply)
delete apply;
}

static icFloatNumber sq(icFloatNumber x) { return x * x; }
Expand All @@ -133,7 +178,7 @@ icFloatNumber CIccApplyCmmSearch::costFunc(CIccSearchVec& point)
// costFunc has no status channel, so report the point as infeasible instead:
// the same sentinel the bounds barrier uses keeps the optimizer away from it
// rather than letting it converge on a garbage minimum.
if (pCmm->m_dst_to_mid[i]->Apply(&m_pixel[0], &point.vec()[0]) != icCmmStatOk)
if (m_dstToMidApply[i]->Apply(&m_pixel[0], &point.vec()[0]) != icCmmStatOk)
return overBoundsCost;

if (m_bNeedPcsToLab) {
Expand Down Expand Up @@ -200,15 +245,15 @@ icStatusCMM CIccApplyCmmSearch::Apply(icFloatNumber* DstPixel, const icFloatNumb
// Propagate the per-PCC forward transform status (#1860). Swallowing it
// left m_mid_data[i] holding whatever the previous pixel wrote, so the
// search then optimised against a stale target and still reported success.
icStatusCMM statMid = pCmm->m_src_to_mid[i]->Apply(&m_mid_data[i][0], SrcPixel);
icStatusCMM statMid = m_srcToMidApply[i]->Apply(&m_mid_data[i][0], SrcPixel);
if (statMid != icCmmStatOk)
return statMid;
}
}

// Same for the transform that seeds the search's starting point: if it fails
// m_startPixel is stale and every subsequent simplex vertex derives from it.
icStatusCMM statStart = pCmm->m_mid_to_dst->Apply(&m_startPixel[0], &m_mid_data[0][0]);
icStatusCMM statStart = m_pMidToDstApply->Apply(&m_startPixel[0], &m_mid_data[0][0]);
if (statStart != icCmmStatOk)
return statStart;

Expand Down Expand Up @@ -374,7 +419,7 @@ icStatusCMM CIccCmmSearch::AttachPCC(IIccProfileConnectionConditions* pPCC, icFl

#define checkCmmStatus(rv) if (rv != icCmmStatOk) return rv

icStatusCMM CIccCmmSearch::Begin(bool /* bAllocNewApply */, bool /* bUsePcsConversion */)
icStatusCMM CIccCmmSearch::Begin(bool bAllocNewApply, bool /* bUsePcsConversion */)
{
icStatusCMM rv;

Expand All @@ -390,8 +435,17 @@ icStatusCMM CIccCmmSearch::Begin(bool /* bAllocNewApply */, bool /* bUsePcsConve
// the reference AddXform overload. Guarding on m_pApply -- which the tail of
// this function sets -- also stops that second pass leaking the CIccApplyCmm
// the first one allocated and pushing a duplicate chain into m_dst_to_mid.
if (m_pApply)
if (m_bValid) {
if (bAllocNewApply && !m_pApply) {
m_pApply = GetNewApplyCmm(rv);
if (!m_pApply || rv != icCmmStatOk) {
delete m_pApply;
m_pApply = nullptr;
return rv;
}
}
return icCmmStatOk;
}

if (m_nAttached < 2)
return icCmmStatBadXform;
Expand Down Expand Up @@ -553,13 +607,49 @@ icStatusCMM CIccCmmSearch::Begin(bool /* bAllocNewApply */, bool /* bUsePcsConve
else
m_bNeedPcsToLab = false;

m_pApply = new CIccApplyCmmSearch(this);

m_bValid = true;

if (bAllocNewApply) {
m_pApply = GetNewApplyCmm(rv);
if (!m_pApply || rv != icCmmStatOk) {
delete m_pApply;
m_pApply = nullptr;
return rv;
}
}

return rv;
}

CIccApplyCmm* CIccCmmSearch::GetNewApplyCmm(icStatusCMM& status)
{
if (!m_bValid) {
status = icCmmStatBad;
return nullptr;
}

CIccApplyCmmSearch* apply = nullptr;
try {
apply = new (std::nothrow) CIccApplyCmmSearch(this);
}
catch (const std::bad_alloc&) {
status = icCmmStatAllocErr;
return nullptr;
}
if (!apply) {
status = icCmmStatAllocErr;
return nullptr;
}
if (!apply->IsReady()) {
delete apply;
status = icCmmStatAllocErr;
return nullptr;
}

status = icCmmStatOk;
return apply;
}

//Call to Detach and remove all pending IO objects attached to the profiles used by the CMM. Should be called only after Begin()
icStatusCMM CIccCmmSearch::RemoveAllIO()
{
Expand Down
8 changes: 7 additions & 1 deletion IccProfLib/IccCmmSearch.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ class ICCPROFLIB_API CIccApplyCmmSearch : public CIccApplyCmm, public CIccMinSea
// Returns icCmmStatOk on success.
virtual icStatusCMM GetApplyCost(icFloatNumber& dCost, const icFloatNumber* SrcPixel);

bool IsReady() const { return m_bReady; }

protected:
CIccApplyCmmSearch(CIccCmm* pCmm);

Expand All @@ -143,6 +145,10 @@ class ICCPROFLIB_API CIccApplyCmmSearch : public CIccApplyCmm, public CIccMinSea
icFloatVector m_maxBounds;

bool m_bNeedPcsToLab;
bool m_bReady;
CIccApplyCmm* m_pMidToDstApply;
std::vector<CIccApplyCmm*> m_srcToMidApply;
std::vector<CIccApplyCmm*> m_dstToMidApply;
};


Expand Down Expand Up @@ -184,7 +190,7 @@ class ICCPROFLIB_API CIccCmmSearch : public CIccCmm
virtual icStatusCMM Begin(bool bAllocNewApply = true, bool bUsePcsConversion = false);

//Get an additional Apply CMM object to apply pixels with. The Apply object should be deleted by the caller.
virtual CIccApplyCmm* GetNewApplyCmm(icStatusCMM& /*status*/) { return nullptr; }
virtual CIccApplyCmm* GetNewApplyCmm(icStatusCMM& status);

//Call to Detach and remove all pending IO objects attached to the profiles used by the CMM. Should be called only after Begin()
virtual icStatusCMM RemoveAllIO();
Expand Down
1 change: 1 addition & 0 deletions IccProfLib/IccCmmThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ class ICCPROFLIB_API CIccThreadedCmm : public CIccCmm
virtual icColorSpaceSignature GetLastXformDest() { return m_pCmm->GetLastXformDest(); }

int GetNumThreads() const { return m_nThreads; }
CIccCmm* GetBaseCmm() const { return m_pCmm; }

protected:
CIccCmm *m_pCmm;
Expand Down
Loading
Loading