Skip to content

Commit f7e0411

Browse files
committed
Merge branch 'cad-text-rendering'
2 parents a9199c8 + d6d46c3 commit f7e0411

File tree

20 files changed

+1191
-64
lines changed

20 files changed

+1191
-64
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@
7070
[submodule "examples_tests"]
7171
path = examples_tests
7272
url = [email protected]:Devsh-Graphics-Programming/Nabla-Examples-and-Tests.git
73+
[submodule "3rdparty/msdfgen"]
74+
path = 3rdparty/msdfgen
75+
url = https://github.com/Chlumsky/msdfgen
7376
branch = master
7477
[submodule "3rdparty/dxc/dxc"]
7578
path = 3rdparty/dxc/dxc

3rdparty/CMakeLists.txt

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,25 @@ add_subdirectory(simdjson simdjson EXCLUDE_FROM_ALL)
2222
set(BUILD_SHARED_LIBS ${_OLD_BUILD_SHARED_LIBS})
2323
set(BUILD_STATIC_LIBS ${_OLD_BUILD_STATIC_LIBS})
2424
set(BUILD_TESTING ${_OLD_BUILD_TESTING})
25+
26+
# freetype2
27+
set(FT_WITH_HARFBUZZ OFF)
28+
add_subdirectory(freetype2 freetype2 EXCLUDE_FROM_ALL)
29+
add_library(Freetype::Freetype ALIAS freetype) # alias target for MSDFGEN not trying to find freetype system-wide but rather to use the logical target available in our build tree
30+
31+
# msdfgen
32+
set(MSDFGEN_CORE_ONLY OFF) # if turned on then MSDFGEN will be built without dependencies like freetype or skia
33+
set(MSDFGEN_INSTALL OFF)
34+
set(MSDFGEN_BUILD_STANDALONE OFF)
35+
set(MSDFGEN_USE_CPP11 ON)
36+
add_subdirectory(msdfgen msdfgen EXCLUDE_FROM_ALL)
37+
38+
if(MSDFGEN_CORE_ONLY)
39+
set(NBL_MSDFGEN_TARGETS msdfgen-core)
40+
else()
41+
set(NBL_MSDFGEN_TARGETS msdfgen-ext)
42+
endif()
43+
2544
set_property(TARGET simdjson PROPERTY CXX_STANDARD 17)
2645

2746
# DXC
@@ -359,6 +378,7 @@ set(NBL_3RDPARTY_TARGETS
359378
jpeg-static
360379
bzip2
361380
simdjson
381+
msdfgen-core
362382
nlohmann_json
363383
glslang
364384
OGLCompiler
@@ -373,6 +393,8 @@ set(NBL_3RDPARTY_TARGETS
373393
Iex
374394
IlmThread
375395
Imath
396+
freetype
397+
${NBL_MSDFGEN_TARGETS}
376398
blake3
377399
${NBL_BOOST_TARGETS}
378400
)
@@ -425,6 +447,13 @@ nbl_adjust_definitions()
425447
add_custom_target(3rdparty)
426448
add_dependencies(3rdparty ${NBL_3RDPARTY_TARGETS})
427449

428-
set(_NBL_3RDPARTY_TARGETS_ ${NBL_3RDPARTY_TARGETS} PARENT_SCOPE)
450+
nbl_install_dir("${CMAKE_CURRENT_SOURCE_DIR}/parallel-hashmap/parallel_hashmap")
451+
452+
# parent scope exports, must be at the end of the file
453+
set(_NBL_3RDPARTY_TARGETS_
454+
${NBL_3RDPARTY_TARGETS}
455+
PARENT_SCOPE)
429456

430-
nbl_install_dir("${CMAKE_CURRENT_SOURCE_DIR}/parallel-hashmap/parallel_hashmap")
457+
set(NBL_MSDFGEN_TARGETS
458+
${NBL_MSDFGEN_TARGETS}
459+
PARENT_SCOPE)

3rdparty/msdfgen

Submodule msdfgen added at 3300ab6

cmake/adjust/flags.cmake

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,7 @@ function(nbl_adjust_flags)
148148
set(NBL_TARGET_MSVC_DEBUG_INFORMATION_FORMAT "$<$<OR:$<STREQUAL:${MAPPED_CONFIG},DEBUG>,$<STREQUAL:${MAPPED_CONFIG},RELWITHDEBINFO>>:ProgramDatabase>")
149149
else()
150150
set(NBL_TARGET_MSVC_DEBUG_INFORMATION_FORMAT "$<$<STREQUAL:${MAPPED_CONFIG},DEBUG>:EditAndContinue>$<$<STREQUAL:${MAPPED_CONFIG},RELWITHDEBINFO>:ProgramDatabase>")
151-
endif()
152-
153-
# test
154-
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TEST/GEN/${NBL_TARGET_ITEM}/test.cmake" CONTENT "TEST\nNBL_TARGET_MSVC_DEBUG_INFORMATION_FORMAT: \"${NBL_TARGET_MSVC_DEBUG_INFORMATION_FORMAT}\"\nmapped config: \"${MAPPED_CONFIG}\"" CONDITION $<CONFIG:DEBUG>)
151+
endif()
155152
endif()
156153

157154
set_target_properties(${NBL_TARGET_ITEM} PROPERTIES

cmake/common.cmake

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,10 @@ macro(nbl_create_ext_library_project EXT_NAME LIB_HEADERS LIB_SOURCES LIB_INCLUD
314314
)
315315
endif()
316316

317-
nbl_install_file_spec(${LIB_HEADERS} "nbl/ext/${EXT_NAME}")
317+
if(LIB_HEADERS)
318+
nbl_install_file_spec(${LIB_HEADERS} "nbl/ext/${EXT_NAME}")
319+
endif()
320+
318321
nbl_install_lib_spec(${LIB_NAME} "nbl/ext/${EXT_NAME}")
319322

320323
set("NBL_EXT_${EXT_NAME}_INCLUDE_DIRS"

include/nbl/asset/filters/CSwizzleAndConvertImageFilter.h

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,23 +65,16 @@ class CSwizzleAndConvertImageFilterBase : public CSwizzleableAndDitherableFilter
6565
constexpr auto MaxPlanes = 4;
6666
const void* srcPix[MaxPlanes] = { commonExecuteData.inData+readBlockArrayOffset,nullptr,nullptr,nullptr };
6767

68-
const uint32_t inChannelCount = [&]() {
69-
if constexpr (kInFormat != EF_UNKNOWN)
70-
return asset::getFormatChannelCount<kInFormat>();
71-
else
72-
return asset::getFormatChannelCount(rInFormat);
73-
}();
74-
7568
for (auto blockY=0u; blockY<blockDims.y; blockY++)
7669
for (auto blockX=0u; blockX<blockDims.x; blockX++)
7770
{
7871
constexpr auto maxChannels = 4;
7972
decodeBufferType decodeBuffer[maxChannels] = {};
8073

8174
if constexpr (kInFormat!=EF_UNKNOWN)
82-
base_t::template onDecode<kInFormat>(state, srcPix, decodeBuffer, blockX, blockY, inChannelCount);
75+
base_t::template onDecode<kInFormat>(state, srcPix, decodeBuffer, blockX, blockY, maxChannels);
8376
else
84-
base_t::template onDecode<encodeBufferType>(rInFormat, state, srcPix, decodeBuffer, blockX, blockY, inChannelCount);
77+
base_t::template onDecode<encodeBufferType>(rInFormat, state, srcPix, decodeBuffer, blockX, blockY, maxChannels);
8578

8679
state->normalization.prepass(decodeBuffer,readBlockPos*blockDims+commonExecuteData.offsetDifferenceInTexels,blockX,blockY,4u/*TODO: figure this out*/);
8780
}
@@ -143,7 +136,6 @@ class CSwizzleAndConvertImageFilter : public CImageFilter<CSwizzleAndConvertImag
143136
base_t::template normalizationPrepass<inFormat,ExecutionPolicy,decodeBufferType,encodeBufferType>(EF_UNKNOWN,policy,state,blockDims);
144137
auto perOutputRegion = [policy,&blockDims,&state](const CMatchedSizeInOutImageFilterCommon::CommonExecuteData& commonExecuteData, CBasicImageFilterCommon::clip_region_functor_t& clip) -> bool
145138
{
146-
constexpr uint32_t inChannelsAmount = asset::getFormatChannelCount<inFormat>();
147139
constexpr uint32_t outChannelsAmount = asset::getFormatChannelCount<outFormat>();
148140

149141
auto swizzle = [&commonExecuteData,&blockDims,&state,&outChannelsAmount](uint32_t readBlockArrayOffset, core::vectorSIMDu32 readBlockPos)
@@ -160,7 +152,7 @@ class CSwizzleAndConvertImageFilter : public CImageFilter<CSwizzleAndConvertImag
160152
constexpr auto maxChannels = 4;
161153
decodeBufferType decodeBuffer[maxChannels] = {};
162154

163-
base_t::template onDecode<inFormat>(state, srcPix, decodeBuffer, blockX, blockY, inChannelsAmount);
155+
base_t::template onDecode<inFormat>(state, srcPix, decodeBuffer, blockX, blockY, maxChannels);
164156
base_t::template onEncode<outFormat>(state, dstPix, decodeBuffer, localOutPos, blockX, blockY, outChannelsAmount);
165157
}
166158
};
@@ -211,9 +203,7 @@ class CSwizzleAndConvertImageFilter<EF_UNKNOWN,EF_UNKNOWN,Swizzle,Dither,Normali
211203
base_t::template normalizationPrepass<EF_UNKNOWN,ExecutionPolicy,double,double>(inFormat,policy,state,blockDims);
212204
auto perOutputRegion = [policy,&blockDims,inFormat,outFormat,outChannelsAmount,&state](const CMatchedSizeInOutImageFilterCommon::CommonExecuteData& commonExecuteData, CBasicImageFilterCommon::clip_region_functor_t& clip) -> bool
213205
{
214-
const uint32_t inChannelsAmount = asset::getFormatChannelCount(inFormat);
215-
216-
auto swizzle = [&commonExecuteData,&blockDims,inFormat,outFormat,outChannelsAmount,&state,inChannelsAmount](uint32_t readBlockArrayOffset, core::vectorSIMDu32 readBlockPos)
206+
auto swizzle = [&commonExecuteData,&blockDims,inFormat,outFormat,outChannelsAmount,&state](uint32_t readBlockArrayOffset, core::vectorSIMDu32 readBlockPos)
217207
{
218208
constexpr auto MaxPlanes = 4;
219209
const void* srcPix[MaxPlanes] = { commonExecuteData.inData+readBlockArrayOffset,nullptr,nullptr,nullptr };
@@ -227,7 +217,7 @@ class CSwizzleAndConvertImageFilter<EF_UNKNOWN,EF_UNKNOWN,Swizzle,Dither,Normali
227217
constexpr auto maxChannels = 4;
228218
double decodeBuffer[maxChannels] = {};
229219

230-
base_t::template onDecode(inFormat, state, srcPix, decodeBuffer, blockX, blockY, inChannelsAmount);
220+
base_t::template onDecode(inFormat, state, srcPix, decodeBuffer, blockX, blockY, maxChannels);
231221
base_t::template onEncode(outFormat, state, dstPix, decodeBuffer, localOutPos, blockX, blockY, outChannelsAmount);
232222
}
233223
};
@@ -285,7 +275,6 @@ class CSwizzleAndConvertImageFilter<EF_UNKNOWN,outFormat,Swizzle,Dither,Normaliz
285275
normalizationPrepass<EF_UNKNOWN,ExecutionPolicy,double,encodeBufferType>(inFormat,policy,state,blockDims);
286276
auto perOutputRegion = [policy,&blockDims,inFormat,&state](const CMatchedSizeInOutImageFilterCommon::CommonExecuteData& commonExecuteData, CBasicImageFilterCommon::clip_region_functor_t& clip) -> bool
287277
{
288-
const uint32_t inChannelsAmount = asset::getFormatChannelCount(inFormat);
289278
constexpr uint32_t outChannelsAmount = asset::getFormatChannelCount<outFormat>();
290279

291280
auto swizzle = [&commonExecuteData,&blockDims,inFormat,&outChannelsAmount,&state](uint32_t readBlockArrayOffset, core::vectorSIMDu32 readBlockPos)
@@ -302,7 +291,7 @@ class CSwizzleAndConvertImageFilter<EF_UNKNOWN,outFormat,Swizzle,Dither,Normaliz
302291
constexpr auto maxChannels = 4;
303292
double decodeBuffer[maxChannels] = {};
304293

305-
base_t::template onDecode(inFormat, state, srcPix, decodeBuffer, blockX, blockY, inChannelsAmount);
294+
base_t::template onDecode(inFormat, state, srcPix, decodeBuffer, blockX, blockY, maxChannels);
306295
base_t::template onEncode<outFormat>(state, dstPix, decodeBuffer, localOutPos, blockX, blockY, outChannelsAmount);
307296
}
308297
};
@@ -361,7 +350,6 @@ class CSwizzleAndConvertImageFilter<inFormat,EF_UNKNOWN,Swizzle,Dither,Normaliza
361350
normalizationPrepass<inFormat,ExecutionPolicy,decodeBufferType,double>(EF_UNKNOWN,policy,state,blockDims);
362351
auto perOutputRegion = [policy,&blockDims,&outFormat,outChannelsAmount,&state](const CMatchedSizeInOutImageFilterCommon::CommonExecuteData& commonExecuteData, CBasicImageFilterCommon::clip_region_functor_t& clip) -> bool
363352
{
364-
constexpr uint32_t inChannelsAmount = asset::getFormatChannelCount<inFormat>();
365353
const uint32_t outChannelsAmount = asset::getFormatChannelCount(outFormat);
366354

367355
auto swizzle = [&commonExecuteData,&blockDims,&outFormat,&outChannelsAmount,&state](uint32_t readBlockArrayOffset, core::vectorSIMDu32 readBlockPos)
@@ -378,7 +366,7 @@ class CSwizzleAndConvertImageFilter<inFormat,EF_UNKNOWN,Swizzle,Dither,Normaliza
378366
constexpr auto maxChannels = 4;
379367
decodeBufferType decodeBuffer[maxChannels] = {};
380368

381-
base_t::template onDecode<inFormat>(state, srcPix, decodeBuffer, blockX, blockY, inChannelsAmount);
369+
base_t::template onDecode<inFormat>(state, srcPix, decodeBuffer, blockX, blockY, maxChannels);
382370
base_t::template onEncode(outFormat, state, dstPix, decodeBuffer, localOutPos, blockX, blockY, outChannelsAmount);
383371
}
384372
};

include/nbl/builtin/hlsl/cpp_compat/intrinsics.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,6 @@ inline matrix<T,M,N> transpose(const matrix<T,N,M>& m)
7474
return reinterpret_cast<matrix<T,M,N>&>(glm::transpose(reinterpret_cast<typename matrix<T,N,M>::Base const&>(m)));
7575
}
7676

77-
template<typename T>
78-
inline T bitfieldExtract( T val, uint32_t offsetBits, uint32_t numBits )
79-
{
80-
return glm::bitfieldExtract( val, int32_t( offsetBits ), int32_t( numBits ) );
81-
}
82-
8377
#undef NBL_BIT_OP_GLM_PASSTHROUGH
8478
#undef NBL_SIMPLE_GLM_PASSTHROUGH
8579

include/nbl/builtin/hlsl/glsl_compat/core.hlsl

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,22 @@ namespace hlsl
1515
namespace glsl
1616
{
1717

18-
#ifdef __HLSL_VERSION
18+
#ifndef __HLSL_VERSION
19+
20+
// GLM Aliases
21+
template<typename genIUType>
22+
genIUType bitfieldExtract(genIUType Value, int Offset, int Bits)
23+
{
24+
return glm::bitfieldExtract<genIUType>(Value, Offset, Bits);
25+
}
26+
27+
template<typename genIUType>
28+
genIUType bitfieldInsert(genIUType const& Base, genIUType const& Insert, int Offset, int Bits)
29+
{
30+
return glm::bitfieldInsert<genIUType>(Base, Insert, Offset, Bits);
31+
}
32+
33+
#else
1934
/**
2035
* Generic SPIR-V
2136
*/
@@ -189,7 +204,7 @@ struct bitfieldExtract<T, false, true>
189204
template<typename T>
190205
T bitfieldExtract( T val, uint32_t offsetBits, uint32_t numBits )
191206
{
192-
return impl::bitfieldExtract<T, is_signed<T>::value, is_integral<T>::value>::template __call(val,offsetBits,numBits);
207+
return impl::bitfieldExtract<T, is_signed<T>::value, is_integral<T>::value>::__call(val,offsetBits,numBits);
193208
}
194209

195210

@@ -199,7 +214,7 @@ namespace impl
199214
template<typename T>
200215
struct bitfieldInsert
201216
{
202-
enable_if_t<is_integral_v<T>, T> __call( T base, T insert, uint32_t offset, uint32_t count )
217+
static enable_if_t<is_integral_v<T>, T> __call( T base, T insert, uint32_t offset, uint32_t count )
203218
{
204219
return spirv::bitFieldInsert<T>( base, insert, offset, count );
205220
}
@@ -210,7 +225,7 @@ struct bitfieldInsert
210225
template<typename T>
211226
T bitfieldInsert( T base, T insert, uint32_t offset, uint32_t count )
212227
{
213-
return impl::bitfieldInsert<T>::template __call(base, insert, offset, count);
228+
return impl::bitfieldInsert<T>::__call(base, insert, offset, count);
214229
}
215230

216231
#endif
@@ -219,4 +234,4 @@ T bitfieldInsert( T base, T insert, uint32_t offset, uint32_t count )
219234
}
220235
}
221236

222-
#endif
237+
#endif
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (C) 2023 - DevSH Graphics Programming Sp. z O.O.
2+
// This file is part of the "Nabla Engine".
3+
// For conditions of distribution and use, see copyright notice in nabla.h
4+
#ifndef _NBL_BUILTIN_HLSL_TEXT_RENDERING_MSDF_INCLUDED_
5+
#define _NBL_BUILTIN_HLSL_TEXT_RENDERING_MSDF_INCLUDED_
6+
7+
namespace nbl
8+
{
9+
namespace hlsl
10+
{
11+
namespace text
12+
{
13+
14+
float median(float r, float g, float b) {
15+
return max(min(r, g), min(max(r, g), b));
16+
}
17+
18+
/*
19+
20+
Returns the distance to the shape in the given MSDF.
21+
This can then be processed using smoothstep to provide anti-alising when rendering the shape.
22+
23+
@params:
24+
- msdfSample: sampled SNORM value from the MSDF texture generated by msdfgen library.
25+
26+
- msdfPixelRange: specifies the width of the range around the shape between the minimum and maximum representable signed distance in shape units or distance field pixels, respectivelly.
27+
for example if msdfPixelRange is 4, then the range of distance values are [-2, +2], and it can be computed by snormValue * MSDFPixelRange/2.0
28+
so an snorm value of 1.0 means a distance of 2 pixels outside the shape (in msdf texture space)
29+
This value is set when rendering the MSDF with MSDFgen.
30+
31+
- screenPxRangeValue: the value used to convert the distance values in the msdf texture/atlas to distance in screen space.
32+
In other words it's DistanceInScreenSpace/DistanceInMSDFTextureSpace, the larger the glyph (or more zoomed in) the larger this value is.
33+
In 2D Text Rendering it is computed by `GlyphScreenSpaceSize/GlyphTextureSpaceSize`
34+
where GlyphTextureSpaceSize is the size of the glyph inside the msdf texture/atlas
35+
*/
36+
float msdfDistance(float3 msdfSample, float msdfPixelRange, float screenPxRangeValue) {
37+
float texelDist = median(msdfSample.r, msdfSample.g, msdfSample.b) * msdfPixelRange / 2.0f;
38+
return texelDist * screenPxRangeValue;
39+
}
40+
41+
}
42+
}
43+
}
44+
45+
#endif

include/nbl/core/containers/LRUCache.h

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ namespace impl
3232
MapEquals m_equals;
3333
const mutable Key* searchedKey;
3434

35-
LRUCacheBase() = default;
36-
3735
LRUCacheBase(const uint32_t capacity, MapHash&& _hash, MapEquals&& _equals, disposal_func_t&& df) : m_list(capacity, std::move(df)), m_hash(std::move(_hash)), m_equals(std::move(_equals)), searchedKey(nullptr)
3836
{ }
3937

@@ -56,7 +54,7 @@ namespace impl
5654
// Stores fixed size amount of elements.
5755
// When the cache is full inserting will remove the least used entry
5856
template<typename Key, typename Value, typename MapHash=std::hash<Key>, typename MapEquals=std::equal_to<Key> >
59-
class LRUCache : protected impl::LRUCacheBase<Key,Value,MapHash,MapEquals>
57+
class LRUCache : protected impl::LRUCacheBase<Key,Value,MapHash,MapEquals>, public core::Unmovable, public core::Uncopyable
6058
{
6159
// typedefs
6260
typedef impl::LRUCacheBase<Key,Value,MapHash,MapEquals> base_t;
@@ -118,21 +116,7 @@ class LRUCache : protected impl::LRUCacheBase<Key,Value,MapHash,MapEquals>
118116
assert(capacity > 1);
119117
m_shortcut_map.reserve(capacity);
120118
}
121-
122-
LRUCache() = default;
123-
124-
LRUCache& operator=(LRUCache&& other)
125-
{
126-
m_shortcut_map = std::move(other.m_shortcut_map);
127-
base_t::m_list = std::move(other.m_list);
128-
base_t::m_hash = std::move(other.m_hash);
129-
base_t::m_equals = std::move(other.m_equals);
130-
base_t::searchedKey = other.searchedKey;
131-
132-
// Nullify other
133-
other.searchedKey = nullptr;
134-
return *this;
135-
}
119+
LRUCache() = delete;
136120

137121
inline void print(core::smart_refctd_ptr<system::ILogger> logger)
138122
{
@@ -165,7 +149,7 @@ class LRUCache : protected impl::LRUCacheBase<Key,Value,MapHash,MapEquals>
165149
const bool overflow = m_shortcut_map.size()>=base_t::m_list.getCapacity();
166150
if (overflow)
167151
{
168-
// evictCallback(base_t::m_list.getBack()->data.second);
152+
evictCallback(base_t::m_list.getBack()->data.second);
169153
m_shortcut_map.erase(base_t::m_list.getLastAddress());
170154
base_t::m_list.popBack();
171155
}

0 commit comments

Comments
 (0)