From cdf0227ad46991a4e226bcdbd1d39da3057981a8 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Fri, 5 Nov 2021 20:31:24 +0100 Subject: [PATCH 01/11] Fixed a small alignment issue in the scraper GUI and removed an ugly hack. --- es-app/src/guis/GuiGameScraper.cpp | 13 ++----------- es-core/src/components/ComponentList.cpp | 18 +++++++++--------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/es-app/src/guis/GuiGameScraper.cpp b/es-app/src/guis/GuiGameScraper.cpp index bcda1e93f..4e4eebf57 100644 --- a/es-app/src/guis/GuiGameScraper.cpp +++ b/es-app/src/guis/GuiGameScraper.cpp @@ -133,9 +133,6 @@ GuiGameScraper::GuiGameScraper(Window* window, static_cast(Renderer::getScreenHeight()) * 0.04f + mButtonGrid->getSize().y + Font::get(FONT_SIZE_MEDIUM)->getHeight() * 8.0f; - // TODO: Temporary hack, see below. - height -= 7.0f * Renderer::getScreenHeightModifier(); - setSize(width, height); setPosition((Renderer::getScreenWidth() - mSize.x) / 2.0f, (Renderer::getScreenHeight() - mSize.y) / 2.0f); @@ -154,17 +151,11 @@ void GuiGameScraper::onSizeChanged() mSize.y / 2.0f); mGrid.setRowHeightPerc(2, mSystemName->getFont()->getLetterHeight() / mSize.y, false); mGrid.setRowHeightPerc(3, 0.04f, false); - mGrid.setRowHeightPerc(4, ((Font::get(FONT_SIZE_MEDIUM)->getHeight() * 8.0f)) / mSize.y, false); - - // TODO: Replace this temporary hack with a proper solution. There is some kind of rounding - // issue somewhere that causes a small alignment error. This code partly compensates for this - // at higher resolutions than 1920x1080. - if (Renderer::getScreenHeightModifier() > 1.0f) - mSize.y -= 3.0f * Renderer::getScreenHeightModifier(); + mGrid.setRowHeightPerc(4, (Font::get(FONT_SIZE_MEDIUM)->getHeight() * 8.0f) / mSize.y, false); mGrid.setColWidthPerc(1, 0.04f); - mGrid.setSize(mSize); + mGrid.setSize(glm::round(mSize)); mBox.fitTo(mSize, glm::vec3{}, glm::vec2{-32.0f, -32.0f}); // Add some extra margins to the game name. diff --git a/es-core/src/components/ComponentList.cpp b/es-core/src/components/ComponentList.cpp index c9d4d7b38..7304e6776 100644 --- a/es-core/src/components/ComponentList.cpp +++ b/es-core/src/components/ComponentList.cpp @@ -289,7 +289,7 @@ void ComponentList::render(const glm::mat4& parentTrans) dim.x = (trans[0].x * dim.x + trans[3].x) - trans[3].x; dim.y = (trans[1].y * dim.y + trans[3].y) - trans[3].y; - const int clipRectPosX{static_cast(std::round(trans[3].x))}; + const int clipRectPosX{static_cast(std::ceil(trans[3].x))}; const int clipRectPosY{static_cast(std::round(trans[3].y))}; const int clipRectSizeX{static_cast(std::round(dim.x))}; const int clipRectSizeY{static_cast(std::round(dim.y))}; @@ -383,12 +383,12 @@ void ComponentList::render(const glm::mat4& parentTrans) const float selectedRowHeight = getRowHeight(mEntries.at(mCursor).data); if (opacity == 1) { - Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x, selectedRowHeight, 0xFFFFFFFF, - 0xFFFFFFFF, false, opacity, trans, + Renderer::drawRect(0.0f, mSelectorBarOffset, std::ceil(mSize.x), selectedRowHeight, + 0xFFFFFFFF, 0xFFFFFFFF, false, opacity, trans, Renderer::Blend::ONE_MINUS_DST_COLOR, Renderer::Blend::ZERO); - Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x, selectedRowHeight, 0x777777FF, - 0x777777FF, false, opacity, trans, Renderer::Blend::ONE, + Renderer::drawRect(0.0f, mSelectorBarOffset, std::ceil(mSize.x), selectedRowHeight, + 0x777777FF, 0x777777FF, false, opacity, trans, Renderer::Blend::ONE, Renderer::Blend::ONE); } @@ -403,13 +403,13 @@ void ComponentList::render(const glm::mat4& parentTrans) // Draw separators. float y = 0; for (unsigned int i = 0; i < mEntries.size(); i++) { - Renderer::drawRect(0.0f, y, mSize.x, 1.0f * Renderer::getScreenHeightModifier(), 0xC6C7C6FF, - 0xC6C7C6FF, false, opacity, trans); + Renderer::drawRect(0.0f, y, std::ceil(mSize.x), 1.0f * Renderer::getScreenHeightModifier(), + 0xC6C7C6FF, 0xC6C7C6FF, false, opacity, trans); y += getRowHeight(mEntries.at(i).data); } - Renderer::drawRect(0.0f, y, mSize.x, 1.0f * Renderer::getScreenHeightModifier(), 0xC6C7C6FF, - 0xC6C7C6FF, false, opacity, trans); + Renderer::drawRect(0.0f, y, std::ceil(mSize.x), 1.0f * Renderer::getScreenHeightModifier(), + 0xC6C7C6FF, 0xC6C7C6FF, false, opacity, trans); Renderer::popClipRect(); } From 46228c6a9dfbd516e03fbf4cc74c1bdc7497c323 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sat, 6 Nov 2021 20:47:30 +0100 Subject: [PATCH 02/11] Fixed an issue where an invalid UIMode entry in es_settings.xml could lead to a crash. --- es-app/src/views/UIModeController.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/es-app/src/views/UIModeController.cpp b/es-app/src/views/UIModeController.cpp index 8c96bb349..f6239ecb2 100644 --- a/es-app/src/views/UIModeController.cpp +++ b/es-app/src/views/UIModeController.cpp @@ -39,6 +39,12 @@ UIModeController::UIModeController() { mPassKeySequence = Settings::getInstance()->getString("UIMode_passkey"); mCurrentUIMode = Settings::getInstance()->getString("UIMode"); + // Handle a potentially invalid entry in the configuration file. + if (mCurrentUIMode != "full" && mCurrentUIMode != "kid" && mCurrentUIMode != "kiosk") { + mCurrentUIMode = "full"; + Settings::getInstance()->setString("UIMode", mCurrentUIMode); + Settings::getInstance()->saveFile(); + } } void UIModeController::monitorUIMode() From af337124d643661c36f51ac02cc771f45492003d Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sat, 6 Nov 2021 21:12:13 +0100 Subject: [PATCH 03/11] Fixed an issue where an invalid scraper entry in es_settings.xml could lead to a crash. --- es-app/src/guis/GuiScraperMenu.cpp | 5 +++++ es-app/src/scrapers/Scraper.cpp | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/es-app/src/guis/GuiScraperMenu.cpp b/es-app/src/guis/GuiScraperMenu.cpp index 17a2526f7..45f6e1683 100644 --- a/es-app/src/guis/GuiScraperMenu.cpp +++ b/es-app/src/guis/GuiScraperMenu.cpp @@ -32,6 +32,11 @@ GuiScraperMenu::GuiScraperMenu(Window* window, std::string title) // just in case the scraper from settings has vanished. for (auto it = scrapers.cbegin(); it != scrapers.cend(); it++) mScraper->add(*it, *it, *it == Settings::getInstance()->getString("Scraper")); + // If there are no objects returned, then there must be a manually modified entry in the + // configuration file. Simply set the scraper to "screenscraper" in this case. + if (mScraper->getSelectedObjects().size() == 0) + mScraper->selectEntry(0); + mMenu.addWithLabel("SCRAPE FROM", mScraper); // Search filters, getSearches() will generate a queue of games to scrape diff --git a/es-app/src/scrapers/Scraper.cpp b/es-app/src/scrapers/Scraper.cpp index e1fbbab6e..3193e4dca 100644 --- a/es-app/src/scrapers/Scraper.cpp +++ b/es-app/src/scrapers/Scraper.cpp @@ -80,8 +80,15 @@ std::vector getScraperList() bool isValidConfiguredScraper() { - const std::string& name = Settings::getInstance()->getString("Scraper"); - return scraper_request_funcs.find(name) != scraper_request_funcs.end(); + std::string scraper = Settings::getInstance()->getString("Scraper"); + // Handle a potentially invalid entry in the configuration file. + if (scraper != "screenscraper" && scraper != "thegamesdb") { + scraper = "screenscraper"; + Settings::getInstance()->setString("Scraper", scraper); + Settings::getInstance()->saveFile(); + } + + return scraper_request_funcs.find(scraper) != scraper_request_funcs.end(); } void ScraperSearchHandle::update() From c673f06eb03348d0dfa9ee8e3b468297749c0df6 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sat, 6 Nov 2021 21:21:41 +0100 Subject: [PATCH 04/11] Improved the handling of invalid scraper configuration file entries. --- es-app/src/scrapers/Scraper.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/es-app/src/scrapers/Scraper.cpp b/es-app/src/scrapers/Scraper.cpp index 3193e4dca..fdb53a8f7 100644 --- a/es-app/src/scrapers/Scraper.cpp +++ b/es-app/src/scrapers/Scraper.cpp @@ -32,7 +32,14 @@ const std::map scraper_request_func std::unique_ptr startScraperSearch(const ScraperSearchParams& params) { - const std::string& name = Settings::getInstance()->getString("Scraper"); + std::string name = Settings::getInstance()->getString("Scraper"); + // Handle a potentially invalid entry in the configuration file. + if (name != "screenscraper" && name != "thegamesdb") { + name = "screenscraper"; + Settings::getInstance()->setString("Scraper", name); + Settings::getInstance()->saveFile(); + } + std::unique_ptr handle(new ScraperSearchHandle()); // Check if the scraper in the settings still exists as a registered scraping source. @@ -80,15 +87,8 @@ std::vector getScraperList() bool isValidConfiguredScraper() { - std::string scraper = Settings::getInstance()->getString("Scraper"); - // Handle a potentially invalid entry in the configuration file. - if (scraper != "screenscraper" && scraper != "thegamesdb") { - scraper = "screenscraper"; - Settings::getInstance()->setString("Scraper", scraper); - Settings::getInstance()->saveFile(); - } - - return scraper_request_funcs.find(scraper) != scraper_request_funcs.end(); + const std::string& name = Settings::getInstance()->getString("Scraper"); + return scraper_request_funcs.find(name) != scraper_request_funcs.end(); } void ScraperSearchHandle::update() From b4492abccdca10baceb9effbb6faaca3f57fd9cc Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sat, 6 Nov 2021 21:43:32 +0100 Subject: [PATCH 05/11] Removed the copying of es_settings.cfg to es_settings.xml on startup. --- es-core/src/Settings.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index ea25a2dcb..cd3879978 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -358,16 +358,9 @@ void Settings::saveFile() void Settings::loadFile() { - // Prior to ES-DE v1.1, the configuration file had the .cfg suffix instead of .xml - const std::string legacyConfigFile = - Utils::FileSystem::getHomePath() + "/.emulationstation/es_settings.cfg"; - const std::string configFile = Utils::FileSystem::getHomePath() + "/.emulationstation/es_settings.xml"; - if (Utils::FileSystem::exists(legacyConfigFile) && !Utils::FileSystem::exists(configFile)) - Utils::FileSystem::copyFile(legacyConfigFile, configFile, false); - if (!Utils::FileSystem::exists(configFile)) return; From c5a1555de3fa686341fa9aae0c14b9ffcf382f23 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 7 Nov 2021 18:14:38 +0100 Subject: [PATCH 06/11] Added proper frame drop support to the FFmpeg video player. Also made multiple large optimizations. --- .../src/components/VideoFFmpegComponent.cpp | 201 +++++++++++------- es-core/src/components/VideoFFmpegComponent.h | 2 + 2 files changed, 129 insertions(+), 74 deletions(-) diff --git a/es-core/src/components/VideoFFmpegComponent.cpp b/es-core/src/components/VideoFFmpegComponent.cpp index 6772db296..45c499d67 100644 --- a/es-core/src/components/VideoFFmpegComponent.cpp +++ b/es-core/src/components/VideoFFmpegComponent.cpp @@ -16,6 +16,7 @@ #include "resources/TextureResource.h" #include +#include enum AVHWDeviceType VideoFFmpegComponent::sDeviceType = AV_HWDEVICE_TYPE_NONE; enum AVPixelFormat VideoFFmpegComponent::sPixelFormat = AV_PIX_FMT_NONE; @@ -165,17 +166,22 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans) mPictureMutex.lock(); if (!mOutputPicture.hasBeenRendered) { - // Copy the contents of mOutputPicture to a temporary vector in order to call + // Move the contents of mOutputPicture to a temporary vector in order to call // initFromPixels() only after the mutex unlock. This significantly reduces the // lock waits in outputFrames(). size_t pictureSize = mOutputPicture.pictureRGBA.size(); - std::vector tempPictureRGBA(pictureSize); + std::vector tempPictureRGBA; int pictureWidth = 0; int pictureHeight = 0; if (pictureSize > 0) { - tempPictureRGBA.insert(tempPictureRGBA.begin(), mOutputPicture.pictureRGBA.begin(), - mOutputPicture.pictureRGBA.end()); + tempPictureRGBA.insert(tempPictureRGBA.begin(), + std::make_move_iterator(mOutputPicture.pictureRGBA.begin()), + std::make_move_iterator(mOutputPicture.pictureRGBA.end())); + + mOutputPicture.pictureRGBA.erase(mOutputPicture.pictureRGBA.begin(), + mOutputPicture.pictureRGBA.end()); + pictureWidth = mOutputPicture.width; pictureHeight = mOutputPicture.height; @@ -528,90 +534,126 @@ void VideoFFmpegComponent::readFrames() if (mVideoFrameQueue.size() > 300 || mAudioFrameQueue.size() > 600) return; + int readLoops = 1; + + // If we can't keep up the audio processing, then drop video frames as it's much worse + // to have stuttering audio than a lower video framerate. + if (mAudioStreamIndex >= 0 && mAudioFrameCount > mAudioTargetQueueSize / 2) { + if (static_cast(mAudioFrameQueue.size()) < mAudioTargetQueueSize / 6) + readLoops = 5; + else if (static_cast(mAudioFrameQueue.size()) < mAudioTargetQueueSize / 4) + readLoops = 3; + else if (static_cast(mAudioFrameQueue.size()) < mAudioTargetQueueSize / 2) + readLoops = 2; + } + if (mVideoCodecContext && mFormatContext) { - if (static_cast(mVideoFrameQueue.size()) < mVideoTargetQueueSize || - (mAudioStreamIndex >= 0 && - static_cast(mAudioFrameQueue.size()) < mAudioTargetQueueSize)) { - while ((readFrameReturn = av_read_frame(mFormatContext, mPacket)) >= 0) { - if (mPacket->stream_index == mVideoStreamIndex) { - if (!avcodec_send_packet(mVideoCodecContext, mPacket) && - !avcodec_receive_frame(mVideoCodecContext, mVideoFrame)) { + for (int i = 0; i < readLoops; i++) { + if (static_cast(mVideoFrameQueue.size()) < mVideoTargetQueueSize || + (mAudioStreamIndex >= 0 && + static_cast(mAudioFrameQueue.size()) < mAudioTargetQueueSize)) { + while ((readFrameReturn = av_read_frame(mFormatContext, mPacket)) >= 0) { + if (mPacket->stream_index == mVideoStreamIndex) { + if (!avcodec_send_packet(mVideoCodecContext, mPacket) && + !avcodec_receive_frame(mVideoCodecContext, mVideoFrame)) { - int returnValue = 0; + int returnValue = 0; + mVideoFrameReadCount++; - if (mSWDecoder) { - returnValue = av_buffersrc_add_frame_flags( - mVBufferSrcContext, mVideoFrame, AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT); - } - else { - AVFrame* destFrame = nullptr; - destFrame = av_frame_alloc(); - - if (mVideoFrame->format == sPixelFormat) { - if (av_hwframe_transfer_data(destFrame, mVideoFrame, 0) < 0) { - LOG(LogError) << "VideoFFmpegComponent::readFrames(): " - "Couldn't transfer decoded video frame to " - "system memory"; - av_frame_free(&destFrame); - av_packet_unref(mPacket); - break; + if (mSWDecoder) { + // Drop the frame if necessary. + if (i == 0 || mAudioFrameCount == 0) { + returnValue = av_buffersrc_add_frame_flags( + mVBufferSrcContext, mVideoFrame, + AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT); } else { - destFrame->pts = mVideoFrame->pts; - destFrame->pkt_dts = mVideoFrame->pkt_dts; - destFrame->pict_type = mVideoFrame->pict_type; - destFrame->chroma_location = mVideoFrame->chroma_location; - destFrame->pkt_pos = mVideoFrame->pkt_pos; - destFrame->pkt_duration = mVideoFrame->pkt_duration; - destFrame->pkt_size = mVideoFrame->pkt_size; + mVideoFrameDroppedCount++; } } else { - LOG(LogError) << "VideoFFmpegComponent::readFrames(): " - "Couldn't decode video frame"; + if (i == 0 || mAudioFrameCount == 0) { + AVFrame* destFrame = nullptr; + destFrame = av_frame_alloc(); + + if (mVideoFrame->format == sPixelFormat) { + if (av_hwframe_transfer_data(destFrame, mVideoFrame, 0) < + 0) { + LOG(LogError) + << "VideoFFmpegComponent::readFrames(): " + "Couldn't transfer decoded video frame to " + "system memory"; + av_frame_free(&destFrame); + av_packet_unref(mPacket); + break; + } + else { + destFrame->pts = mVideoFrame->pts; + destFrame->pkt_dts = mVideoFrame->pkt_dts; + destFrame->pict_type = mVideoFrame->pict_type; + destFrame->chroma_location = + mVideoFrame->chroma_location; + destFrame->pkt_pos = mVideoFrame->pkt_pos; + destFrame->pkt_duration = mVideoFrame->pkt_duration; + destFrame->pkt_size = mVideoFrame->pkt_size; + } + } + else { + LOG(LogError) << "VideoFFmpegComponent::readFrames(): " + "Couldn't decode video frame"; + } + + returnValue = av_buffersrc_add_frame_flags( + mVBufferSrcContext, destFrame, + AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT); + av_frame_free(&destFrame); + } + else { + mVideoFrameDroppedCount++; + } } - returnValue = av_buffersrc_add_frame_flags( - mVBufferSrcContext, destFrame, AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT); - av_frame_free(&destFrame); - } + if (returnValue < 0) { + LOG(LogError) << "VideoFFmpegComponent::readFrames(): " + "Couldn't add video frame to buffer source"; + } - if (returnValue < 0) { - LOG(LogError) << "VideoFFmpegComponent::readFrames(): " - "Couldn't add video frame to buffer source"; + av_packet_unref(mPacket); + break; } + else { + av_packet_unref(mPacket); + } + } + else if (mPacket->stream_index == mAudioStreamIndex) { + if (!avcodec_send_packet(mAudioCodecContext, mPacket) && + !avcodec_receive_frame(mAudioCodecContext, mAudioFrame)) { - av_packet_unref(mPacket); - break; + // We have an audio frame that needs conversion and resampling. + int returnValue = av_buffersrc_add_frame_flags( + mABufferSrcContext, mAudioFrame, AV_BUFFERSRC_FLAG_KEEP_REF); + + if (returnValue < 0) { + LOG(LogError) << "VideoFFmpegComponent::readFrames(): " + "Couldn't add audio frame to buffer source"; + } + + av_packet_unref(mPacket); + continue; + } + else { + av_packet_unref(mPacket); + } } else { + // Ignore any stream that is not video or audio. av_packet_unref(mPacket); } } - else if (mPacket->stream_index == mAudioStreamIndex) { - if (!avcodec_send_packet(mAudioCodecContext, mPacket) && - !avcodec_receive_frame(mAudioCodecContext, mAudioFrame)) { - - // We have an audio frame that needs conversion and resampling. - int returnValue = av_buffersrc_add_frame_flags( - mABufferSrcContext, mAudioFrame, AV_BUFFERSRC_FLAG_KEEP_REF); - - if (returnValue < 0) { - LOG(LogError) << "VideoFFmpegComponent::readFrames(): " - "Couldn't add audio frame to buffer source"; - } - - av_packet_unref(mPacket); - continue; - } - else { - av_packet_unref(mPacket); - } - } - else { - // Ignore any stream that is not video or audio. - av_packet_unref(mPacket); - } + } + else { + // The target queue sizes have been reached. + break; } } } @@ -649,10 +691,11 @@ void VideoFFmpegComponent::getProcessedFrames() int bufferSize = mVideoFrameResampled->width * mVideoFrameResampled->height * 4; - currFrame.frameRGBA.insert(currFrame.frameRGBA.begin(), &mVideoFrameResampled->data[0][0], - &mVideoFrameResampled->data[0][bufferSize]); + currFrame.frameRGBA.insert( + currFrame.frameRGBA.begin(), std::make_move_iterator(&mVideoFrameResampled->data[0][0]), + std::make_move_iterator(&mVideoFrameResampled->data[0][bufferSize])); - mVideoFrameQueue.push(currFrame); + mVideoFrameQueue.push(std::move(currFrame)); av_frame_unref(mVideoFrameResampled); } @@ -680,7 +723,7 @@ void VideoFFmpegComponent::getProcessedFrames() &mAudioFrameResampled->data[0][0], &mAudioFrameResampled->data[0][bufferSize]); - mAudioFrameQueue.push(currFrame); + mAudioFrameQueue.push(std::move(currFrame)); av_frame_unref(mAudioFrameResampled); } } @@ -751,6 +794,14 @@ void VideoFFmpegComponent::outputFrames() LOG(LogDebug) << "Total video frames processed / video frame queue size: " << mVideoFrameCount << " / " << std::to_string(mVideoFrameQueue.size()); + if (mVideoFrameDroppedCount > 0) { + LOG(LogDebug) << "Video frames dropped: " << mVideoFrameDroppedCount << " of " + << mVideoFrameReadCount << " (" << std::setprecision(2) + << (static_cast(mVideoFrameDroppedCount) / + static_cast(mVideoFrameReadCount)) * + 100.0f + << "%)"; + } } mPictureMutex.lock(); @@ -1136,6 +1187,8 @@ void VideoFFmpegComponent::startVideo() mEndOfVideo = false; mVideoFrameCount = 0; mAudioFrameCount = 0; + mVideoFrameReadCount = 0; + mVideoFrameDroppedCount = 0; mOutputPicture = {}; // Get an empty texture for rendering the video. diff --git a/es-core/src/components/VideoFFmpegComponent.h b/es-core/src/components/VideoFFmpegComponent.h index 255e2fe09..66b80e984 100644 --- a/es-core/src/components/VideoFFmpegComponent.h +++ b/es-core/src/components/VideoFFmpegComponent.h @@ -158,6 +158,8 @@ private: int mAudioFrameCount; int mVideoFrameCount; + int mVideoFrameReadCount; + int mVideoFrameDroppedCount; double mAccumulatedTime; bool mStartTimeAccumulation; From 14e1b800fa917696d2d44040d9c87e4c080108d2 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 7 Nov 2021 18:18:41 +0100 Subject: [PATCH 07/11] Made two optimizations in TextureData. --- es-core/src/resources/TextureData.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/es-core/src/resources/TextureData.cpp b/es-core/src/resources/TextureData.cpp index e51908489..8182106f5 100644 --- a/es-core/src/resources/TextureData.cpp +++ b/es-core/src/resources/TextureData.cpp @@ -105,8 +105,9 @@ bool TextureData::initSVGFromMemory(const std::string& fileData) nsvgDeleteRasterizer(rast); - mDataRGBA.insert(mDataRGBA.begin(), tempVector.data(), - tempVector.data() + (mWidth * mHeight * 4)); + mDataRGBA.insert(mDataRGBA.begin(), std::make_move_iterator(tempVector.data()), + std::make_move_iterator(tempVector.data() + (mWidth * mHeight * 4))); + tempVector.erase(tempVector.begin(), tempVector.end()); ImageIO::flipPixelsVert(mDataRGBA.data(), mWidth, mHeight); mPendingRasterization = false; @@ -160,7 +161,8 @@ bool TextureData::initFromRGBA(const unsigned char* dataRGBA, size_t width, size return true; mDataRGBA.reserve(width * height * 4); - mDataRGBA.insert(mDataRGBA.begin(), dataRGBA, dataRGBA + (width * height * 4)); + mDataRGBA.insert(mDataRGBA.begin(), std::make_move_iterator(dataRGBA), + std::make_move_iterator(dataRGBA + (width * height * 4))); mWidth = static_cast(width); mHeight = static_cast(height); From c136f87a9f524ee9b66bec27e95973e8154a3842 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 7 Nov 2021 19:21:01 +0100 Subject: [PATCH 08/11] Small optimization when opening the menu. --- es-core/src/Window.cpp | 11 ++++++++--- es-core/src/Window.h | 4 ++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/es-core/src/Window.cpp b/es-core/src/Window.cpp index 39c419136..68edeee2a 100644 --- a/es-core/src/Window.cpp +++ b/es-core/src/Window.cpp @@ -128,6 +128,10 @@ bool Window::init() mBackgroundOverlay->setResize(static_cast(Renderer::getScreenWidth()), static_cast(Renderer::getScreenHeight())); +#if defined(USE_OPENGL_21) + mPostprocessedBackground = TextureResource::get(""); +#endif + mListScrollFont = Font::get(FONT_SIZE_LARGE); // Update our help because font sizes probably changed. @@ -143,6 +147,10 @@ void Window::deinit() for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++) (*it)->onHide(); +#if defined(USE_OPENGL_21) + mPostprocessedBackground.reset(); +#endif + InputManager::getInstance()->deinit(); ResourceManager::getInstance()->unloadAll(); #if defined(BUILD_VLC_PLAYER) @@ -429,9 +437,6 @@ void Window::render() #if (CLOCK_BACKGROUND_CREATION) const auto backgroundStartTime = std::chrono::system_clock::now(); #endif - - std::shared_ptr mPostprocessedBackground; - mPostprocessedBackground = TextureResource::get(""); unsigned char* processedTexture = new unsigned char[Renderer::getScreenWidth() * Renderer::getScreenHeight() * 4]; diff --git a/es-core/src/Window.h b/es-core/src/Window.h index d02ac3f31..a1c73d84e 100644 --- a/es-core/src/Window.h +++ b/es-core/src/Window.h @@ -167,6 +167,10 @@ private: std::queue> mInfoPopupQueue; +#if defined(USE_OPENGL_21) + std::shared_ptr mPostprocessedBackground; +#endif + std::string mListScrollText; std::shared_ptr mListScrollFont; unsigned char mListScrollOpacity; From 433c77261ff6d9cfabd02e16c043a3dc4326ee2e Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 7 Nov 2021 22:22:34 +0100 Subject: [PATCH 09/11] Fixed a small issue with the sizing of the badges. --- es-core/src/components/FlexboxComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/es-core/src/components/FlexboxComponent.cpp b/es-core/src/components/FlexboxComponent.cpp index 3b9fe9a0d..4d2998c1d 100644 --- a/es-core/src/components/FlexboxComponent.cpp +++ b/es-core/src/components/FlexboxComponent.cpp @@ -231,7 +231,7 @@ void FlexboxComponent::computeLayout() } // This rasterizes the SVG images so they look nice and smooth. - item.baseImage.setResize(item.baseImage.getSize()); + item.baseImage.setResize(glm::ceil(item.baseImage.getSize())); itemsOnLastRow++; pos++; From c64284808164cbc92083ee4cf3a8aebb61e977f0 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 7 Nov 2021 22:49:23 +0100 Subject: [PATCH 10/11] Reverted the last commit as the issue does not seem to be in the code. --- es-core/src/components/FlexboxComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/es-core/src/components/FlexboxComponent.cpp b/es-core/src/components/FlexboxComponent.cpp index 4d2998c1d..3b9fe9a0d 100644 --- a/es-core/src/components/FlexboxComponent.cpp +++ b/es-core/src/components/FlexboxComponent.cpp @@ -231,7 +231,7 @@ void FlexboxComponent::computeLayout() } // This rasterizes the SVG images so they look nice and smooth. - item.baseImage.setResize(glm::ceil(item.baseImage.getSize())); + item.baseImage.setResize(item.baseImage.getSize()); itemsOnLastRow++; pos++; From ac4710a18ef820245db40c1666885d8a1b5274a6 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 7 Nov 2021 23:54:52 +0100 Subject: [PATCH 11/11] Added proper support for the Raspberry Pi 4. --- CMakeLists.txt | 69 +++++++++++++------ es-app/src/guis/GuiMenu.cpp | 2 +- es-core/src/Settings.cpp | 23 ++++--- .../src/components/VideoFFmpegComponent.cpp | 2 +- 4 files changed, 64 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08e7418a4..eafc59c04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ option(RPI "Set to ON to enable Raspberry Pi specific build" ${RPI}) option(CEC "Set to ON to enable CEC" ${CEC}) option(VLC_PLAYER "Set to ON to build the VLC-based video player" ${VLC_PLAYER}) option(CLANG_TIDY "Set to ON to build using the clang-tidy static analyzer" ${CLANG_TIDY}) +option(VIDEO_HW_DECODING "Set to OFF to disable FFmpeg HW decoding" ON) if(CLANG_TIDY) find_program(CLANG_TIDY_BINARY NAMES clang-tidy) @@ -58,14 +59,7 @@ endif() #--------------------------------------------------------------------------------------------------- # OpenGL setup. -# Check if we're running on a Raspberry Pi. -if(EXISTS "${CMAKE_FIND_ROOT_PATH}/opt/vc/include/bcm_host.h") - message("-- Building on a Raspberry Pi (bcm_host.h found)") - # Setting BCMHOST seems to break OpenGL ES on the RPi 4 so set RPI instead. - #set(BCMHOST found) - set(RPI ON) - set(GLSYSTEM "Embedded OpenGL" CACHE STRING "The OpenGL system to be used") -elseif(GLES OR RPI) +if(GLES) set(GLSYSTEM "Embedded OpenGL" CACHE STRING "The OpenGL system to be used") else() set(GLSYSTEM "Desktop OpenGL" CACHE STRING "The OpenGL system to be used") @@ -73,6 +67,32 @@ endif() set_property(CACHE GLSYSTEM PROPERTY STRINGS "Desktop OpenGL" "Embedded OpenGL") +#--------------------------------------------------------------------------------------------------- +# Raspberry Pi setup. + +# If manually set to RPI (used for testing purposes). +if(RPI) + set(VIDEO_HW_DECODING OFF) +endif() + +# Raspberry Pi OS 32-bit (armv7l) +if(EXISTS "${CMAKE_FIND_ROOT_PATH}/opt/vc/include/bcm_host.h") + set(RPI ON) + set(RPI_32 ON) + set(VIDEO_HW_DECODING OFF) + set(BCMHOST found) + message("-- Building on a Raspberry Pi (32-bit OS)") +endif() + +# Raspberry Pi OS 64-bit (aarch64) +if(EXISTS "/usr/include/bcm_host.h") + set(RPI ON) + set(RPI_64 ON) + set(VIDEO_HW_DECODING OFF) + set(BCMHOST found) + message("-- Building on a Raspberry Pi (64-bit OS)") +endif() + #--------------------------------------------------------------------------------------------------- # Package dependencies. @@ -196,18 +216,22 @@ else() add_definitions(-DUSE_OPENGLES_10) endif() +if(RPI) + add_definitions(-D_RPI_) +endif() + if(VLC_PLAYER) add_definitions(-DBUILD_VLC_PLAYER) endif() -if(DEFINED BCMHOST OR RPI) - add_definitions(-D_RPI_) -endif() - if(DEFINED libCEC_FOUND) add_definitions(-DHAVE_LIBCEC) endif() +if(VIDEO_HW_DECODING) + add_definitions(-DVIDEO_HW_DECODING) +endif() + # GLM library options. add_definitions(-DGLM_FORCE_CXX17) add_definitions(-DGLM_FORCE_XYZW_ONLY) @@ -279,7 +303,7 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") list(APPEND COMMON_INCLUDE_DIRS ${ALSA_INCLUDE_DIRS}) endif() -if(DEFINED BCMHOST OR RPI) +if(RPI_32) list(APPEND COMMON_INCLUDE_DIRS "${CMAKE_FIND_ROOT_PATH}/opt/vc/include" "${CMAKE_FIND_ROOT_PATH}/opt/vc/include/interface/vcos" "${CMAKE_FIND_ROOT_PATH}/opt/vc/include/interface/vmcs_host/linux" @@ -358,9 +382,6 @@ endif() # Add libCEC libraries. if(DEFINED libCEC_FOUND) - if(DEFINED BCMHOST OR RPI) - list(APPEND COMMON_LIBRARIES bcm_host vchiq_arm) - endif() list(APPEND COMMON_LIBRARIES dl ${libCEC_LIBRARIES}) endif() @@ -369,14 +390,22 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") list(APPEND COMMON_LIBRARIES ${ALSA_LIBRARY}) endif() +# Raspberry Pi. if(DEFINED BCMHOST) - link_directories("${CMAKE_FIND_ROOT_PATH}/opt/vc/lib") - list(APPEND COMMON_LIBRARIES bcm_host brcmEGL ${OPENGLES_LIBRARIES}) -elseif(RPI) - link_directories("${CMAKE_FIND_ROOT_PATH}/opt/vc/lib") + list(APPEND COMMON_LIBRARIES bcm_host vchiq_arm) + if(RPI_32) + link_directories("${CMAKE_FIND_ROOT_PATH}/opt/vc/lib") + endif() +endif() + +# Note: Building with GLES support on the Raspberry Pi currently seems to be broken. +if(GLES AND RPI_32) + list(APPEND COMMON_LIBRARIES brcmEGL ${OPENGLES_LIBRARIES}) +elseif(GLES AND RPI_64) list(APPEND COMMON_LIBRARIES ${OPENGLES_LIBRARIES}) endif() +# OpenGL. if(GLSYSTEM MATCHES "Desktop OpenGL") list(APPEND COMMON_LIBRARIES ${OPENGL_LIBRARIES}) else() diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index 7ca851bb6..acb13f325 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -1010,7 +1010,7 @@ void GuiMenu::openOtherOptions() } #endif -#if !defined(_RPI_) +#if defined(VIDEO_HW_DECODING) // Whether to enable hardware decoding for the FFmpeg video player. auto video_hardware_decoding = std::make_shared(mWindow); video_hardware_decoding->setState(Settings::getInstance()->getBool("VideoHardwareDecoding")); diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index cd3879978..f066a4f76 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -98,7 +98,7 @@ void Settings::setDefaults() // Scraper. mStringMap["Scraper"] = {"screenscraper", "screenscraper"}; - mBoolMap["ScraperUseAccountScreenScraper"] = {false, false}; + mBoolMap["ScraperUseAccountScreenScraper"] = {true, true}; mStringMap["ScraperUsernameScreenScraper"] = {"", ""}; mStringMap["ScraperPasswordScreenScraper"] = {"", ""}; @@ -154,7 +154,11 @@ void Settings::setDefaults() // UI settings -> media viewer settings. mBoolMap["MediaViewerKeepVideoRunning"] = {true, true}; mBoolMap["MediaViewerStretchVideos"] = {false, false}; +#if defined(_RPI_) + mBoolMap["MediaViewerVideoScanlines"] = {false, false}; +#else mBoolMap["MediaViewerVideoScanlines"] = {true, true}; +#endif mBoolMap["MediaViewerVideoBlur"] = {false, false}; mBoolMap["MediaViewerScreenshotScanlines"] = {true, true}; @@ -177,7 +181,11 @@ void Settings::setDefaults() mIntMap["ScreensaverSwapVideoTimeout"] = {0, 0}; mBoolMap["ScreensaverStretchVideos"] = {false, false}; mBoolMap["ScreensaverVideoGameInfo"] = {true, true}; +#if defined(_RPI_) + mBoolMap["ScreensaverVideoScanlines"] = {false, false}; +#else mBoolMap["ScreensaverVideoScanlines"] = {true, true}; +#endif mBoolMap["ScreensaverVideoBlur"] = {false, false}; mBoolMap["MenuBlurBackground"] = {true, true}; @@ -199,8 +207,8 @@ void Settings::setDefaults() mBoolMap["EnableMenuKidMode"] = {false, false}; // Sound settings. - mIntMap["SoundVolumeNavigation"] = {80, 80}; - mIntMap["SoundVolumeVideos"] = {100, 100}; + mIntMap["SoundVolumeNavigation"] = {70, 70}; + mIntMap["SoundVolumeVideos"] = {80, 80}; mBoolMap["GamelistVideoAudio"] = {true, true}; mBoolMap["MediaViewerVideoAudio"] = {true, true}; mBoolMap["ScreensaverVideoAudio"] = {false, false}; @@ -221,7 +229,7 @@ void Settings::setDefaults() // Other settings. mStringMap["MediaDirectory"] = {"", ""}; #if defined(_RPI_) - mIntMap["MaxVRAM"] = {80, 80}; + mIntMap["MaxVRAM"] = {180, 180}; #else mIntMap["MaxVRAM"] = {256, 256}; #endif @@ -230,12 +238,7 @@ void Settings::setDefaults() mStringMap["FullscreenMode"] = {"normal", "normal"}; #endif #if defined(BUILD_VLC_PLAYER) -#if defined(_RPI_) - // As the FFmpeg video player is not HW accelerated, use VLC as default on this weak device. - mStringMap["VideoPlayer"] = {"vlc", "vlc"}; -#else mStringMap["VideoPlayer"] = {"ffmpeg", "ffmpeg"}; -#endif #endif mStringMap["ExitButtonCombo"] = {"F4", "F4"}; mStringMap["SaveGamelistsMode"] = {"always", "always"}; @@ -246,7 +249,7 @@ void Settings::setDefaults() #if defined(_WIN64) mBoolMap["LaunchWorkaround"] = {true, true}; #endif -#if !defined(_RPI_) +#if !defined(VIDEO_HW_DECODING) mBoolMap["VideoHardwareDecoding"] = {false, false}; #endif mBoolMap["VideoUpscaleFrameRate"] = {false, false}; diff --git a/es-core/src/components/VideoFFmpegComponent.cpp b/es-core/src/components/VideoFFmpegComponent.cpp index 45c499d67..9bb31a8f3 100644 --- a/es-core/src/components/VideoFFmpegComponent.cpp +++ b/es-core/src/components/VideoFFmpegComponent.cpp @@ -1227,7 +1227,7 @@ void VideoFFmpegComponent::startVideo() // Video stream setup. -#if defined(_RPI_) +#if !defined(VIDEO_HW_DECODING) bool hwDecoding = false; #else bool hwDecoding = Settings::getInstance()->getBool("VideoHardwareDecoding");