Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Waveform Rendering #2635

Closed
wants to merge 92 commits into from
Closed

Conversation

crsib
Copy link
Member

@crsib crsib commented Mar 5, 2022

Resolves: #2531

The goals of this PR are to separate waveform rendering logic into a library and to provide a base for the protentional hardware accelerated approach.

Approach to data caching

Data is cached in blocks with 256 columns each. Each block is identified by a pair of (zoomLevel, firstSample). Each clip has its own set of caches.

Dividing data into blocks helps to avoid unnecessary copying of data, which is expensive on the high-resolution displays. On top of that, we can have hierarchies of caches.

  • I signed CLA
  • The title of the pull request describes an issue it addresses
  • If changes are extensive, then there is a sequence of easily reviewable commits
  • Each commit's message describes its purpose and effects
  • There are no behavior changes unnecessary for the stated purpose of the PR

Recommended:

  • Each commit compiles and runs on my machine without known undesirable changes of behavior

@@ -0,0 +1,30 @@
#[[
A library responsible for custom rendering in Audacity
]]#
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trailing # isn't needed to bracket a long comment

@@ -0,0 +1,130 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a comment convention we should do in all files?

There should be more regularity but I'm not sure what exactly it should be.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a standardized approach, so yes, I would like it see more of it!

@@ -0,0 +1,130 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/**********************************************************************
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Start with /*! so Doxygen properly sees it


FrameStatistics.h

Dmitry Vedenko
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again /*! and use @file before the file name, and add at least a @brief line about the purpose of the header.

Much more Doxygenation might be added but that much is the minimum I would like so there is some summary on pages like this one https://doxy.audacityteam.org/dir_68267d1309a1af8e8297ef4c3efbcdba.html

I'm less concerned to add @file to .cpp files, because they are not interfaces. It's generally understood that they implement whatever the companion .h file is about.

@@ -502,6 +503,7 @@ static void QuitAudacity(bool bForce)
// termination when exiting is requested
#if !defined(__WXMAC__)
LogWindow::Destroy();
FrameStatisticsDialog::Destroy();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the FrameStatisticsDialog is a per-application non-modal dialog (not per-project)?

@@ -0,0 +1,149 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/**********************************************************************
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto doxygen

std::chrono::steady_clock::time_point mLastUpdate;
};

Destroy_ptr<Dialog> sDialog;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish to deprecate Destroy_ptr in favor of: https://docs.wxwidgets.org/3.0/classwx_window_ptr_3_01_t_01_4.html

I didn't know of that when I reinvented Destroy_ptr.

explicit operator bool() const noexcept;
};
// GCC 9.3.0 fails horribly if you do not initialize variant explicitly here
std::variant<LinearMapper, CustomMapper> mMapper { LinearMapper {} };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commit that introduces this variant didn't compile for me with clang either. I fixed it for myself by initializing with one argument std::in_place_type<LinearMapper>. I expect the build fix-ups will be squashed with interactive rebasing in a future version of this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see a commit "Fixes GCC build" adding this line but followed by another that fixes Clang again.

Using in_place_type instead is enough to fix Clang in the first commit, without including SampleCount.h.

If you are curious about why the incomlete type was a problem... I looked a bit at the error-novel for clang and I think there is a metaprogram deducing the correct alternative of the variant to initialize from the constructor arguments, which leads to the expansion of a conditional noexcept specifier, and somehow the operator () of this type is used in an unevaluated context.

But use in_place_type instead and that metaprogram isn't needed to resolve the overloaded constructor.

So, avoiding one more #include inside a header is nice if you can do it, plus there is in-place construction instead of a copy of a LinearMapper. Small gains.


const auto result = numerator / denominator;

return result * denominator == numerator ? result : result + 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://en.cppreference.com/w/cpp/language/operator_arithmetic

If the denominator is zero, there is UB not an exception, so noexcept is strictly speaking correct.

If one value is negative and the other is not, what should happen? (Division must truncate toward zero in C++11 and later; so if this case matters, then it is already "rounded up" and adding 1 is wrong.)

If those cases aren't supposed to happen, add a doxygen @pre that numerator is nonnegative and denominator is positive. (Precondition means "it is the caller's responsibility to exclude those cases, not mine to handle them")

Ignoring the sign question, I would simplify:

return (numerator + denominator - 1) / denominator;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch, thank you!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your version is faster, but does not consider the possible integer overflow. I think I will just add Unsafe to the function name, though :-)

// A multiplier used to control the cache size
int32_t mCacheSizeMultiplier { 4 };

template <typename CacheElementType>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get a clang build error:

GraphicsDataCache.h:213:23: error: declaration of 'CacheElementType' shadows template parameter
   template <typename CacheElementType>

Easily fixed just by omitting the template parameter name

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build errors are fixed in later commits. Given that I have to build on 3 different systems I will postpone force pushes to the much later times

PRIVATE
lib-math-interface
lib-screen-geometry-interface
wxwidgets::base
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the later commit that adds more dependencies, I would simplify:

set( LIBRARIES
       lib-math-interface
       lib-screen-geometry-interface
PRIVATE
       wxwidgets::base
)

The transitive dependency on lib-utility-interface is now implied, so the generated graph of dependencies can have one less arc. Consistently with other libraries, only the dependency on wxBase should be private. Libraries that depend on lib-graphics could themselves simplify their CMakeLists.txt by using transitive dependency on lib-math and lib-screen-geometry.

if (section < SectionID::Count)
{
GetInstance().mSections[size_t(section)].AddEvent(duration);
GetInstance().mUpdatePublisher.Invoke(section);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does not provide noexcept guarantees

{
if (!mInitializer(key, *element))
{
DisposeElement(element);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No noexcept guarantees

@crsib crsib force-pushed the 2531_waveform_rendering branch 3 times, most recently from d2eebd6 to b9f3eab Compare April 22, 2022 16:11
@crsib crsib force-pushed the 2531_waveform_rendering branch 2 times, most recently from 1d51e77 to 1b71e23 Compare April 29, 2022 12:19
@LWinterberg
Copy link
Member

Some quick tests:

  • "Generate Silence" is really silent now:
    image
  • The scrub ruler isn't granted space and is overlaying the tracks and z-fighting it
    image
  • The entire project area is now flickering slightly on my HDR-capable/OLED monitor but not my LCD. Fwiw: This is also the case for Ableton Live, but is not the case for Audacity 3.1.3
  • The entire thing still seems to be locked to 20Hz

you probably know half of these, but I thought I'd note them down anyway :)

@crsib crsib force-pushed the 2531_waveform_rendering branch from d3fe397 to b79a6f8 Compare May 4, 2022 09:05
@crsib
Copy link
Member Author

crsib commented May 4, 2022

The entire thing still seems to be locked to 20Hz

There was an issue with how is selection handled, for example. And there is still lots of stuff to be fixed in that domain.

The entire project area is now flickering slightly

Well, that is something we will have to investigate later. Too bad I have no HDR display available

@crsib crsib closed this Jun 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Move rendering code away from WaveformView. WaveformView should only supply data to the renderer.
4 participants