Performance optimalization of patch meshes

This commit is contained in:
Jakub Melka 2021-03-20 18:04:58 +01:00
parent e9bff58c06
commit 67872a532f
4 changed files with 63 additions and 20 deletions

View File

@ -22,7 +22,7 @@
namespace pdf
{
static constexpr const std::array<std::pair<QChar, const char*>, 4281> glyphNameToUnicode = {
static constexpr const std::array glyphNameToUnicode = {
std::pair<QChar, const char*>{ QChar(0x0041), "A" }, // Character 'A' Letter, Uppercase
std::pair<QChar, const char*>{ QChar(0x00C6), "AE" }, // Character 'Æ' Letter, Uppercase
std::pair<QChar, const char*>{ QChar(0x01FC), "AEacute" }, // Character 'Ǽ' Letter, Uppercase
@ -1831,6 +1831,10 @@ static constexpr const std::array<std::pair<QChar, const char*>, 4281> glyphName
std::pair<QChar, const char*>{ QChar(0x01B9), "ezhreversed" }, // Character 'ƹ' Letter, Lowercase
std::pair<QChar, const char*>{ QChar(0x01BA), "ezhtail" }, // Character 'ƺ' Letter, Lowercase
std::pair<QChar, const char*>{ QChar(0x0066), "f" }, // Character 'f' Letter, Lowercase
std::pair<QChar, const char*>{ QChar(0xFB00), "f_f" }, // Character 'ff' Letter, Lowercase // NOT LISTED IN UNICODE CHARACTER LIST
std::pair<QChar, const char*>{ QChar(0xFB03), "f_f_i" }, // Character 'ffi' Letter, Lowercase // NOT LISTED IN UNICODE CHARACTER LIST
std::pair<QChar, const char*>{ QChar(0xFB04), "f_f_l" }, // Character 'ffl' Letter, Lowercase // NOT LISTED IN UNICODE CHARACTER LIST
std::pair<QChar, const char*>{ QChar(0xFB01), "f_i" }, // Character 'fi' Letter, Lowercase // NOT LISTED IN UNICODE CHARACTER LIST
std::pair<QChar, const char*>{ QChar(0x095E), "fadeva" }, // Character 'फ़' Letter
std::pair<QChar, const char*>{ QChar(0x0A5E), "fagurmukhi" }, // Character 'ਫ਼' Letter
std::pair<QChar, const char*>{ QChar(0x2109), "fahrenheit" }, // Character '℉' Symbol

View File

@ -2604,6 +2604,13 @@ QPointF PDFTensorPatch::getValue(PDFReal u, PDFReal v, int derivativeOrderU, int
bool PDFTensorPatch::getUV(PDFReal& u, PDFReal& v, PDFReal x, PDFReal y, PDFReal epsilon, int maximalNumberOfSteps) const
{
// First we will text, if point (x, y) is in bounding rectangle of the patch.
// If it isn't, then return false immediately, because point is not in tensor patch.
if (!m_boundingBox.contains(x, y))
{
return false;
}
int i = 0;
// Jakub Melka: We are finding root of function F(u, v) defined as:
@ -2816,6 +2823,27 @@ constexpr PDFReal PDFTensorPatch::B3(PDFReal t, int derivative)
return std::numeric_limits<PDFReal>::signaling_NaN();
}
void PDFTensorPatch::computeBoundingRectangle()
{
PDFReal xMin = std::numeric_limits<PDFReal>::infinity();
PDFReal xMax = -xMin;
PDFReal yMin = xMin;
PDFReal yMax = xMax;
for (const auto& row : m_P)
{
for (const auto& point : row)
{
xMin = qMin(xMin, point.x());
xMax = qMax(xMax, point.x());
yMin = qMin(yMin, point.y());
yMax = qMax(yMax, point.y());
}
}
m_boundingBox = QRectF(xMin, yMin, xMax - xMin, yMax - yMin);
}
ShadingType PDFTensorProductPatchShading::getShadingType() const
{
return ShadingType::TensorProductPatchMesh;
@ -3198,7 +3226,8 @@ void PDFTensorProductPatchShadingBase::fillMesh(PDFMesh& mesh,
const PDFTensorPatch& patch,
const PDFCMS* cms,
RenderingIntent intent,
PDFRenderErrorReporter* reporter) const
PDFRenderErrorReporter* reporter,
bool fastAlgorithm) const
{
// We implement algorithm similar to Ruppert's algorithm (see https://en.wikipedia.org/wiki/Ruppert%27s_algorithm), but
// we do not need a mesh for FEM calculation, so we do not care about quality of the triangles (we can have triangles with
@ -3216,24 +3245,31 @@ void PDFTensorProductPatchShadingBase::fillMesh(PDFMesh& mesh,
std::atomic<PDFReal> maximalCurvature(0.0);
Q_ASSERT(settings.patchTestPoints > 2);
const PDFReal testPointScale = 1.0 / (settings.patchTestPoints - 1.0);
PDFIntegerRange<PDFInteger> range(0, settings.patchTestPoints * settings.patchTestPoints);
auto updateCurvature = [&](PDFInteger i)
if (!fastAlgorithm)
{
PDFInteger row = i / settings.patchTestPoints;
PDFInteger column = i % settings.patchTestPoints;
Q_ASSERT(settings.patchTestPoints > 2);
const PDFReal testPointScale = 1.0 / (settings.patchTestPoints - 1.0);
PDFIntegerRange<PDFInteger> range(0, settings.patchTestPoints * settings.patchTestPoints);
auto updateCurvature = [&](PDFInteger i)
{
PDFInteger row = i / settings.patchTestPoints;
PDFInteger column = i % settings.patchTestPoints;
const PDFReal u = column * testPointScale;
const PDFReal v = row * testPointScale;
const PDFReal u = column * testPointScale;
const PDFReal v = row * testPointScale;
const PDFReal curvature = patch.getCurvature_u(u, v) + patch.getCurvature_v(u, v);
const PDFReal curvature = patch.getCurvature_u(u, v) + patch.getCurvature_v(u, v);
// Atomically update the maximum curvature
PDFReal previousCurvature = maximalCurvature;
while (previousCurvature < curvature && !maximalCurvature.compare_exchange_weak(previousCurvature, curvature)) { }
};
PDFExecutionPolicy::execute(PDFExecutionPolicy::Scope::Content, range.begin(), range.end(), updateCurvature);
// Atomically update the maximum curvature
PDFReal previousCurvature = maximalCurvature;
while (previousCurvature < curvature && !maximalCurvature.compare_exchange_weak(previousCurvature, curvature)) { }
};
std::for_each(range.begin(), range.end(), updateCurvature);
}
else
{
maximalCurvature = std::numeric_limits<PDFReal>::infinity();
}
auto getColorForUV = [&](PDFReal u, PDFReal v)
{
@ -3382,9 +3418,10 @@ void PDFTensorProductPatchShadingBase::fillMesh(PDFMesh& mesh,
RenderingIntent intent,
PDFRenderErrorReporter* reporter) const
{
const bool fastAlgorithm = patches.size() > 16;
for (const auto& patch : patches)
{
fillMesh(mesh, settings, patch, cms, intent, reporter);
fillMesh(mesh, settings, patch, cms, intent, reporter, fastAlgorithm);
}
// Create bounding path

View File

@ -546,7 +546,7 @@ public:
using PointMatrix = std::array<std::array<QPointF, 4>, 4>;
using Colors = std::array<PDFColor, 4>;
explicit inline PDFTensorPatch(PointMatrix P, Colors colors) : m_P(P), m_colors(colors) { }
explicit inline PDFTensorPatch(PointMatrix P, Colors colors) : m_P(P), m_colors(colors) { computeBoundingRectangle(); }
/// Calculates value at point in the patch.
/// \param u Horizontal coordinate of the patch, must be in range [0, 1]
@ -654,8 +654,11 @@ private:
static constexpr PDFReal pow2(PDFReal x) { return x * x; }
static constexpr PDFReal pow3(PDFReal x) { return x * x * x; }
void computeBoundingRectangle();
PointMatrix m_P = { };
Colors m_colors = { };
QRectF m_boundingBox; ///< Bounding box of the tensor product patch
};
using PDFTensorPatches = std::vector<PDFTensorPatch>;
@ -671,7 +674,7 @@ public:
protected:
struct Triangle;
void fillMesh(PDFMesh& mesh, const PDFMeshQualitySettings& settings, const PDFTensorPatch& patch, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const;
void fillMesh(PDFMesh& mesh, const PDFMeshQualitySettings& settings, const PDFTensorPatch& patch, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool fastAlgorithm) const;
void fillMesh(PDFMesh& mesh, const QMatrix& patternSpaceToDeviceSpaceMatrix, const PDFMeshQualitySettings& settings, const PDFTensorPatches& patches, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const;
static void addTriangle(std::vector<Triangle>& triangles, const PDFTensorPatch& patch, std::array<QPointF, 3> uvCoordinates);

View File

@ -1117,7 +1117,6 @@ void PDFTransparencyRenderer::collapseSpotColorsToDeviceColors(PDFFloatBitmapWit
{
case PDFAbstractColorSpace::ColorSpace::Separation:
{
PDFFloatBitmap spotColorBitmap = bitmap.extractSpotChannel(i);
PDFFloatBitmap processColorBitmap(spotColorBitmap.getWidth(), spotColorBitmap.getHeight(), PDFPixelFormat::createFormat(pixelFormat.getProcessColorChannelCount(), 0, false, pixelFormat.hasProcessColorsSubtractive(), false));
if (!PDFAbstractColorSpace::transform(spotColor->colorSpace.data(), bitmap.getColorSpace().data(), getCMS(), getGraphicState()->getRenderingIntent(), spotColorBitmap.getPixels(), processColorBitmap.getPixels(), this))