69 return static_cast<uint8_t
>( std::clamp( aValue, 0.0, 1.0 ) * 255.0 );
75 aHash.
addData(
static_cast<const uint8_t*
>( aData ), aSize );
89template <
typename T,
typename COUNT>
90static void updateRuns( std::vector<RHI_RUN_BOUNDS>& aRuns,
const std::vector<T>& aElements,
91 const std::vector<std::pair<uint32_t, uint32_t>>& aDirty,
size_t aCounted,
bool aAll,
92 size_t aRunLength,
COUNT aCount )
94 const size_t size = aElements.size();
95 const size_t runs = ( size + aRunLength - 1 ) / aRunLength;
99 auto recount = [&](
size_t aRun )
101 const size_t first = aRun * aRunLength;
103 aRuns[aRun] = aCount( aElements.data() + first, std::min( aRunLength, size - first ) );
106 const size_t tail = aAll ? 0 : ( size == aCounted ? runs : std::min( aCounted, size ) / aRunLength );
108 for(
size_t run = tail; run < runs; ++run )
111 for(
const auto& [begin, spanEnd] : aDirty )
113 const size_t end = std::min<size_t>( spanEnd, size );
115 for(
size_t run = begin / aRunLength; run < tail && run * aRunLength <
end; ++run )
126 return glm::packHalf1x16( std::clamp( glm::unpackHalf1x16( aDepth ) - aBase, -limit, limit ) );
130template <
typename POOL>
131static void hashPool(
MMH3_HASH& aHash,
const POOL& aPool,
const std::vector<LAYER_RANGE>& aRanges )
133 auto mixVector = [&](
const auto& aVector )
135 aHash.
add(
static_cast<int32_t
>( aVector.size() ) );
136 hashBytes( aHash, aVector.data(), aVector.size() *
sizeof( aVector[0] ) );
139 for(
const std::vector<RHI_INSTANCE>& instances : aPool.instances )
140 mixVector( instances );
142 mixVector( aPool.polygonVertices );
146 hashBytes( aHash, range.start.data(),
sizeof( range.start ) );
147 hashBytes( aHash, range.count.data(),
sizeof( range.count ) );
148 hashBytes( aHash, &range.alpha,
sizeof( range.alpha ) );
149 hashBytes( aHash, &range.depth,
sizeof( range.depth ) );
154template <
typename IT>
160 for(
IT prev = aBegin, it = std::next( aBegin ); it != aEnd; ++prev, ++it )
166template <
typename IT>
171 for(
IT it = aBegin; it != aEnd; ++it )
193 static std::mutex s_mutex;
194 static std::weak_ptr<RENDER_THREAD> s_shared;
196 std::lock_guard<std::mutex> lock( s_mutex );
198 std::shared_ptr<RENDER_THREAD> thread = s_shared.lock();
200 if( thread && !thread->IsDeviceLost() )
208 thread = std::make_shared<RENDER_THREAD>(
209 [aEnableValidation]()
214 if( !thread->Start() )
224 static std::atomic<uint32_t> s_nextWindowId{ 1 };
226 return s_nextWindowId++;
271 if( layer.polygons.buffer )
405 if( aOwnedOnly && !bq.ownsResources )
408 if( bq.ownsTexture && bq.texture )
411 if( bq.vertexBuffer )
422 [&](
const std::pair<uint64_t, RHI_BufferHandle>& aRetired )
424 if( aRetired.first > aConsumedGeneration )
432 [&](
const std::pair<uint64_t, RHI_TextureHandle>& aRetired )
434 if( aRetired.first > aConsumedGeneration )
444 size_t aNeeded,
size_t aStride )
449 if( aCapacity < aNeeded )
451 size_t newCapacity = std::max( aNeeded, aCapacity * 2 );
454 if( aStride != 0 && newCapacity > std::numeric_limits<size_t>::max() / aStride )
472 aCapacity = newCapacity;
481 auto partitionRange = []( std::vector<RHI_INSTANCE>& aInstances, uint32_t aStart, uint32_t aEnd,
482 uint32_t& aNormalCount, uint32_t& aNegStart, uint32_t& aNegCount )
484 auto rangeBegin = aInstances.begin() + aStart;
485 auto rangeEnd = aInstances.begin() + aEnd;
487 auto it = std::stable_partition( rangeBegin, rangeEnd,
493 aNormalCount =
static_cast<uint32_t
>( std::distance( rangeBegin, it ) );
494 aNegStart = aStart + aNormalCount;
495 aNegCount =
static_cast<uint32_t
>( std::distance( it, rangeEnd ) );
506 if( aRanges.empty() && !aPool.
Empty() )
510 aRanges.push_back( synth );
516 bool negative =
false;
518 for(
size_t i = 0; i < aRanges.size(); ++i )
521 const bool last = i + 1 == aRanges.size();
523 const uint32_t bmpEnd = last ?
static_cast<uint32_t
>( aPool.
bitmapQuads.size() )
524 : aRanges[i + 1].bitmapStart;
528 const size_t firstMark = mark;
536 if( negative || mark > firstMark )
544 for(
int shape = 0; shape <
RHI_SHAPES; ++shape )
545 run.
count[shape] = std::min( aAt[shape],
end[shape] ) - run.
start[shape];
550 for(
int shape = 0; shape <
RHI_SHAPES; ++shape )
554 for(
size_t m = firstMark; m < mark; ++m )
558 closeRun( change.
at );
568 bool ordered =
false;
569 bool cleared =
false;
578 ordered = ordered || cleared;
607 || std::ranges::any_of( lr.
negCount, []( uint32_t aCount ) { return aCount > 0; } );
613 uint8_t minAlpha = 255;
614 uint8_t maxAlpha = 0;
617 auto scan = [&](
const auto& aElements, uint32_t aStart, uint32_t aCount )
619 for( uint32_t j = aStart; j < aStart + aCount; ++j )
621 minAlpha = std::min( minAlpha, aElements[j].a );
622 maxAlpha = std::max( maxAlpha, aElements[j].a );
630 scan( aPool.
instances[shape], aStart[shape], aCount[shape] );
660 for( uint32_t j = lr.
start[shape]; j <
end[shape]; ++j )
674 else if( hasAny && minAlpha == maxAlpha && minAlpha < 255 )
676 lr.
alpha =
static_cast<float>( minAlpha ) / 255.0f;
680 for( uint32_t j = lr.
start[shape]; j <
end[shape]; ++j )
700 aPool.
lastCount[shape] += lr.count[shape];
711 auto table = std::make_shared<RHI_RUN_TABLE>();
715 const std::vector<RHI_INSTANCE>& instances = aPool.
instances[shape];
720 return RhiInstanceRun( aFirst, aCount, RHI_SHAPE( shape ) );
737 makeCullRuns(
buf() );
743 makeCullRuns(
obuf() );
751 bool gridChanged =
false;
762 const std::array<uint64_t, 2> digest =
hashDigest( hash );
781 auto uploadBatch = [&](
auto& aElements,
RHI_BufferHandle& aBuffer,
size_t& aCapacity,
bool aAdopt )
783 if( aElements.empty() )
786 using ElemType =
typename std::decay_t<
decltype( aElements )>::value_type;
787 size_t count = aElements.size();
789 if( !
ensureBuffer( aBuffer, aCapacity, count,
sizeof( ElemType ) ) || !aBuffer )
791 allocationFailed =
true;
817 uploadPool(
buf(),
true );
820 uploadPool(
obuf(),
true );
829 bool patchedStatic =
false;
839 if( !aBuffer || aSpan.end > aElements.size() )
847 patchedStatic =
true;
865 if( allocationFailed && std::uncaught_exceptions() == 0 )
866 throw GPU_OOM_ERROR(
"RHI geometry buffer allocation failed (GPU out of memory)" );
874 pool->ClearGeometry();
924 float depth =
static_cast<float>( aLayerDepth );
927 if( ranges.empty() || ranges.back().depth != depth )
946 range.
depth = aDepth;
948 range.start = pool.
Sizes();
949 range.bitmapStart =
static_cast<uint32_t
>( pool.
bitmapQuads.size() );
988 const bool fresh = !ranges.empty() && ranges.back().start == pool.
Sizes()
989 && ranges.back().bitmapStart == pool.
bitmapQuads.size();
992 ranges.back().difference =
true;
1008 if( !ranges.empty() && ranges.back().difference )
1020 if( !ranges.empty() )
1021 ranges.back().hasNegatives =
true;
1058 if( aSetting && !ranges.empty() )
1059 ranges.back().hasNegatives =
true;
1105 if( !it->unbounded && !it->highlighted )
1111 if( !it->unbounded && it->highlighted )
1133 const double majorWidth = 2.0 * minorWidth;
1137 auto nextStep = [&]()
1153 const double left = ( std::floor( view.
GetLeft() / cell ) - 1.0 ) * cell;
1154 const double top = ( std::floor( view.
GetTop() / cell ) - 1.0 ) * cell;
1155 const double right = ( std::ceil( view.
GetRight() / cell ) + 1.0 ) * cell;
1156 const double bottom = ( std::ceil( view.
GetBottom() / cell ) + 1.0 ) * cell;
1159 auto dotAt = [&](
const VECTOR2D& aPos,
bool aMajorX,
bool aMajorY )
1164 const VECTOR2D half( ( aMajorX ? majorWidth : minorWidth ) / 2.0, ( aMajorY ? majorWidth : minorWidth ) / 2.0 );
1168 auto crossAt = [&](
const VECTOR2D& aPos,
bool aMajor,
double aArmAngle )
1173 const double width = aMajor ? majorWidth : minorWidth;
1174 const VECTOR2D arm1( std::cos( aArmAngle ) * 2.0 * width, std::sin( aArmAngle ) * 2.0 * width );
1178 DrawLine( aPos - arm1, aPos + arm1 );
1179 DrawLine( aPos - arm2, aPos + arm2 );
1194 const double rMax = aSrc.
extent.
x;
1195 const double phiMax = aSrc.
extent.
y;
1196 const double dr = lattice.
pitch.
x;
1197 const double dPhi = lattice.
pitch.
y;
1203 for(
double r = dr; r <= rMax + 1e-6; r += dr, ++rIdx )
1211 for(
double phi = 0; phi <= phiMax + 1e-6; phi += dPhi, ++pIdx )
1221 for(
double r = 0; r <= rMax + 1e-6; r += dr, ++rIdx )
1225 for(
double phi = 0; phi <= phiMax + 1e-6; phi += dPhi, ++pIdx )
1227 const VECTOR2D pos( r * std::cos( phi ), r * std::sin( phi ) );
1232 crossAt( pos, lattice.
IsMajor( rIdx ) && lattice.
IsMajor( pIdx ), phi );
1239 const double dx = lattice.
pitch.
x;
1240 const double dy = lattice.
pitch.
y;
1244 const double yMin = std::max( reach.
GetTop(), -aSrc.
extent.
y );
1247 const int ixMin =
static_cast<int>( std::ceil( xMin / dx ) );
1248 const int ixMax =
static_cast<int>( std::floor( xMax / dx ) );
1249 const int iyMin =
static_cast<int>( std::ceil( yMin / dy ) );
1250 const int iyMax =
static_cast<int>( std::floor( yMax / dy ) );
1254 for(
int ix = ixMin; ix <= ixMax; ++ix )
1260 for(
int iy = iyMin; iy <= iyMax; ++iy )
1268 for(
int ix = ixMin; ix <= ixMax; ++ix )
1270 for(
int iy = iyMin; iy <= iyMax; ++iy )
1316 if(
static_cast<float>( aStartPoint.
x ) ==
static_cast<float>( aEndPoint.
x )
1317 &&
static_cast<float>( aStartPoint.
y ) ==
static_cast<float>( aEndPoint.
y ) )
1324 const double halfWidth = aWidth / 2.0;
1326 const double angle = std::atan2(
delta.y,
delta.x );
1337 double aWidth,
const COLOR4D& aColor )
1344 double aCornerRadius,
float aShapeType,
double aRotation,
1347 addPadInstance( aCenter, aHalfWidth, aHalfHeight, aCornerRadius, aShapeType, aRotation,
1354 for(
size_t i = 1; i < aPointList.size(); ++i )
1356 DrawSegment( aPointList[i - 1], aPointList[i], aWidth );
1376 double aWidth,
const COLOR4D& aColor )
1383 double length =
delta.EuclideanNorm();
1384 double halfWidth = ( aWidth *
scale ) / 2.0;
1385 double halfLength = length / 2.0;
1386 double rotation = std::atan2(
delta.y,
delta.x );
1399 inst.
SetPosition(
static_cast<float>( midpoint.
x ),
static_cast<float>( midpoint.
y ) );
1400 inst.
SetRotation(
static_cast<float>( rotation ) );
1401 inst.
SetParam( 0,
static_cast<float>( halfWidth ) );
1402 inst.
SetParam( 1,
static_cast<float>( halfLength ) );
1461 double startAngle = aStartAngle.
AsRadians();
1462 double endAngle = startAngle + aAngle.
AsRadians();
1465 const double sweep = endAngle - startAngle;
1467 const int segCount = std::max( 1,
static_cast<int>( std::ceil( sweep /
calcAngleStep( aRadius ) ) ) );
1469 std::vector<VECTOR2D> sectorPts;
1470 sectorPts.reserve(
static_cast<size_t>( segCount ) + 2 );
1471 sectorPts.push_back( aCenterPoint );
1473 for(
int ii = 0; ii <= segCount; ++ii )
1475 const double a = startAngle + sweep * ii / segCount;
1476 sectorPts.emplace_back( aCenterPoint.
x + std::cos( a ) * aRadius,
1477 aCenterPoint.
y + std::sin( a ) * aRadius );
1494 double aWidth,
double )
1506 double startAngle = aStartAngle.
AsRadians();
1507 double endAngle = startAngle + aAngle.
AsRadians();
1510 const double halfWidth = aWidth / 2.0;
1511 const double sweep = endAngle - startAngle;
1512 const VECTOR2D startPoint( aCenterPoint.
x + std::cos( startAngle ) * aRadius,
1513 aCenterPoint.
y + std::sin( startAngle ) * aRadius );
1514 const VECTOR2D endPoint( aCenterPoint.
x + std::cos( endAngle ) * aRadius,
1515 aCenterPoint.
y + std::sin( endAngle ) * aRadius );
1519 if( aRadius > halfWidth )
1535 double aSweepAngle,
double aWidth,
const COLOR4D& aColor )
1543 inst.
SetParam( 1,
static_cast<float>( aWidth *
scale / 2.0 ) );
1545 inst.
SetParam( 3,
static_cast<float>( aSweepAngle ) );
1574 if( aMajorRadius <= 0 || aMinorRadius <= 0 )
1586 if( aMajorRadius <= 0 || aMinorRadius <= 0 )
1590 aRotation, aStartAngle, aEndAngle ) );
1604 if( aEllipse.
IsArc() )
1632 double hw =
std::abs( aEndPoint.
x - aStartPoint.
x ) / 2.0;
1633 double hh =
std::abs( aEndPoint.
y - aStartPoint.
y ) / 2.0;
1635 ( aStartPoint.
y + aEndPoint.
y ) / 2.0 );
1659 if( aPointList.size() < 2 )
1708 for(
int h = 0; h < aPolySet.
HoleCount( j ); ++h )
1730 double aFilterValue )
1732 std::vector<VECTOR2D> controlPts = { aStartPoint, aControlPointA, aControlPointB, aEndPoint };
1735 std::vector<VECTOR2D> output;
1736 converter.
GetPoly( output, aFilterValue );
1738 if( output.size() < 2 )
1741 for(
size_t i = 1; i < output.size(); ++i )
1743 DrawLine( output[i - 1], output[i] );
1757 float alpha =
static_cast<float>( std::clamp( alphaBlend, 0.0, 1.0 ) );
1761 if(
image->GetWidth() <= 0 ||
image->GetHeight() <= 0 || sizePixels.
x <= 0 || sizePixels.
y <= 0 )
1766 std::array<uint64_t, 2> bitmapContentHash{};
1772 texture = cacheIt->second.texture;
1773 bitmapContentHash = cacheIt->second.contentHash;
1781 if( !fitted.IsOk() )
1785 texDesc.
width =
static_cast<uint32_t
>( fitted.GetWidth() );
1786 texDesc.
height =
static_cast<uint32_t
>( fitted.GetHeight() );
1795 std::vector<uint8_t> rgba =
ImageToRgba( fitted );
1798 contentHash.
add(
static_cast<int32_t
>( texDesc.
width ) );
1799 contentHash.
add(
static_cast<int32_t
>( texDesc.
height ) );
1800 hashBytes( contentHash, rgba.data(), rgba.size() );
1801 bitmapContentHash =
hashDigest( contentHash );
1803 m_deviceProxy.UploadTexture( texture, rgba.data(), rgba.size() );
1807 entry.
bytes = rgba.size();
1815 double w =
static_cast<double>( sizePixels.
x ) *
scale;
1816 double h =
static_cast<double>( sizePixels.
y ) *
scale;
1818 float hw =
static_cast<float>( w / 2.0 );
1819 float hh =
static_cast<float>( h / 2.0 );
1821 float texStartX = aBitmap.
IsMirroredX() ? 1.0f : 0.0f;
1822 float texEndX = aBitmap.
IsMirroredX() ? 0.0f : 1.0f;
1823 float texStartY = aBitmap.
IsMirroredY() ? 1.0f : 0.0f;
1824 float texEndY = aBitmap.
IsMirroredY() ? 0.0f : 1.0f;
1836 for(
auto& corner : corners )
1837 corner =
xform( corner );
1844 const double du = tu - 0.5;
1845 const double dv = tv - 0.5;
1847 v.
SetPosition(
static_cast<float>( pos.x ),
static_cast<float>( pos.y ) );
1848 v.
SetUV(
static_cast<float>( 0.5 + du * texCos - dv * texSin ),
1849 static_cast<float>( 0.5 + du * texSin + dv * texCos ) );
1850 v.
SetColor( 255, 255, 255, alphaU8 );
1859 setVert( quad.
vertices[0], corners[0], texStartX, texStartY );
1860 setVert( quad.
vertices[1], corners[1], texEndX, texStartY );
1861 setVert( quad.
vertices[2], corners[2], texEndX, texEndY );
1862 setVert( quad.
vertices[3], corners[0], texStartX, texStartY );
1863 setVert( quad.
vertices[4], corners[2], texEndX, texEndY );
1864 setVert( quad.
vertices[5], corners[3], texStartX, texEndY );
1909 for(
const auto& points : aPointLists )
1919uint32_t tableGlyphCount()
1926std::shared_ptr<const RHI_GLYPH_ATLAS_DATA> buildGlyphAtlas()
1928 static const std::shared_ptr<const RHI_GLYPH_ATLAS_DATA> built = []()
1932 auto atlas = std::make_shared<RHI_GLYPH_ATLAS_DATA>();
1933 atlas->width = font_image.
width;
1934 atlas->height = font_image.
height;
1935 atlas->rgba =
RgbToRgba( font_image.
pixels,
nullptr,
size_t( atlas->width ) * atlas->height );
1939 const FONT_GLYPH_TYPE* first = LookupGlyph(
'!' );
1941 for( uint32_t ii = 0; ii < tableGlyphCount() && first; ++ii )
1943 const GLYPH_BOX box = ComputeGlyphBox( first[ii] );
1945 atlas->table[ii * 4 + 0] = box.atlasX / atlas->width;
1946 atlas->table[ii * 4 + 1] = box.atlasY / atlas->height;
1947 atlas->table[ii * 4 + 2] = box.w / atlas->width;
1948 atlas->table[ii * 4 + 3] = box.h / atlas->height;
1969 || aText.Contains( wxT(
"_{" ) ) || aText.Contains( wxT(
"~{" ) ) || aText.Contains( wxT(
"\n" ) ) )
1977 std::tie( textSize, commonOffset ) = ComputeBitmapTextSize(
text );
1979 if( textSize.
y <= 0.0 )
1985 const FONT_GLYPH_TYPE* first = LookupGlyph(
'!' );
1988 const FONT_GLYPH_TYPE*
const limit = first + tableGlyphCount();
1991 const double angle = aAngle.
AsRadians();
1996 double cursorX = 0.0;
1997 double cursorY = -commonOffset;
2014 const double cosA = std::cos( angle );
2015 const double sinA = std::sin( angle );
2017 std::vector<RHI_INSTANCE> glyphs;
2018 glyphs.reserve(
size_t( aText.length() ) );
2024 cursorX += SpaceAdvance();
2028 const FONT_GLYPH_TYPE* glyph = LookupGlyph( *chIt );
2031 glyph = LookupGlyph(
'?' );
2036 if( glyph < first || glyph >= limit )
2039 const GLYPH_BOX box = ComputeGlyphBox( *glyph );
2040 const double width = box.w;
2041 const double height = box.h;
2042 const double centerX = cursorX + box.x + width / 2.0;
2043 const double centerY = cursorY + box.y + height / 2.0;
2047 VECTOR2D turned( local.
x * cosA + local.
y * sinA, -local.
x * sinA + local.
y * cosA );
2052 inst.
SetRotation(
static_cast<float>( xfAngle - angle ) );
2053 inst.
SetParam( 0,
static_cast<float>(
scale * width / 2.0 * xfScale ) );
2054 inst.
SetParam( 1,
static_cast<float>(
scale * height / 2.0 * xfScale ) );
2055 inst.
SetParam( 2,
static_cast<float>( glyph - first ) );
2070 glyphs.push_back( inst );
2071 cursorX += glyph->advance;
2077 tracks.insert( tracks.end(), glyphs.begin(), glyphs.end() );
2108 outlineGlyph.Triangulate(
2118 double aCornerRadius,
float aShapeType,
double aRotation,
2127 inst.
SetParam( 0,
static_cast<float>( aHalfWidth *
scale ) );
2128 inst.
SetParam( 1,
static_cast<float>( aHalfHeight *
scale ) );
2129 inst.
SetParam( 2,
static_cast<float>( aCornerRadius *
scale ) );
2173 for(
int i = 0; i < static_cast<int>( triPoly->GetTriangleCount() ); ++i )
2176 triPoly->GetTriangle( i, a, b, c );
2200 for(
const VECTOR2D& corner : { aA, aB, aC } )
2204 vertices.push_back( aFill );
2205 vertices.back().SetPosition(
static_cast<float>( placed.
x ),
static_cast<float>( placed.
y ) );
2277 auto mix = [&](
const void* aData,
size_t aSize )
2282 auto mixVector = [&](
const auto& aVector )
2284 const uint64_t count = aVector.size();
2285 mix( &count,
sizeof( count ) );
2286 mix( aVector.data(), aVector.size() *
sizeof( aVector[0] ) );
2289 for(
const std::vector<RHI_INSTANCE>& instances : aGroup.
instances )
2290 mixVector( instances );
2297 const uint64_t quadCount = aGroup.
bitmapQuads.size();
2298 mix( &quadCount,
sizeof( quadCount ) );
2313 auto it =
m_groups.find( aGroupNumber );
2320 if( !
group.contentFingerprintValid )
2323 group.contentFingerprintValid =
true;
2326 return group.contentFingerprint;
2332 auto it =
m_groups.find( aGroupNumber );
2336 wxLogTrace(
traceGalGroups, wxS(
"DrawGroup(%d) NOT FOUND (total groups=%zu)" ),
2353 slot.
start = before;
2356 slot.
count[shape] =
static_cast<uint32_t
>(
group.instances[shape].size() );
2367 auto rebase = [shift]( uint16_t& aDepth )
2369 aDepth = glm::packHalf1x16( glm::unpackHalf1x16( aDepth ) + shift );
2374 std::vector<RHI_INSTANCE>& instances = pool.
instances[shape];
2376 instances.insert( instances.end(),
group.instances[shape].begin(),
group.instances[shape].end() );
2378 if( !
overlay && shift == 0.0f )
2381 for(
size_t ii = before[shape]; ii < instances.size(); ++ii )
2387 rebase( instances[ii].depth );
2392 group.polygonVertices.end() );
2400 if( !
group.bitmapQuads.empty() )
2409 for(
const auto& bq :
group.bitmapQuads )
2415 copy.ownsResources =
false;
2453template <
typename ARENA>
2457 static constexpr size_t MAX_SPANS = 8;
2459 if( aCount == 0 || aArena.uploadAll )
2462 for(
auto& span : aArena.dirty )
2465 if( aStart >= span.begin && aStart <= span.end )
2467 span.end = std::max( span.end, aStart + aCount );
2472 if( aArena.dirty.size() >= MAX_SPANS )
2474 for(
size_t ii = 1; ii < aArena.dirty.size(); ++ii )
2475 aArena.dirty[0].add( aArena.dirty[ii].begin, aArena.dirty[ii].end - aArena.dirty[ii].begin );
2477 aArena.dirty.resize( 1 );
2480 aArena.dirty.emplace_back();
2481 aArena.dirty.back().add( aStart, aCount );
2485template <
typename T>
2492 auto it = aArena.
freeSlots.find( aCount );
2494 if( it != aArena.
freeSlots.end() && !it->second.empty() )
2496 start = it->second.back();
2497 it->second.pop_back();
2498 aArena.
dead -= aCount;
2502 start =
static_cast<uint32_t
>( aArena.
elements.size() );
2503 aArena.
elements.resize( start + aCount );
2511template <
typename T>
2518 if(
static_cast<size_t>( aStart ) + aCount == aArena.
elements.size() )
2526 aArena.
dead += aCount;
2527 aArena.
freeSlots[aCount].push_back( aStart );
2531template <
typename T>
2534 std::vector<GAL_GROUP*> owners;
2535 owners.reserve( aLayer.
residents.size() );
2541 if(
group.slotCount[aArenaId] > 0 )
2542 owners.push_back( &
group );
2546 std::sort( owners.begin(), owners.end(),
2549 return aLhs->slotStart[aArenaId] < aRhs->slotStart[aArenaId];
2552 std::vector<T> packed;
2553 packed.reserve( aArena.
elements.size() - aArena.
dead );
2557 auto first = aArena.
elements.begin() +
group->slotStart[aArenaId];
2559 group->slotStart[aArenaId] =
static_cast<uint32_t
>( packed.size() );
2560 packed.insert( packed.end(), first, first +
group->slotCount[aArenaId] );
2565 aArena.
dirty.clear();
2574 auto count = [&](
const std::vector<RHI_INSTANCE>& aInstances )
2583 for(
const std::vector<RHI_INSTANCE>& instances : aGroup.
instances )
2598 const std::vector<RHI_INSTANCE>& instances = aGroup.
instances[shape];
2599 const auto negatives = std::ranges::count_if( instances,
2606 aCounts[
arenaOf( shape,
false )] =
static_cast<uint32_t
>( instances.size() - negatives );
2607 aCounts[
arenaOf( shape,
true )] =
static_cast<uint32_t
>( negatives );
2617 const bool opaque = aLayer.
bakedAlpha >= 0 && composited;
2624 const int normalArena =
arenaOf( shape,
false );
2625 const int negativeArena =
arenaOf( shape,
true );
2629 uint32_t negative = aGroup.
slotStart[negativeArena];
2716 for(
auto it = first; it != last; ++it )
2718 if( it->second == aGroupId )
2731 const int last = layer.
residents.back();
2764 bool candidateCounted =
false;
2766 auto countCandidate = [&]()
2768 if( candidateCounted )
2773 candidateCounted =
true;
2776 auto candidateStart = [&](
int aArena )
2778 const uint32_t count = candidateCounts[aArena];
2789 auto it = arena.
freeSlots.find( count );
2790 return it != arena.
freeSlots.end() && !it->second.empty()
2792 :
static_cast<uint32_t
>( arena.
elements.size() );
2797 for(
auto it = first; it != last; ++it )
2799 const int peerId = it->second;
2801 if( peerId == aGroupId )
2823 if( candidateCounts[arena] == 0 || peer.
slotCount[arena] == 0 )
2826 if( ( candidateStart( arena ) < peer.
slotStart[arena] ) != ( aGroup.
order < peer.
order ) )
2852 auto reset = [](
auto& aArena )
2854 aArena.elements.clear();
2855 aArena.freeSlots.clear();
2856 aArena.dirty.clear();
2858 aArena.uploadAll =
true;
2866 reset( layer.polygons );
2868 layer.residents.clear();
2869 layer.bitmapResidents.clear();
2870 layer.retainedPrefixIndex.reset();
2871 std::fill( std::begin( layer.alphaCount ), std::end( layer.alphaCount ), 0 );
2872 layer.bakedAlpha = -1;
2873 layer.alphaStale =
false;
2874 layer.translucent =
false;
2876 layer.runsStale =
false;
2877 layer.knockoutGroups = 0;
2881 group.resident =
false;
2892 const float depth =
static_cast<float>( aOrder );
2907 if( aVisible && !layer.
visible )
2921 layer.
depth = depth;
2942 dim.
toward[0] =
static_cast<float>( aToward.
r );
2943 dim.
toward[1] =
static_cast<float>( aToward.
g );
2944 dim.
toward[2] =
static_cast<float>( aToward.
b );
2945 dim.
keep =
static_cast<float>( std::max( aKeep, 0.0 ) );
2955 if( layer.
dim == dim )
2983 [
this](
int aLhs,
int aRhs )
2985 return m_sceneLayers.at( aLhs ).depth > m_sceneLayers.at( aRhs ).depth;
3034 auto first =
m_lodGroups.lower_bound( std::min( previous, aScale ) );
3035 auto last =
m_lodGroups.lower_bound( std::max( previous, aScale ) );
3036 std::vector<int> crossed;
3038 for(
auto entry = first; entry != last; ++entry )
3039 crossed.push_back( entry->second );
3041 std::sort( crossed.begin(), crossed.end(), [&](
int a,
int b )
3043 const GAL_GROUP& lhs = m_groups.at( a );
3044 const GAL_GROUP& rhs = m_groups.at( b );
3046 if( lhs.lodScale != rhs.lodScale )
3047 return lhs.lodScale < rhs.lodScale;
3049 if( lhs.sceneLayer != rhs.sceneLayer )
3050 return lhs.sceneLayer < rhs.sceneLayer;
3052 return lhs.order < rhs.order;
3056 if( aScale < previous )
3057 std::reverse( crossed.begin(), crossed.end() );
3059 for(
int groupId : crossed )
3064 if( wanted ==
group.resident )
3075 if( layerIt ==
m_sceneLayers.end() || !layerIt->second.inOrder )
3109 const bool wanted = aShown && aLodScale <
m_sceneScale;
3118 if(
group.resident && ( !wanted ||
group.sceneLayer != aLayer ) )
3121 if(
group.resident && !
group.order.SamePrefix( order ) )
3127 group.sceneLayer = aLayer;
3128 group.lodScale = aLodScale;
3129 group.shown = aShown;
3130 group.order = std::move( order );
3132 trackGroupLod( aGroup,
group, aShown && aLodScale > 0.0 && aLodScale < std::numeric_limits<double>::max() );
3134 if( !wanted ||
group.resident )
3149 if( layerIt ==
m_sceneLayers.end() || !layerIt->second.inOrder )
3165template <
typename T>
3168 const size_t bytes =
static_cast<size_t>( aSpan.
end - aSpan.
begin ) *
sizeof(
T );
3178template <
typename T>
3181 const size_t count = aArena.
elements.size();
3186 aArena.
dirty.clear();
3194 const size_t wanted = std::max( count + count / 4 + 64, aArena.
capacity * 2 );
3207 aArena.
dirty.clear();
3208 aArena.
dirty.emplace_back();
3209 aArena.
dirty.back().add( 0,
static_cast<uint32_t
>( count ) );
3215 span.
end = std::min<uint32_t>( span.
end,
static_cast<uint32_t
>( count ) );
3224 aArena.
dirty.clear();
3232 auto changed = [](
const auto& aArena,
size_t aCounted )
3234 return !aArena.dirty.empty() || aArena.elements.size() != aCounted
3235 || ( aArena.uploadAll && !aArena.elements.empty() );
3247 aLayer.
cullRuns ? std::make_shared<RHI_RUN_TABLE>( *aLayer.
cullRuns ) : std::make_shared<RHI_RUN_TABLE>();
3249 auto spans = [](
const auto& aArena )
3251 std::vector<std::pair<uint32_t, uint32_t>> out;
3253 for(
const auto& span : aArena.dirty )
3254 out.emplace_back( span.begin, span.end );
3263 std::vector<RHI_RUN_BOUNDS>& runs = arena % 2 ?
table->negRuns[shape] :
table->runs[shape];
3269 return RhiInstanceRun( aFirst, aCount, shape );
3287 static constexpr uint32_t COMPACT_MIN_DEAD = 256;
3294 auto wantsCompaction = [](
const auto& aArena )
3296 return aArena.dead > COMPACT_MIN_DEAD &&
static_cast<size_t>( aArena.dead ) * 2 > aArena.elements.size();
3315 for(
int alpha = 0; alpha < 256; ++alpha )
3319 minAlpha = std::min( minAlpha, alpha );
3320 maxAlpha = std::max( maxAlpha, alpha );
3326 const int hoisted = ( maxAlpha >= 0 && minAlpha == maxAlpha && minAlpha < 255 ) ? minAlpha : -1;
3328 const bool translucent = minAlpha < 255;
3346 if( wantsCompaction( layer.
instances[arena] ) )
3353 if( wantsCompaction( layer.
polygons ) )
3374 layer.
cullRuns = std::move( runs );
3394 layer.runsStale = layer.runsStale || layer.knockoutGroups > 0;
3402 aLayer.
runs.clear();
3410 std::vector<const GAL_GROUP*> placed;
3411 placed.reserve( aLayer.
residents.size() );
3414 placed.push_back( &
m_groups.at( groupId ) );
3416 std::sort( placed.begin(), placed.end(),
3419 return aLhs->placeSeq < aRhs->placeSeq;
3424 bool ordered =
false;
3425 bool cleared =
false;
3429 for(
int shape = 0; shape <
RHI_SHAPES; ++shape )
3431 if( aNext.count[shape] != 0 && aLast.
count[shape] != 0
3432 && aLast.
start[shape] + aLast.
count[shape] != aNext.start[shape] )
3438 return aLast.
negative == aNext.negative;
3446 if( aNext.negative )
3449 ordered = ordered || cleared;
3451 cleared = cleared || aNext.negative;
3453 if( aLayer.
runs.empty() || !joins( aLayer.
runs.back(), aNext ) )
3455 aLayer.
runs.push_back( aNext );
3461 for(
int shape = 0; shape <
RHI_SHAPES; ++shape )
3463 if( last.
count[shape] == 0 )
3464 last.
start[shape] = aNext.start[shape];
3466 last.
count[shape] += aNext.count[shape];
3476 clear.negative =
true;
3495 aLayer.
runs.clear();
3501 float lowest = std::numeric_limits<float>::max();
3502 float highest = std::numeric_limits<float>::lowest();
3508 lowest = std::min( lowest, layer.depth );
3509 highest = std::max( highest, layer.depth );
3513 if( lowest > highest )
3518 const float base = lowest - 1.0f;
3519 const float span = highest - lowest + 2.0f;
3521 for(
size_t ii = aFirst; ii < aRanges.size(); ++ii )
3525 range.depthNear = std::clamp( ( range.depth - 0.5f - base ) / span, 0.0f, 1.0f );
3526 range.depthFar = std::clamp( ( range.depth + 0.5f - base ) / span, 0.0f, 1.0f );
3535 auto count = [](
const auto& aArena )
3537 return static_cast<uint32_t
>( aArena.elements.size() );
3540 const size_t firstRange = aDesc.
layerRanges.size();
3553 range.alpha = ( layer.
bakedAlpha >= 0 && composited )
3554 ?
static_cast<float>( layer.
bakedAlpha ) / 255.0f
3559 range.singleCoverage = !composited && layer.
translucent;
3560 range.depthKnockout = !composited && layer.
hasNegatives;
3561 range.dim = layer.
dim;
3564 range.runStart =
static_cast<uint32_t
>( aDesc.
polarityRuns.size() );
3565 range.runCount =
static_cast<uint32_t
>( layer.
runs.size() );
3573 range.count[shape] = count( normals );
3574 range.negCount[shape] = count( negatives );
3575 range.buffer[shape] = normals.
buffer;
3576 range.negBuffer[shape] = negatives.
buffer;
3585 range.bitmapStart =
static_cast<uint32_t
>( aDesc.
bitmapDraws.size() );
3591 if( bq.texture && bq.vertexBuffer )
3592 aDesc.
bitmapDraws.push_back( { bq.vertexBuffer, bq.texture, 6 } );
3596 range.bitmapCount =
static_cast<uint32_t
>( aDesc.
bitmapDraws.size() ) - range.bitmapStart;
3598 if( !range.HasGeometry() )
3601 for(
int shape = 0; shape <
RHI_SHAPES; ++shape )
3603 aDesc.
count[shape] += range.count[shape];
3604 aDesc.
negCount[shape] += range.negCount[shape];
3610 const size_t slices = aDesc.
layerRanges.size() - firstRange;
3621 for(
size_t ii = 0; ii < slices; ++ii )
3625 range.depthFar = 1.0f -
static_cast<float>( ii ) /
static_cast<float>( slices );
3626 range.depthNear = 1.0f -
static_cast<float>( ii + 1 ) /
static_cast<float>( slices );
3631template <
typename GROUP,
typename INSTANCE_FN,
typename VERTEX_FN>
3634 for( std::vector<RHI_INSTANCE>& instances : aGroup.instances )
3635 std::ranges::for_each( instances, aInstance );
3637 std::ranges::for_each( aGroup.polygonVertices, aVertex );
3641template <
typename INSTANCE_FN,
typename VERTEX_FN>
3655 for(
int shape = 0; shape <
RHI_SHAPES; ++shape )
3657 if(
static_cast<size_t>( slot.
start[shape] ) + slot.
count[shape] > sizes[shape] )
3667 std::for_each( first, first + slot.
count[shape], aInstance );
3673 for(
int shape = 0; shape <
RHI_SHAPES; ++shape )
3702 auto it =
m_groups.find( aGroupNumber );
3716 auto unchanged = [&](
const auto& aElements )
3718 return !aElements.empty() && aElements.front().r == cr && aElements.front().g == cg
3719 && aElements.front().b == cb && aElements.front().a == ca;
3722 if( std::ranges::any_of(
group.instances, unchanged ) || unchanged(
group.polygonVertices ) )
3739 aVertex.SetColor( cr, cg, cb,
group.negative ? 255 : ca );
3742 group.contentFingerprintValid =
false;
3744 if(
group.order.contentTie )
3756 if(
group.sceneLayer >= 0 )
3760 auto recolor = [&](
auto& aElement )
3762 aElement.SetColor( cr, cg, cb, ca );
3772 auto it =
m_groups.find( aGroupNumber );
3778 const float depth =
static_cast<float>( aDepth );
3781 auto setInstanceDepth = [depth](
RHI_INSTANCE& aInstance )
3783 aInstance.SetDepth( depth );
3786 auto setVertexDepth = [depth](
RHI_VERTEX& aVertex )
3788 aVertex.u = glm::packHalf1x16( depth );
3793 group.baseDepth = depth;
3794 group.contentFingerprintValid =
false;
3796 if(
group.order.contentTie )
3801 if(
group.sceneLayer >= 0 )
3811 auto it =
m_groups.find( aGroupNumber );
3818 if(
group.undimmed == aUndimmed )
3821 group.undimmed = aUndimmed;
3835 aVertex.v = glm::packHalf1x16( aUndimmed ? 1.0f : 0.0f );
3838 group.contentFingerprintValid =
false;
3840 if(
group.order.contentTie )
3849 auto it =
m_groups.find( aGroupNumber );
3854 if( it->second.resident )
3874 if( entry.texture == bq.
texture )
3876 entry.groupRefs += aDelta;
3886 auto cachedBytes = [&]()
3891 bytes += entry.bytes;
3906 if( it->second.groupRefs > 0 )
3916 if( lru->second.texture )
4017 aDest[0] =
static_cast<float>( aColor.
r );
4018 aDest[1] =
static_cast<float>( aColor.
g );
4019 aDest[2] =
static_cast<float>( aColor.
b );
4020 aDest[3] =
static_cast<float>( aColor.
a );
4024template <
typename QUADS>
4027 for(
const auto& bq : aQuads )
4029 if( bq.texture && bq.vertexBuffer )
4030 aDesc.
bitmapDraws.push_back( { bq.vertexBuffer, bq.texture, 6 } );
4037template <
typename POOL>
4039 std::vector<LAYER_RANGE>& aDest,
size_t aAt, uint32_t aBitmapBase )
4041 const uint32_t runBase =
static_cast<uint32_t
>( aDesc.
polarityRuns.size() );
4045 std::vector<LAYER_RANGE> ranges;
4049 range.runStart += runBase;
4050 range.buffer = aPool.buffer;
4051 range.negBuffer = aPool.buffer;
4052 range.bitmapStart += aBitmapBase;
4053 range.cullRuns = aPool.cullRuns;
4054 ranges.push_back( std::move( range ) );
4057 aDest.insert( aDest.begin() + aAt, ranges.begin(), ranges.end() );
4059 for(
int shape = 0; shape <
RHI_SHAPES; ++shape )
4061 aDesc.
count[shape] += aPool.lastCount[shape];
4062 aDesc.
negCount[shape] += aPool.lastNegCount[shape];
4069 aDesc.
buffer = aPool.buffer;
4070 aDesc.
count = aPool.lastCount;
4071 aDesc.
negCount = aPool.lastNegCount;
4124 const uint32_t bitmapBase =
static_cast<uint32_t
>( desc.
bitmapDraws.size() );
4141 return aRange.HasGeometry();
4147 if( !range.HasGeometry() )
4150 range.depthFar = 1.0f -
static_cast<float>( slice ) /
static_cast<float>( slices );
4151 range.depthNear = 1.0f -
static_cast<float>( slice + 1 ) /
static_cast<float>( slices );
4174 for(
int shape = 0; shape <
RHI_SHAPES; ++shape )
4194 float hw = w * 0.5f;
4195 float hh = h * 0.5f;
4200 float M00 =
static_cast<float>(
S.m_data[0][0] ) * hw;
4201 float M01 =
static_cast<float>(
S.m_data[0][1] ) * -hh;
4202 float M02 =
static_cast<float>(
S.m_data[0][0] * hw +
S.m_data[0][1] * hh +
S.m_data[0][2] );
4203 float M10 =
static_cast<float>(
S.m_data[1][0] ) * hw;
4204 float M11 =
static_cast<float>(
S.m_data[1][1] ) * -hh;
4205 float M12 =
static_cast<float>(
S.m_data[1][0] * hw +
S.m_data[1][1] * hh +
S.m_data[1][2] );
4206 float M20 =
static_cast<float>(
S.m_data[2][0] ) * hw;
4207 float M21 =
static_cast<float>(
S.m_data[2][1] ) * -hh;
4208 float M22 =
static_cast<float>(
S.m_data[2][0] * hw +
S.m_data[2][1] * hh +
S.m_data[2][2] );
4214 float ySign = flipY ? -1.0f : 1.0f;
4217 ip[0] = M00; ip[1] = M10; ip[2] = 0.0f; ip[3] = M20;
4218 ip[4] = M01 * ySign; ip[5] = M11 * ySign; ip[6] = 0.0f; ip[7] = M21 * ySign;
4219 ip[8] = 0.0f; ip[9] = 0.0f; ip[10] = 1.0f; ip[11] = 0.0f;
4220 ip[12] = M02; ip[13] = M12; ip[14] = 0.0f; ip[15] = M22;
4229 fp[0] =
static_cast<float>( worldToNdc.
m_data[0][0] );
4230 fp[1] =
static_cast<float>( worldToNdc.
m_data[1][0] );
4233 fp[4] =
static_cast<float>( worldToNdc.
m_data[0][1] );
4234 fp[5] =
static_cast<float>( worldToNdc.
m_data[1][1] );
4244 fp[12] =
static_cast<float>( worldToNdc.
m_data[0][2] );
4245 fp[13] =
static_cast<float>( worldToNdc.
m_data[1][2] );
4300 float w = std::fmax(
static_cast<float>(
m_screenWidth ), 1.0f );
4301 float h = std::fmax(
static_cast<float>(
m_screenHeight ), 1.0f );
4306 float ndcY =
static_cast<float>( 1.0 - cursorScreen.
y / ( h * 0.5 ) );
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Bezier curves to polygon converter.
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMaxError=10)
Convert a Bezier curve to a polygon.
This class handle bitmap images in KiCad.
const wxImage * GetOriginalImageData() const
VECTOR2I GetSizePixels() const
EDA_ANGLE Rotation() const
constexpr size_type GetWidth() const
constexpr size_type GetHeight() const
constexpr coord_type GetLeft() const
constexpr bool Contains(const Vec &aPoint) const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
virtual bool IsStroke() const
virtual bool IsOutline() const
A color representation with 4 components: red, green, blue, alpha.
COLOR4D Darkened(double aFactor) const
Return a color that is darker by a given factor, without modifying object.
GAL that turns drawing commands into instanced primitives for the RHI device.
void addCapsuleInstance(const VECTOR2D &aStart, const VECTOR2D &aEnd, double aWidth, const COLOR4D &aColor)
void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle) override
Draw an arc.
GEOMETRY_BUFFER_SET m_gridPool
The grids of the grid items, which the static target draws over the grid and under all else.
void endUpdate() override
Disable item update mode.
void Scale(const VECTOR2D &aScale) override
Scale the context.
static void countGroupArenas(const GAL_GROUP &aGroup, uint32_t *aCounts)
Fill aCounts with how many of a group's instances go in each instance arena.
void StartNegativesLayer() override
Begins rendering in a new layer that will be copied to the main layer in EndNegativesLayer().
bool keepsRelativeDepth(const GEOMETRY_BUFFER_SET &aPool) const
The pool is a kept target whose ranges are drawn in depth slices, see Flush()
void SetTarget(RENDER_TARGET aTarget) override
Set the target for rendering.
double xformAngle() const
void countGroupAlpha(const GAL_GROUP &aGroup, SCENE_LAYER &aLayer, int aDelta)
void beginUpdate() override
Enable item update mode.
void SetSceneDrawOrdered(bool aOrdered) override
Tell the retained scene whether cached groups are placed in an order that matters.
static std::array< uint64_t, 2 > computeGroupFingerprint(const GAL_GROUP &aGroup)
double m_bitmapTextHeight
glyph height while bitmap text is stroked, else 0
RHI_INSTANCE & addArcInstance(const VECTOR2D &aCenter, double aRadius, double aStartAngle, double aSweepAngle, double aWidth, const COLOR4D &aColor)
void notePolarity(bool aNegative)
Note the polarity of what is about to be drawn, so that a pool remembers where it changed.
std::vector< std::pair< uint64_t, RHI_TextureHandle > > m_retiredTextures
void writeGroupToScene(const GAL_GROUP &aGroup, SCENE_LAYER &aLayer)
Copy a resident group's elements into its slots, applying the layer's hoisted alpha.
void ClearCache() override
Delete all data created during caching of graphic items.
std::multimap< double, int > m_lodGroups
groups with a scale threshold, by it
float m_strokeLengthPad
see SetStrokeLengthPad(), 0 when off
void ClearTarget(RENDER_TARGET aTarget) override
Clear the target for rendering.
void emitInstance(RHI_SHAPE aShape, const RHI_INSTANCE &aInstance)
Append to the current target's pool.
void SetSceneScale(double aScale) override
Set the view scale that group placements are tested against.
void DrawPolylines(const std::vector< std::vector< VECTOR2D > > &aPointLists) override
Draw multiple polylines.
void refillDynamicTarget(RENDER_TARGET aTarget)
Rotate a dynamic target's ring, empty the new slot and open a range at the current depth.
void countBitmapRefs(const GAL_GROUP &aGroup, int aDelta)
Count a group's quads against the cached textures they draw, so a texture a cached group still shows ...
void SetLayerDepth(double aLayerDepth) override
Set the depth of the layer (position on the z-axis)
bool m_nonCachedRefilled
non-cached pool was emptied for the frame being drawn
void evictBitmapCacheEntries()
Evict least recently used entries down to the entry and byte caps, sparing those used this frame sinc...
uint64_t m_bufferGeneration
Bumped whenever a resource is retired.
void PopulateCameraUBOs(KIGFX::FRAME_DRAW_DESC &aDesc) const
Update the camera-dependent UBOs of an existing descriptor.
void ClearScreen() override
Clear the screen.
void EndDiffLayer() override
Ends rendering of a differential layer.
void Rotate(double aAngle) override
Rotate the context.
void Restore() override
Restore the context.
std::array< PATCH_SPAN, RHI_SHAPES > m_staticPatches
KIGFX::FRAME_DRAW_DESC GetStaticDrawDesc() const
Draw descriptor of the static pool.
static bool sceneLayerComposited(const SCENE_LAYER &aLayer)
Whether a scene layer goes through the temp target and is composited with its alpha.
GEOMETRY_BUFFER_SET m_overlaySets[BUFFER_RING_SIZE]
void ResizeScreen(int aWidth, int aHeight) override
Resize the canvas.
bool retainedTieOrderChanged(int aGroupId, GAL_GROUP &aGroup, SCENE_LAYER &aLayer)
void DrawGrid() override
Draw the grid.
void retireBuffer(RHI_BufferHandle aBuffer)
void retireTexture(RHI_TextureHandle aTexture)
static constexpr int BUFFER_RING_SIZE
bool assignSlicesByOrder(std::vector< LAYER_RANGE > &aRanges, size_t aFirst) const
Give ranges their slices of the depth range from one mapping of layer order, the same for every targe...
bool patchStaticGroup(int aGroup, INSTANCE_FN aInstance, VERTEX_FN aVertex)
Patch a cached group in place in the static pool, applying aInstance to each instance and aVertex to ...
bool uploadSceneArena(SCENE_ARENA< T > &aArena)
Upload the arena's pending spans, growing its buffer first.
uint64_t m_bitmapFrameStartSeq
use counter at frame start, entries used since are pinned
MATRIX3x3D m_currentTransform
void Flush() override
Force all remaining objects to be drawn.
GAL_MODERN(GAL_DISPLAY_OPTIONS &aOptions, RHI_DEVICE_PROXY &aDeviceProxy)
std::vector< LAYER_RANGE > m_gridLayerRanges
bool m_transformIsIdentity
The GPU applies world to screen, so most geometry skips the matrix math on the hot path.
GEOMETRY_BUFFER_SET m_bufferSets[BUFFER_RING_SIZE]
The non-cached pool.
uint64_t m_bitmapUseCounter
bumped on every cache touch
SCENE_LAYER * m_openSceneLayer
std::vector< BITMAP_QUAD > m_groupScratchBitmapQuads
void EndDrawing() override
End the drawing, needs to be called for every new frame.
bool SyncScene()
Upload scene changes made outside a drawing context, such as groups crossing their level of detail on...
void sortSceneOrder()
Put the declared layers back in decreasing depth order after one was added or moved.
std::unordered_map< int, std::vector< STATIC_GROUP_SLOT > > m_staticGroupSlots
A group may be drawn into the static pool more than once per build, so a patch touches every slot.
RENDER_TARGET GetTarget() const override
Get the currently used target for rendering.
std::array< uint64_t, 2 > GroupContentFingerprint(int aGroupNumber) const override
KIGFX::FRAME_DRAW_DESC GetDrawDesc() const
Snapshot buffer handles, draw counts and grid and cursor uniforms after EndDrawing()
void ChangeGroupDepth(int aGroupNumber, int aDepth) override
Change the depth (Z-axis position) of the group.
static constexpr int ARENA_INSTANCE_COUNT
Arenas of one retained scene layer.
void DrawCurve(const VECTOR2D &aStartPoint, const VECTOR2D &aControlPointA, const VECTOR2D &aControlPointB, const VECTOR2D &aEndPoint, double aFilterValue=0.0) override
Draw a cubic bezier spline.
bool ensureBuffer(RHI_BufferHandle &aBuffer, size_t &aCapacity, size_t aNeeded, size_t aStride)
Grow aBuffer to hold aNeeded elements.
RENDER_THREAD * m_renderThread
int GetSwapInterval() const override
Return the swap interval. -1 for adaptive, 0 for disabled/unknown.
void SetSceneLayerOverlayAlpha(int aLayer) override
Blend a cached layer the way the other canvases blend the overlay they draw it in.
static constexpr int arenaOf(int aShape, bool aNegative)
std::vector< std::pair< uint64_t, RHI_BufferHandle > > m_retiredBuffers
RHI_VERTEX fillVertex(const COLOR4D &aColor)
A vertex filled in aColor at the layer depth, for emitTriangle() to place.
int BeginGroup() override
Begin a group.
bool IsInitialized() const override
Return the initialization status for the canvas.
void appendSceneRanges(FRAME_DRAW_DESC &aDesc) const
void SetNegativeDrawMode(bool aSetting) override
Set negative draw mode in the renderer.
uint16_t m_strokePixelPad
see SetStrokePixelPad(), in sixteenths of a pixel
std::vector< MATRIX3x3D > m_transformStack
static constexpr int ARENA_POLYGON
RENDER_TARGET m_currentTarget
bool m_groupNegative
the group being recorded has drawn a knockout
void DrawHoleWall(const VECTOR2D &aCenterPoint, double aHoleRadius, double aWallWidth) override
Draw a hole wall ring.
bool m_bitmapGlyphs
see SetBitmapGlyphs()
static std::shared_ptr< const RHI_RUN_TABLE > updateSceneCullRuns(SCENE_LAYER &aLayer)
Bring a layer's culling bounds up to date, recounting only runs whose elements changed.
static uint32_t AllocateWindowId()
bool drawBitmapGlyphs(const wxString &aText, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle)
Emit bitmap text glyph by glyph.
void EndGroup() override
End the group.
std::unordered_map< KIID, BITMAP_CACHE_ENTRY > m_bitmapTextureCache
static std::shared_ptr< RENDER_THREAD > AcquireRenderThread(bool aEnableValidation)
Return the render thread every RHI canvas in the process shares, starting it on first use and replaci...
void compactSceneArena(SCENE_LAYER &aLayer, SCENE_ARENA< T > &aArena, int aArenaId)
float m_dpiScale
see SetDpiScale()
void DrawPad(const VECTOR2D &aCenter, double aHalfWidth, double aHalfHeight, double aCornerRadius, float aShapeType, double aRotation, const COLOR4D &aColor) override
Draw a filled pad as one primitive in aColor.
RHI_DEVICE_PROXY & m_deviceProxy
std::vector< int > m_sceneOrder
layer ids in draw order
void emitTriangle(const VECTOR2D &aA, const VECTOR2D &aB, const VECTOR2D &aC, const RHI_VERTEX &aFill)
Append a triangle given in world coordinates under the current transform.
static constexpr int ARENA_COUNT
double m_strokeLod
see SetStrokeLevelOfDetail(), 0 when off
void freeSceneSlot(SCENE_ARENA< T > &aArena, uint32_t aStart, uint32_t aCount)
static constexpr size_t BITMAP_CACHE_MAX_ENTRIES
void ChangeGroupUndimmed(int aGroupNumber, bool aUndimmed) override
Exempt the group from its layer's dim, see SetSceneLayerDim().
std::array< uint64_t, 2 > m_gridPoolHash
hash of what the GPU buffers hold
void DrawEllipseArc(const VECTOR2D &aCenterPoint, double aMajorRadius, double aMinorRadius, const EDA_ANGLE &aRotation, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aEndAngle) override
Draw an elliptical arc in world coordinates.
void DeleteGroup(int aGroupNumber) override
Delete the group from the memory.
SHAPE_INSTANCES m_groupScratchInstances
BeginGroup() swaps these with the current pool's vectors and EndGroup() swaps them back.
void beginLayerRange(float aDepth)
void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a line.
bool currentTargetOpen() const
Whether drawing to the current target lands in a pool that this frame has emptied.
void BeginSceneLayer(int aLayer) override
Open a cached layer of the retained scene during a rebuild.
void SetSceneLayerDim(int aLayer, const COLOR4D &aToward, double aKeep) override
Fade a cached layer towards a colour in the shader, so dimming it recolours none of its groups.
void submitSpan(const std::vector< T > &aElements, RHI_BufferHandle aBuffer, const PATCH_SPAN &aSpan)
Queue an upload of a span of aElements to the same place in aBuffer.
void Translate(const VECTOR2D &aTranslation) override
Translate the context.
std::vector< LAYER_RANGE > m_staticLayerRanges
Kept per pool so static ranges survive BeginDrawing when m_staticDirty is false.
GEOMETRY_BUFFER_SET m_staticPool
Pool for TARGET_CACHED.
void DrawPolygon(const std::deque< VECTOR2D > &aPointList) override
Draw a polygon.
void PopulateCursorUBO(KIGFX::FRAME_DRAW_DESC &aDesc) const
Update only the cursor UBO fields, for overlay-only frames that reuse the scene geometry.
void rewriteResidentGroup(int aGroupNumber, GAL_GROUP &aGroup)
Write a resident group back into its scene layer after its elements changed.
void DrawTrack(const VECTOR2D &aStart, const VECTOR2D &aEnd, double aWidth, const COLOR4D &aColor) override
Draw a filled track capsule in aColor without touching the fill and stroke state.
void StartDiffLayer() override
Begins rendering of a differential layer.
GEOMETRY_BUFFER_SET & poolForCurrentTarget()
TARGET_CACHED draws to the static pool and every other target to its dynamic ring slot.
void DrawGlyph(const KIFONT::GLYPH &aGlyph, int aNth=0, int aTotal=1) override
Draw a polygon representing a font glyph.
void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth) override
Draw a rounded segment.
void resetScene()
Empty every arena and forget residency ahead of a full rebuild.
void SetGroupPlacement(int aGroup, int aLayer, double aLodScale, bool aShown, const RETAINED_GROUP_ORDER &aOrder) override
Declare where a cached group belongs in the retained scene.
void DrawSegmentChain(const std::vector< VECTOR2D > &aPointList, double aWidth) override
Draw a chain of rounded segments.
void recomputeTransformIdentity()
Exact comparison is enough since a false negative only takes the slow path.
double screenPixelSize() const
The world size of a screen pixel, which grid lines are measured in.
void DrawEllipse(const VECTOR2D &aCenterPoint, double aMajorRadius, double aMinorRadius, const EDA_ANGLE &aRotation) override
Draw a closed ellipse.
KIGFX::FRAME_DRAW_DESC GetDynamicDrawDesc() const
Draw descriptor of the current dynamic ring slot, which is rebuilt every frame.
void strokeLineChain(const SHAPE_LINE_CHAIN &aChain)
Stroke a chain as segments, adding a last-to-first segment when it is closed.
void placeGroupInScene(int aGroupId, GAL_GROUP &aGroup, SCENE_LAYER &aLayer)
void DrawCursor(const VECTOR2D &aCursorPosition) override
Draw the cursor.
VECTOR2D xform(const VECTOR2D &aPt) const
std::vector< LAYER_RANGE > m_overlayLayerRanges
uint32_t allocSceneSlot(SCENE_ARENA< T > &aArena, uint32_t aCount)
void BitmapText(const wxString &aText, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle) override
Draw a text using a bitmap font.
GEOMETRY_BUFFER_SET & obuf()
void drawGridSource(const GRID_SOURCE &aSrc)
void emitTriangulatedPolygon(const SHAPE_POLY_SET &aPolySet, const COLOR4D &aColor)
void fillOutline(SHAPE_LINE_CHAIN aOutline, const COLOR4D &aColor)
Fill an outline, closed or not, without stroking it.
std::unordered_map< int, SCENE_LAYER > m_sceneLayers
by VIEW layer id
bool flushScene()
Settle hoisted alpha, compact and upload.
std::vector< RHI_VERTEX > m_groupScratchPolygonVertices
void BeginDrawing() override
Start/end drawing functions, draw calls can be only made in between the calls to BeginDrawing()/EndDr...
void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a rectangle.
void clearStaticSlots()
Forget where groups sit in the static pool and the patches pending for it.
void trackGroupLod(int aGroupId, GAL_GROUP &aGroup, bool aTrack)
Keep m_lodGroups to the shown groups whose threshold a zoom can actually cross.
bool m_drawingGridSources
emissions go to m_gridPool
void SetSceneLayerState(int aLayer, int aOrder, bool aVisible, bool aHasNegatives) override
Describe a cached layer to the retained scene.
GEOMETRY_BUFFER_SET & buf()
void DrawArcSegment(const VECTOR2D &aCenterPoint, double aRadius, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle, double aWidth, double aMaxError) override
Draw an arc segment.
double xformScale() const
void drawEllipseShape(const SHAPE_ELLIPSE &aEllipse)
Fill and stroke an ellipse per the current settings, filling an arc as a sector.
RHI_INSTANCE & addPadInstance(const VECTOR2D &aCenter, double aHalfWidth, double aHalfHeight, double aCornerRadius, float aShapeType, double aRotation, const COLOR4D &aColor)
void DrawPolyline(const std::deque< VECTOR2D > &aPointList) override
Draw a polyline.
void Transform(const MATRIX3x3D &aTransformation) override
Transform the context.
void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius) override
Draw a circle using world coordinates.
std::vector< LAYER_RANGE > & layerRangesForCurrentTarget()
void buildSceneRuns(SCENE_LAYER &aLayer)
Work out a layer's polarity runs again after its residents changed or moved.
void drawGridSources()
Draw the grid sources into m_gridPool, each over its own area as the Cairo canvas paints them.
void releaseBitmapQuads(std::vector< BITMAP_QUAD > &aQuads, bool aOwnedOnly)
Retire the textures and vertex buffers the quads own, then empty the list.
void ReleaseRetiredBuffers(uint64_t aConsumedGeneration)
Free retired buffers and textures once the render thread has consumed a frame built after them.
void EndNegativesLayer() override
Ends rendering of a negatives layer and draws it to the main layer.
void DestroyBuffers()
Destroy every GPU resource this GAL holds and forget the handles.
void DrawGroup(int aGroupNumber) override
Draw the stored group.
void Save() override
Save the context.
void ReleaseBuffers()
Drop all GPU handles without destroying them.
std::unordered_map< int, GAL_GROUP > m_groups
void ChangeGroupColor(int aGroupNumber, const COLOR4D &aNewColor) override
Change the color used to draw the group.
std::vector< LAYER_RANGE > m_dynamicLayerRanges
void removeGroupFromScene(int aGroupId, GAL_GROUP &aGroup)
void DrawBitmap(const BITMAP_BASE &aBitmap, double alphaBlend=1.0) override
Draw a bitmap image.
bool m_staticRebuiltThisFlush
see TakeStaticChanged()
RHI_INSTANCE makeInstance(const COLOR4D &aColor)
An instance in aColor at the layer depth, with the current polarity and padding.
bool IsTextMirrored() const
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
bool IsCursorEnabled() const
Return information about cursor visibility.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
MATRIX3x3D m_worldScreenMatrix
World transformation.
VECTOR2D GetVisibleGridSize() const
Return the visible grid size in x and y directions.
double m_layerDepth
The actual layer depth.
COLOR4D gridSourceColor(const GRID_SOURCE &aSrc) const
The colour a grid source is drawn in, brightened while it is being edited.
MATRIX3x3D m_screenWorldMatrix
Screen transformation.
friend class GAL_SCOPED_ATTRS
bool m_axesEnabled
Should the axes be drawn.
float m_gridLineWidth
Line width of the grid.
GR_TEXT_H_ALIGN_T GetHorizontalJustify() const
void normalize(T &a, T &b)
Ensure that the first element is smaller than the second.
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
double m_zoomFactor
The zoom factor.
GRID_STYLE m_gridStyle
Grid display style.
COLOR4D m_axesColor
Color of the axes.
float m_lineWidth
The line width.
GRID_LATTICE gridLattice(const GRID_SOURCE &aSrc) const
Thin a grid source's pitch out until its lines are far enough apart on screen.
void drawGridCoverageShape(const GRID_SOURCE &aSrc)
Draw the area a grid source covers in its own frame with the current fill and stroke.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
COLOR4D getCursorColor() const
Get the actual cursor color to draw.
COLOR4D m_fillColor
The fill color.
double m_worldUnitLength
The unit length of the world coordinates [inch].
void SetAxesColor(const COLOR4D &aAxesColor)
Set the axes color.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
BOX2D gridScreenBBox(const GRID_SOURCE &aSrc) const
VECTOR2D m_cursorPosition
Current cursor position (world coordinates)
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
const VECTOR2I & GetGlyphSize() const
int m_gridTick
Every tick line gets the double width.
double m_worldScale
The scale factor world->screen.
VECTOR2D m_gridOrigin
The grid origin.
bool m_globalFlipY
Flag for Y axis flipping.
void SetScreenSize(const VECTOR2I &aSize)
bool m_isFillEnabled
Is filling of graphic objects enabled ?
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
float gridMinorLineWidth(double aWorldPixelSize, double aScaleFactor) const
Compute the world width of a minor grid line.
COLOR4D m_gridColor
Color of the grid.
COLOR4D m_strokeColor
The color of the outlines.
bool m_isStrokeEnabled
Are the outlines stroked ?
std::vector< GRID_SOURCE > m_gridSources
Sources overlayed on the display grid.
virtual void BitmapText(const wxString &aText, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle)
Draw a text using a bitmap font.
bool m_globalFlipX
Flag for X axis flipping.
GR_TEXT_V_ALIGN_T GetVerticalJustify() const
KIGFX::CROSS_HAIR_MODE m_crossHairMode
Crosshair drawing mode.
GAL(GAL_DISPLAY_OPTIONS &aOptions)
static const int MAX_DEPTH
static double calcAngleStep(double aRadius)
Compute the angle step when drawing arcs/circles approximated with lines.
Raised when a GPU buffer allocation is predicted to exceed the available video memory.
UI-thread access to GPU resources without touching the device, which only the render thread may mutat...
void SetIdentity()
Set the matrix to the identity matrix.
void SetRotation(T aAngle)
Set the rotation components of the matrix.
void SetScale(VECTOR2< T > aScale)
Set the scale components of the matrix.
void SetTranslation(VECTOR2< T > aTranslation)
Set the translation components of the matrix.
MATRIX3x3 Inverse() const
Determine the inverse of the matrix.
A streaming C++ equivalent for MurmurHash3_x64_128.
FORCE_INLINE void addData(const uint8_t *data, size_t length)
FORCE_INLINE void add(const std::string &input)
FORCE_INLINE HASH_128 digest()
int GetMajorRadius() const
SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError) const
Build a polyline approximation of the ellipse or arc.
const VECTOR2I & GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
void Insert(size_t aVertex, const VECTOR2I &aP)
Represent a set of closed polygons.
bool IsTriangulationUpToDate() const
virtual void CacheTriangulation(bool aSimplify=false, const TASK_SUBMITTER &aSubmitter={}, bool aBuildIndexes=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
unsigned int TriangulatedPolyCount() const
Return the number of triangulated polygons.
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
uni_iter is a non-mutating iterator that walks through unicode code points in the UTF8 encoded string...
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
A type-safe container of any type.
static constexpr EDA_ANGLE ANGLE_0
static void markSceneDirty(ARENA &aArena, uint32_t aStart, uint32_t aCount)
static uint16_t relativeDepth(uint16_t aDepth, float aBase)
static RHI_INSTANCE deadInstance()
static uint8_t packColorChannel(double aValue)
static void fillDead(RHI_INSTANCE *aFirst, uint32_t aCount)
static void hashBytes(MMH3_HASH &aHash, const void *aData, size_t aSize)
static void forEachElement(GROUP &aGroup, INSTANCE_FN aInstance, VERTEX_FN aVertex)
static void buildDescForPool(FRAME_DRAW_DESC &aDesc, const auto &aPool, const std::vector< LAYER_RANGE > &aRanges)
static size_t retainedPrefixHash(const RETAINED_GROUP_ORDER &aOrder)
static SHAPE_LINE_CHAIN roundedOutline(IT aBegin, IT aEnd)
static void drawPolylineSegments(GAL_MODERN &aGal, IT aBegin, IT aEnd)
static void appendPoolRanges(FRAME_DRAW_DESC &aDesc, const POOL &aPool, const std::vector< LAYER_RANGE > &aRanges, std::vector< LAYER_RANGE > &aDest, size_t aAt, uint32_t aBitmapBase)
static void toFloat4(float *aDest, const COLOR4D &aColor)
static RHI_VERTEX deadVertex()
static void hashPool(MMH3_HASH &aHash, const POOL &aPool, const std::vector< LAYER_RANGE > &aRanges)
static void appendBitmapDraws(FRAME_DRAW_DESC &aDesc, const QUADS &aQuads)
static std::array< uint64_t, 2 > hashDigest(MMH3_HASH &aHash)
static void updateRuns(std::vector< RHI_RUN_BOUNDS > &aRuns, const std::vector< T > &aElements, const std::vector< std::pair< uint32_t, uint32_t > > &aDirty, size_t aCounted, bool aAll, size_t aRunLength, COUNT aCount)
const wxChar *const traceGalGroups
Flag to enable debug output of GAL cached group creation and drawing.
static constexpr std::size_t hash_val(const Types &... args)
MATRIX3x3< double > MATRIX3x3D
unsigned int GlyphCount()
The number of glyphs in the font, starting at LookupGlyph( '!
The Cairo implementation of the graphics abstraction layer.
std::vector< uint8_t > ImageToRgba(const wxImage &aImage)
The pixels of aImage as tightly packed RGBA, transparent where it has alpha or a mask.
constexpr double GRID_DIM_ALPHA
Opacity of the background wash laid over a selected grid item's area, to fade the grids showing throu...
@ SMALL_CROSS
Use small cross instead of dots for the grid.
@ DOTS
Use dots for the grid.
@ LINES
Use lines for the grid.
constexpr uint32_t RHI_CULL_RUN_LENGTH
RHI_SHAPE
Shapes a frame draws, each with its own array and pipelines.
RENDER_TARGET
RENDER_TARGET: Possible rendering targets.
@ TARGET_NONCACHED
Auxiliary rendering target (noncached)
@ TARGET_CACHED
Main rendering target (cached)
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
std::array< uint32_t, RHI_SHAPES > RHI_SHAPE_COUNTS
Elements of each shape, indexed by RHI_SHAPE.
RHI_RUN_BOUNDS RhiVertexRun(const RHI_VERTEX *aVertices, size_t aCount)
constexpr int RHI_INSTANCED_SHAPES
constexpr size_t BITMAP_CACHE_MAX_BYTES
Texture memory the GPU canvases may hold for placed bitmaps before they evict the oldest.
std::vector< uint8_t > RgbToRgba(const uint8_t *aRgb, const uint8_t *aAlpha, size_t aPixelCount)
Expand packed RGB to tightly packed RGBA.
wxImage FitImageToTexture(const wxImage &aImage, int aMaxTextureSize)
Fit an image into the largest texture a GPU can hold.
constexpr uint32_t RHI_CULL_VERTEX_RUN_LENGTH
Polygon vertices per run, three per triangle.
constexpr double GRID_EDGE_DARKEN
How far the hairline round a grid's coverage sits below its own colour.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
std::shared_ptr< PNS_LOG_VIEWER_OVERLAY > overlay
constexpr uint32_t RHI_GLYPH_TABLE_SIZE
Length of the shaders' glyph table.
RHI_HANDLE< RHI_TAG_TEXTURE > RHI_TextureHandle
RHI_HANDLE< RHI_TAG_BUFFER > RHI_BufferHandle
@ RHI_INSTANCE_FADE_SMALL
text stroke that fades as its glyph height (param 2) shrinks
@ RHI_INSTANCE_BITMAP_GLYPH
a track that draws the bitmap font glyph named by param 2
@ RHI_INSTANCE_OVERLAY_ALPHA
premultiplied with alpha squared, as the OpenGL overlay leaves it
@ RHI_INSTANCE_LENGTH_PAD
a track longer at each end by param 2 pixels
@ RHI_INSTANCE_PIXEL_CIRCLE
a circle on whole pixels, as the OpenGL canvas draws it
@ RHI_INSTANCE_UNDIMMED
keeps its colour when its layer is dimmed
@ RHI_INSTANCE_GROW_OUTWARD
a PIXEL_CIRCLE stroke grows outward from its inner edge
@ RHI_INSTANCE_SCREEN_SPACE
@ RHI_INSTANCE_SCALE_LOD
a track shown only while the view scale is above param 3
@ RHI_INSTANCE_HARD_EDGE
no antialiased edge, for layers that take a pixel once
bool RhiBackendNeedsYFlip(RHI_BACKEND backend)
void RhiAdjustProjectionForBackend(float *m, RHI_BACKEND backend)
Convert a column-major OpenGL projection, with NDC Z in [-1, 1] and Y up, in place to the backend's c...
RHI_BACKEND
Identifies which graphics backend a device implements.
void RhiUploadAdoptStaging(RHI_STAGING &aUpload, std::vector< T > &&aVector)
Move the vector into the upload without a copy, for data the producer does not read after queuing.
void RhiUploadCopyStaging(RHI_STAGING &aUpload, const void *aSrc, size_t aBytes)
Copy the source into the upload, for data the producer keeps using after queuing.
double orientation
Rotation about origin, radians CCW.
VECTOR2D extent
Cartesian: (dx, dy) = size/2 from origin.
A storage class for 128-bit hash value.
unsigned char pixels[1024 *1107 *3]
float cursorPos[2]
NDC [-1, 1].
float cursorSize
small cross extent in pixels
int cursorType
0 = small cross, 1 = fullscreen, 2 = diagonal 45°
GPU geometry of one frame, built by GAL_MODERN after EndDrawing() and passed through the FRAME_MAILBO...
RHI_SHAPE_COUNTS negCount
bool gridFirst
Draw the grid before the layers instead of over them.
bool relativeDepth
Element depth is relative to its layer's slice in LAYER_RANGE::depthNear, and the projection scales d...
uint64_t bufferGeneration
Generation of the producer's buffers this descriptor was built from.
bool testAgainstStatic
Slices share the static target's layer order mapping, so this target can be depth tested against a co...
std::vector< LAYER_RANGE > layerRanges
std::vector< POLARITY_RUN > polarityRuns
static constexpr float RELATIVE_DEPTH_RANGE
Largest depth offset an element can have from its layer when relativeDepth is set.
CURSOR_UBO_DATA cursorUBO
std::vector< BITMAP_DRAW_DESC > bitmapDraws
std::array< RHI_BufferHandle, RHI_SHAPES > buffer
Each shape's buffer, normal elements before negatives.
float projection[16]
column-major for GLSL
float viewScale
the view's scale, which levels of detail are compared with
The spacing of a grid source's lattice as it is drawn at the current zoom.
bool IsMajor(int aIndex) const
VECTOR2D pitch
along x and y, or of radius and angle for a polar grid
GPU texture per bitmap, keyed on the image KIID so redrawing reuses the upload.
std::array< uint64_t, 2 > contentHash
RHI_TextureHandle texture
size_t bytes
texture memory, which can be less than the image takes
uint64_t lastUse
use counter for LRU eviction
bool ownsTexture
false when the shared cache owns the texture
std::array< uint64_t, 2 > contentHash
RHI_BufferHandle vertexBuffer
RHI_TextureHandle texture
uint32_t slotCount[ARENA_COUNT]
std::vector< RHI_VERTEX > polygonVertices
RETAINED_GROUP_ORDER order
float baseDepth
Layer depth the group was cached at.
uint64_t placeSeq
When the group was placed in the scene, which orders a layer's polarity runs.
std::vector< BITMAP_QUAD > bitmapQuads
bool undimmed
Keeps its colour when its layer is dimmed, see ChangeGroupUndimmed.
SHAPE_INSTANCES instances
uint32_t slotStart[ARENA_COUNT]
bool negative
Recorded as a knockout, so it erases instead of drawing.
bool resident
Slot held in each arena of sceneLayer while resident.
int sceneLayer
Placement in the retained scene, set by SetGroupPlacement.
std::optional< std::multimap< double, int >::iterator > lodEntry
Entry in m_lodGroups while a zoom can show or hide the group.
bool drawsNegative
polarity of the last element drawn
std::vector< POLARITY_RUN > polarityRuns
built from the marks by Flush()
std::array< size_t, RHI_SHAPES > capacity
std::shared_ptr< const RHI_RUN_TABLE > cullRuns
Bounds of the arrays above as last processed, for culling off-screen runs.
RHI_SHAPE_COUNTS Sizes() const
RHI_SHAPE_COUNTS lastCount
Elements of each shape as last processed, normal and negative.
std::vector< RHI_VERTEX > polygonVertices
std::array< RHI_BufferHandle, RHI_SHAPES > buffer
SHAPE_INSTANCES instances
std::vector< POLARITY_MARK > polarityMarks
RHI_SHAPE_COUNTS lastNegCount
std::vector< BITMAP_QUAD > bitmapQuads
Half-open index span touched by patches since the last upload, empty when end <= begin.
A point in a pool's drawing order where the polarity of what is drawn changes.
RHI_SHAPE_COUNTS at
elements of each shape drawn before it
Retained scene arena holding one slot per placed group, patched in place so changing one item uploads...
std::vector< PATCH_SPAN > dirty
spans to upload at the next Flush
std::unordered_map< uint32_t, std::vector< uint32_t > > freeSlots
Freed slot starts by slot length, reused last-in first-out so a group re-cached with the same size ge...
uint32_t dead
elements sitting in freed slots
std::vector< T > elements
CPU mirror of the GPU buffer, dead slots included.
size_t capacity
elements the GPU buffer can hold
bool translucent
some element is drawn with less than full alpha
bool visible
hidden layers keep their groups but are not uploaded
bool overlayAlpha
see SetSceneLayerOverlayAlpha
bool inOrder
declared, so it has a place in the draw order
std::vector< POLARITY_RUN > runs
The layer's content in the order and polarity it was placed in.
int bakedAlpha
hoisted alpha, or -1 when elements keep their own
uint32_t alphaCount[256]
Elements per alpha value.
std::vector< int > residents
groups holding a slot here
SCENE_ARENA< RHI_VERTEX > polygons
uint32_t knockoutGroups
residents recorded as knockouts
size_t cullCounted[ARENA_COUNT]
Elements each arena held when cullRuns was counted.
std::shared_ptr< const RHI_RUN_TABLE > cullRuns
Bounds of the arenas as last uploaded, for culling off-screen runs.
SCENE_ARENA< RHI_INSTANCE > instances[ARENA_INSTANCE_COUNT]
std::vector< int > bitmapResidents
the residents that carry bitmap quads
std::optional< std::unordered_multimap< size_t, int > > retainedPrefixIndex
Where a cached group landed in the static pool at the last full build, so a colour or depth change is...
Render-time projection of a grid: GRID_GEOMETRY (kind/origin/pitch/orientation/extent) plus rendering...
bool highlighted
Render with edit-mode emphasis (selected grid).
float gridSpacing[2]
visible spacing from GetVisibleGridSize
float minorLineWidth
pixels, at least 1 and drawn rounded to whole pixels
float majorLineWorld
world units, see GAL::gridMinorLineWidth()
float worldPixelSize
world units that majorLineWorld is divided by
int gridStyle
0 = lines, 1 = dots, 2 = small cross
int gridTick
coarse grid multiplier
One layer's instance ranges within the flat GPU buffers, normal instances before negatives.
RHI_SHAPE_COUNTS negStart
bool hasNegatives
Subtractive instances go through a temp FBO so their erasure stays within the layer.
bool singleCoverage
Draw straight into the target using the range's own depth slice, either taking each pixel once at tra...
float alpha
Compositing alpha.
RHI_SHAPE_COUNTS negCount
RENDER_TARGET target
Picks the static (cached) or dynamic scene pool for this range.
RHI_SHAPE_COUNTS start
Each shape's normal elements, then for an instanced shape its negatives.
uint32_t runStart
The range's runs in FRAME_DRAW_DESC::polarityRuns, none when its order does not matter.
A stretch of one layer range drawn in one polarity.
std::array< uint64_t, 2 > contentHash
std::array< int, 4 > bbox
bool SamePrefix(const RETAINED_GROUP_ORDER &aOther) const
Fade of a whole layer towards a colour, laid out as the push constants of layer_dim....
float keep
1 leaves the layer as it is
RHI_BufferHandle targetBuffer
Per-instance data for instanced 2D rendering, packed into 40 bytes.
void SetDepth(float aNormalized)
void SetFlag(RHI_INSTANCE_FLAG aFlag)
bool HasFlag(RHI_INSTANCE_FLAG aFlag) const
uint16_t pixelPad
extra stroke width in sixteenths of a pixel
void SetColor(uint8_t aR, uint8_t aG, uint8_t aB, uint8_t aA=255)
void SetParam(int aIndex, float aValue)
void ClearFlag(RHI_INSTANCE_FLAG aFlag)
void SetRotation(float aRadians)
void SetPosition(float aX, float aY)
RHI_TEXTURE_FORMAT format
Position is in world coordinates, color is premultiplied alpha and u, v hold half floats.
void SetPosition(float aX, float aY)
void SetColor(uint8_t aR, uint8_t aG, uint8_t aB, uint8_t aA=255)
void SetUV(float aU, float aV)
KIBIS top(path, &reporter)
wxLogTrace helper definitions.
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D