diff --git a/desmume/src/frontend/cocoa/ClientDisplayView.cpp b/desmume/src/frontend/cocoa/ClientDisplayView.cpp index 92c6589a8..79e1c66f0 100644 --- a/desmume/src/frontend/cocoa/ClientDisplayView.cpp +++ b/desmume/src/frontend/cocoa/ClientDisplayView.cpp @@ -17,155 +17,440 @@ #include "ClientDisplayView.h" +#include + ClientDisplayView::ClientDisplayView() { - _property.normalWidth = GPU_FRAMEBUFFER_NATIVE_WIDTH; - _property.normalHeight = GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2.0; - _property.clientWidth = _property.normalWidth; - _property.clientHeight = _property.normalHeight; - _property.rotation = 0.0; - _property.viewScale = 1.0; - _property.gapScale = 0.0; - _property.gapDistance = DS_DISPLAY_UNSCALED_GAP * _property.gapScale; - _property.mode = ClientDisplayMode_Dual; - _property.layout = ClientDisplayLayout_Vertical; - _property.order = ClientDisplayOrder_MainFirst; + ClientDisplayViewProperties defaultProperty; + defaultProperty.normalWidth = GPU_FRAMEBUFFER_NATIVE_WIDTH; + defaultProperty.normalHeight = GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2.0; + defaultProperty.clientWidth = defaultProperty.normalWidth; + defaultProperty.clientHeight = defaultProperty.normalHeight; + defaultProperty.rotation = 0.0; + defaultProperty.viewScale = 1.0; + defaultProperty.gapScale = 0.0; + defaultProperty.gapDistance = DS_DISPLAY_UNSCALED_GAP * defaultProperty.gapScale; + defaultProperty.mode = ClientDisplayMode_Dual; + defaultProperty.layout = ClientDisplayLayout_Vertical; + defaultProperty.order = ClientDisplayOrder_MainFirst; - _initialTouchInMajorDisplay = new InitialTouchPressMap; + __InstanceInit(defaultProperty); } -ClientDisplayView::ClientDisplayView(const ClientDisplayViewProperties props) +ClientDisplayView::ClientDisplayView(const ClientDisplayViewProperties &props) { - _property = props; - _initialTouchInMajorDisplay = new InitialTouchPressMap; + __InstanceInit(props); } ClientDisplayView::~ClientDisplayView() { delete _initialTouchInMajorDisplay; -} - -ClientDisplayViewProperties ClientDisplayView::GetProperties() const -{ - return this->_property; -} - -void ClientDisplayView::SetProperties(const ClientDisplayViewProperties props) -{ - this->_property = props; - ClientDisplayView::CalculateNormalSize(props.mode, props.layout, props.gapScale, this->_property.normalWidth, this->_property.normalHeight); + FT_Done_FreeType(this->_ftLibrary); } -void ClientDisplayView::SetClientSize(const double w, const double h) +void ClientDisplayView::__InstanceInit(const ClientDisplayViewProperties &props) { - this->_property.clientWidth = w; - this->_property.clientHeight = h; - this->_property.viewScale = ClientDisplayView::GetMaxScalarWithinBounds(this->_property.normalWidth, this->_property.normalHeight, w, h); + _stagedProperty = props; + _renderProperty = _stagedProperty; + _initialTouchInMajorDisplay = new InitialTouchPressMap; + + _useDeposterize = false; + _pixelScaler = VideoFilterTypeID_None; + _outputFilter = OutputFilterTypeID_Bilinear; + + _scaleFactor = 1.0; + + _hudObjectScale = 1.0; + _isHUDVisible = true; + _showVideoFPS = true; + _showRender3DFPS = false; + _showFrameIndex = false; + _showLagFrameCount = false; + _showCPULoadAverage = false; + _showRTC = false; + + memset(&_frameInfo, 0, sizeof(_frameInfo)); + _hudString = "\x01"; // Char value 0x01 will represent the "text box" character, which will always be first in the string. + + FT_Error error = FT_Init_FreeType(&_ftLibrary); + if (error) + { + printf("ClientDisplayView: FreeType failed to init!\n"); + } + + memset(_glyphInfo, 0, sizeof(_glyphInfo)); + _glyphTileSize = ((double)HUD_TEXTBOX_BASEGLYPHSIZE * _scaleFactor) + 0.0001; + _glyphSize = ((double)_glyphTileSize * 0.75) + 0.0001; + + // Set up the text box, which resides at glyph position 1. + GlyphInfo &boxInfo = _glyphInfo[1]; + boxInfo.width = _glyphTileSize; + boxInfo.texCoord[0] = 1.0f/16.0f; boxInfo.texCoord[1] = 0.0f; + boxInfo.texCoord[2] = 2.0f/16.0f; boxInfo.texCoord[3] = 0.0f; + boxInfo.texCoord[4] = 2.0f/16.0f; boxInfo.texCoord[5] = 1.0f/16.0f; + boxInfo.texCoord[6] = 1.0f/16.0f; boxInfo.texCoord[7] = 1.0f/16.0f; +} + +void ClientDisplayView::_UpdateHUDString() +{ + std::ostringstream ss; + ss << "\x01"; // This represents the text box. It must always be the first character. + + if (this->_showVideoFPS) + { + ss << "Video FPS: " << this->_frameInfo.videoFPS << "\n"; + } + + if (this->_showRender3DFPS) + { + ss << "3D Rendering FPS: " << this->_frameInfo.render3DFPS << "\n"; + } + + if (this->_showFrameIndex) + { + ss << "Frame Index: " << this->_frameInfo.frameIndex << "\n"; + } + + if (this->_showLagFrameCount) + { + ss << "Lag Frame Count: " << this->_frameInfo.lagFrameCount << "\n"; + } + + if (this->_showCPULoadAverage) + { + static char buffer[32]; + memset(buffer, 0, sizeof(buffer)); + snprintf(buffer, 25, "CPU Load Avg: %02d%% / %02d%%\n", this->_frameInfo.cpuLoadAvgARM9, this->_frameInfo.cpuLoadAvgARM7); + + ss << buffer; + } + + if (this->_showRTC) + { + ss << "RTC: " << this->_frameInfo.rtcString << "\n"; + } + + this->_hudString = ss.str(); +} + +void ClientDisplayView::_SetHUDShowInfoItem(bool &infoItemFlag, const bool visibleState) +{ + if (infoItemFlag == visibleState) + { + return; + } + + infoItemFlag = visibleState; + this->_UpdateHUDString(); + this->FrameProcessHUD(); +} + +void ClientDisplayView::Init() +{ + // Do nothing. This is implementation dependent. +} + +double ClientDisplayView::GetScaleFactor() const +{ + return this->_scaleFactor; +} + +void ClientDisplayView::SetScaleFactor(const double scaleFactor) +{ + this->_scaleFactor = scaleFactor; + + const bool willChangeScaleFactor = (this->_scaleFactor != scaleFactor); + if (willChangeScaleFactor) + { + this->_glyphTileSize = (double)HUD_TEXTBOX_BASEGLYPHSIZE * scaleFactor; + this->_glyphSize = (double)this->_glyphTileSize * 0.75; + + this->SetHUDFontUsingPath(this->_lastFontFilePath); + } +} + +void ClientDisplayView::_UpdateViewScale() +{ + double checkWidth = this->_renderProperty.normalWidth; + double checkHeight = this->_renderProperty.normalHeight; + ClientDisplayView::ConvertNormalToTransformedBounds(1.0, this->_renderProperty.rotation, checkWidth, checkHeight); + this->_renderProperty.viewScale = ClientDisplayView::GetMaxScalarWithinBounds(checkWidth, checkHeight, this->_renderProperty.clientWidth, this->_renderProperty.clientHeight); + + this->_hudObjectScale = this->_renderProperty.clientWidth / this->_renderProperty.normalWidth; + if (this->_hudObjectScale > 2.0) + { + // If the view scale is <= 2.0, we scale the HUD objects linearly. Otherwise, we scale + // the HUD objects logarithmically, up to a maximum scale of 3.0. + this->_hudObjectScale = ( -1.0/((1.0/12000.0)*pow(this->_hudObjectScale+4.5438939, 5.0)) ) + 3.0; + } +} + +// NDS screen layout +const ClientDisplayViewProperties& ClientDisplayView::GetViewProperties() const +{ + return this->_renderProperty; +} + +void ClientDisplayView::CommitViewProperties(const ClientDisplayViewProperties &props) +{ + this->_stagedProperty = props; +} + +void ClientDisplayView::SetupViewProperties() +{ + // Validate the staged properties. + this->_stagedProperty.gapDistance = (double)DS_DISPLAY_UNSCALED_GAP * this->_stagedProperty.gapScale; + ClientDisplayView::CalculateNormalSize(this->_stagedProperty.mode, this->_stagedProperty.layout, this->_stagedProperty.gapScale, this->_stagedProperty.normalWidth, this->_stagedProperty.normalHeight); + + const bool didNormalSizeChange = (this->_renderProperty.mode != this->_stagedProperty.mode) || + (this->_renderProperty.layout != this->_stagedProperty.layout) || + (this->_renderProperty.gapScale != this->_stagedProperty.gapScale); + + const bool didOrderChange = (this->_renderProperty.order != this->_stagedProperty.order); + const bool didRotationChange = (this->_renderProperty.rotation != this->_stagedProperty.rotation); + const bool didClientSizeChange = (this->_renderProperty.clientWidth != this->_stagedProperty.clientWidth) || (this->_renderProperty.clientHeight != this->_stagedProperty.clientHeight); + + // Copy the staged properties to the current rendering properties. + this->_renderProperty = this->_stagedProperty; + + // Update internal states based on the new render properties + this->_UpdateViewScale(); + + if (didNormalSizeChange) + { + this->_UpdateNormalSize(); + } + + if (didOrderChange) + { + this->_UpdateOrder(); + } + + if (didRotationChange) + { + this->_UpdateRotation(); + } + + if (didClientSizeChange) + { + this->_UpdateClientSize(); + } } double ClientDisplayView::GetRotation() const { - return this->_property.rotation; -} - -void ClientDisplayView::SetRotation(const double r) -{ - this->_property.rotation = r; - - double checkWidth = this->_property.normalWidth; - double checkHeight = this->_property.normalHeight; - ClientDisplayView::ConvertNormalToTransformedBounds(1.0, r, checkWidth, checkHeight); - this->_property.viewScale = ClientDisplayView::GetMaxScalarWithinBounds(checkWidth, checkHeight, this->_property.clientWidth, this->_property.clientHeight); + return this->_renderProperty.rotation; } double ClientDisplayView::GetViewScale() const { - return this->_property.viewScale; + return this->_renderProperty.viewScale; } ClientDisplayMode ClientDisplayView::GetMode() const { - return this->_property.mode; -} - -void ClientDisplayView::SetMode(const ClientDisplayMode mode) -{ - this->_property.mode = mode; - ClientDisplayView::CalculateNormalSize(this->_property.mode, this->_property.layout, this->_property.gapScale, this->_property.normalWidth, this->_property.normalHeight); - this->_property.viewScale = ClientDisplayView::GetMaxScalarWithinBounds(this->_property.normalWidth, this->_property.normalHeight, this->_property.clientWidth, this->_property.clientHeight); + return this->_renderProperty.mode; } ClientDisplayLayout ClientDisplayView::GetLayout() const { - return this->_property.layout; -} - -void ClientDisplayView::SetLayout(const ClientDisplayLayout layout) -{ - this->_property.layout = layout; - ClientDisplayView::CalculateNormalSize(this->_property.mode, this->_property.layout, this->_property.gapScale, this->_property.normalWidth, this->_property.normalHeight); - this->_property.viewScale = ClientDisplayView::GetMaxScalarWithinBounds(this->_property.normalWidth, this->_property.normalHeight, this->_property.clientWidth, this->_property.clientHeight); + return this->_renderProperty.layout; } ClientDisplayOrder ClientDisplayView::GetOrder() const { - return this->_property.order; -} - -void ClientDisplayView::SetOrder(const ClientDisplayOrder order) -{ - this->_property.order = order; + return this->_renderProperty.order; } double ClientDisplayView::GetGapScale() const { - return this->_property.gapScale; -} - -void ClientDisplayView::SetGapWithScalar(const double gapScale) -{ - this->_property.gapScale = gapScale; - this->_property.gapDistance = (double)DS_DISPLAY_UNSCALED_GAP * gapScale; + return this->_renderProperty.gapScale; } double ClientDisplayView::GetGapDistance() const { - return this->_property.gapDistance; + return this->_renderProperty.gapDistance; } -void ClientDisplayView::SetGapWithDistance(const double gapDistance) +// NDS screen filters +bool ClientDisplayView::GetSourceDeposterize() { - this->_property.gapScale = gapDistance / (double)DS_DISPLAY_UNSCALED_GAP; - this->_property.gapDistance = gapDistance; + return this->_useDeposterize; } +void ClientDisplayView::SetSourceDeposterize(const bool useDeposterize) +{ + this->_useDeposterize = useDeposterize; +} + +OutputFilterTypeID ClientDisplayView::GetOutputFilter() const +{ + return this->_outputFilter; +} + +void ClientDisplayView::SetOutputFilter(const OutputFilterTypeID filterID) +{ + this->_outputFilter = filterID; +} + +VideoFilterTypeID ClientDisplayView::GetPixelScaler() const +{ + return this->_pixelScaler; +} + +void ClientDisplayView::SetPixelScaler(const VideoFilterTypeID filterID) +{ + this->_pixelScaler = filterID; +} + +// HUD appearance +void ClientDisplayView::SetHUDFontUsingPath(const char *filePath) +{ + FT_Face fontFace; + FT_Error error = FT_Err_Ok; + + error = FT_New_Face(this->_ftLibrary, filePath, 0, &fontFace); + if (error == FT_Err_Unknown_File_Format) + { + printf("ClientDisplayView: FreeType failed to load font face because it is in an unknown format from:\n%s\n", filePath); + return; + } + else if (error) + { + printf("ClientDisplayView: FreeType failed to load font face with an unknown error from:\n%s\n", filePath); + return; + } + + this->CopyHUDFont(fontFace, this->_glyphSize, this->_glyphTileSize, this->_glyphInfo); + + FT_Done_Face(fontFace); + this->_lastFontFilePath = filePath; +} + +void ClientDisplayView::CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, const size_t glyphTileSize, GlyphInfo *glyphInfo) +{ + // Do nothing. This is implementation dependent. +} + +void ClientDisplayView::SetHUDInfo(const NDSFrameInfo &frameInfo) +{ + this->_frameInfo = frameInfo; + this->_UpdateHUDString(); +} + +const std::string& ClientDisplayView::GetHUDString() const +{ + return this->_hudString; +} + +float ClientDisplayView::GetHUDObjectScale() const +{ + return this->_hudObjectScale; +} + +void ClientDisplayView::SetHUDObjectScale(float objectScale) +{ + this->_hudObjectScale = objectScale; +} + +bool ClientDisplayView::GetHUDVisibility() const +{ + return this->_isHUDVisible; +} + +void ClientDisplayView::SetHUDVisibility(const bool visibleState) +{ + this->_isHUDVisible = visibleState; +} + +bool ClientDisplayView::GetHUDShowVideoFPS() const +{ + return this->_showVideoFPS; +} + +void ClientDisplayView::SetHUDShowVideoFPS(const bool visibleState) +{ + this->_SetHUDShowInfoItem(this->_showVideoFPS, visibleState); +} + +bool ClientDisplayView::GetHUDShowRender3DFPS() const +{ + return this->_showRender3DFPS; +} + +void ClientDisplayView::SetHUDShowRender3DFPS(const bool visibleState) +{ + this->_SetHUDShowInfoItem(this->_showRender3DFPS, visibleState); +} + +bool ClientDisplayView::GetHUDShowFrameIndex() const +{ + return this->_showFrameIndex; +} + +void ClientDisplayView::SetHUDShowFrameIndex(const bool visibleState) +{ + this->_SetHUDShowInfoItem(this->_showFrameIndex, visibleState); +} + +bool ClientDisplayView::GetHUDShowLagFrameCount() const +{ + return this->_showLagFrameCount; +} + +void ClientDisplayView::SetHUDShowLagFrameCount(const bool visibleState) +{ + this->_SetHUDShowInfoItem(this->_showLagFrameCount, visibleState); +} + +bool ClientDisplayView::GetHUDShowCPULoadAverage() const +{ + return this->_showCPULoadAverage; +} + +void ClientDisplayView::SetHUDShowCPULoadAverage(const bool visibleState) +{ + this->_SetHUDShowInfoItem(this->_showCPULoadAverage, visibleState); +} + +bool ClientDisplayView::GetHUDShowRTC() const +{ + return this->_showRTC; +} + +void ClientDisplayView::SetHUDShowRTC(const bool visibleState) +{ + this->_SetHUDShowInfoItem(this->_showRTC, visibleState); +} + +// Touch screen input handling void ClientDisplayView::GetNDSPoint(const int inputID, const bool isInitialTouchPress, const double clientX, const double clientY, u8 &outX, u8 &outY) const { double x = clientX; double y = clientY; - double w = this->_property.normalWidth; - double h = this->_property.normalHeight; + double w = this->_renderProperty.normalWidth; + double h = this->_renderProperty.normalHeight; - ClientDisplayView::ConvertNormalToTransformedBounds(1.0, this->_property.rotation, w, h); - const double s = ClientDisplayView::GetMaxScalarWithinBounds(w, h, this->_property.clientWidth, this->_property.clientHeight); + ClientDisplayView::ConvertNormalToTransformedBounds(1.0, this->_renderProperty.rotation, w, h); + const double s = ClientDisplayView::GetMaxScalarWithinBounds(w, h, this->_renderProperty.clientWidth, this->_renderProperty.clientHeight); - ClientDisplayView::ConvertClientToNormalPoint(this->_property.normalWidth, this->_property.normalHeight, - this->_property.clientWidth, this->_property.clientHeight, + ClientDisplayView::ConvertClientToNormalPoint(this->_renderProperty.normalWidth, this->_renderProperty.normalHeight, + this->_renderProperty.clientWidth, this->_renderProperty.clientHeight, s, - this->_property.rotation, + this->_renderProperty.rotation, x, y); // Normalize the touch location to the DS. - if (this->_property.mode == ClientDisplayMode_Dual) + if (this->_renderProperty.mode == ClientDisplayMode_Dual) { - switch (this->_property.layout) + switch (this->_renderProperty.layout) { case ClientDisplayLayout_Horizontal: { - if (this->_property.order == ClientDisplayOrder_MainFirst) + if (this->_renderProperty.order == ClientDisplayOrder_MainFirst) { x -= GPU_FRAMEBUFFER_NATIVE_WIDTH; } @@ -178,14 +463,14 @@ void ClientDisplayView::GetNDSPoint(const int inputID, const bool isInitialTouch { if (isInitialTouchPress) { - const bool isClickWithinMajorDisplay = (this->_property.order == ClientDisplayOrder_TouchFirst) && (x >= 0.0) && (x < 256.0); + const bool isClickWithinMajorDisplay = (this->_renderProperty.order == ClientDisplayOrder_TouchFirst) && (x >= 0.0) && (x < 256.0); (*_initialTouchInMajorDisplay)[inputID] = isClickWithinMajorDisplay; } const bool handleClickInMajorDisplay = (*_initialTouchInMajorDisplay)[inputID]; if (!handleClickInMajorDisplay) { - const double minorDisplayScale = (this->_property.normalWidth - (double)GPU_FRAMEBUFFER_NATIVE_WIDTH) / (double)GPU_FRAMEBUFFER_NATIVE_WIDTH; + const double minorDisplayScale = (this->_renderProperty.normalWidth - (double)GPU_FRAMEBUFFER_NATIVE_WIDTH) / (double)GPU_FRAMEBUFFER_NATIVE_WIDTH; x = (x - GPU_FRAMEBUFFER_NATIVE_WIDTH) / minorDisplayScale; y = y / minorDisplayScale; } @@ -194,9 +479,9 @@ void ClientDisplayView::GetNDSPoint(const int inputID, const bool isInitialTouch default: // Default to vertical orientation. { - if (this->_property.order == ClientDisplayOrder_TouchFirst) + if (this->_renderProperty.order == ClientDisplayOrder_TouchFirst) { - y -= ((double)GPU_FRAMEBUFFER_NATIVE_HEIGHT + this->_property.gapDistance); + y -= ((double)GPU_FRAMEBUFFER_NATIVE_HEIGHT + this->_renderProperty.gapDistance); } break; } @@ -506,3 +791,45 @@ void ClientDisplayView::CalculateNormalSize(const ClientDisplayMode mode, const outHeight = (double)GPU_FRAMEBUFFER_NATIVE_HEIGHT; } } + +ClientDisplay3DView::ClientDisplay3DView() +{ + _canFilterOnGPU = false; + _willFilterOnGPU = false; + _filtersPreferGPU = false; +} + +bool ClientDisplay3DView::CanFilterOnGPU() const +{ + return this->_canFilterOnGPU; +} + +bool ClientDisplay3DView::WillFilterOnGPU() const +{ + return this->_willFilterOnGPU; +} + +bool ClientDisplay3DView::GetFiltersPreferGPU() const +{ + return this->_filtersPreferGPU; +} + +void ClientDisplay3DView::SetFiltersPreferGPU(const bool preferGPU) +{ + this->_filtersPreferGPU = preferGPU; +} + +void ClientDisplay3DView::SetSourceDeposterize(bool useDeposterize) +{ + this->_useDeposterize = (this->_canFilterOnGPU) ? useDeposterize : false; +} + +void ClientDisplay3DView::SetVideoBuffers(const uint32_t colorFormat, + const void *videoBufferHead, + const void *nativeBuffer0, + const void *nativeBuffer1, + const void *customBuffer0, const size_t customWidth0, const size_t customHeight0, + const void *customBuffer1, const size_t customWidth1, const size_t customHeight1) +{ + // Do nothing. This is implementation dependent. +} diff --git a/desmume/src/frontend/cocoa/ClientDisplayView.h b/desmume/src/frontend/cocoa/ClientDisplayView.h index 427c92b9e..c5712c8ec 100644 --- a/desmume/src/frontend/cocoa/ClientDisplayView.h +++ b/desmume/src/frontend/cocoa/ClientDisplayView.h @@ -19,8 +19,18 @@ #define _CLIENT_DISPLAY_VIEW_H_ #include +#include +#include "../../filter/videofilter.h" #include "../../GPU.h" +#include +#include FT_FREETYPE_H + +#define HUD_MAX_CHARACTERS 2048 +#define HUD_TEXTBOX_BASEGLYPHSIZE 64.0 +#define HUD_TEXTBOX_BASE_SCALE (1.0/3.0) +#define HUD_TEXTBOX_MIN_SCALE 0.70 + #define DS_DISPLAY_VERTICAL_GAP_TO_HEIGHT_RATIO (21.0/46.0) // Based on the official DS specification: 21mm/46mm #define DS_DISPLAY_UNSCALED_GAP (GPU_FRAMEBUFFER_NATIVE_HEIGHT * DS_DISPLAY_VERTICAL_GAP_TO_HEIGHT_RATIO) @@ -46,58 +56,165 @@ enum ClientDisplayOrder ClientDisplayOrder_TouchFirst }; +enum OutputFilterTypeID +{ + OutputFilterTypeID_NearestNeighbor = 0, + OutputFilterTypeID_Bilinear = 1, + OutputFilterTypeID_BicubicBSpline = 2, + OutputFilterTypeID_BicubicMitchell = 3, + OutputFilterTypeID_Lanczos2 = 4, + OutputFilterTypeID_Lanczos3 = 5 +}; + typedef std::map InitialTouchPressMap; // Key = An ID number of the host input, Value = Flag that indicates if the initial touch press was in the major display -typedef struct +struct GlyphInfo +{ + float width; + float texCoord[8]; +}; +typedef struct GlyphInfo GlyphInfo; + +struct NDSFrameInfo +{ + uint32_t videoFPS; + uint32_t render3DFPS; + uint32_t frameIndex; + uint32_t lagFrameCount; + uint32_t cpuLoadAvgARM9; + uint32_t cpuLoadAvgARM7; + char rtcString[25]; +}; +typedef struct NDSFrameInfo NDSFrameInfo; + +struct ClientDisplayViewProperties { - double normalWidth; - double normalHeight; - double clientWidth; - double clientHeight; - double rotation; - double viewScale; - double gapScale; - double gapDistance; ClientDisplayMode mode; ClientDisplayLayout layout; ClientDisplayOrder order; -} ClientDisplayViewProperties; + double gapScale; + double rotation; + double clientWidth; + double clientHeight; + + double normalWidth; + double normalHeight; + double viewScale; + double gapDistance; +}; +typedef struct ClientDisplayViewProperties ClientDisplayViewProperties; class ClientDisplayView { +private: + void __InstanceInit(const ClientDisplayViewProperties &props); + protected: - ClientDisplayViewProperties _property; + ClientDisplayViewProperties _renderProperty; + ClientDisplayViewProperties _stagedProperty; InitialTouchPressMap *_initialTouchInMajorDisplay; + bool _useDeposterize; + VideoFilterTypeID _pixelScaler; + OutputFilterTypeID _outputFilter; + + double _scaleFactor; + + double _hudObjectScale; + bool _isHUDVisible; + bool _showVideoFPS; + bool _showRender3DFPS; + bool _showFrameIndex; + bool _showLagFrameCount; + bool _showCPULoadAverage; + bool _showRTC; + + NDSFrameInfo _frameInfo; + std::string _hudString; + + FT_Library _ftLibrary; + const char *_lastFontFilePath; + GlyphInfo _glyphInfo[256]; + size_t _glyphSize; + size_t _glyphTileSize; + + void _UpdateHUDString(); + void _SetHUDShowInfoItem(bool &infoItemFlag, const bool visibleState); + + virtual void _UpdateNormalSize() = 0; + virtual void _UpdateOrder() = 0; + virtual void _UpdateRotation() = 0; + virtual void _UpdateClientSize() = 0; + virtual void _UpdateViewScale(); + public: ClientDisplayView(); - ClientDisplayView(const ClientDisplayViewProperties props); - ~ClientDisplayView(); + ClientDisplayView(const ClientDisplayViewProperties &props); + virtual ~ClientDisplayView(); - ClientDisplayViewProperties GetProperties() const; - void SetProperties(const ClientDisplayViewProperties properties); + virtual void Init(); - void SetClientSize(const double w, const double h); + double GetScaleFactor() const; + virtual void SetScaleFactor(const double scaleFactor); + + // NDS screen layout + const ClientDisplayViewProperties& GetViewProperties() const; + void CommitViewProperties(const ClientDisplayViewProperties &props); + virtual void SetupViewProperties(); double GetRotation() const; - void SetRotation(const double r); double GetViewScale() const; ClientDisplayMode GetMode() const; - void SetMode(const ClientDisplayMode mode); ClientDisplayLayout GetLayout() const; - void SetLayout(const ClientDisplayLayout layout); ClientDisplayOrder GetOrder() const; - void SetOrder(const ClientDisplayOrder order); - double GetGapScale() const; - void SetGapWithScalar(const double gapScale); double GetGapDistance() const; - void SetGapWithDistance(const double gapDistance); + // NDS screen filters + bool GetSourceDeposterize(); + virtual void SetSourceDeposterize(const bool useDeposterize); + OutputFilterTypeID GetOutputFilter() const; + virtual void SetOutputFilter(const OutputFilterTypeID filterID); + VideoFilterTypeID GetPixelScaler() const; + virtual void SetPixelScaler(const VideoFilterTypeID filterID); + + // HUD appearance + void SetHUDFontUsingPath(const char *filePath); + virtual void CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, const size_t glyphTileSize, GlyphInfo *glyphInfo); + virtual void SetHUDInfo(const NDSFrameInfo &frameInfo); + + const std::string& GetHUDString() const; + float GetHUDObjectScale() const; + virtual void SetHUDObjectScale(float objectScale); + + bool GetHUDVisibility() const; + virtual void SetHUDVisibility(const bool visibleState); + bool GetHUDShowVideoFPS() const; + virtual void SetHUDShowVideoFPS(const bool visibleState); + bool GetHUDShowRender3DFPS() const; + virtual void SetHUDShowRender3DFPS(const bool visibleState); + bool GetHUDShowFrameIndex() const; + virtual void SetHUDShowFrameIndex(const bool visibleState); + bool GetHUDShowLagFrameCount() const; + virtual void SetHUDShowLagFrameCount(const bool visibleState); + bool GetHUDShowCPULoadAverage() const; + virtual void SetHUDShowCPULoadAverage(const bool visibleState); + bool GetHUDShowRTC() const; + virtual void SetHUDShowRTC(const bool visibleState); + + // NDS GPU interface + virtual void FrameLoadGPU(bool isMainSizeNative, bool isTouchSizeNative) = 0; + virtual void FrameProcessGPU() = 0; + virtual void FrameProcessHUD() = 0; + virtual void FrameRender() = 0; + virtual void FrameFinish() = 0; + + // Touch screen input handling void GetNDSPoint(const int inputID, const bool isInitialTouchPress, const double clientX, const double clientY, u8 &outX, u8 &outY) const; + // Utility methods static void ConvertNormalToTransformedBounds(const double scalar, const double angleDegrees, double &inoutWidth, double &inoutHeight); @@ -115,4 +232,34 @@ public: double &outWidth, double &outHeight); }; +class ClientDisplay3DView : public ClientDisplayView +{ +protected: + bool _canFilterOnGPU; + bool _willFilterOnGPU; + bool _filtersPreferGPU; + +public: + ClientDisplay3DView(); + + bool CanFilterOnGPU() const; + bool GetFiltersPreferGPU() const; + virtual void SetFiltersPreferGPU(const bool preferGPU); + bool WillFilterOnGPU() const; + + virtual void SetSourceDeposterize(const bool useDeposterize); + + virtual void SetVideoBuffers(const uint32_t colorFormat, + const void *videoBufferHead, + const void *nativeBuffer0, + const void *nativeBuffer1, + const void *customBuffer0, const size_t customWidth0, const size_t customHeight0, + const void *customBuffer1, const size_t customWidth1, const size_t customHeight1) = 0; + + virtual void FrameFlush() = 0; + virtual void FrameRenderAndFlush() = 0; + + virtual void UpdateView() = 0; +}; + #endif // _CLIENT_DISPLAY_VIEW_H_ diff --git a/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp b/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp index 672758313..65079f7ee 100644 --- a/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp +++ b/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp @@ -4459,6 +4459,7 @@ OGLInfo::OGLInfo() _useShader150 = false; _isVBOSupported = false; + _isVAOSupported = false; _isPBOSupported = false; _isFBOSupported = false; } @@ -4478,6 +4479,11 @@ bool OGLInfo::IsVBOSupported() return this->_isVBOSupported; } +bool OGLInfo::IsVAOSupported() +{ + return this->_isVAOSupported; +} + bool OGLInfo::IsPBOSupported() { return this->_isPBOSupported; @@ -4577,6 +4583,11 @@ OGLInfo_Legacy::OGLInfo_Legacy() } } + _isVAOSupported = isShaderSupported && + _isVBOSupported && + (this->IsExtensionPresent(oglExtensionSet, "GL_ARB_vertex_array_object") || + this->IsExtensionPresent(oglExtensionSet, "GL_APPLE_vertex_array_object")); + _isPBOSupported = this->IsExtensionPresent(oglExtensionSet, "GL_ARB_vertex_buffer_object") && (this->IsExtensionPresent(oglExtensionSet, "GL_ARB_pixel_buffer_object") || this->IsExtensionPresent(oglExtensionSet, "GL_EXT_pixel_buffer_object")); @@ -4899,10 +4910,89 @@ bool OGLShaderProgram::LinkOGL() OGLVideoOutput::OGLVideoOutput() { - _info = OGLInfoCreate_Func(); - _scaleFactor = 1.0f; + _needUpdateViewport = true; _layerList = new std::vector; _layerList->reserve(8); +} + +OGLVideoOutput::~OGLVideoOutput() +{ + for (size_t i = 0; i < _layerList->size(); i++) + { + delete (*_layerList)[i]; + } + + delete _layerList; + delete _info; +} + +void OGLVideoOutput::_UpdateNormalSize() +{ + this->GetDisplayLayer()->SetNeedsUpdateVertices(); +} + +void OGLVideoOutput::_UpdateOrder() +{ + this->GetDisplayLayer()->SetNeedsUpdateVertices(); +} + +void OGLVideoOutput::_UpdateRotation() +{ + this->GetDisplayLayer()->SetNeedsUpdateRotationScale(); +} + +void OGLVideoOutput::_UpdateClientSize() +{ + this->_viewportWidth = (GLsizei)(this->_renderProperty.clientWidth + 0.0015); + this->_viewportHeight = (GLsizei)(this->_renderProperty.clientHeight + 0.0015); + this->_needUpdateViewport = true; + + this->GetHUDLayer()->SetNeedsUpdateVertices(); +} + +void OGLVideoOutput::_UpdateViewScale() +{ + this->ClientDisplayView::_UpdateViewScale(); + this->GetDisplayLayer()->SetNeedsUpdateRotationScale(); +} + +void OGLVideoOutput::_UpdateViewport() +{ + glViewport(0, 0, this->_viewportWidth, this->_viewportHeight); + + for (size_t i = 0; i < _layerList->size(); i++) + { + OGLVideoLayer *theLayer = (*_layerList)[i]; + + if (theLayer->IsVisible()) + { + theLayer->UpdateViewportOGL(); + } + } + + this->_needUpdateViewport = false; +} + +OGLInfo* OGLVideoOutput::GetInfo() +{ + return this->_info; +} + +void OGLVideoOutput::Init() +{ + this->_info = OGLInfoCreate_Func(); + this->_canFilterOnGPU = ( this->_info->IsShaderSupported() && this->_info->IsFBOSupported() ); + this->_filtersPreferGPU = this->_canFilterOnGPU; + this->_willFilterOnGPU = false; + + for (size_t i = 0; i < _layerList->size(); i++) + { + delete (*_layerList)[i]; + } + + this->_layerList->clear(); + this->_layerList->push_back(new OGLDisplayLayer(this)); + this->_layerList->push_back(new OGLHUDLayer(this)); // Render State Setup (common to both shaders and fixed-function pipeline) glEnable(GL_BLEND); @@ -4926,48 +5016,54 @@ OGLVideoOutput::OGLVideoOutput() glClear(GL_COLOR_BUFFER_BIT); } -OGLVideoOutput::~OGLVideoOutput() +void OGLVideoOutput::SetOutputFilter(const OutputFilterTypeID filterID) { - for (size_t i = 0; i < _layerList->size(); i++) - { - delete (*_layerList)[i]; - } + this->_outputFilter = this->GetDisplayLayer()->SetOutputFilterOGL(filterID); + this->GetDisplayLayer()->SetNeedsUpdateRotationScale(); + this->_needUpdateViewport = true; +} + +void OGLVideoOutput::SetPixelScaler(const VideoFilterTypeID filterID) +{ + std::string cpuTypeIDString = std::string( VideoFilter::GetTypeStringByID(filterID) ); + const VideoFilterTypeID newFilterID = (cpuTypeIDString != std::string(VIDEOFILTERTYPE_UNKNOWN_STRING)) ? filterID : VideoFilterTypeID_None; - delete _layerList; - delete _info; -} - -void OGLVideoOutput::InitLayers() -{ - for (size_t i = 0; i < _layerList->size(); i++) - { - delete (*_layerList)[i]; - } + this->GetDisplayLayer()->SetCPUPixelScalerOGL(newFilterID); - this->_layerList->clear(); - this->_layerList->push_back(new OGLDisplayLayer(this)); - this->_layerList->push_back(new OGLHUDLayer(this)); + this->_pixelScaler = newFilterID; + this->_willFilterOnGPU = (this->GetFiltersPreferGPU()) ? this->GetDisplayLayer()->SetGPUPixelScalerOGL(newFilterID) : false; } -OGLInfo* OGLVideoOutput::GetInfo() +void OGLVideoOutput::CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, const size_t glyphTileSize, GlyphInfo *glyphInfo) { - return this->_info; + this->GetHUDLayer()->CopyHUDFont(fontFace, glyphSize, glyphTileSize, glyphInfo); } -float OGLVideoOutput::GetScaleFactor() +void OGLVideoOutput::SetHUDVisibility(const bool visibleState) { - return this->_scaleFactor; + this->ClientDisplay3DView::SetHUDVisibility(visibleState); + this->GetHUDLayer()->SetVisibility(visibleState); } -void OGLVideoOutput::SetScaleFactor(float scaleFactor) +void OGLVideoOutput::SetFiltersPreferGPU(const bool preferGPU) { - this->_scaleFactor = scaleFactor; + this->_filtersPreferGPU = preferGPU; + this->_willFilterOnGPU = (preferGPU) ? this->GetDisplayLayer()->SetGPUPixelScalerOGL(this->_pixelScaler) : false; - for (size_t i = 0; i < _layerList->size(); i++) - { - OGLVideoLayer *theLayer = (*_layerList)[i]; - theLayer->SetScaleFactor(scaleFactor); - } + this->GetDisplayLayer()->SetFiltersPreferGPUOGL(); +} + +void OGLVideoOutput::SetVideoBuffers(const uint32_t colorFormat, + const void *videoBufferHead, + const void *nativeBuffer0, + const void *nativeBuffer1, + const void *customBuffer0, const size_t customWidth0, const size_t customHeight0, + const void *customBuffer1, const size_t customWidth1, const size_t customHeight1) +{ + this->GetDisplayLayer()->SetVideoBuffers(colorFormat, videoBufferHead, + nativeBuffer0, nativeBuffer1, + customBuffer0, customWidth0, customHeight0, + customBuffer1, customWidth1, customHeight1); } GLsizei OGLVideoOutput::GetViewportWidth() @@ -4990,42 +5086,35 @@ OGLHUDLayer* OGLVideoOutput::GetHUDLayer() return (OGLHUDLayer *)this->_layerList->at(1); } -void OGLVideoOutput::SetViewportSizeOGL(GLsizei w, GLsizei h) +void OGLVideoOutput::FrameLoadGPU(bool isMainSizeNative, bool isTouchSizeNative) { - this->_viewportWidth = w; - this->_viewportHeight = h; - glViewport(0, 0, w, h); + this->GetDisplayLayer()->LoadFrameOGL(isMainSizeNative, isTouchSizeNative); +} + +void OGLVideoOutput::FrameProcessGPU() +{ + OGLDisplayLayer *displayLayer = this->GetDisplayLayer(); + if (displayLayer->IsVisible()) + { + displayLayer->ProcessOGL(); + } +} + +void OGLVideoOutput::FrameProcessHUD() +{ + if (this->GetHUDVisibility()) + { + this->GetHUDLayer()->ProcessOGL(); + } +} + +void OGLVideoOutput::FrameRender() +{ + if (this->_needUpdateViewport) + { + this->_UpdateViewport(); + } - for (size_t i = 0; i < _layerList->size(); i++) - { - OGLVideoLayer *theLayer = (*_layerList)[i]; - - if (theLayer->IsVisible()) - { - theLayer->SetViewportSizeOGL(w, h); - } - else - { - theLayer->OGLVideoLayer::SetViewportSizeOGL(w, h); - } - } -} - -void OGLVideoOutput::ProcessOGL() -{ - for (size_t i = 0; i < _layerList->size(); i++) - { - OGLVideoLayer *theLayer = (*_layerList)[i]; - - if (theLayer->IsVisible()) - { - theLayer->ProcessOGL(); - } - } -} - -void OGLVideoOutput::RenderOGL() -{ glClear(GL_COLOR_BUFFER_BIT); for (size_t i = 0; i < _layerList->size(); i++) @@ -5039,7 +5128,7 @@ void OGLVideoOutput::RenderOGL() } } -void OGLVideoOutput::FinishOGL() +void OGLVideoOutput::FrameFinish() { for (size_t i = 0; i < _layerList->size(); i++) { @@ -6121,14 +6210,9 @@ void OGLImage::RenderOGL() #pragma mark - -float OGLVideoLayer::GetScaleFactor() +void OGLVideoLayer::SetNeedsUpdateVertices() { - return this->_scaleFactor; -} - -void OGLVideoLayer::SetScaleFactor(float scaleFactor) -{ - this->_scaleFactor = scaleFactor; + this->_needUpdateVertices = true; } bool OGLVideoLayer::IsVisible() @@ -6141,7 +6225,7 @@ void OGLVideoLayer::SetVisibility(const bool visibleState) if (!this->_isVisible && visibleState) { this->_isVisible = visibleState; - this->SetViewportSizeOGL(this->_viewportWidth, this->_viewportHeight); + this->UpdateViewportOGL(); this->ProcessOGL(); return; @@ -6150,47 +6234,19 @@ void OGLVideoLayer::SetVisibility(const bool visibleState) this->_isVisible = visibleState; } -void OGLVideoLayer::SetViewportSizeOGL(GLsizei w, GLsizei h) -{ - this->_viewportWidth = w; - this->_viewportHeight = h; -}; - #pragma mark - OGLHUDLayer::OGLHUDLayer(OGLVideoOutput *oglVO) { - FT_Error error = FT_Init_FreeType(&_ftLibrary); - if (error) - { - printf("OGLVideoOutput: FreeType failed to init!\n"); - } - - _scaleFactor = oglVO->GetScaleFactor(); - + _needUpdateVertices = true; _isVisible = false; - _showVideoFPS = false; - _showRender3DFPS = false; - _showFrameIndex = false; - _showLagFrameCount = false; - _showCPULoadAverage = false; - _showRTC = false; - - _lastVideoFPS = 0; - _lastRender3DFPS = 0; - _lastFrameIndex = 0; - _lastLagFrameCount = 0; - _lastCpuLoadAvgARM9 = 0; - _lastCpuLoadAvgARM7 = 0; - memset(_lastRTCString, 0, sizeof(_lastRTCString)); - - _hudObjectScale = 1.00f; - - _isVAOPresent = true; _output = oglVO; - _canUseShaderOutput = oglVO->GetInfo()->IsShaderSupported(); - if (_canUseShaderOutput) + _glyphInfo = NULL; + _glyphSize = 0.0f; + _glyphTileSize = 0.0f; + + if (_output->GetInfo()->IsShaderSupported()) { _program = new OGLShaderProgram; _program->SetShaderSupport(oglVO->GetInfo()->GetShaderSupport()); @@ -6205,19 +6261,6 @@ OGLHUDLayer::OGLHUDLayer(OGLVideoOutput *oglVO) _program = NULL; } - memset(this->_glyphInfo, 0, sizeof(this->_glyphInfo)); - _statusString = "\x01"; // Char value 0x01 will represent the "text box" character, which will always be first in the string. - _glyphTileSize = HUD_TEXTBOX_BASEGLYPHSIZE * _scaleFactor; - _glyphSize = (GLfloat)_glyphTileSize * 0.75f; - - // Set up the text box, which resides at glyph position 1. - GlyphInfo &boxInfo = this->_glyphInfo[1]; - boxInfo.width = this->_glyphTileSize; - boxInfo.texCoord[0] = 1.0f/16.0f; boxInfo.texCoord[1] = 0.0f; - boxInfo.texCoord[2] = 2.0f/16.0f; boxInfo.texCoord[3] = 0.0f; - boxInfo.texCoord[4] = 2.0f/16.0f; boxInfo.texCoord[5] = 1.0f/16.0f; - boxInfo.texCoord[6] = 1.0f/16.0f; boxInfo.texCoord[7] = 1.0f/16.0f; - glGenTextures(1, &_texCharMap); // Set up VBOs @@ -6280,7 +6323,7 @@ OGLHUDLayer::OGLHUDLayer(OGLVideoOutput *oglVO) OGLHUDLayer::~OGLHUDLayer() { - if (_canUseShaderOutput) + if (_output->GetInfo()->IsShaderSupported()) { glUseProgram(0); delete this->_program; @@ -6292,26 +6335,15 @@ OGLHUDLayer::~OGLHUDLayer() glDeleteBuffersARB(1, &this->_vboElementID); glDeleteTextures(1, &this->_texCharMap); - - FT_Done_FreeType(this->_ftLibrary); } -void OGLHUDLayer::SetFontUsingPath(const char *filePath) +void OGLHUDLayer::CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, const size_t glyphTileSize, GlyphInfo *glyphInfo) { - FT_Face fontFace; FT_Error error = FT_Err_Ok; - error = FT_New_Face(this->_ftLibrary, filePath, 0, &fontFace); - if (error == FT_Err_Unknown_File_Format) - { - printf("OGLVideoOutput: FreeType failed to load font face because it is in an unknown format from:\n%s\n", filePath); - return; - } - else if (error) - { - printf("OGLVideoOutput: FreeType failed to load font face with an unknown error from:\n%s\n", filePath); - return; - } + this->_glyphInfo = glyphInfo; + this->_glyphSize = (GLfloat)glyphSize; + this->_glyphTileSize = (GLfloat)glyphTileSize; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, this->_texCharMap); @@ -6321,7 +6353,7 @@ void OGLHUDLayer::SetFontUsingPath(const char *filePath) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GLint texLevel = 0; - for (size_t tileSize = this->_glyphTileSize, glyphSize = this->_glyphSize; tileSize >= 4; texLevel++, tileSize >>= 1, glyphSize = (GLfloat)tileSize * 0.75f) + for (size_t tileSize = glyphTileSize, gSize = glyphSize; tileSize >= 4; texLevel++, tileSize >>= 1, gSize = (GLfloat)tileSize * 0.75f) { const size_t charMapBufferPixCount = (16 * tileSize) * (16 * tileSize); @@ -6332,7 +6364,7 @@ void OGLHUDLayer::SetFontUsingPath(const char *filePath) charMapBuffer[i] = fontColor; } - error = FT_Set_Char_Size(fontFace, glyphSize << 6, glyphSize << 6, 72, 72); + error = FT_Set_Char_Size(fontFace, gSize << 6, gSize << 6, 72, 72); if (error) { printf("OGLVideoOutput: FreeType failed to set the font size!\n"); @@ -6361,18 +6393,18 @@ void OGLHUDLayer::SetFontUsingPath(const char *filePath) const uint16_t tileOffsetX = (c & 0x0F) * tileSize; const uint16_t tileOffsetY = (c >> 4) * tileSize; - const uint16_t tileOffsetY_texture = tileOffsetY - (tileSize - glyphSize + (glyphSize / 16)); + const uint16_t tileOffsetY_texture = tileOffsetY - (tileSize - gSize + (gSize / 16)); const uint16_t texSize = tileSize * 16; const GLuint glyphWidth = glyphSlot->bitmap.width; - if (tileSize == this->_glyphTileSize) + if (tileSize == glyphTileSize) { - GlyphInfo &glyphInfo = this->_glyphInfo[c]; - glyphInfo.width = (c != ' ') ? glyphWidth : (GLfloat)tileSize / 5.0f; - glyphInfo.texCoord[0] = (GLfloat)tileOffsetX / (GLfloat)texSize; glyphInfo.texCoord[1] = (GLfloat)tileOffsetY / (GLfloat)texSize; - glyphInfo.texCoord[2] = (GLfloat)(tileOffsetX + glyphWidth) / (GLfloat)texSize; glyphInfo.texCoord[3] = (GLfloat)tileOffsetY / (GLfloat)texSize; - glyphInfo.texCoord[4] = (GLfloat)(tileOffsetX + glyphWidth) / (GLfloat)texSize; glyphInfo.texCoord[5] = (GLfloat)(tileOffsetY + tileSize) / (GLfloat)texSize; - glyphInfo.texCoord[6] = (GLfloat)tileOffsetX / (GLfloat)texSize; glyphInfo.texCoord[7] = (GLfloat)(tileOffsetY + tileSize) / (GLfloat)texSize; + GlyphInfo &gi = glyphInfo[c]; + gi.width = (c != ' ') ? glyphWidth : (GLfloat)tileSize / 5.0f; + gi.texCoord[0] = (GLfloat)tileOffsetX / (GLfloat)texSize; gi.texCoord[1] = (GLfloat)tileOffsetY / (GLfloat)texSize; + gi.texCoord[2] = (GLfloat)(tileOffsetX + glyphWidth) / (GLfloat)texSize; gi.texCoord[3] = (GLfloat)tileOffsetY / (GLfloat)texSize; + gi.texCoord[4] = (GLfloat)(tileOffsetX + glyphWidth) / (GLfloat)texSize; gi.texCoord[5] = (GLfloat)(tileOffsetY + tileSize) / (GLfloat)texSize; + gi.texCoord[6] = (GLfloat)tileOffsetX / (GLfloat)texSize; gi.texCoord[7] = (GLfloat)(tileOffsetY + tileSize) / (GLfloat)texSize; } // Draw the glyph to the client-side buffer. @@ -6392,158 +6424,19 @@ void OGLHUDLayer::SetFontUsingPath(const char *filePath) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, texLevel - 1); glBindTexture(GL_TEXTURE_2D, 0); - - FT_Done_Face(fontFace); - this->_lastFontFilePath = filePath; } -void OGLHUDLayer::SetInfo(const uint32_t videoFPS, const uint32_t render3DFPS, const uint32_t frameIndex, const uint32_t lagFrameCount, const char *rtcString, const uint32_t cpuLoadAvgARM9, const uint32_t cpuLoadAvgARM7) +void OGLHUDLayer::_UpdateVerticesOGL() { - this->_lastVideoFPS = videoFPS; - this->_lastRender3DFPS = render3DFPS; - this->_lastFrameIndex = frameIndex; - this->_lastLagFrameCount = lagFrameCount; - this->_lastCpuLoadAvgARM9 = cpuLoadAvgARM9; - this->_lastCpuLoadAvgARM7 = cpuLoadAvgARM7; - memcpy(this->_lastRTCString, rtcString, sizeof(this->_lastRTCString)); - - this->RefreshInfo(); -} - -void OGLHUDLayer::RefreshInfo() -{ - std::ostringstream ss; - ss << "\x01"; // This represents the text box. It must always be the first character. - - if (this->_showVideoFPS) - { - ss << "Video FPS: " << this->_lastVideoFPS << "\n"; - } - - if (this->_showRender3DFPS) - { - ss << "3D Rendering FPS: " << this->_lastRender3DFPS << "\n"; - } - - if (this->_showFrameIndex) - { - ss << "Frame Index: " << this->_lastFrameIndex << "\n"; - } - - if (this->_showLagFrameCount) - { - ss << "Lag Frame Count: " << this->_lastLagFrameCount << "\n"; - } - - if (this->_showCPULoadAverage) - { - static char buffer[32]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, 25, "CPU Load Avg: %02d%% / %02d%%\n", this->_lastCpuLoadAvgARM9, this->_lastCpuLoadAvgARM7); - - ss << buffer; - } - - if (this->_showRTC) - { - ss << "RTC: " << this->_lastRTCString << "\n"; - } - - this->_statusString = ss.str(); -} - -void OGLHUDLayer::_SetShowInfoItemOGL(bool &infoItemFlag, const bool visibleState) -{ - if (infoItemFlag == visibleState) - { - return; - } - - infoItemFlag = visibleState; - this->RefreshInfo(); - this->ProcessOGL(); -} - -void OGLHUDLayer::SetObjectScale(float objectScale) -{ - this->_hudObjectScale = objectScale; -} - -float OGLHUDLayer::GetObjectScale() const -{ - return this->_hudObjectScale; -} - -void OGLHUDLayer::SetShowVideoFPS(const bool visibleState) -{ - this->_SetShowInfoItemOGL(this->_showVideoFPS, visibleState); -} - -bool OGLHUDLayer::GetShowVideoFPS() const -{ - return this->_showVideoFPS; -} - -void OGLHUDLayer::SetShowRender3DFPS(const bool visibleState) -{ - this->_SetShowInfoItemOGL(this->_showRender3DFPS, visibleState); -} - -bool OGLHUDLayer::GetShowRender3DFPS() const -{ - return this->_showRender3DFPS; -} - -void OGLHUDLayer::SetShowFrameIndex(const bool visibleState) -{ - this->_SetShowInfoItemOGL(this->_showFrameIndex, visibleState); -} - -bool OGLHUDLayer::GetShowFrameIndex() const -{ - return this->_showFrameIndex; -} - -void OGLHUDLayer::SetShowLagFrameCount(const bool visibleState) -{ - this->_SetShowInfoItemOGL(this->_showLagFrameCount, visibleState); -} - -bool OGLHUDLayer::GetShowLagFrameCount() const -{ - return this->_showLagFrameCount; -} - -void OGLHUDLayer::SetShowCPULoadAverage(const bool visibleState) -{ - this->_SetShowInfoItemOGL(this->_showCPULoadAverage, visibleState); -} - -bool OGLHUDLayer::GetShowCPULoadAverage() const -{ - return this->_showCPULoadAverage; -} - -void OGLHUDLayer::SetShowRTC(const bool visibleState) -{ - this->_SetShowInfoItemOGL(this->_showRTC, visibleState); -} - -bool OGLHUDLayer::GetShowRTC() const -{ - return this->_showRTC; -} - -void OGLHUDLayer::ProcessVerticesOGL() -{ - const size_t length = this->_statusString.length(); + const size_t length = this->_output->GetHUDString().length(); if (length <= 1) { + this->_needUpdateVertices = false; return; } - const char *cString = this->_statusString.c_str(); - const GLfloat charSize = (GLfloat)this->_glyphSize; + const char *cString = this->_output->GetHUDString().c_str(); + const GLfloat charSize = this->_glyphSize; const GLfloat lineHeight = charSize * 0.8f; const GLfloat textBoxTextOffset = charSize * 0.25f; GLfloat charLocX = textBoxTextOffset; @@ -6581,7 +6474,7 @@ void OGLHUDLayer::ProcessVerticesOGL() continue; } - const GLfloat charWidth = this->_glyphInfo[c].width * charSize / (GLfloat)this->_glyphTileSize; + const GLfloat charWidth = this->_glyphInfo[c].width * charSize / this->_glyphTileSize; vtxBufferPtr[(i*8)+0] = charLocX; vtxBufferPtr[(i*8)+1] = charLocY + charSize; // Top Left vtxBufferPtr[(i*8)+2] = charLocX + charWidth; vtxBufferPtr[(i*8)+3] = charLocY + charSize; // Top Right @@ -6590,13 +6483,13 @@ void OGLHUDLayer::ProcessVerticesOGL() charLocX += (charWidth + (charSize * 0.03f) + 0.10f); } - GLfloat textBoxScale = HUD_TEXTBOX_BASE_SCALE * this->_hudObjectScale; + GLfloat textBoxScale = HUD_TEXTBOX_BASE_SCALE * this->_output->GetHUDObjectScale(); if (textBoxScale < (HUD_TEXTBOX_BASE_SCALE * HUD_TEXTBOX_MIN_SCALE)) { textBoxScale = HUD_TEXTBOX_BASE_SCALE * HUD_TEXTBOX_MIN_SCALE; } - GLfloat boxOffset = 8.0f * HUD_TEXTBOX_BASE_SCALE * this->_hudObjectScale; + GLfloat boxOffset = 8.0f * HUD_TEXTBOX_BASE_SCALE * this->_output->GetHUDObjectScale(); if (boxOffset < 1.0f) { boxOffset = 1.0f; @@ -6606,7 +6499,7 @@ void OGLHUDLayer::ProcessVerticesOGL() boxOffset = 8.0f; } - boxOffset *= this->_scaleFactor; + boxOffset *= this->_output->GetScaleFactor(); // Set the width of the text box vtxBufferPtr[2] += textBoxWidth; @@ -6620,47 +6513,31 @@ void OGLHUDLayer::ProcessVerticesOGL() vtxBufferPtr[i+1] *= textBoxScale; // Translate - vtxBufferPtr[i+0] += boxOffset - (this->_viewportWidth / 2.0f); - vtxBufferPtr[i+1] += (this->_viewportHeight / 2.0f) - boxOffset; + vtxBufferPtr[i+0] += boxOffset - (this->_output->GetViewportWidth() / 2.0f); + vtxBufferPtr[i+1] += (this->_output->GetViewportHeight() / 2.0f) - boxOffset; } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + + this->_needUpdateVertices = false; } -void OGLHUDLayer::SetScaleFactor(float scaleFactor) +void OGLHUDLayer::UpdateViewportOGL() { - const bool willChangeScaleFactor = (this->_scaleFactor != scaleFactor); - OGLVideoLayer::SetScaleFactor(scaleFactor); - - if (willChangeScaleFactor) - { - this->_glyphTileSize = HUD_TEXTBOX_BASEGLYPHSIZE * this->_scaleFactor; - this->_glyphSize = (GLfloat)this->_glyphTileSize * 0.75f; - - this->SetFontUsingPath(this->_lastFontFilePath); - } -} - -void OGLHUDLayer::SetViewportSizeOGL(GLsizei w, GLsizei h) -{ - this->OGLVideoLayer::SetViewportSizeOGL(w, h); - glUseProgram(this->_program->GetProgramID()); - glUniform2f(this->_uniformViewSize, this->_viewportWidth, this->_viewportHeight); - - this->ProcessVerticesOGL(); + glUniform2f(this->_uniformViewSize, this->_output->GetViewProperties().clientWidth, this->_output->GetViewProperties().clientHeight); }; void OGLHUDLayer::ProcessOGL() { - const size_t length = this->_statusString.length(); + const size_t length = this->_output->GetHUDString().length(); if (length <= 1) { return; } - const char *cString = this->_statusString.c_str(); + const char *cString = this->_output->GetHUDString().c_str(); glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboTexCoordID); glBufferDataARB(GL_ARRAY_BUFFER_ARB, HUD_VERTEX_ATTRIBUTE_BUFFER_SIZE, NULL, GL_STREAM_DRAW_ARB); @@ -6669,7 +6546,7 @@ void OGLHUDLayer::ProcessOGL() for (size_t i = 0; i < length; i++) { const char c = cString[i]; - GLfloat *glyphTexCoord = this->_glyphInfo[c].texCoord; + const float *glyphTexCoord = this->_glyphInfo[c].texCoord; GLfloat *hudTexCoord = &texCoordBufferPtr[i * 8]; hudTexCoord[0] = glyphTexCoord[0]; @@ -6685,18 +6562,26 @@ void OGLHUDLayer::ProcessOGL() glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - this->ProcessVerticesOGL(); + this->_needUpdateVertices = true; } void OGLHUDLayer::RenderOGL() { - const size_t length = this->_statusString.length(); + const size_t length = this->_output->GetHUDString().length(); if (length <= 1) { return; } - glUseProgram(this->_program->GetProgramID()); + if (this->_output->GetInfo()->IsShaderSupported()) + { + glUseProgram(this->_program->GetProgramID()); + } + + if (this->_needUpdateVertices) + { + this->_UpdateVerticesOGL(); + } glBindVertexArrayDESMUME(this->_vaoMainStatesID); glBindTexture(GL_TEXTURE_2D, this->_texCharMap); @@ -6707,7 +6592,7 @@ void OGLHUDLayer::RenderOGL() glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); // Next, draw each character inside the box. - const GLfloat textBoxScale = (GLfloat)HUD_TEXTBOX_BASE_SCALE * this->_hudObjectScale; + const GLfloat textBoxScale = (GLfloat)HUD_TEXTBOX_BASE_SCALE * this->_output->GetHUDObjectScale(); if (textBoxScale >= (2.0/3.0)) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -6733,17 +6618,8 @@ OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO) _isVisible = true; _output = oglVO; _useClientStorage = GL_FALSE; + _needUpdateRotationScale = true; _needUpdateVertices = true; - _useDeposterize = false; - - _displayMode = ClientDisplayMode_Dual; - _displayOrder = ClientDisplayOrder_MainFirst; - _displayOrientation = ClientDisplayLayout_Vertical; - - _gapScalar = 0.0f; - _rotation = 0.0f; - _normalWidth = GPU_FRAMEBUFFER_NATIVE_WIDTH; - _normalHeight = GPU_FRAMEBUFFER_NATIVE_HEIGHT*2.0 + (DS_DISPLAY_UNSCALED_GAP*_gapScalar); _vf[0] = new VideoFilter(GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, VideoFilterTypeID_None, 0); _vf[1] = new VideoFilter(GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, VideoFilterTypeID_None, 0); @@ -6861,13 +6737,10 @@ OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO) } glBindVertexArrayDESMUME(0); - _isVAOPresent = true; - _pixelScaler = VideoFilterTypeID_None; _useShader150 = _output->GetInfo()->IsUsingShader150(); _shaderSupport = _output->GetInfo()->GetShaderSupport(); - _canUseShaderOutput = _output->GetInfo()->IsShaderSupported(); - if (_canUseShaderOutput) + if (_output->GetInfo()->IsShaderSupported()) { _finalOutputProgram = new OGLShaderProgram; _finalOutputProgram->SetShaderSupport(_shaderSupport); @@ -6885,8 +6758,7 @@ OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO) _finalOutputProgram = NULL; } - _canUseShaderBasedFilters = (_canUseShaderOutput && _output->GetInfo()->IsFBOSupported()); - if (_canUseShaderBasedFilters) + if (_output->CanFilterOnGPU()) { for (size_t i = 0; i < 2; i++) { @@ -6907,18 +6779,13 @@ OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO) _shaderFilter[0] = NULL; _shaderFilter[1] = NULL; } - - _useShaderBasedPixelScaler = false; - _filtersPreferGPU = true; - _outputFilter = OutputFilterTypeID_Bilinear; } OGLDisplayLayer::~OGLDisplayLayer() { - if (_isVAOPresent) + if (_output->GetInfo()->IsVAOSupported()) { glDeleteVertexArraysDESMUME(1, &this->_vaoMainStatesID); - _isVAOPresent = false; } glDeleteBuffersARB(1, &this->_vboVertexID); @@ -6935,13 +6802,13 @@ OGLDisplayLayer::~OGLDisplayLayer() glDeleteTextures(1, &this->_texHQ4xLUT); glActiveTexture(GL_TEXTURE0); - if (_canUseShaderOutput) + if (_output->GetInfo()->IsShaderSupported()) { glUseProgram(0); delete this->_finalOutputProgram; } - if (_canUseShaderBasedFilters) + if (_output->CanFilterOnGPU()) { delete this->_filterDeposterize[0]; delete this->_filterDeposterize[1]; @@ -6999,7 +6866,7 @@ void OGLDisplayLayer::UploadHQnxLUTs() void OGLDisplayLayer::DetermineTextureStorageHints(GLint &videoSrcTexStorageHint, GLint &cpuFilterTexStorageHint) { - const bool isUsingCPUPixelScaler = (this->_pixelScaler != VideoFilterTypeID_None) && !this->_useShaderBasedPixelScaler; + const bool isUsingCPUPixelScaler = (this->_output->GetPixelScaler() != VideoFilterTypeID_None) && !this->_output->WillFilterOnGPU(); videoSrcTexStorageHint = GL_STORAGE_PRIVATE_APPLE; cpuFilterTexStorageHint = GL_STORAGE_PRIVATE_APPLE; @@ -7086,16 +6953,13 @@ void OGLDisplayLayer::SetVideoBuffers(const uint32_t colorFormat, glFinish(); } -bool OGLDisplayLayer::GetFiltersPreferGPU() +void OGLDisplayLayer::SetNeedsUpdateRotationScale() { - return this->_filtersPreferGPU; + this->_needUpdateRotationScale = true; } -void OGLDisplayLayer::SetFiltersPreferGPUOGL(bool preferGPU) +void OGLDisplayLayer::SetFiltersPreferGPUOGL() { - this->_filtersPreferGPU = preferGPU; - this->_useShaderBasedPixelScaler = (preferGPU) ? this->SetGPUPixelScalerOGL(this->_pixelScaler) : false; - GLint videoSrcTexStorageHint = GL_STORAGE_PRIVATE_APPLE; GLint cpuFilterTexStorageHint = GL_STORAGE_PRIVATE_APPLE; this->DetermineTextureStorageHints(videoSrcTexStorageHint, cpuFilterTexStorageHint); @@ -7116,85 +6980,43 @@ void OGLDisplayLayer::SetFiltersPreferGPUOGL(bool preferGPU) glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); } -ClientDisplayMode OGLDisplayLayer::GetMode() const +void OGLDisplayLayer::_UpdateRotationScaleOGL() { - return this->_displayMode; + const ClientDisplayViewProperties &cdv = this->_output->GetViewProperties(); + + const double r = cdv.rotation; + const double s = cdv.viewScale; + + if (this->_output->GetInfo()->IsShaderSupported()) + { + glUniform1f(this->_uniformFinalOutputAngleDegrees, r); + glUniform1f(this->_uniformFinalOutputScalar, s); + } + else + { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glRotatef(r, 0.0f, 0.0f, 1.0f); + glScalef(s, s, 1.0f); + } + + //this->_needUpdateRotationScale = false; } -void OGLDisplayLayer::SetMode(const ClientDisplayMode dispMode) +void OGLDisplayLayer::_UpdateVerticesOGL() { - this->_displayMode = dispMode; - ClientDisplayView::CalculateNormalSize(this->_displayMode, this->_displayOrientation, this->_gapScalar, this->_normalWidth, this->_normalHeight); - this->_needUpdateVertices = true; -} - -ClientDisplayLayout OGLDisplayLayer::GetOrientation() const -{ - return this->_displayOrientation; -} - -void OGLDisplayLayer::SetOrientation(ClientDisplayLayout dispOrientation) -{ - this->_displayOrientation = dispOrientation; - ClientDisplayView::CalculateNormalSize(this->_displayMode, this->_displayOrientation, this->_gapScalar, this->_normalWidth, this->_normalHeight); - this->_needUpdateVertices = true; -} - -double OGLDisplayLayer::GetGapScalar() const -{ - return this->_gapScalar; -} - -void OGLDisplayLayer::SetGapScalar(double theScalar) -{ - this->_gapScalar = theScalar; - ClientDisplayView::CalculateNormalSize(this->_displayMode, this->_displayOrientation, this->_gapScalar, this->_normalWidth, this->_normalHeight); - this->_needUpdateVertices = true; -} - -double OGLDisplayLayer::GetRotation() const -{ - return this->_rotation; -} - -void OGLDisplayLayer::SetRotation(double theRotation) -{ - this->_rotation = theRotation; -} - -bool OGLDisplayLayer::GetSourceDeposterize() -{ - return this->_useDeposterize; -} - -void OGLDisplayLayer::SetSourceDeposterize(bool useDeposterize) -{ - this->_useDeposterize = (this->_canUseShaderBasedFilters) ? useDeposterize : false; -} - -ClientDisplayOrder OGLDisplayLayer::GetOrder() const -{ - return this->_displayOrder; -} - -void OGLDisplayLayer::SetOrder(ClientDisplayOrder dispOrder) -{ - this->_displayOrder = dispOrder; - this->_needUpdateVertices = true; -} - -void OGLDisplayLayer::UpdateVerticesOGL() -{ - const GLfloat w = this->_normalWidth / 2.0f; - const GLfloat h = this->_normalHeight / 2.0f; - const size_t f = (this->_displayOrder == ClientDisplayOrder_MainFirst) ? 0 : 8; + const ClientDisplayViewProperties &cdv = this->_output->GetViewProperties(); + + const GLfloat w = cdv.normalWidth / 2.0f; + const GLfloat h = cdv.normalHeight / 2.0f; + const size_t f = (cdv.order == ClientDisplayOrder_MainFirst) ? 0 : 8; glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboVertexID); GLfloat *vtxBufferPtr = (GLfloat *)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - if (this->_displayMode == ClientDisplayMode_Dual) + if (cdv.mode == ClientDisplayMode_Dual) { - switch (this->_displayOrientation) + switch (cdv.layout) { case ClientDisplayLayout_Horizontal: { @@ -7235,7 +7057,7 @@ void OGLDisplayLayer::UpdateVerticesOGL() case ClientDisplayLayout_Hybrid_16_9: { - const GLfloat g = (GLfloat)DS_DISPLAY_UNSCALED_GAP * this->_gapScalar * (this->_normalWidth - (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH) / (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH; + const GLfloat g = (GLfloat)cdv.gapDistance * (cdv.normalWidth - (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH) / (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH; vtxBufferPtr[0] = -w + (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH; vtxBufferPtr[1] = -h + g + (64.0f * 2.0f); // Minor top display, top left vtxBufferPtr[2] = w; vtxBufferPtr[3] = -h + g + (64.0f * 2.0f); // Minor top display, top right @@ -7258,7 +7080,7 @@ void OGLDisplayLayer::UpdateVerticesOGL() case ClientDisplayLayout_Hybrid_16_10: { - const GLfloat g = (GLfloat)DS_DISPLAY_UNSCALED_GAP * this->_gapScalar * (this->_normalWidth - (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH) / (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH; + const GLfloat g = (GLfloat)cdv.gapDistance * (cdv.normalWidth - (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH) / (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH; vtxBufferPtr[0] = -w + (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH; vtxBufferPtr[1] = -h + g + (38.4f * 2.0f); // Minor top display, top left vtxBufferPtr[2] = w; vtxBufferPtr[3] = -h + g + (38.4f * 2.0f); // Minor top display, top right @@ -7281,7 +7103,7 @@ void OGLDisplayLayer::UpdateVerticesOGL() default: // Default to vertical orientation. { - const GLfloat g = (GLfloat)DS_DISPLAY_UNSCALED_GAP * this->_gapScalar; + const GLfloat g = (GLfloat)cdv.gapDistance; vtxBufferPtr[0+f] = -w; vtxBufferPtr[1+f] = h; // Top display, top left vtxBufferPtr[2+f] = w; vtxBufferPtr[3+f] = h; // Top display, top right @@ -7313,18 +7135,7 @@ void OGLDisplayLayer::UpdateVerticesOGL() glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - this->_needUpdateVertices = false; -} - -bool OGLDisplayLayer::CanUseShaderBasedFilters() -{ - return this->_canUseShaderBasedFilters; -} - -void OGLDisplayLayer::GetNormalSize(double &outWidth, double &outHeight) const -{ - outWidth = this->_normalWidth; - outHeight = this->_normalHeight; + //this->_needUpdateVertices = false; } void OGLDisplayLayer::ResizeCPUPixelScalerOGL(const size_t srcWidthMain, const size_t srcHeightMain, const size_t srcWidthTouch, const size_t srcHeightTouch, const size_t scaleMultiply, const size_t scaleDivide) @@ -7370,51 +7181,16 @@ void OGLDisplayLayer::ResizeCPUPixelScalerOGL(const size_t srcWidthMain, const s free(oldMasterBuffer); } -void OGLDisplayLayer::UploadTransformationOGL() +OutputFilterTypeID OGLDisplayLayer::SetOutputFilterOGL(const OutputFilterTypeID filterID) { - const GLdouble w = this->_viewportWidth; - const GLdouble h = this->_viewportHeight; + OutputFilterTypeID outputFilter = OutputFilterTypeID_NearestNeighbor; - double checkWidth = this->_normalWidth; - double checkHeight = this->_normalHeight; - ClientDisplayView::ConvertNormalToTransformedBounds(1.0, this->_rotation, checkWidth, checkHeight); - const GLdouble s = ClientDisplayView::GetMaxScalarWithinBounds(checkWidth, checkHeight, w, h); - - if (this->_output->GetInfo()->IsShaderSupported()) - { - glUniform2f(this->_uniformFinalOutputViewSize, w, h); - glUniform1f(this->_uniformFinalOutputAngleDegrees, this->_rotation); - glUniform1f(this->_uniformFinalOutputScalar, s); - } - else - { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(-w/2.0, -w/2.0 + w, -h/2.0, -h/2.0 + h, -1.0, 1.0); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glRotatef(this->_rotation, 0.0f, 0.0f, 1.0f); - glScalef(s, s, 1.0f); - } - - glViewport(0, 0, this->_viewportWidth, this->_viewportHeight); - this->_needUpdateVertices = true; -} - -int OGLDisplayLayer::GetOutputFilter() -{ - return this->_outputFilter; -} - -void OGLDisplayLayer::SetOutputFilterOGL(const int filterID) -{ this->_displayTexFilter[0] = GL_NEAREST; this->_displayTexFilter[1] = GL_NEAREST; - if (this->_canUseShaderBasedFilters) + if (this->_output->CanFilterOnGPU()) { - this->_outputFilter = filterID; + outputFilter = filterID; switch (filterID) { @@ -7459,7 +7235,7 @@ void OGLDisplayLayer::SetOutputFilterOGL(const int filterID) default: this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150); - this->_outputFilter = OutputFilterTypeID_NearestNeighbor; + outputFilter = OutputFilterTypeID_NearestNeighbor; break; } } @@ -7469,35 +7245,18 @@ void OGLDisplayLayer::SetOutputFilterOGL(const int filterID) { this->_displayTexFilter[0] = GL_LINEAR; this->_displayTexFilter[1] = GL_LINEAR; - this->_outputFilter = filterID; - } - else - { - this->_outputFilter = OutputFilterTypeID_NearestNeighbor; + outputFilter = filterID; } } -} - -int OGLDisplayLayer::GetPixelScaler() -{ - return (int)this->_pixelScaler; -} - -void OGLDisplayLayer::SetPixelScalerOGL(const int filterID) -{ - std::string cpuTypeIDString = std::string( VideoFilter::GetTypeStringByID((VideoFilterTypeID)filterID) ); - const VideoFilterTypeID newFilterID = (cpuTypeIDString != std::string(VIDEOFILTERTYPE_UNKNOWN_STRING)) ? (VideoFilterTypeID)filterID : VideoFilterTypeID_None; - this->SetCPUPixelScalerOGL(newFilterID); - this->_useShaderBasedPixelScaler = (this->GetFiltersPreferGPU()) ? this->SetGPUPixelScalerOGL(newFilterID) : false; - this->_pixelScaler = newFilterID; + return outputFilter; } bool OGLDisplayLayer::SetGPUPixelScalerOGL(const VideoFilterTypeID filterID) { bool willUseShaderBasedPixelScaler = true; - if (!this->_canUseShaderBasedFilters || filterID == VideoFilterTypeID_None) + if (!this->_output->CanFilterOnGPU() || filterID == VideoFilterTypeID_None) { willUseShaderBasedPixelScaler = false; return willUseShaderBasedPixelScaler; @@ -7799,9 +7558,12 @@ void OGLDisplayLayer::SetCPUPixelScalerOGL(const VideoFilterTypeID filterID) void OGLDisplayLayer::LoadFrameOGL(bool isMainSizeNative, bool isTouchSizeNative) { - const bool isUsingCPUPixelScaler = (this->_pixelScaler != VideoFilterTypeID_None) && !this->_useShaderBasedPixelScaler; - const bool loadMainScreen = (this->_displayMode == ClientDisplayMode_Main) || (this->_displayMode == ClientDisplayMode_Dual); - const bool loadTouchScreen = (this->_displayMode == ClientDisplayMode_Touch) || (this->_displayMode == ClientDisplayMode_Dual); + const ClientDisplayMode mode = this->_output->GetViewProperties().mode; + const bool canFilterOnGPU = this->_output->CanFilterOnGPU(); + const bool useDeposterize = this->_output->GetSourceDeposterize(); + const bool isUsingCPUPixelScaler = (this->_output->GetPixelScaler() != VideoFilterTypeID_None) && !this->_output->WillFilterOnGPU(); + const bool loadMainScreen = (mode == ClientDisplayMode_Main) || (mode == ClientDisplayMode_Dual); + const bool loadTouchScreen = (mode == ClientDisplayMode_Touch) || (mode == ClientDisplayMode_Dual); this->_isTexVideoInputDataNative[0] = isMainSizeNative; this->_isTexVideoInputDataNative[1] = isTouchSizeNative; @@ -7814,7 +7576,7 @@ void OGLDisplayLayer::LoadFrameOGL(bool isMainSizeNative, bool isTouchSizeNative { if (this->_isTexVideoInputDataNative[0]) { - if (this->_useDeposterize && this->_canUseShaderBasedFilters) + if (useDeposterize && canFilterOnGPU) { if ( (this->_filterDeposterize[0]->GetSrcWidth() != this->_texLoadedWidth[0]) || (this->_filterDeposterize[0]->GetSrcHeight() != this->_texLoadedHeight[0]) ) { @@ -7824,7 +7586,7 @@ void OGLDisplayLayer::LoadFrameOGL(bool isMainSizeNative, bool isTouchSizeNative } } - if (!isUsingCPUPixelScaler || this->_useDeposterize) + if (!isUsingCPUPixelScaler || useDeposterize) { glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoInputDataNativeID[0]); glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, this->_videoColorFormat, this->_videoSrcNativeBuffer[0]); @@ -7856,7 +7618,7 @@ void OGLDisplayLayer::LoadFrameOGL(bool isMainSizeNative, bool isTouchSizeNative { if (this->_isTexVideoInputDataNative[1]) { - if (this->_useDeposterize && this->_canUseShaderBasedFilters) + if (useDeposterize && canFilterOnGPU) { if ( (this->_filterDeposterize[1]->GetSrcWidth() != this->_texLoadedWidth[1]) || (this->_filterDeposterize[1]->GetSrcHeight() != this->_texLoadedHeight[1]) ) { @@ -7866,7 +7628,7 @@ void OGLDisplayLayer::LoadFrameOGL(bool isMainSizeNative, bool isTouchSizeNative } } - if (!isUsingCPUPixelScaler || this->_useDeposterize) + if (!isUsingCPUPixelScaler || useDeposterize) { glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoInputDataNativeID[1]); glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, this->_videoColorFormat, this->_videoSrcNativeBuffer[1]); @@ -7895,10 +7657,32 @@ void OGLDisplayLayer::LoadFrameOGL(bool isMainSizeNative, bool isTouchSizeNative } } +void OGLDisplayLayer::UpdateViewportOGL() +{ + const ClientDisplayViewProperties &cdv = this->_output->GetViewProperties(); + + const double w = cdv.clientWidth; + const double h = cdv.clientHeight; + + if (this->_output->GetInfo()->IsShaderSupported()) + { + glUseProgram(this->_finalOutputProgram->GetProgramID()); + glUniform2f(this->_uniformFinalOutputViewSize, w, h); + } + else + { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-w/2.0, -w/2.0 + w, -h/2.0, -h/2.0 + h, -1.0, 1.0); + } +} + void OGLDisplayLayer::ProcessOGL() { - const bool isUsingCPUPixelScaler = (this->_pixelScaler != VideoFilterTypeID_None) && !this->_useShaderBasedPixelScaler; - const int displayMode = this->GetMode(); + const bool willFilterOnGPU = this->_output->WillFilterOnGPU(); + const bool useDeposterize = this->_output->GetSourceDeposterize(); + const bool isUsingCPUPixelScaler = (this->_output->GetPixelScaler() != VideoFilterTypeID_None) && !willFilterOnGPU; + const ClientDisplayMode mode = this->_output->GetViewProperties().mode; // Source GLuint texVideoSourceID[2] = { (this->_isTexVideoInputDataNative[0]) ? this->_texVideoInputDataNativeID[0] : this->_texVideoInputDataCustomID[0], @@ -7910,9 +7694,9 @@ void OGLDisplayLayer::ProcessOGL() GLfloat w1 = this->_texLoadedWidth[1]; GLfloat h1 = this->_texLoadedHeight[1]; - if (this->_isTexVideoInputDataNative[0] && (displayMode == ClientDisplayMode_Main || displayMode == ClientDisplayMode_Dual)) + if (this->_isTexVideoInputDataNative[0] && (mode == ClientDisplayMode_Main || mode == ClientDisplayMode_Dual)) { - if (this->_useDeposterize) + if (useDeposterize) { // For all shader-based filters, we need to temporarily disable GL_UNPACK_CLIENT_STORAGE_APPLE. // Filtered images are supposed to remain on the GPU for immediate use for further GPU processing, @@ -7923,7 +7707,7 @@ void OGLDisplayLayer::ProcessOGL() if (isUsingCPUPixelScaler) // Hybrid CPU/GPU-based path (may cause a performance hit on pixel download) { - if ( this->_isTexVideoInputDataNative[0] && ((displayMode == ClientDisplayMode_Main) || (displayMode == ClientDisplayMode_Dual)) ) + if ( this->_isTexVideoInputDataNative[0] && ((mode == ClientDisplayMode_Main) || (mode == ClientDisplayMode_Dual)) ) { this->_filterDeposterize[0]->DownloadDstBufferOGL(this->_vf[0]->GetSrcBufferPtr(), 0, this->_filterDeposterize[0]->GetSrcHeight()); } @@ -7932,7 +7716,7 @@ void OGLDisplayLayer::ProcessOGL() if (!isUsingCPUPixelScaler) { - if (this->_useShaderBasedPixelScaler) + if (willFilterOnGPU) { glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); texVideoSourceID[0] = this->_shaderFilter[0]->RunFilterOGL(texVideoSourceID[0]); @@ -7955,9 +7739,9 @@ void OGLDisplayLayer::ProcessOGL() } } - if (this->_isTexVideoInputDataNative[1] && (displayMode == ClientDisplayMode_Touch || displayMode == ClientDisplayMode_Dual)) + if (this->_isTexVideoInputDataNative[1] && (mode == ClientDisplayMode_Touch || mode == ClientDisplayMode_Dual)) { - if (this->_useDeposterize) + if (useDeposterize) { glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); texVideoSourceID[1] = this->_filterDeposterize[1]->RunFilterOGL(texVideoSourceID[1]); @@ -7965,7 +7749,7 @@ void OGLDisplayLayer::ProcessOGL() if (isUsingCPUPixelScaler) // Hybrid CPU/GPU-based path (may cause a performance hit on pixel download) { - if ( this->_isTexVideoInputDataNative[1] && ((displayMode == ClientDisplayMode_Touch) || (displayMode == ClientDisplayMode_Dual)) ) + if ( this->_isTexVideoInputDataNative[1] && ((mode == ClientDisplayMode_Touch) || (mode == ClientDisplayMode_Dual)) ) { this->_filterDeposterize[1]->DownloadDstBufferOGL(this->_vf[1]->GetSrcBufferPtr(), 0, this->_filterDeposterize[1]->GetSrcHeight()); } @@ -7974,7 +7758,7 @@ void OGLDisplayLayer::ProcessOGL() if (!isUsingCPUPixelScaler) { - if (this->_useShaderBasedPixelScaler) + if (willFilterOnGPU) { glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); texVideoSourceID[1] = this->_shaderFilter[1]->RunFilterOGL(texVideoSourceID[1]); @@ -8022,22 +7806,30 @@ void OGLDisplayLayer::ProcessOGL() glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + glViewport(0, 0, this->_output->GetViewportWidth(), this->_output->GetViewportHeight()); } void OGLDisplayLayer::RenderOGL() { - glUseProgram(this->_finalOutputProgram->GetProgramID()); - this->UploadTransformationOGL(); + if (this->_output->GetInfo()->IsShaderSupported()) + { + glUseProgram(this->_finalOutputProgram->GetProgramID()); + } + + if (this->_needUpdateRotationScale) + { + this->_UpdateRotationScaleOGL(); + } if (this->_needUpdateVertices) { - this->UpdateVerticesOGL(); + this->_UpdateVerticesOGL(); } // Enable vertex attributes glBindVertexArrayDESMUME(this->_vaoMainStatesID); - switch (this->_displayMode) + switch (this->_output->GetViewProperties().mode) { case ClientDisplayMode_Main: glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID[0]); @@ -8055,10 +7847,10 @@ void OGLDisplayLayer::RenderOGL() case ClientDisplayMode_Dual: { - const size_t majorDisplayTex = (this->_displayOrder == ClientDisplayOrder_MainFirst) ? 0 : 1; - const size_t majorDisplayVtx = (this->_displayOrder == ClientDisplayOrder_MainFirst) ? 8 : 12; + const size_t majorDisplayTex = (this->_output->GetViewProperties().order == ClientDisplayOrder_MainFirst) ? 0 : 1; + const size_t majorDisplayVtx = (this->_output->GetViewProperties().order == ClientDisplayOrder_MainFirst) ? 8 : 12; - switch (this->_displayOrientation) + switch (this->_output->GetViewProperties().layout) { case ClientDisplayLayout_Hybrid_2_1: case ClientDisplayLayout_Hybrid_16_9: @@ -8096,7 +7888,83 @@ void OGLDisplayLayer::RenderOGL() void OGLDisplayLayer::FinishOGL() { - const bool isUsingCPUPixelScaler = (this->_pixelScaler != VideoFilterTypeID_None) && !this->_useShaderBasedPixelScaler; + const bool isUsingCPUPixelScaler = (this->_output->GetPixelScaler() != VideoFilterTypeID_None) && !this->_output->WillFilterOnGPU(); + glFinishObjectAPPLE(GL_TEXTURE_RECTANGLE_ARB, (isUsingCPUPixelScaler) ? this->_texCPUFilterDstID[0] : ( (this->_isTexVideoInputDataNative[0]) ? this->_texVideoInputDataNativeID[0] : this->_texVideoInputDataCustomID[0]) ); glFinishObjectAPPLE(GL_TEXTURE_RECTANGLE_ARB, (isUsingCPUPixelScaler) ? this->_texCPUFilterDstID[1] : ( (this->_isTexVideoInputDataNative[1]) ? this->_texVideoInputDataNativeID[1] : this->_texVideoInputDataCustomID[1]) ); } + +#pragma mark - + +MacOGLDisplayView::MacOGLDisplayView(CGLContextObj context) +{ + this->_context = context; +} + +CGLContextObj MacOGLDisplayView::GetContext() const +{ + return this->_context; +} + +void MacOGLDisplayView::SetContext(CGLContextObj context) +{ + this->_context = context; +} + +void MacOGLDisplayView::SetHUDInfo(const NDSFrameInfo &frameInfo) +{ + this->OGLVideoOutput::SetHUDInfo(frameInfo); + + CGLLockContext(this->_context); + CGLSetCurrentContext(this->_context); + this->FrameProcessHUD(); + this->FrameRenderAndFlush(); + CGLUnlockContext(this->_context); +} + +void MacOGLDisplayView::SetVideoBuffers(const uint32_t colorFormat, + const void *videoBufferHead, + const void *nativeBuffer0, + const void *nativeBuffer1, + const void *customBuffer0, const size_t customWidth0, const size_t customHeight0, + const void *customBuffer1, const size_t customWidth1, const size_t customHeight1) +{ + CGLLockContext(this->_context); + CGLSetCurrentContext(this->_context); + + this->OGLVideoOutput::SetVideoBuffers(colorFormat, + videoBufferHead, + nativeBuffer0, + nativeBuffer1, + customBuffer0, customWidth0, customHeight0, + customBuffer1, customWidth1, customHeight1); + + CGLUnlockContext(this->_context); +} + +void MacOGLDisplayView::FrameFinish() +{ + CGLLockContext(this->_context); + CGLSetCurrentContext(this->_context); + this->OGLVideoOutput::FrameFinish(); + CGLUnlockContext(this->_context); +} + +void MacOGLDisplayView::FrameFlush() +{ + CGLFlushDrawable(this->_context); +} + +void MacOGLDisplayView::FrameRenderAndFlush() +{ + this->FrameRender(); + this->FrameFlush(); +} + +void MacOGLDisplayView::UpdateView() +{ + CGLLockContext(this->_context); + CGLSetCurrentContext(this->_context); + this->FrameRenderAndFlush(); + CGLUnlockContext(this->_context); +} diff --git a/desmume/src/frontend/cocoa/OGLDisplayOutput.h b/desmume/src/frontend/cocoa/OGLDisplayOutput.h index 07d492ca3..5deceb488 100644 --- a/desmume/src/frontend/cocoa/OGLDisplayOutput.h +++ b/desmume/src/frontend/cocoa/OGLDisplayOutput.h @@ -23,6 +23,7 @@ #if defined(__APPLE__) #include #include + #include #endif #endif // _OGLDISPLAYOUTPUT_3_2_H_ @@ -33,28 +34,11 @@ #include "ClientDisplayView.h" -#include -#include FT_FREETYPE_H - -#define HUD_MAX_CHARACTERS 2048 #define HUD_VERTEX_ATTRIBUTE_BUFFER_SIZE (sizeof(GLfloat) * HUD_MAX_CHARACTERS * (2 * 4)) -#define HUD_TEXTBOX_BASEGLYPHSIZE 64.0 -#define HUD_TEXTBOX_BASE_SCALE (1.0/3.0) -#define HUD_TEXTBOX_MIN_SCALE 0.70 class OGLVideoOutput; struct NDSFrameInfo; -enum OutputFilterTypeID -{ - OutputFilterTypeID_NearestNeighbor = 0, - OutputFilterTypeID_Bilinear = 1, - OutputFilterTypeID_BicubicBSpline = 2, - OutputFilterTypeID_BicubicMitchell = 3, - OutputFilterTypeID_Lanczos2 = 4, - OutputFilterTypeID_Lanczos3 = 5 -}; - enum ShaderSupportTier { ShaderSupport_Unsupported = 0, @@ -76,6 +60,7 @@ protected: bool _useShader150; bool _isVBOSupported; + bool _isVAOSupported; bool _isPBOSupported; bool _isFBOSupported; @@ -85,6 +70,7 @@ public: bool IsUsingShader150(); bool IsVBOSupported(); + bool IsVAOSupported(); bool IsPBOSupported(); bool IsShaderSupported(); bool IsFBOSupported(); @@ -271,102 +257,49 @@ class OGLVideoLayer protected: OGLVideoOutput *_output; bool _isVisible; - GLfloat _scaleFactor; - GLsizei _viewportWidth; - GLsizei _viewportHeight; + bool _needUpdateRotationScale; + bool _needUpdateVertices; public: virtual ~OGLVideoLayer() {}; - virtual float GetScaleFactor(); - virtual void SetScaleFactor(float scaleFactor); + void SetNeedsUpdateVertices(); + virtual bool IsVisible(); virtual void SetVisibility(const bool visibleState); - virtual void SetViewportSizeOGL(GLsizei w, GLsizei h); + virtual void UpdateViewportOGL() {}; virtual void ProcessOGL() = 0; virtual void RenderOGL() = 0; virtual void FinishOGL() {}; }; -typedef struct -{ - GLfloat width; - GLfloat texCoord[8]; -} GlyphInfo; - class OGLHUDLayer : public OGLVideoLayer { protected: - FT_Library _ftLibrary; - const char *_lastFontFilePath; - GLuint _texCharMap; - GlyphInfo _glyphInfo[256]; - - std::string _statusString; - size_t _glyphSize; - size_t _glyphTileSize; - OGLShaderProgram *_program; - - bool _isVAOPresent; - bool _canUseShaderOutput; - GLint _uniformViewSize; GLuint _vaoMainStatesID; GLuint _vboVertexID; GLuint _vboTexCoordID; GLuint _vboElementID; + GLuint _texCharMap; - bool _showVideoFPS; - bool _showRender3DFPS; - bool _showFrameIndex; - bool _showLagFrameCount; - bool _showCPULoadAverage; - bool _showRTC; - - uint32_t _lastVideoFPS; - uint32_t _lastRender3DFPS; - uint32_t _lastFrameIndex; - uint32_t _lastLagFrameCount; - uint32_t _lastCpuLoadAvgARM9; - uint32_t _lastCpuLoadAvgARM7; - char _lastRTCString[25]; - - GLfloat _hudObjectScale; + GlyphInfo *_glyphInfo; + GLfloat _glyphSize; + GLfloat _glyphTileSize; void _SetShowInfoItemOGL(bool &infoItemFlag, const bool visibleState); + void _UpdateVerticesOGL(); public: OGLHUDLayer(OGLVideoOutput *oglVO); virtual ~OGLHUDLayer(); - void SetFontUsingPath(const char *filePath); + void CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, const size_t glyphTileSize, GlyphInfo *glyphInfo); - void SetInfo(const uint32_t videoFPS, const uint32_t render3DFPS, const uint32_t frameIndex, const uint32_t lagFrameCount, const char *rtcString, const uint32_t cpuLoadAvgARM9, const uint32_t cpuLoadAvgARM7); - void RefreshInfo(); - - void SetObjectScale(float objectScale); - float GetObjectScale() const; - - void SetShowVideoFPS(const bool visibleState); - bool GetShowVideoFPS() const; - void SetShowRender3DFPS(const bool visibleState); - bool GetShowRender3DFPS() const; - void SetShowFrameIndex(const bool visibleState); - bool GetShowFrameIndex() const; - void SetShowLagFrameCount(const bool visibleState); - bool GetShowLagFrameCount() const; - void SetShowCPULoadAverage(const bool visibleState); - bool GetShowCPULoadAverage() const; - void SetShowRTC(const bool visibleState); - bool GetShowRTC() const; - - void ProcessVerticesOGL(); - - virtual void SetScaleFactor(float scaleFactor); - virtual void SetViewportSizeOGL(GLsizei w, GLsizei h); + virtual void UpdateViewportOGL(); virtual void ProcessOGL(); virtual void RenderOGL(); }; @@ -374,19 +307,9 @@ public: class OGLDisplayLayer : public OGLVideoLayer { protected: - bool _isVAOPresent; - bool _canUseShaderBasedFilters; - bool _canUseShaderOutput; bool _useShader150; ShaderSupportTier _shaderSupport; - GLboolean _useClientStorage; - bool _needUpdateVertices; - bool _useDeposterize; - bool _useShaderBasedPixelScaler; - bool _filtersPreferGPU; - int _outputFilter; - VideoFilterTypeID _pixelScaler; OGLShaderProgram *_finalOutputProgram; OGLFilter *_filterDeposterize[2]; @@ -413,14 +336,6 @@ protected: VideoFilter *_vf[2]; GLuint _texCPUFilterDstID[2]; - ClientDisplayMode _displayMode; - ClientDisplayOrder _displayOrder; - ClientDisplayLayout _displayOrientation; - double _normalWidth; - double _normalHeight; - double _gapScalar; - double _rotation; - GLuint _texLQ2xLUT; GLuint _texHQ2xLUT; GLuint _texHQ3xLUT; @@ -438,9 +353,9 @@ protected: void DetermineTextureStorageHints(GLint &videoSrcTexStorageHint, GLint &cpuFilterTexStorageHint); void ResizeCPUPixelScalerOGL(const size_t srcWidthMain, const size_t srcHeightMain, const size_t srcWidthTouch, const size_t srcHeightTouch, const size_t scaleMultiply, const size_t scaleDivide); - void UploadTransformationOGL(); - void UpdateVerticesOGL(); + void _UpdateRotationScaleOGL(); + void _UpdateVerticesOGL(); public: OGLDisplayLayer() {}; @@ -454,64 +369,100 @@ public: const void *customBuffer0, const size_t customWidth0, const size_t customHeight0, const void *customBuffer1, const size_t customWidth1, const size_t customHeight1); - bool GetFiltersPreferGPU(); - void SetFiltersPreferGPUOGL(bool preferGPU); - - ClientDisplayMode GetMode() const; - void SetMode(ClientDisplayMode dispMode); - ClientDisplayLayout GetOrientation() const; - void SetOrientation(ClientDisplayLayout dispOrientation); - ClientDisplayOrder GetOrder() const; - void SetOrder(ClientDisplayOrder dispOrder); - double GetGapScalar() const; - void SetGapScalar(double theScalar); - double GetRotation() const; - void SetRotation(double theRotation); - bool GetSourceDeposterize(); - void SetSourceDeposterize(bool useDeposterize); + void SetNeedsUpdateRotationScale(); + void SetFiltersPreferGPUOGL(); bool CanUseShaderBasedFilters(); - void GetNormalSize(double &w, double &h) const; - int GetOutputFilter(); - virtual void SetOutputFilterOGL(const int filterID); - int GetPixelScaler(); - void SetPixelScalerOGL(const int filterID); + OutputFilterTypeID SetOutputFilterOGL(const OutputFilterTypeID filterID); bool SetGPUPixelScalerOGL(const VideoFilterTypeID filterID); void SetCPUPixelScalerOGL(const VideoFilterTypeID filterID); void LoadFrameOGL(bool isMainSizeNative, bool isTouchSizeNative); + virtual void UpdateViewportOGL(); virtual void ProcessOGL(); virtual void RenderOGL(); virtual void FinishOGL(); }; -class OGLVideoOutput +class OGLVideoOutput : public ClientDisplay3DView { protected: OGLInfo *_info; - GLfloat _scaleFactor; GLsizei _viewportWidth; GLsizei _viewportHeight; + bool _needUpdateViewport; std::vector *_layerList; + void _UpdateViewport(); + + virtual void _UpdateNormalSize(); + virtual void _UpdateOrder(); + virtual void _UpdateRotation(); + virtual void _UpdateClientSize(); + virtual void _UpdateViewScale(); + public: OGLVideoOutput(); ~OGLVideoOutput(); - void InitLayers(); OGLInfo* GetInfo(); - float GetScaleFactor(); - void SetScaleFactor(float scaleFactor); + GLsizei GetViewportWidth(); GLsizei GetViewportHeight(); OGLDisplayLayer* GetDisplayLayer(); OGLHUDLayer* GetHUDLayer(); + + virtual void Init(); + + virtual void SetOutputFilter(const OutputFilterTypeID filterID); + virtual void SetPixelScaler(const VideoFilterTypeID filterID); + + virtual void CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, const size_t glyphTileSize, GlyphInfo *glyphInfo); + virtual void SetHUDVisibility(const bool visibleState); + + virtual void SetFiltersPreferGPU(const bool preferGPU); + + virtual void SetVideoBuffers(const uint32_t colorFormat, + const void *videoBufferHead, + const void *nativeBuffer0, + const void *nativeBuffer1, + const void *customBuffer0, const size_t customWidth0, const size_t customHeight0, + const void *customBuffer1, const size_t customWidth1, const size_t customHeight1); + + virtual void FrameLoadGPU(bool isMainSizeNative, bool isTouchSizeNative); + virtual void FrameProcessGPU(); + virtual void FrameProcessHUD(); + virtual void FrameRender(); + virtual void FrameFinish(); +}; + +class MacOGLDisplayView : public OGLVideoOutput +{ +protected: + CGLContextObj _context; + +public: + MacOGLDisplayView(CGLContextObj context); + + CGLContextObj GetContext() const; + void SetContext(CGLContextObj context); - void ProcessOGL(); - void RenderOGL(); - void SetViewportSizeOGL(GLsizei w, GLsizei h); - void FinishOGL(); + virtual void SetHUDInfo(const NDSFrameInfo &frameInfo); + + virtual void SetVideoBuffers(const uint32_t colorFormat, + const void *videoBufferHead, + const void *nativeBuffer0, + const void *nativeBuffer1, + const void *customBuffer0, const size_t customWidth0, const size_t customHeight0, + const void *customBuffer1, const size_t customWidth1, const size_t customHeight1); + + virtual void FrameFinish(); + + virtual void FrameFlush(); + virtual void FrameRenderAndFlush(); + + virtual void UpdateView(); }; OGLInfo* OGLInfoCreate_Legacy(); diff --git a/desmume/src/frontend/cocoa/OGLDisplayOutput_3_2.cpp b/desmume/src/frontend/cocoa/OGLDisplayOutput_3_2.cpp index a7e478648..3715e465a 100644 --- a/desmume/src/frontend/cocoa/OGLDisplayOutput_3_2.cpp +++ b/desmume/src/frontend/cocoa/OGLDisplayOutput_3_2.cpp @@ -47,6 +47,7 @@ OGLInfo_3_2::OGLInfo_3_2() { _useShader150 = true; _isVBOSupported = true; + _isVAOSupported = true; _isPBOSupported = true; _isFBOSupported = true; diff --git a/desmume/src/frontend/cocoa/OGLDisplayOutput_3_2.h b/desmume/src/frontend/cocoa/OGLDisplayOutput_3_2.h index 30bc475f9..c20c80d25 100644 --- a/desmume/src/frontend/cocoa/OGLDisplayOutput_3_2.h +++ b/desmume/src/frontend/cocoa/OGLDisplayOutput_3_2.h @@ -21,6 +21,7 @@ #if defined(__APPLE__) #include #include + #include #endif #include "OGLDisplayOutput.h" diff --git a/desmume/src/frontend/cocoa/cocoa_core.h b/desmume/src/frontend/cocoa/cocoa_core.h index de5dd0fed..c30ebcedf 100644 --- a/desmume/src/frontend/cocoa/cocoa_core.h +++ b/desmume/src/frontend/cocoa/cocoa_core.h @@ -45,19 +45,6 @@ typedef struct pthread_rwlock_t rwlockCoreExecute; } CoreThreadParam; -struct NDSFrameInfo -{ - uint32_t videoFPS; - uint32_t render3DFPS; - uint32_t frameIndex; - uint32_t lagFrameCount; - uint32_t cpuLoadAvgARM9; - uint32_t cpuLoadAvgARM7; - char rtcString[25]; -}; - -typedef struct NDSFrameInfo NDSFrameInfo; - @interface CocoaDSCore : NSObject { CocoaDSController *cdsController; diff --git a/desmume/src/frontend/cocoa/cocoa_globals.h b/desmume/src/frontend/cocoa/cocoa_globals.h index 363b3daba..13adf2ede 100644 --- a/desmume/src/frontend/cocoa/cocoa_globals.h +++ b/desmume/src/frontend/cocoa/cocoa_globals.h @@ -405,16 +405,11 @@ enum // Video Messages MESSAGE_RECEIVE_GPU_FRAME, - MESSAGE_RESIZE_VIEW, - MESSAGE_TRANSFORM_VIEW, + MESSAGE_CHANGE_VIEW_PROPERTIES, MESSAGE_REDRAW_VIEW, MESSAGE_RELOAD_AND_REDRAW, MESSAGE_REPROCESS_AND_REDRAW, MESSAGE_SET_GPU_STATE_FLAGS, - MESSAGE_CHANGE_DISPLAY_TYPE, - MESSAGE_CHANGE_DISPLAY_ORIENTATION, - MESSAGE_CHANGE_DISPLAY_ORDER, - MESSAGE_CHANGE_DISPLAY_GAP, MESSAGE_SET_RENDER3D_METHOD, MESSAGE_SET_RENDER3D_HIGH_PRECISION_COLOR_INTERPOLATION, MESSAGE_SET_RENDER3D_EDGE_MARKING, diff --git a/desmume/src/frontend/cocoa/cocoa_output.h b/desmume/src/frontend/cocoa/cocoa_output.h index 1bdd023ec..99062a575 100644 --- a/desmume/src/frontend/cocoa/cocoa_output.h +++ b/desmume/src/frontend/cocoa/cocoa_output.h @@ -21,21 +21,14 @@ #include #import "cocoa_util.h" +#include "ClientDisplayView.h" +#undef BOOL @class NSImage; @class NSBitmapImageRep; struct NDSFrameInfo; -typedef struct -{ - double scale; - double rotation; // Angle is in degrees - double translationX; - double translationY; - double translationZ; -} DisplayOutputTransformData; - @interface CocoaDSOutput : CocoaDSThread { NSMutableDictionary *property; @@ -106,7 +99,7 @@ typedef struct @required - (void) doFinishFrame; -- (void) doDisplayModeChanged:(NSInteger)displayModeID; +- (void) doViewPropertiesChanged; @end @@ -131,12 +124,7 @@ typedef struct - (void) doProcessVideoFrameWithInfo:(const NDSFrameInfo &)frameInfo; @optional -- (void) doResizeView:(NSRect)rect; -- (void) doTransformView:(const DisplayOutputTransformData *)transformData; - (void) doRedraw; -- (void) doDisplayOrientationChanged:(NSInteger)displayOrientationID; -- (void) doDisplayOrderChanged:(NSInteger)displayOrderID; -- (void) doDisplayGapChanged:(float)displayGapScalar; @end @@ -145,7 +133,7 @@ typedef struct { id delegate; NSSize displaySize; - NSInteger displayMode; + ClientDisplayMode displayMode; uint32_t _receivedFrameIndex; uint32_t _currentReceivedFrameIndex; @@ -161,11 +149,10 @@ typedef struct @property (retain) id delegate; @property (readonly) NSSize displaySize; -@property (assign) NSInteger displayMode; +@property (assign) ClientDisplayMode displayMode; - (void) doReceiveGPUFrame; - (void) handleReceiveGPUFrame; -- (void) handleChangeDisplayMode:(NSData *)displayModeData; - (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData; - (void) handleCopyToPasteboard; @@ -185,14 +172,9 @@ typedef struct } - (void) handleReceiveGPUFrame; -- (void) handleResizeView:(NSData *)rectData; -- (void) handleTransformView:(NSData *)transformData; - (void) handleRedrawView; - (void) handleReloadAndRedraw; - (void) handleReprocessAndRedraw; -- (void) handleChangeDisplayOrientation:(NSData *)displayOrientationIdData; -- (void) handleChangeDisplayOrder:(NSData *)displayOrderIdData; -- (void) handleChangeDisplayGap:(NSData *)displayGapScalarData; - (void) resetVideoBuffers; diff --git a/desmume/src/frontend/cocoa/cocoa_output.mm b/desmume/src/frontend/cocoa/cocoa_output.mm index 49bde44fc..b1ea3c92a 100644 --- a/desmume/src/frontend/cocoa/cocoa_output.mm +++ b/desmume/src/frontend/cocoa/cocoa_output.mm @@ -32,8 +32,6 @@ #include "../../metaspu/metaspu.h" #include "../../rtc.h" -#include "OGLDisplayOutput.h" - #import #undef BOOL @@ -84,7 +82,6 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage { NSInteger message = (NSInteger)[portMessage msgid]; - NSArray *messageComponents = [portMessage components]; switch (message) { @@ -553,7 +550,7 @@ return size; } -- (void) setDisplayMode:(NSInteger)displayModeID +- (void) setDisplayMode:(ClientDisplayMode)displayModeID { NSString *newDispString = nil; @@ -583,10 +580,10 @@ OSSpinLockUnlock(&spinlockDisplayType); } -- (NSInteger) displayMode +- (ClientDisplayMode) displayMode { OSSpinLockLock(&spinlockDisplayType); - NSInteger displayModeID = displayMode; + ClientDisplayMode displayModeID = displayMode; OSSpinLockUnlock(&spinlockDisplayType); return displayModeID; @@ -608,8 +605,8 @@ [self handleReceiveGPUFrame]; break; - case MESSAGE_CHANGE_DISPLAY_TYPE: - [self handleChangeDisplayMode:[messageComponents objectAtIndex:0]]; + case MESSAGE_CHANGE_VIEW_PROPERTIES: + [self handleChangeViewProperties]; break; case MESSAGE_REQUEST_SCREENSHOT: @@ -633,16 +630,9 @@ OSSpinLockUnlock(&spinlockReceivedFrameIndex); } -- (void) handleChangeDisplayMode:(NSData *)displayModeData +- (void) handleChangeViewProperties { - if (delegate == nil || ![delegate respondsToSelector:@selector(doDisplayModeChanged:)]) - { - return; - } - - const NSInteger displayModeID = *(NSInteger *)[displayModeData bytes]; - [self setDisplayMode:displayModeID]; - [(id)delegate doDisplayModeChanged:displayModeID]; + [(id)delegate doViewPropertiesChanged]; } - (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData @@ -822,7 +812,6 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage { NSInteger message = (NSInteger)[portMessage msgid]; - NSArray *messageComponents = [portMessage components]; switch (message) { @@ -834,30 +823,10 @@ [self handleReprocessAndRedraw]; break; - case MESSAGE_RESIZE_VIEW: - [self handleResizeView:[messageComponents objectAtIndex:0]]; - break; - - case MESSAGE_TRANSFORM_VIEW: - [self handleTransformView:[messageComponents objectAtIndex:0]]; - break; - case MESSAGE_REDRAW_VIEW: [self handleRedrawView]; break; - case MESSAGE_CHANGE_DISPLAY_ORIENTATION: - [self handleChangeDisplayOrientation:[messageComponents objectAtIndex:0]]; - break; - - case MESSAGE_CHANGE_DISPLAY_ORDER: - [self handleChangeDisplayOrder:[messageComponents objectAtIndex:0]]; - break; - - case MESSAGE_CHANGE_DISPLAY_GAP: - [self handleChangeDisplayGap:[messageComponents objectAtIndex:0]]; - break; - default: [super handlePortMessage:portMessage]; break; @@ -925,27 +894,6 @@ [(id)delegate doLoadVideoFrameWithMainSizeNative:isMainSizeNative touchSizeNative:isTouchSizeNative]; } -- (void) handleResizeView:(NSData *)rectData -{ - if (delegate == nil || ![delegate respondsToSelector:@selector(doResizeView:)]) - { - return; - } - - const NSRect resizeRect = *(NSRect *)[rectData bytes]; - [(id)delegate doResizeView:resizeRect]; -} - -- (void) handleTransformView:(NSData *)transformData -{ - if (delegate == nil || ![delegate respondsToSelector:@selector(doTransformView:)]) - { - return; - } - - [(id)delegate doTransformView:(DisplayOutputTransformData *)[transformData bytes]]; -} - - (void) handleRedrawView { if (delegate == nil || ![delegate respondsToSelector:@selector(doRedraw)]) @@ -967,39 +915,6 @@ [self handleEmuFrameProcessed]; } -- (void) handleChangeDisplayOrientation:(NSData *)displayOrientationIdData -{ - if (delegate == nil || ![delegate respondsToSelector:@selector(doDisplayOrientationChanged:)]) - { - return; - } - - const NSInteger theOrientation = *(NSInteger *)[displayOrientationIdData bytes]; - [(id)delegate doDisplayOrientationChanged:theOrientation]; -} - -- (void) handleChangeDisplayOrder:(NSData *)displayOrderIdData -{ - if (delegate == nil || ![delegate respondsToSelector:@selector(doDisplayOrderChanged:)]) - { - return; - } - - const NSInteger theOrder = *(NSInteger *)[displayOrderIdData bytes]; - [(id)delegate doDisplayOrderChanged:theOrder]; -} - -- (void) handleChangeDisplayGap:(NSData *)displayGapScalarData -{ - if (delegate == nil || ![delegate respondsToSelector:@selector(doDisplayGapChanged:)]) - { - return; - } - - const float gapScalar = *(float *)[displayGapScalarData bytes]; - [(id)delegate doDisplayGapChanged:gapScalar]; -} - - (void) resetVideoBuffers { const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); diff --git a/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.h b/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.h index 4629d2aee..446aaad18 100644 --- a/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.h +++ b/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.h @@ -38,8 +38,8 @@ class OGLVideoOutput; @interface DisplayView : NSView { InputManager *inputManager; - ClientDisplayView *_cdv; - OGLVideoOutput *oglv; + ClientDisplay3DView *_cdv; + ClientDisplayViewProperties _intermediateViewProps; BOOL canUseShaderBasedFilters; BOOL _useVerticalSync; @@ -51,6 +51,8 @@ class OGLVideoOutput; OSSpinLock spinlockSourceDeposterize; OSSpinLock spinlockPixelScaler; + OSSpinLock spinlockViewProperties; + // OpenGL context NSOpenGLContext *context; CGLContextObj cglDisplayContext; @@ -72,7 +74,8 @@ class OGLVideoOutput; @property (assign) NSInteger pixelScaler; - (void) setScaleFactor:(float)theScaleFactor; -- (void) drawVideoFrame; +- (void) commitViewProperties:(const ClientDisplayViewProperties &)viewProps; +- (void) setupViewProperties; - (BOOL) handleKeyPress:(NSEvent *)theEvent keyPressed:(BOOL)keyPressed; - (BOOL) handleMouseButton:(NSEvent *)theEvent buttonPressed:(BOOL)buttonPressed; - (void) requestScreenshot:(NSURL *)fileURL fileType:(NSBitmapImageFileType)fileType; @@ -138,6 +141,7 @@ class OGLVideoOutput; @property (assign) NSScreen *assignedScreen; @property (retain) NSWindow *masterWindow; +@property (readonly, nonatomic) BOOL isFullScreen; @property (assign) double displayScale; @property (assign) double displayRotation; @property (assign) BOOL videoFiltersPreferGPU; @@ -154,10 +158,21 @@ class OGLVideoOutput; - (id)initWithWindowNibName:(NSString *)windowNibName emuControlDelegate:(EmuControllerDelegate *)theEmuController; +- (ClientDisplayViewProperties &) localViewProperties; +- (void) setDisplayMode:(ClientDisplayMode)mode + layout:(ClientDisplayLayout)layout + order:(ClientDisplayOrder)order + rotation:(double)rotation + viewScale:(double)viewScale + gapScale:(double)gapScale + isMinSizeNormal:(BOOL)isMinSizeNormal + isShowingStatusBar:(BOOL)isShowingStatusBar; + - (void) setupUserDefaults; - (BOOL) masterStatusBarState; - (NSRect) masterWindowFrame; - (double) masterWindowScale; +- (NSRect) updateViewProperties; - (void) resizeWithTransform; - (double) maxScalarForContentBoundsWidth:(double)contentBoundsWidth height:(double)contentBoundsHeight; - (void) enterFullScreen; diff --git a/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm b/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm index 39d157a95..6820caf1a 100644 --- a/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm +++ b/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm @@ -59,6 +59,7 @@ @synthesize microphoneGainSlider; @synthesize microphoneMuteButton; +@dynamic isFullScreen; @dynamic displayScale; @dynamic displayRotation; @dynamic videoFiltersPreferGPU; @@ -152,6 +153,11 @@ static std::unordered_map _screenMap; // #pragma mark Dynamic Property Methods +- (BOOL) isFullScreen +{ + return ([self assignedScreen] != nil); +} + - (void) setDisplayScale:(double)s { // There are two ways that this property is used: @@ -199,37 +205,29 @@ static std::unordered_map _screenMap; // // Convert angle to clockwise-direction degrees (left-handed Cartesian coordinate system). _localViewProps.rotation = 360.0 - newAngleDegrees; - NSWindow *theWindow = [self window]; - // Set the minimum content size for the window, since this will change based on rotation. - double contentMinWidth = _minDisplayViewSize.width; - double contentMinHeight = _minDisplayViewSize.height; - ClientDisplayView::ConvertNormalToTransformedBounds(1.0, _localViewProps.rotation, contentMinWidth, contentMinHeight); - contentMinHeight += _statusBarHeight; - [theWindow setContentMinSize:NSMakeSize(contentMinWidth, contentMinHeight)]; + [self setIsMinSizeNormal:[self isMinSizeNormal]]; - // Resize the window. - const NSSize oldBounds = [theWindow frame].size; - [self resizeWithTransform]; - const NSSize newBounds = [theWindow frame].size; - - // If the window size didn't change, it is possible that the old and new rotation angles - // are 180 degrees offset from each other. In this case, we'll need to force the - // display view to update itself. - if (oldBounds.width == newBounds.width && oldBounds.height == newBounds.height) + if ([self isFullScreen]) { - [view setNeedsDisplay:YES]; + [view commitViewProperties:_localViewProps]; + } + else + { + // Resize the window. + NSWindow *theWindow = [self window]; + const NSSize oldBounds = [theWindow frame].size; + [self resizeWithTransform]; + const NSSize newBounds = [theWindow frame].size; + + // If the window size didn't change, it is possible that the old and new rotation angles + // are 180 degrees offset from each other. In this case, we'll need to force the + // display view to update itself. + if (oldBounds.width == newBounds.width && oldBounds.height == newBounds.height) + { + [view commitViewProperties:_localViewProps]; + } } - - DisplayOutputTransformData transformData = { _localViewProps.viewScale, - _localViewProps.rotation, - 0.0, - 0.0, - 0.0 }; - - [CocoaDSUtil messageSendOneWayWithData:[[self cdsVideoOutput] receivePort] - msgID:MESSAGE_TRANSFORM_VIEW - data:[NSData dataWithBytes:&transformData length:sizeof(DisplayOutputTransformData)]]; } - (double) displayRotation @@ -243,35 +241,21 @@ static std::unordered_map _screenMap; // - (void) setDisplayMode:(NSInteger)displayModeID { - NSString *modeString = @"Unknown"; - - switch (displayModeID) - { - case ClientDisplayMode_Main: - modeString = NSSTRING_DISPLAYMODE_MAIN; - break; - - case ClientDisplayMode_Touch: - modeString = NSSTRING_DISPLAYMODE_TOUCH; - break; - - case ClientDisplayMode_Dual: - modeString = NSSTRING_DISPLAYMODE_DUAL; - break; - - default: - break; - } - OSSpinLockLock(&spinlockDisplayMode); _localViewProps.mode = (ClientDisplayMode)displayModeID; OSSpinLockUnlock(&spinlockDisplayMode); - ClientDisplayView::CalculateNormalSize((ClientDisplayMode)[self displayMode], (ClientDisplayLayout)[self displayOrientation], [self displayGap], _localViewProps.normalWidth, _localViewProps.normalHeight); + ClientDisplayView::CalculateNormalSize((ClientDisplayMode)displayModeID, (ClientDisplayLayout)[self displayOrientation], [self displayGap], _localViewProps.normalWidth, _localViewProps.normalHeight); [self setIsMinSizeNormal:[self isMinSizeNormal]]; - [self resizeWithTransform]; - [CocoaDSUtil messageSendOneWayWithInteger:[[self cdsVideoOutput] receivePort] msgID:MESSAGE_CHANGE_DISPLAY_TYPE integerValue:displayModeID]; + if ([self isFullScreen]) + { + [view commitViewProperties:_localViewProps]; + } + else if ([self displayMode] == ClientDisplayMode_Dual) + { + [self resizeWithTransform]; + } } - (NSInteger) displayMode @@ -289,15 +273,17 @@ static std::unordered_map _screenMap; // _localViewProps.layout = (ClientDisplayLayout)theOrientation; OSSpinLockUnlock(&spinlockDisplayOrientation); - ClientDisplayView::CalculateNormalSize((ClientDisplayMode)[self displayMode], (ClientDisplayLayout)[self displayOrientation], [self displayGap], _localViewProps.normalWidth, _localViewProps.normalHeight); + ClientDisplayView::CalculateNormalSize((ClientDisplayMode)[self displayMode], (ClientDisplayLayout)theOrientation, [self displayGap], _localViewProps.normalWidth, _localViewProps.normalHeight); [self setIsMinSizeNormal:[self isMinSizeNormal]]; - if ([self displayMode] == ClientDisplayMode_Dual) + if ([self isFullScreen]) + { + [view commitViewProperties:_localViewProps]; + } + else if ([self displayMode] == ClientDisplayMode_Dual) { [self resizeWithTransform]; } - - [CocoaDSUtil messageSendOneWayWithInteger:[[self cdsVideoOutput] receivePort] msgID:MESSAGE_CHANGE_DISPLAY_ORIENTATION integerValue:theOrientation]; } - (NSInteger) displayOrientation @@ -315,7 +301,7 @@ static std::unordered_map _screenMap; // _localViewProps.order = (ClientDisplayOrder)theOrder; OSSpinLockUnlock(&spinlockDisplayOrder); - [CocoaDSUtil messageSendOneWayWithInteger:[[self cdsVideoOutput] receivePort] msgID:MESSAGE_CHANGE_DISPLAY_ORDER integerValue:theOrder]; + [view commitViewProperties:_localViewProps]; } - (NSInteger) displayOrder @@ -333,15 +319,31 @@ static std::unordered_map _screenMap; // _localViewProps.gapScale = gapScalar; OSSpinLockUnlock(&spinlockDisplayGap); - ClientDisplayView::CalculateNormalSize((ClientDisplayMode)[self displayMode], (ClientDisplayLayout)[self displayOrientation], [self displayGap], _localViewProps.normalWidth, _localViewProps.normalHeight); + ClientDisplayView::CalculateNormalSize((ClientDisplayMode)[self displayMode], (ClientDisplayLayout)[self displayOrientation], gapScalar, _localViewProps.normalWidth, _localViewProps.normalHeight); [self setIsMinSizeNormal:[self isMinSizeNormal]]; - if ([self displayMode] == ClientDisplayMode_Dual) + if ([self isFullScreen]) { - [self resizeWithTransform]; + [view commitViewProperties:_localViewProps]; + } + else if ([self displayMode] == ClientDisplayMode_Dual) + { + switch ([self displayOrientation]) + { + case ClientDisplayLayout_Hybrid_16_9: + case ClientDisplayLayout_Hybrid_16_10: + [view commitViewProperties:_localViewProps]; + break; + + case ClientDisplayLayout_Horizontal: + case ClientDisplayLayout_Hybrid_2_1: + break; + + default: + [self resizeWithTransform]; + break; + } } - - [CocoaDSUtil messageSendOneWayWithFloat:[[self cdsVideoOutput] receivePort] msgID:MESSAGE_CHANGE_DISPLAY_GAP floatValue:(float)gapScalar]; } - (double) displayGap @@ -464,18 +466,75 @@ static std::unordered_map _screenMap; // #pragma mark Class Methods +- (ClientDisplayViewProperties &) localViewProperties +{ + return _localViewProps; +} + +- (void) setDisplayMode:(ClientDisplayMode)mode + layout:(ClientDisplayLayout)layout + order:(ClientDisplayOrder)order + rotation:(double)rotation + viewScale:(double)viewScale + gapScale:(double)gapScale + isMinSizeNormal:(BOOL)isMinSizeNormal + isShowingStatusBar:(BOOL)isShowingStatusBar +{ + _statusBarHeight = (isShowingStatusBar) ? WINDOW_STATUS_BAR_HEIGHT : 0; + + _localRotation = fmod(rotation, 360.0); + if (_localRotation < 0.0) + { + _localRotation = 360.0 + _localRotation; + } + + if (_localRotation == 360.0) + { + _localRotation = 0.0; + } + + _localViewProps.mode = mode; + _localViewProps.layout = layout; + _localViewProps.order = order; + _localViewProps.viewScale = viewScale; + _localViewProps.gapScale = gapScale; + _localViewProps.gapDistance = DS_DISPLAY_UNSCALED_GAP * gapScale; + _localViewProps.rotation = 360.0 - _localRotation; + + ClientDisplayView::CalculateNormalSize(mode, layout, gapScale, _localViewProps.normalWidth, _localViewProps.normalHeight); + + // Set the minimum content size. + _isMinSizeNormal = isMinSizeNormal; + _minDisplayViewSize.width = _localViewProps.normalWidth; + _minDisplayViewSize.height = _localViewProps.normalHeight; + + if (!_isMinSizeNormal) + { + _minDisplayViewSize.width /= 4.0; + _minDisplayViewSize.height /= 4.0; + } + + double transformedMinWidth = _minDisplayViewSize.width; + double transformedMinHeight = _minDisplayViewSize.height; + ClientDisplayView::ConvertNormalToTransformedBounds(1.0, _localViewProps.rotation, transformedMinWidth, transformedMinHeight); + [[self window] setContentMinSize:NSMakeSize(transformedMinWidth, transformedMinHeight + _statusBarHeight)]; + + // Set the client size and resize the windows. + NSRect newWindowFrame = [self updateViewProperties]; + [masterWindow setFrame:newWindowFrame display:YES animate:NO]; +} + - (void) setupUserDefaults { - // Set the display window per user preferences. - [self setIsShowingStatusBar:[[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayView_ShowStatusBar"]]; + [self setDisplayMode:(ClientDisplayMode)[[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayView_Mode"] + layout:(ClientDisplayLayout)[[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayViewCombo_Orientation"] + order:(ClientDisplayOrder)[[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayViewCombo_Order"] + rotation:[[NSUserDefaults standardUserDefaults] doubleForKey:@"DisplayView_Rotation"] + viewScale:([[NSUserDefaults standardUserDefaults] doubleForKey:@"DisplayView_Size"] / 100.0) + gapScale:([[NSUserDefaults standardUserDefaults] doubleForKey:@"DisplayViewCombo_Gap"] / 100.0) + isMinSizeNormal:[self isMinSizeNormal] + isShowingStatusBar:[[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayView_ShowStatusBar"]]; - // Set the display settings per user preferences. - [self setDisplayGap:([[NSUserDefaults standardUserDefaults] doubleForKey:@"DisplayViewCombo_Gap"] / 100.0)]; - [self setDisplayMode:[[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayView_Mode"]]; - [self setDisplayOrientation:[[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayViewCombo_Orientation"]]; - [self setDisplayOrder:[[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayViewCombo_Order"]]; - [self setDisplayScale:([[NSUserDefaults standardUserDefaults] doubleForKey:@"DisplayView_Size"] / 100.0)]; - [self setDisplayRotation:[[NSUserDefaults standardUserDefaults] doubleForKey:@"DisplayView_Rotation"]]; [self setVideoFiltersPreferGPU:[[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayView_FiltersPreferGPU"]]; [self setVideoSourceDeposterize:[[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayView_Deposterize"]]; [self setVideoOutputFilter:[[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayView_OutputFilter"]]; @@ -494,27 +553,22 @@ static std::unordered_map _screenMap; // - (BOOL) masterStatusBarState { - return (([self assignedScreen] == nil) || !_useMavericksFullScreen) ? [self isShowingStatusBar] : _masterStatusBarState; + return (![self isFullScreen] || !_useMavericksFullScreen) ? [self isShowingStatusBar] : _masterStatusBarState; } - (NSRect) masterWindowFrame { - return (([self assignedScreen] == nil) || !_useMavericksFullScreen) ? [masterWindow frame] : _masterWindowFrame; + return (![self isFullScreen] || !_useMavericksFullScreen) ? [masterWindow frame] : _masterWindowFrame; } - (double) masterWindowScale { - return (([self assignedScreen] == nil) || !_useMavericksFullScreen) ? [self displayScale] : _masterWindowScale; + return (![self isFullScreen] || !_useMavericksFullScreen) ? [self displayScale] : _masterWindowScale; } -- (void) resizeWithTransform +- (NSRect) updateViewProperties { - if ([self assignedScreen] != nil) - { - return; - } - - // Get the maximum scalar size within drawBounds. Constrain scalar to maxScalar if necessary. + // Get the maximum scalar size within drawBounds. double checkWidth = _localViewProps.normalWidth; double checkHeight = _localViewProps.normalHeight; ClientDisplayView::ConvertNormalToTransformedBounds(1.0, _localViewProps.rotation, checkWidth, checkHeight); @@ -522,9 +576,7 @@ static std::unordered_map _screenMap; // const double constrainedScale = [self maxScalarForContentBoundsWidth:checkWidth height:checkHeight]; if (_localViewProps.viewScale > constrainedScale) { - _isUpdatingDisplayScaleValueOnly = YES; - [self setDisplayScale:constrainedScale]; - _isUpdatingDisplayScaleValueOnly = NO; + _localViewProps.viewScale = constrainedScale; } // Get the new bounds for the window's content view based on the transformed draw bounds. @@ -540,7 +592,22 @@ static std::unordered_map _screenMap; // // Resize the window. const NSRect windowFrame = [masterWindow frame]; const NSRect newFrame = [masterWindow frameRectForContentRect:NSMakeRect(windowFrame.origin.x + translationX, windowFrame.origin.y + translationY, transformedWidth, transformedHeight + _statusBarHeight)]; - [masterWindow setFrame:newFrame display:YES animate:NO]; + + _localViewProps.clientWidth = newFrame.size.width; + _localViewProps.clientHeight = newFrame.size.height; + + return newFrame; +} + +- (void) resizeWithTransform +{ + if ([self isFullScreen]) + { + return; + } + + NSRect newWindowFrame = [self updateViewProperties]; + [masterWindow setFrame:newWindowFrame display:YES animate:NO]; } - (double) maxScalarForContentBoundsWidth:(double)contentBoundsWidth height:(double)contentBoundsHeight @@ -657,7 +724,7 @@ static std::unordered_map _screenMap; // { // This method only applies for displays in full screen mode. For displays in // windowed mode, we don't need to do anything. - if ([self assignedScreen] == nil) + if (![self isFullScreen]) { return; } @@ -797,13 +864,13 @@ static std::unordered_map _screenMap; // else #endif { - if ([self assignedScreen] == nil) + if ([self isFullScreen]) { - [self enterFullScreen]; + [self exitFullScreen]; } else { - [self exitFullScreen]; + [self enterFullScreen]; } } } @@ -1173,7 +1240,7 @@ static std::unordered_map _screenMap; // [(NSMenuItem *)theItem setTitle:([self isShowingStatusBar]) ? NSSTRING_TITLE_HIDE_STATUS_BAR : NSSTRING_TITLE_SHOW_STATUS_BAR]; } - if ([self assignedScreen] != nil) + if ([self isFullScreen]) { enable = NO; } @@ -1182,7 +1249,7 @@ static std::unordered_map _screenMap; // { if ([(id)theItem isMemberOfClass:[NSMenuItem class]]) { - [(NSMenuItem *)theItem setTitle:([self assignedScreen] != nil) ? NSSTRING_TITLE_EXIT_FULL_SCREEN : NSSTRING_TITLE_ENTER_FULL_SCREEN]; + [(NSMenuItem *)theItem setTitle:([self isFullScreen]) ? NSSTRING_TITLE_EXIT_FULL_SCREEN : NSSTRING_TITLE_ENTER_FULL_SCREEN]; } } else if (theAction == @selector(toggleKeepMinDisplaySizeAtNormal:)) @@ -1192,7 +1259,7 @@ static std::unordered_map _screenMap; // [(NSMenuItem *)theItem setState:([self isMinSizeNormal]) ? NSOnState : NSOffState]; } - if ([self assignedScreen] != nil) + if ([self isFullScreen]) { enable = NO; } @@ -1262,7 +1329,7 @@ static std::unordered_map _screenMap; // - (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize { - if ([self assignedScreen] != nil) + if ([self isFullScreen]) { return frameSize; } @@ -1290,7 +1357,7 @@ static std::unordered_map _screenMap; // - (void)windowDidResize:(NSNotification *)notification { - if ([self assignedScreen] != nil) + if ([self isFullScreen]) { return; } @@ -1318,7 +1385,7 @@ static std::unordered_map _screenMap; // - (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)newFrame { - if ([self assignedScreen] != nil) + if ([self isFullScreen]) { return newFrame; } @@ -1574,7 +1641,6 @@ static std::unordered_map _screenMap; // #endif inputManager = nil; - _cdv = new ClientDisplayView(); // Initialize the OpenGL context NSOpenGLPixelFormatAttribute attributes[] = { @@ -1614,18 +1680,13 @@ static std::unordered_map _screenMap; // CGLContextObj prevContext = CGLGetCurrentContext(); CGLSetCurrentContext(cglDisplayContext); - oglv = new OGLVideoOutput(); - oglv->InitLayers(); + _cdv = new MacOGLDisplayView(cglDisplayContext); + _cdv->Init(); NSString *fontPath = [[NSBundle mainBundle] pathForResource:@"SourceSansPro-Bold" ofType:@"otf"]; - oglv->GetHUDLayer()->SetFontUsingPath([fontPath cStringUsingEncoding:NSUTF8StringEncoding]); + _cdv->SetHUDFontUsingPath([fontPath cStringUsingEncoding:NSUTF8StringEncoding]); - OGLDisplayLayer *displayLayer = oglv->GetDisplayLayer(); - displayLayer->SetFiltersPreferGPUOGL(true); - displayLayer->SetSourceDeposterize(false); - displayLayer->SetOutputFilterOGL(OutputFilterTypeID_Bilinear); - displayLayer->SetPixelScalerOGL(VideoFilterTypeID_None); - canUseShaderBasedFilters = (displayLayer->CanUseShaderBasedFilters()) ? YES : NO; + canUseShaderBasedFilters = (_cdv->CanFilterOnGPU()) ? YES : NO; CGLSetCurrentContext(prevContext); @@ -1638,6 +1699,8 @@ static std::unordered_map _screenMap; // spinlockSourceDeposterize = OS_SPINLOCK_INIT; spinlockPixelScaler = OS_SPINLOCK_INIT; + spinlockViewProperties = OS_SPINLOCK_INIT; + return self; } @@ -1645,10 +1708,9 @@ static std::unordered_map _screenMap; // { CGLContextObj prevContext = CGLGetCurrentContext(); CGLSetCurrentContext(cglDisplayContext); - delete oglv; + delete _cdv; CGLSetCurrentContext(prevContext); - delete _cdv; [self setInputManager:nil]; [context clearDrawable]; [context release]; @@ -1664,8 +1726,8 @@ static std::unordered_map _screenMap; // CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - oglv->GetHUDLayer()->SetVisibility((theState) ? true : false); - [self drawVideoFrame]; + _cdv->SetHUDVisibility((theState) ? true : false); + _cdv->FrameRenderAndFlush(); CGLUnlockContext(cglDisplayContext); OSSpinLockUnlock(&spinlockIsHUDVisible); @@ -1674,7 +1736,7 @@ static std::unordered_map _screenMap; // - (BOOL) isHUDVisible { OSSpinLockLock(&spinlockIsHUDVisible); - const BOOL theState = (oglv->GetHUDLayer()->IsVisible()) ? YES : NO; + const BOOL theState = (_cdv->GetHUDVisibility()) ? YES : NO; OSSpinLockUnlock(&spinlockIsHUDVisible); return theState; @@ -1686,8 +1748,8 @@ static std::unordered_map _screenMap; // CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - oglv->GetHUDLayer()->SetShowVideoFPS((theState) ? true : false); - [self drawVideoFrame]; + _cdv->SetHUDShowVideoFPS((theState) ? true : false); + _cdv->FrameRenderAndFlush(); CGLUnlockContext(cglDisplayContext); OSSpinLockUnlock(&spinlockIsHUDVisible); @@ -1696,7 +1758,7 @@ static std::unordered_map _screenMap; // - (BOOL) isHUDVideoFPSVisible { OSSpinLockLock(&spinlockIsHUDVisible); - const BOOL theState = (oglv->GetHUDLayer()->GetShowVideoFPS()) ? YES : NO; + const BOOL theState = (_cdv->GetHUDShowVideoFPS()) ? YES : NO; OSSpinLockUnlock(&spinlockIsHUDVisible); return theState; @@ -1708,8 +1770,8 @@ static std::unordered_map _screenMap; // CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - oglv->GetHUDLayer()->SetShowRender3DFPS((theState) ? true : false); - [self drawVideoFrame]; + _cdv->SetHUDShowRender3DFPS((theState) ? true : false); + _cdv->FrameRenderAndFlush(); CGLUnlockContext(cglDisplayContext); OSSpinLockUnlock(&spinlockIsHUDVisible); @@ -1718,7 +1780,7 @@ static std::unordered_map _screenMap; // - (BOOL) isHUDRender3DFPSVisible { OSSpinLockLock(&spinlockIsHUDVisible); - const BOOL theState = (oglv->GetHUDLayer()->GetShowRender3DFPS()) ? YES : NO; + const BOOL theState = (_cdv->GetHUDShowRender3DFPS()) ? YES : NO; OSSpinLockUnlock(&spinlockIsHUDVisible); return theState; @@ -1730,8 +1792,8 @@ static std::unordered_map _screenMap; // CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - oglv->GetHUDLayer()->SetShowFrameIndex((theState) ? true : false); - [self drawVideoFrame]; + _cdv->SetHUDShowFrameIndex((theState) ? true : false); + _cdv->FrameRenderAndFlush(); CGLUnlockContext(cglDisplayContext); OSSpinLockUnlock(&spinlockIsHUDVisible); @@ -1740,7 +1802,7 @@ static std::unordered_map _screenMap; // - (BOOL) isHUDFrameIndexVisible { OSSpinLockLock(&spinlockIsHUDVisible); - const BOOL theState = (oglv->GetHUDLayer()->GetShowFrameIndex()) ? YES : NO; + const BOOL theState = (_cdv->GetHUDShowFrameIndex()) ? YES : NO; OSSpinLockUnlock(&spinlockIsHUDVisible); return theState; @@ -1752,8 +1814,8 @@ static std::unordered_map _screenMap; // CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - oglv->GetHUDLayer()->SetShowLagFrameCount((theState) ? true : false); - [self drawVideoFrame]; + _cdv->SetHUDShowLagFrameCount((theState) ? true : false); + _cdv->FrameRenderAndFlush(); CGLUnlockContext(cglDisplayContext); OSSpinLockUnlock(&spinlockIsHUDVisible); @@ -1762,7 +1824,7 @@ static std::unordered_map _screenMap; // - (BOOL) isHUDLagFrameCountVisible { OSSpinLockLock(&spinlockIsHUDVisible); - const BOOL theState = (oglv->GetHUDLayer()->GetShowLagFrameCount()) ? YES : NO; + const BOOL theState = (_cdv->GetHUDShowLagFrameCount()) ? YES : NO; OSSpinLockUnlock(&spinlockIsHUDVisible); return theState; @@ -1774,8 +1836,8 @@ static std::unordered_map _screenMap; // CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - oglv->GetHUDLayer()->SetShowCPULoadAverage((theState) ? true : false); - [self drawVideoFrame]; + _cdv->SetHUDShowCPULoadAverage((theState) ? true : false); + _cdv->FrameRenderAndFlush(); CGLUnlockContext(cglDisplayContext); OSSpinLockUnlock(&spinlockIsHUDVisible); @@ -1784,7 +1846,7 @@ static std::unordered_map _screenMap; // - (BOOL) isHUDCPULoadAverageVisible { OSSpinLockLock(&spinlockIsHUDVisible); - const BOOL theState = (oglv->GetHUDLayer()->GetShowCPULoadAverage()) ? YES : NO; + const BOOL theState = (_cdv->GetHUDShowCPULoadAverage()) ? YES : NO; OSSpinLockUnlock(&spinlockIsHUDVisible); return theState; @@ -1796,8 +1858,8 @@ static std::unordered_map _screenMap; // CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - oglv->GetHUDLayer()->SetShowRTC((theState) ? true : false); - [self drawVideoFrame]; + _cdv->SetHUDShowRTC((theState) ? true : false); + _cdv->FrameRenderAndFlush(); CGLUnlockContext(cglDisplayContext); OSSpinLockUnlock(&spinlockIsHUDVisible); @@ -1806,7 +1868,7 @@ static std::unordered_map _screenMap; // - (BOOL) isHUDRealTimeClockVisible { OSSpinLockLock(&spinlockIsHUDVisible); - const BOOL theState = (oglv->GetHUDLayer()->GetShowRTC()) ? YES : NO; + const BOOL theState = (_cdv->GetHUDShowRTC()) ? YES : NO; OSSpinLockUnlock(&spinlockIsHUDVisible); return theState; @@ -1841,7 +1903,7 @@ static std::unordered_map _screenMap; // CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - oglv->GetDisplayLayer()->SetFiltersPreferGPUOGL((theState) ? true : false); + _cdv->SetFiltersPreferGPU((theState) ? true : false); CGLUnlockContext(cglDisplayContext); OSSpinLockUnlock(&spinlockVideoFiltersPreferGPU); @@ -1850,7 +1912,7 @@ static std::unordered_map _screenMap; // - (BOOL) videoFiltersPreferGPU { OSSpinLockLock(&spinlockVideoFiltersPreferGPU); - const BOOL theState = (oglv->GetDisplayLayer()->GetFiltersPreferGPU()) ? YES : NO; + const BOOL theState = (_cdv->GetFiltersPreferGPU()) ? YES : NO; OSSpinLockUnlock(&spinlockVideoFiltersPreferGPU); return theState; @@ -1859,14 +1921,14 @@ static std::unordered_map _screenMap; // - (void) setSourceDeposterize:(BOOL)theState { OSSpinLockLock(&spinlockSourceDeposterize); - oglv->GetDisplayLayer()->SetSourceDeposterize((theState) ? true : false); + _cdv->SetSourceDeposterize((theState) ? true : false); OSSpinLockUnlock(&spinlockSourceDeposterize); } - (BOOL) sourceDeposterize { OSSpinLockLock(&spinlockSourceDeposterize); - const BOOL theState = (oglv->GetDisplayLayer()->GetSourceDeposterize()) ? YES : NO; + const BOOL theState = (_cdv->GetSourceDeposterize()) ? YES : NO; OSSpinLockUnlock(&spinlockSourceDeposterize); return theState; @@ -1878,7 +1940,7 @@ static std::unordered_map _screenMap; // CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - oglv->GetDisplayLayer()->SetOutputFilterOGL(filterID); + _cdv->SetOutputFilter((OutputFilterTypeID)filterID); CGLUnlockContext(cglDisplayContext); OSSpinLockUnlock(&spinlockOutputFilter); @@ -1887,7 +1949,7 @@ static std::unordered_map _screenMap; // - (NSInteger) outputFilter { OSSpinLockLock(&spinlockOutputFilter); - const NSInteger filterID = oglv->GetDisplayLayer()->GetOutputFilter(); + const NSInteger filterID = _cdv->GetOutputFilter(); OSSpinLockUnlock(&spinlockOutputFilter); return filterID; @@ -1899,7 +1961,7 @@ static std::unordered_map _screenMap; // CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - oglv->GetDisplayLayer()->SetPixelScalerOGL(filterID); + _cdv->SetPixelScaler((VideoFilterTypeID)filterID); CGLUnlockContext(cglDisplayContext); OSSpinLockUnlock(&spinlockPixelScaler); @@ -1908,7 +1970,7 @@ static std::unordered_map _screenMap; // - (NSInteger) pixelScaler { OSSpinLockLock(&spinlockPixelScaler); - const NSInteger filterID = oglv->GetDisplayLayer()->GetPixelScaler(); + const NSInteger filterID = _cdv->GetPixelScaler(); OSSpinLockUnlock(&spinlockPixelScaler); return filterID; @@ -1922,16 +1984,33 @@ static std::unordered_map _screenMap; // CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - oglv->SetScaleFactor(theScaleFactor); + _cdv->SetScaleFactor(theScaleFactor); CGLUnlockContext(cglDisplayContext); OSSpinLockUnlock(&spinlockIsHUDVisible); } -- (void) drawVideoFrame +- (void) commitViewProperties:(const ClientDisplayViewProperties &)viewProps { - oglv->RenderOGL(); - CGLFlushDrawable(cglDisplayContext); + OSSpinLockLock(&spinlockViewProperties); + _intermediateViewProps = viewProps; + OSSpinLockUnlock(&spinlockViewProperties); + + DisplayWindowController *windowController = (DisplayWindowController *)[[self window] delegate]; + [CocoaDSUtil messageSendOneWay:[[windowController cdsVideoOutput] receivePort] msgID:MESSAGE_CHANGE_VIEW_PROPERTIES]; +} + +- (void) setupViewProperties +{ + OSSpinLockLock(&spinlockViewProperties); + _cdv->CommitViewProperties(_intermediateViewProps); + OSSpinLockUnlock(&spinlockViewProperties); + + CGLLockContext(cglDisplayContext); + CGLSetCurrentContext(cglDisplayContext); + _cdv->SetupViewProperties(); + _cdv->FrameRenderAndFlush(); + CGLUnlockContext(cglDisplayContext); } #pragma mark InputHIDManagerTarget Protocol @@ -2081,7 +2160,11 @@ static std::unordered_map _screenMap; // #else const NSRect newViewportRect = rect; #endif - [CocoaDSUtil messageSendOneWayWithRect:[[windowController cdsVideoOutput] receivePort] msgID:MESSAGE_RESIZE_VIEW rect:newViewportRect]; + + ClientDisplayViewProperties &props = [windowController localViewProperties]; + props.clientWidth = newViewportRect.size.width; + props.clientHeight = newViewportRect.size.height; + [self commitViewProperties:props]; } } @@ -2198,12 +2281,10 @@ static std::unordered_map _screenMap; // - (void)doLoadVideoFrameWithMainSizeNative:(bool)isMainSizeNative touchSizeNative:(bool)isTouchSizeNative { - OGLDisplayLayer *displayLayer = oglv->GetDisplayLayer(); - CGLLockContext(cglDisplayContext); CGLSetCurrentContext(cglDisplayContext); - displayLayer->LoadFrameOGL(isMainSizeNative, isTouchSizeNative); - displayLayer->ProcessOGL(); + _cdv->FrameLoadGPU(isMainSizeNative, isTouchSizeNative); + _cdv->FrameProcessGPU(); CGLUnlockContext(cglDisplayContext); } @@ -2218,139 +2299,32 @@ static std::unordered_map _screenMap; // customWidth1:(const size_t)customWidth1 customHeight1:(const size_t)customHeight1 { - OGLDisplayLayer *displayLayer = oglv->GetDisplayLayer(); - - CGLLockContext(cglDisplayContext); - CGLSetCurrentContext(cglDisplayContext); - displayLayer->SetVideoBuffers(colorFormat, - videoBufferHead, - nativeBuffer0, - nativeBuffer1, - customBuffer0, customWidth0, customHeight0, - customBuffer1, customWidth1, customHeight1); - CGLUnlockContext(cglDisplayContext); + _cdv->SetVideoBuffers(colorFormat, + videoBufferHead, + nativeBuffer0, + nativeBuffer1, + customBuffer0, customWidth0, customHeight0, + customBuffer1, customWidth1, customHeight1); } - (void)doFinishFrame { - OGLDisplayLayer *displayLayer = oglv->GetDisplayLayer(); - - CGLLockContext(cglDisplayContext); - CGLSetCurrentContext(cglDisplayContext); - displayLayer->FinishOGL(); - CGLUnlockContext(cglDisplayContext); + _cdv->FrameFinish(); } - (void)doProcessVideoFrameWithInfo:(const NDSFrameInfo &)frameInfo { - OGLHUDLayer *hudLayer = oglv->GetHUDLayer(); - - CGLLockContext(cglDisplayContext); - CGLSetCurrentContext(cglDisplayContext); - - if (hudLayer->IsVisible()) - { - hudLayer->SetInfo(frameInfo.videoFPS, - frameInfo.render3DFPS, - frameInfo.frameIndex, - frameInfo.lagFrameCount, - frameInfo.rtcString, - frameInfo.cpuLoadAvgARM9, - frameInfo.cpuLoadAvgARM7); - hudLayer->ProcessOGL(); - } - - [self drawVideoFrame]; - CGLUnlockContext(cglDisplayContext); + _cdv->SetHUDInfo(frameInfo); } -- (void)doResizeView:(NSRect)rect +- (void)doViewPropertiesChanged { - const GLsizei w = (GLsizei)rect.size.width; - const GLsizei h = (GLsizei)rect.size.height; - - _cdv->SetClientSize(rect.size.width, rect.size.height); - - double hudObjectScale = _cdv->GetViewScale(); - if (hudObjectScale > 2.0) - { - // If the view scale is <= 2.0, we scale the HUD objects linearly. Otherwise, we scale - // the HUD objects logarithmically, up to a maximum scale of 3.0. - hudObjectScale = ( -1.0/((1.0/12000.0)*pow(hudObjectScale+4.5438939, 5.0)) ) + 3.0; - } - - CGLLockContext(cglDisplayContext); - CGLSetCurrentContext(cglDisplayContext); - oglv->SetViewportSizeOGL(w, h); - oglv->GetHUDLayer()->SetObjectScale(hudObjectScale); - oglv->GetHUDLayer()->ProcessVerticesOGL(); - [self drawVideoFrame]; - CGLUnlockContext(cglDisplayContext); -} - -- (void)doTransformView:(const DisplayOutputTransformData *)transformData -{ - _cdv->SetRotation(transformData->rotation); - - OGLDisplayLayer *display = oglv->GetDisplayLayer(); - display->SetRotation((GLfloat)transformData->rotation); - [self doRedraw]; + [self setupViewProperties]; } - (void)doRedraw { - CGLLockContext(cglDisplayContext); - CGLSetCurrentContext(cglDisplayContext); - [self drawVideoFrame]; - CGLUnlockContext(cglDisplayContext); -} - -- (void)doDisplayModeChanged:(NSInteger)displayModeID -{ - _cdv->SetMode((ClientDisplayMode)displayModeID); - - OGLDisplayLayer *display = oglv->GetDisplayLayer(); - display->SetMode((ClientDisplayMode)displayModeID); - [self doRedraw]; -} - -- (void)doDisplayOrientationChanged:(NSInteger)displayOrientationID -{ - _cdv->SetLayout((ClientDisplayLayout)displayOrientationID); - - OGLDisplayLayer *display = oglv->GetDisplayLayer(); - display->SetOrientation((ClientDisplayLayout)displayOrientationID); - - if (display->GetMode() == ClientDisplayMode_Dual) - { - [self doRedraw]; - } -} - -- (void)doDisplayOrderChanged:(NSInteger)displayOrderID -{ - _cdv->SetOrder((ClientDisplayOrder)displayOrderID); - - OGLDisplayLayer *display = oglv->GetDisplayLayer(); - display->SetOrder((ClientDisplayOrder)displayOrderID); - - if (display->GetMode() == ClientDisplayMode_Dual) - { - [self doRedraw]; - } -} - -- (void)doDisplayGapChanged:(float)displayGapScalar -{ - _cdv->SetGapWithScalar(displayGapScalar); - - OGLDisplayLayer *display = oglv->GetDisplayLayer(); - display->SetGapScalar((GLfloat)displayGapScalar); - - if (display->GetMode() == ClientDisplayMode_Dual) - { - [self doRedraw]; - } + _cdv->UpdateView(); } @end diff --git a/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm b/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm index de9317bb6..16e17963d 100644 --- a/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm @@ -32,8 +32,6 @@ #import "cocoa_rom.h" #import "cocoa_slot2.h" -#include "../OGLDisplayOutput.h" - @implementation EmuControllerDelegate @synthesize inputManager; diff --git a/desmume/src/frontend/cocoa/userinterface/appDelegate.mm b/desmume/src/frontend/cocoa/userinterface/appDelegate.mm index 4d4b25d6d..9036725d5 100644 --- a/desmume/src/frontend/cocoa/userinterface/appDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/appDelegate.mm @@ -648,22 +648,26 @@ int frameX = 0; int frameY = 0; int frameWidth = 256; - int frameHeight = 192; + int frameHeight = 192*2; const char *frameCStr = [windowFrameStr cStringUsingEncoding:NSUTF8StringEncoding]; sscanf(frameCStr, "%i %i %i %i", &frameX, &frameY, &frameWidth, &frameHeight); - [windowController setIsShowingStatusBar:isShowingStatusBar]; + // Force the window to load now so that we can overwrite its internal defaults with the user's defaults. + [windowController window]; + + [windowController setDisplayMode:(ClientDisplayMode)displayMode + layout:(ClientDisplayLayout)displayOrientation + order:(ClientDisplayOrder)displayOrder + rotation:displayRotation + viewScale:displayScale + gapScale:displayGap + isMinSizeNormal:isMinSizeNormal + isShowingStatusBar:isShowingStatusBar]; + [windowController setVideoFiltersPreferGPU:videoFiltersPreferGPU]; [windowController setVideoSourceDeposterize:videoSourceDeposterize]; [windowController setVideoPixelScaler:videoPixelScaler]; [windowController setVideoOutputFilter:videoOutputFilter]; - [windowController setDisplayMode:displayMode]; - [windowController setDisplayOrientation:displayOrientation]; - [windowController setDisplayOrder:displayOrder]; - [windowController setDisplayGap:displayGap]; - [windowController setIsMinSizeNormal:isMinSizeNormal]; - [windowController setDisplayRotation:displayRotation]; - [windowController setDisplayScale:displayScale]; [windowController setScreenshotFileFormat:screenshotFileFormat]; [[windowController view] setUseVerticalSync:useVerticalSync]; [[windowController view] setIsHUDVisible:hudEnable]; @@ -719,7 +723,6 @@ for (DisplayWindowController *windowController in windowList) { - const BOOL isInFullScreenMode = ([windowController assignedScreen] != nil); const NSUInteger screenIndex = [[NSScreen screens] indexOfObject:[[windowController masterWindow] screen]]; const NSRect windowFrame = [windowController masterWindowFrame]; @@ -748,7 +751,7 @@ [NSNumber numberWithBool:[[windowController view] isHUDRealTimeClockVisible]], @"hudShowRTC", [NSNumber numberWithBool:[windowController isMinSizeNormal]], @"isMinSizeNormal", [NSNumber numberWithBool:[windowController masterStatusBarState]], @"isShowingStatusBar", - [NSNumber numberWithBool:isInFullScreenMode], @"isInFullScreenMode", + [NSNumber numberWithBool:[windowController isFullScreen]], @"isInFullScreenMode", [NSNumber numberWithUnsignedInteger:screenIndex], @"screenIndex", windowFrameStr, @"windowFrame", nil];