From d880c58f759411b90131026c098e69e676aa1afb Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 21 Jan 2015 02:09:59 +0000 Subject: [PATCH] Cocoa Port: - Read the GPU_screen buffer directly and avoid making multiple copies of it. Improves performance when many display windows are used. --- desmume/src/cocoa/OGLDisplayOutput.cpp | 140 +++++++++------- desmume/src/cocoa/OGLDisplayOutput.h | 17 +- desmume/src/cocoa/cocoa_GPU.h | 3 +- desmume/src/cocoa/cocoa_GPU.mm | 24 ++- desmume/src/cocoa/cocoa_core.mm | 1 + desmume/src/cocoa/cocoa_globals.h | 4 +- desmume/src/cocoa/cocoa_output.h | 28 ++-- desmume/src/cocoa/cocoa_output.mm | 224 ++++++------------------- 8 files changed, 178 insertions(+), 263 deletions(-) diff --git a/desmume/src/cocoa/OGLDisplayOutput.cpp b/desmume/src/cocoa/OGLDisplayOutput.cpp index 0b16aa919..f9de866a7 100644 --- a/desmume/src/cocoa/OGLDisplayOutput.cpp +++ b/desmume/src/cocoa/OGLDisplayOutput.cpp @@ -1470,11 +1470,11 @@ void OGLVideoOutput::SetViewportSizeOGL(GLsizei w, GLsizei h) } } -void OGLVideoOutput::ProcessOGL(const uint16_t *videoData, GLsizei w, GLsizei h) +void OGLVideoOutput::ProcessOGL() { for (size_t i = 0; i < _layerList->size(); i++) { - (*_layerList)[i]->ProcessOGL(videoData, w, h); + (*_layerList)[i]->ProcessOGL(); } } @@ -1736,6 +1736,9 @@ OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO) _displayOrder = DS_DISPLAY_ORDER_MAIN_FIRST; _displayOrientation = DS_DISPLAY_ORIENTATION_VERTICAL; + _vtxElementCount = (_displayMode == DS_DISPLAY_TYPE_DUAL) ? 12 : 6; + _vtxElementPointer = !(_displayMode == DS_DISPLAY_TYPE_TOUCH) ? 0 : (GLubyte *)(_vtxElementCount * sizeof(GLubyte)); + _normalWidth = GPU_DISPLAY_WIDTH; _normalHeight = GPU_DISPLAY_HEIGHT*2.0 + (DS_DISPLAY_GAP*_gapScalar); _rotation = 0.0f; @@ -1756,9 +1759,10 @@ OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO) // Set up textures glGenTextures(1, &_texCPUFilterDstID); - glGenTextures(1, &_texInputVideoDataID); - _texOutputVideoDataID = _texInputVideoDataID; - _texPrevOutputVideoDataID = _texInputVideoDataID; + glGenTextures(1, &_texVideoInputDataID); + _texVideoSourceID = _texVideoInputDataID; + _texVideoPixelScalerID = _texVideoInputDataID; + _texVideoOutputID = _texVideoInputDataID; glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texCPUFilterDstID); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -1768,7 +1772,7 @@ OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE); glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, _vfDual->GetDstWidth() * _vfDual->GetDstHeight() * sizeof(uint32_t), _vfMasterDstBuffer); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texInputVideoDataID); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texVideoInputDataID); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -1865,7 +1869,7 @@ OGLDisplayLayer::~OGLDisplayLayer() glDeleteBuffersARB(1, &this->_vboTexCoordID); glDeleteBuffersARB(1, &this->_vboElementID); glDeleteTextures(1, &this->_texCPUFilterDstID); - glDeleteTextures(1, &this->_texInputVideoDataID); + glDeleteTextures(1, &this->_texVideoInputDataID); if (_canUseShaderOutput) { @@ -1908,15 +1912,21 @@ void OGLDisplayLayer::SetMode(int dispMode) case DS_DISPLAY_TYPE_MAIN: this->_vfSingle->SetDstBufferPtr(_vfMasterDstBuffer); this->_vf = this->_vfSingle; + this->_vtxElementCount = 6; + this->_vtxElementPointer = 0; break; case DS_DISPLAY_TYPE_TOUCH: this->_vfSingle->SetDstBufferPtr(_vfMasterDstBuffer + (this->_vfSingle->GetDstWidth() * this->_vfSingle->GetDstHeight()) ); this->_vf = this->_vfSingle; + this->_vtxElementCount = 6; + this->_vtxElementPointer = (GLubyte *)(this->_vtxElementCount * sizeof(GLubyte)); break; case DS_DISPLAY_TYPE_DUAL: this->_vf = this->_vfDual; + this->_vtxElementCount = 12; + this->_vtxElementPointer = 0; break; default: @@ -2279,8 +2289,8 @@ void OGLDisplayLayer::SetCPUFilterOGL(const VideoFilterTypeID videoFilterTypeID) const VideoFilterAttributes newFilterAttr = VideoFilter::GetAttributesByID(videoFilterTypeID); const size_t oldDstBufferWidth = this->_vfDual->GetDstWidth(); const size_t oldDstBufferHeight = this->_vfDual->GetDstHeight(); - const GLsizei newDstBufferWidth = GPU_DISPLAY_WIDTH * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide; - const GLsizei newDstBufferHeight = GPU_DISPLAY_HEIGHT * 2 * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide; + const GLsizei newDstBufferWidth = this->_vfDual->GetSrcWidth() * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide; + const GLsizei newDstBufferHeight = this->_vfDual->GetSrcHeight() * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide; if (oldDstBufferWidth != newDstBufferWidth || oldDstBufferHeight != newDstBufferHeight) { @@ -2327,73 +2337,80 @@ void OGLDisplayLayer::SetCPUFilterOGL(const VideoFilterTypeID videoFilterTypeID) this->_vfDual->ChangeFilterByID(videoFilterTypeID); } -void OGLDisplayLayer::ProcessOGL(const uint16_t *videoData, GLsizei w, GLsizei h) +void OGLDisplayLayer::LoadFrameOGL(const uint16_t *frameData, GLsizei w, GLsizei h) +{ + const GLint lineOffset = (this->_displayMode == DS_DISPLAY_TYPE_TOUCH) ? h : 0; + const bool isUsingCPUPixelScaler = this->_pixelScaler != VideoFilterTypeID_None && !(this->_useShaderBasedPixelScaler && this->_filtersPreferGPU); + + if (!isUsingCPUPixelScaler) + { + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoInputDataID); + glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, lineOffset, w, h, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frameData); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + } + else + { + RGB555ToBGRA8888Buffer((const uint16_t *)frameData, this->_vf->GetSrcBufferPtr(), w * h); + } +} + +void OGLDisplayLayer::ProcessOGL() { VideoFilter *currentFilter = this->_vf; - GLint lineOffset = (this->_displayMode == DS_DISPLAY_TYPE_TOUCH) ? h : 0; + const bool isUsingCPUPixelScaler = this->_pixelScaler != VideoFilterTypeID_None && !(this->_useShaderBasedPixelScaler && this->_filtersPreferGPU); - // Determine whether we should take CPU-based path or a GPU-based path - if (this->_pixelScaler != VideoFilterTypeID_None && !(this->_useShaderBasedPixelScaler && this->_filtersPreferGPU) ) + // Source + if (this->_useDeposterize) { - if (!this->_useDeposterize) // Pure CPU-based path + this->_texVideoSourceID = this->_filterDeposterize->RunFilterOGL(this->_texVideoInputDataID, this->_viewportWidth, this->_viewportHeight); + + if (isUsingCPUPixelScaler) // Hybrid CPU/GPU-based path (may cause a performance hit on pixel download) { - RGB555ToBGRA8888Buffer((const uint16_t *)videoData, (uint32_t *)currentFilter->GetSrcBufferPtr(), w * h); - } - else // Hybrid CPU/GPU-based path (may cause a performance hit on pixel download) - { - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texInputVideoDataID); - glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, lineOffset, w, h, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, videoData); - - this->_filterDeposterize->RunFilterOGL(this->_texInputVideoDataID, this->_viewportWidth, this->_viewportHeight); - + const GLint lineOffset = (this->_displayMode == DS_DISPLAY_TYPE_TOUCH) ? GPU_DISPLAY_HEIGHT : 0; const GLsizei readLineCount = (this->_displayMode == DS_DISPLAY_TYPE_DUAL) ? GPU_DISPLAY_HEIGHT * 2 : GPU_DISPLAY_HEIGHT; this->_filterDeposterize->DownloadDstBufferOGL(currentFilter->GetSrcBufferPtr(), lineOffset, readLineCount); } - - uint32_t *texData = currentFilter->RunFilter(); - w = currentFilter->GetDstWidth(); - h = currentFilter->GetDstHeight(); - lineOffset = (this->_displayMode == DS_DISPLAY_TYPE_TOUCH) ? h : 0; - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texCPUFilterDstID); - glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, lineOffset, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texData); - - this->_texOutputVideoDataID = this->_texCPUFilterDstID; - this->UpdateTexCoords(w, (this->_displayMode == DS_DISPLAY_TYPE_DUAL) ? h : h*2); } - else // Pure GPU-based path + else + { + this->_texVideoSourceID = this->_texVideoInputDataID; + } + + // Pixel scaler + if (!isUsingCPUPixelScaler) { - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texInputVideoDataID); - glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, lineOffset, w, h, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, videoData); - - if (this->_useDeposterize) - { - this->_texOutputVideoDataID = this->_filterDeposterize->RunFilterOGL(this->_texInputVideoDataID, this->_viewportWidth, this->_viewportHeight); - } - else - { - this->_texOutputVideoDataID = this->_texInputVideoDataID; - } - - if (this->_displayMode != DS_DISPLAY_TYPE_DUAL) - { - h *= 2; - } - if (this->_useShaderBasedPixelScaler) { - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texOutputVideoDataID); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoSourceID); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - this->_texOutputVideoDataID = this->_shaderFilter->RunFilterOGL(this->_texOutputVideoDataID, this->_viewportWidth, this->_viewportHeight); - w = this->_shaderFilter->GetDstWidth(); - h = this->_shaderFilter->GetDstHeight(); + this->_texVideoPixelScalerID = this->_shaderFilter->RunFilterOGL(this->_texVideoSourceID, this->_viewportWidth, this->_viewportHeight); + + this->UpdateTexCoords(this->_shaderFilter->GetDstWidth(), this->_shaderFilter->GetDstHeight()); } + else + { + this->_texVideoPixelScalerID = this->_texVideoSourceID; + this->UpdateTexCoords(GPU_DISPLAY_WIDTH, GPU_DISPLAY_HEIGHT*2); + } + } + else + { + uint32_t *texData = currentFilter->RunFilter(); - this->UpdateTexCoords(w, h); + const GLfloat w = currentFilter->GetDstWidth(); + const GLfloat h = currentFilter->GetDstHeight(); + const GLsizei lineOffset = (this->_displayMode == DS_DISPLAY_TYPE_TOUCH) ? h : 0; + this->_texVideoPixelScalerID = this->_texCPUFilterDstID; + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoPixelScalerID); + glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, lineOffset, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texData); + this->UpdateTexCoords(w, (this->_displayMode == DS_DISPLAY_TYPE_DUAL) ? h : h*2); } + // Output + this->_texVideoOutputID = this->_texVideoPixelScalerID; this->UploadTexCoordsOGL(); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); } @@ -2403,7 +2420,7 @@ void OGLDisplayLayer::RenderOGL() glUseProgram(this->_finalOutputProgram->GetProgramID()); this->UploadTransformationOGL(); - if (_needUploadVertices) + if (this->_needUploadVertices) { this->UploadVerticesOGL(); } @@ -2411,14 +2428,11 @@ void OGLDisplayLayer::RenderOGL() // Enable vertex attributes glBindVertexArrayAPPLE(this->_vaoMainStatesID); - const GLsizei vtxElementCount = (this->_displayMode == DS_DISPLAY_TYPE_DUAL) ? 12 : 6; - const GLubyte *elementPointer = !(this->_displayMode == DS_DISPLAY_TYPE_TOUCH) ? 0 : (GLubyte *)(vtxElementCount * sizeof(GLubyte)); - glClear(GL_COLOR_BUFFER_BIT); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texOutputVideoDataID); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter); - glDrawElements(GL_TRIANGLES, vtxElementCount, GL_UNSIGNED_BYTE, elementPointer); + glDrawElements(GL_TRIANGLES, this->_vtxElementCount, GL_UNSIGNED_BYTE, this->_vtxElementPointer); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); // Disable vertex attributes diff --git a/desmume/src/cocoa/OGLDisplayOutput.h b/desmume/src/cocoa/OGLDisplayOutput.h index c3c88260c..3d2015c68 100644 --- a/desmume/src/cocoa/OGLDisplayOutput.h +++ b/desmume/src/cocoa/OGLDisplayOutput.h @@ -185,7 +185,7 @@ public: this->_viewportHeight = h; }; - virtual void ProcessOGL(const uint16_t *videoData, GLsizei w, GLsizei h) {}; + virtual void ProcessOGL() {}; virtual void RenderOGL() {}; }; @@ -219,6 +219,9 @@ protected: GLfloat _gapScalar; GLfloat _rotation; + GLsizei _vtxElementCount; + GLubyte *_vtxElementPointer; + GLint _displayTexFilter; GLuint _texCPUFilterDstID; @@ -226,9 +229,10 @@ protected: GLfloat texCoordBuffer[2 * 8]; size_t _vtxBufferOffset; - GLuint _texInputVideoDataID; - GLuint _texOutputVideoDataID; - GLuint _texPrevOutputVideoDataID; + GLuint _texVideoInputDataID; + GLuint _texVideoSourceID; + GLuint _texVideoPixelScalerID; + GLuint _texVideoOutputID; GLuint _vaoMainStatesID; GLuint _vboVertexID; GLuint _vboTexCoordID; @@ -275,7 +279,8 @@ public: int GetPixelScaler(); virtual void SetPixelScalerOGL(const int filterID); virtual void SetCPUFilterOGL(const VideoFilterTypeID videoFilterTypeID); - virtual void ProcessOGL(const uint16_t *videoData, GLsizei w, GLsizei h); + virtual void LoadFrameOGL(const uint16_t *frameData, GLsizei w, GLsizei h); + virtual void ProcessOGL(); virtual void RenderOGL(); }; @@ -297,7 +302,7 @@ public: virtual GLsizei GetViewportHeight(); OGLDisplayLayer* GetDisplayLayer(); - virtual void ProcessOGL(const uint16_t *videoData, GLsizei w, GLsizei h); + virtual void ProcessOGL(); virtual void RenderOGL(); virtual void SetViewportSizeOGL(GLsizei w, GLsizei h); }; diff --git a/desmume/src/cocoa/cocoa_GPU.h b/desmume/src/cocoa/cocoa_GPU.h index d0d6f17c7..5576dd1ca 100644 --- a/desmume/src/cocoa/cocoa_GPU.h +++ b/desmume/src/cocoa/cocoa_GPU.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2014 DeSmuME team + Copyright (C) 2013-2015 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -70,6 +70,7 @@ extern "C" { #endif +void GPU_FillScreenWithBGRA5551(const uint16_t colorValue); void SetGPULayerState(const int gpuType, const unsigned int i, const bool state); bool GetGPULayerState(const int gpuType, const unsigned int i); void SetGPUDisplayState(const int gpuType, const bool state); diff --git a/desmume/src/cocoa/cocoa_GPU.mm b/desmume/src/cocoa/cocoa_GPU.mm index db5b79e0e..0b6a20b1b 100644 --- a/desmume/src/cocoa/cocoa_GPU.mm +++ b/desmume/src/cocoa/cocoa_GPU.mm @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2014 DeSmuME team + Copyright (C) 2013-2015 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -100,6 +100,8 @@ GPU3DInterface *core3DList[] = { &OSXOpenGLRendererBegin, &OSXOpenGLRendererEnd); + GPU_FillScreenWithBGRA5551(0x8000); + return self; } @@ -821,6 +823,26 @@ bool GetGPUDisplayState(const int gpuType) return theState; } +void GPU_FillScreenWithBGRA5551(const uint16_t colorValue) +{ + const size_t pixCount = sizeof(GPU_screen) / sizeof(uint16_t); + +#ifdef __APPLE__ + if (pixCount % 16 == 0) + { + const uint16_t colorValuePattern[] = {colorValue, colorValue, colorValue, colorValue, colorValue, colorValue, colorValue, colorValue}; + memset_pattern16(GPU_screen, colorValuePattern, sizeof(GPU_screen)); + } + else +#endif + { + for (size_t i = 0; i < pixCount; i++) + { + ((uint16_t *)GPU_screen)[i] = colorValue; + } + } +} + CGLContextObj OSXOpenGLRendererContext = NULL; CGLPBufferObj OSXOpenGLRendererPBuffer = NULL; diff --git a/desmume/src/cocoa/cocoa_core.mm b/desmume/src/cocoa/cocoa_core.mm index 4ff2aed25..fd7771b8d 100644 --- a/desmume/src/cocoa/cocoa_core.mm +++ b/desmume/src/cocoa/cocoa_core.mm @@ -890,6 +890,7 @@ volatile bool execute = true; pthread_mutex_lock(&threadParam.mutexThreadExecute); NDS_Reset(); + GPU_FillScreenWithBGRA5551(0xFFFF); pthread_mutex_unlock(&threadParam.mutexThreadExecute); [self restoreCoreState]; diff --git a/desmume/src/cocoa/cocoa_globals.h b/desmume/src/cocoa/cocoa_globals.h index 0f303ee40..3de60a501 100644 --- a/desmume/src/cocoa/cocoa_globals.h +++ b/desmume/src/cocoa/cocoa_globals.h @@ -1,6 +1,6 @@ /* Copyright (C) 2011 Roger Manuel - Copyright (C) 2012-2014 DeSmuME Team + Copyright (C) 2012-2015 DeSmuME Team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -438,8 +438,6 @@ enum MESSAGE_SET_RENDER3D_THREADS, MESSAGE_SET_RENDER3D_LINE_HACK, MESSAGE_SET_RENDER3D_MULTISAMPLE, - MESSAGE_SET_VIEW_TO_BLACK, - MESSAGE_SET_VIEW_TO_WHITE, MESSAGE_SET_AUDIO_PROCESS_METHOD, MESSAGE_SET_SPU_ADVANCED_LOGIC, diff --git a/desmume/src/cocoa/cocoa_output.h b/desmume/src/cocoa/cocoa_output.h index 86ee148bd..3aee00f1c 100644 --- a/desmume/src/cocoa/cocoa_output.h +++ b/desmume/src/cocoa/cocoa_output.h @@ -1,6 +1,6 @@ /* Copyright (C) 2011 Roger Manuel - Copyright (C) 2011-2014 DeSmuME team + Copyright (C) 2011-2015 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -36,18 +36,17 @@ typedef struct typedef struct { - int32_t videoSourceID; - int32_t displayModeID; - uint16_t width; // Measured in pixels - uint16_t height; // Measured in pixels -} DisplaySrcPixelAttributes; + uint16_t *buffer; // Pointer to frame buffer + size_t bufferSize; // Size (in bytes) of frame buffer + int32_t displayModeID; // The selected display to read from + uint16_t width; // Measured in pixels + uint16_t height; // Measured in pixels +} GPUFrame; @interface CocoaDSOutput : CocoaDSThread { BOOL isStateChanged; NSUInteger frameCount; - NSData *frameData; - NSData *frameAttributesData; NSMutableDictionary *property; pthread_mutex_t *mutexConsume; @@ -56,14 +55,12 @@ typedef struct @property (assign) BOOL isStateChanged; @property (assign) NSUInteger frameCount; -@property (retain) NSData *frameData; -@property (retain) NSData *frameAttributesData; @property (readonly) NSMutableDictionary *property; @property (assign) pthread_rwlock_t *rwlockProducer; @property (readonly) pthread_mutex_t *mutexConsume; - (void) doCoreEmuFrame; -- (void) handleEmuFrameProcessed:(NSData *)mainData attributes:(NSData *)attributesData; +- (void) handleEmuFrameProcessed; @end @@ -127,7 +124,8 @@ typedef struct @required - (void) doInitVideoOutput:(NSDictionary *)properties; -- (void) doProcessVideoFrame:(const void *)videoFrameData displayMode:(const NSInteger)frameDisplayMode width:(const NSInteger)frameWidth height:(const NSInteger)frameHeight; +- (void) doLoadVideoFrame:(const void *)videoFrameData displayMode:(const NSInteger)frameDisplayMode width:(const NSInteger)frameWidth height:(const NSInteger)frameHeight; +- (void) doProcessVideoFrame; @optional - (void) doResizeView:(NSRect)rect; @@ -145,6 +143,7 @@ typedef struct id delegate; NSInteger displayMode; NSSize frameSize; + GPUFrame _gpuFrame; OSSpinLock spinlockDisplayType; } @@ -154,14 +153,9 @@ typedef struct @property (readonly) NSSize frameSize; - (void) handleChangeDisplayMode:(NSData *)displayModeData; -- (void) handleSetViewToBlack; -- (void) handleSetViewToWhite; - (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData; - (void) handleCopyToPasteboard; -- (NSData *) videoFrameUsingRGBA5551:(uint16_t)colorValue pixelCount:(size_t)pixCount; -- (void) sendVideoFrameOfRGBA5551:(uint16_t)colorValue; - - (NSImage *) image; - (NSBitmapImageRep *) bitmapImageRep; diff --git a/desmume/src/cocoa/cocoa_output.mm b/desmume/src/cocoa/cocoa_output.mm index ddffd3aff..24548d39f 100644 --- a/desmume/src/cocoa/cocoa_output.mm +++ b/desmume/src/cocoa/cocoa_output.mm @@ -36,8 +36,6 @@ @synthesize isStateChanged; @synthesize frameCount; -@synthesize frameData; -@synthesize frameAttributesData; @synthesize property; @synthesize mutexConsume; @synthesize rwlockProducer; @@ -52,8 +50,6 @@ isStateChanged = NO; frameCount = 0; - frameData = nil; - frameAttributesData = nil; property = [[NSMutableDictionary alloc] init]; [property setValue:[NSDate date] forKey:@"outputTime"]; @@ -69,8 +65,6 @@ // Force the thread to exit now so that we can safely release other resources. [self forceThreadExit]; - self.frameData = nil; - self.frameAttributesData = nil; [property release]; pthread_mutex_destroy(mutexConsume); @@ -93,7 +87,7 @@ switch (message) { case MESSAGE_EMU_FRAME_PROCESSED: - [self handleEmuFrameProcessed:[messageComponents objectAtIndex:0] attributes:[messageComponents objectAtIndex:1]]; + [self handleEmuFrameProcessed]; break; default: @@ -102,11 +96,9 @@ } } -- (void) handleEmuFrameProcessed:(NSData *)mainData attributes:(NSData *)attributesData +- (void) handleEmuFrameProcessed { self.frameCount++; - self.frameData = mainData; - self.frameAttributesData = attributesData; } @end @@ -433,10 +425,6 @@ switch (message) { - case MESSAGE_EMU_FRAME_PROCESSED: - [self handleEmuFrameProcessed:nil attributes:nil]; - break; - case MESSAGE_SET_AUDIO_PROCESS_METHOD: [self handleSetAudioOutputEngine:[messageComponents objectAtIndex:0]]; break; @@ -467,11 +455,11 @@ } } -- (void) handleEmuFrameProcessed:(NSData *)mainData attributes:(NSData *)attributesData +- (void) handleEmuFrameProcessed { SPU_Emulate_user(); - [super handleEmuFrameProcessed:mainData attributes:attributesData]; + [super handleEmuFrameProcessed]; } - (void) handleSetVolume:(NSData *)volumeData @@ -533,6 +521,12 @@ displayMode = DS_DISPLAY_TYPE_DUAL; frameSize = NSMakeSize((CGFloat)GPU_DISPLAY_WIDTH, (CGFloat)GPU_DISPLAY_HEIGHT * 2); + _gpuFrame.buffer = (uint16_t *)GPU_screen; + _gpuFrame.bufferSize = GPU_DISPLAY_WIDTH * GPU_DISPLAY_HEIGHT * 2 * sizeof(uint16_t); + _gpuFrame.displayModeID = DS_DISPLAY_TYPE_DUAL; + _gpuFrame.width = frameSize.width; + _gpuFrame.height = frameSize.height; + [property setValue:[NSNumber numberWithInteger:displayMode] forKey:@"displayMode"]; [property setValue:NSSTRING_DISPLAYMODE_MAIN forKey:@"displayModeString"]; @@ -542,7 +536,7 @@ - (void)dealloc { [self setDelegate:nil]; - + [super dealloc]; } @@ -597,31 +591,6 @@ return size; } -- (void) doCoreEmuFrame -{ - NSInteger displayModeID = [self displayMode]; - NSSize displayFrameSize = [self frameSize]; - - // We will be ignoring the actual video data here since we will be pulling the video data - // from the consumer thread instead. - NSData *gpuData = [[NSData alloc] init]; - - DisplaySrcPixelAttributes attr; - attr.videoSourceID = VIDEO_SOURCE_EMULATOR; - attr.displayModeID = (int32_t)displayModeID; - attr.width = (uint16_t)displayFrameSize.width; - attr.height = (uint16_t)displayFrameSize.height; - - NSData *attributesData = [[NSData alloc] initWithBytes:&attr length:sizeof(DisplaySrcPixelAttributes)]; - - NSArray *messageComponents = [[NSArray alloc] initWithObjects:gpuData, attributesData, nil]; - [CocoaDSUtil messageSendOneWayWithMessageComponents:self.receivePort msgID:MESSAGE_EMU_FRAME_PROCESSED array:messageComponents]; - - [gpuData release]; - [attributesData release]; - [messageComponents release]; -} - - (void)handlePortMessage:(NSPortMessage *)portMessage { NSInteger message = (NSInteger)[portMessage msgid]; @@ -629,22 +598,10 @@ switch (message) { - case MESSAGE_EMU_FRAME_PROCESSED: - [self handleEmuFrameProcessed:[messageComponents objectAtIndex:0] attributes:[messageComponents objectAtIndex:1]]; - break; - case MESSAGE_CHANGE_DISPLAY_TYPE: [self handleChangeDisplayMode:[messageComponents objectAtIndex:0]]; break; - case MESSAGE_SET_VIEW_TO_BLACK: - [self handleSetViewToBlack]; - break; - - case MESSAGE_SET_VIEW_TO_WHITE: - [self handleSetViewToWhite]; - break; - case MESSAGE_REQUEST_SCREENSHOT: [self handleRequestScreenshot:[messageComponents objectAtIndex:0] fileTypeData:[messageComponents objectAtIndex:1]]; break; @@ -659,9 +616,34 @@ } } -- (void) handleEmuFrameProcessed:(NSData *)mainData attributes:(NSData *)attributesData +- (void) handleEmuFrameProcessed { - [super handleEmuFrameProcessed:mainData attributes:attributesData]; + _gpuFrame.displayModeID = [self displayMode]; + _gpuFrame.width = [self frameSize].width; + _gpuFrame.height = [self frameSize].height; + + switch (_gpuFrame.displayModeID) + { + case DS_DISPLAY_TYPE_MAIN: + _gpuFrame.buffer = (uint16_t *)GPU_screen; + _gpuFrame.bufferSize = GPU_SCREEN_SIZE_BYTES; + break; + + case DS_DISPLAY_TYPE_TOUCH: + _gpuFrame.buffer = (uint16_t *)GPU_screen + (GPU_DISPLAY_WIDTH * GPU_DISPLAY_HEIGHT); + _gpuFrame.bufferSize = GPU_SCREEN_SIZE_BYTES; + break; + + case DS_DISPLAY_TYPE_DUAL: + _gpuFrame.buffer = (uint16_t *)GPU_screen; + _gpuFrame.bufferSize = GPU_SCREEN_SIZE_BYTES * 2; + break; + + default: + break; + } + + [super handleEmuFrameProcessed]; } - (void) handleChangeDisplayMode:(NSData *)displayModeData @@ -676,16 +658,6 @@ [delegate doDisplayModeChanged:displayModeID]; } -- (void) handleSetViewToBlack -{ - [self sendVideoFrameOfRGBA5551:0x8000]; -} - -- (void) handleSetViewToWhite -{ - [self sendVideoFrameOfRGBA5551:0xFFFF]; -} - - (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData { NSString *fileURLString = [[NSString alloc] initWithData:fileURLStringData encoding:NSUTF8StringEncoding]; @@ -717,54 +689,6 @@ [pboard setData:[screenshot TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1.0f] forType:NSTIFFPboardType]; } -- (NSData *) videoFrameUsingRGBA5551:(uint16_t)colorValue pixelCount:(size_t)pixCount -{ - NSData *gpuData = nil; - const size_t bufSize = pixCount * sizeof(uint16_t); - uint16_t *gpuBytes = (uint16_t *)malloc(bufSize); - if (gpuBytes == NULL) - { - return gpuData; - } - - if (pixCount % 16 == 0) - { - const uint16_t colorValuePattern[] = {colorValue, colorValue, colorValue, colorValue, colorValue, colorValue, colorValue, colorValue}; - memset_pattern16(gpuBytes, colorValuePattern, bufSize); - } - else - { - memset(gpuBytes, colorValue, bufSize); - } - - - gpuData = [NSData dataWithBytes:gpuBytes length:bufSize]; - - free(gpuBytes); - gpuBytes = nil; - - return gpuData; -} - -- (void) sendVideoFrameOfRGBA5551:(uint16_t)colorValue -{ - const NSInteger displayModeID = [self displayMode]; - const NSSize displayFrameSize = [self frameSize]; - const size_t pixCount = (displayModeID == DS_DISPLAY_TYPE_DUAL) ? GPU_DISPLAY_WIDTH * GPU_DISPLAY_HEIGHT * 2 : GPU_DISPLAY_WIDTH * GPU_DISPLAY_HEIGHT; - - NSData *videoData = [self videoFrameUsingRGBA5551:colorValue pixelCount:pixCount]; - - DisplaySrcPixelAttributes attr; - attr.videoSourceID = VIDEO_SOURCE_INTERNAL; - attr.displayModeID = (int32_t)displayModeID; - attr.width = (uint16_t)displayFrameSize.width; - attr.height = (uint16_t)displayFrameSize.height; - - NSData *attributesData = [NSData dataWithBytes:&attr length:sizeof(DisplaySrcPixelAttributes)]; - - [self handleEmuFrameProcessed:videoData attributes:attributesData]; -} - - (NSImage *) image { NSImage *newImage = [[NSImage alloc] initWithSize:self.frameSize]; @@ -790,7 +714,7 @@ - (NSBitmapImageRep *) bitmapImageRep { - if (self.frameData == nil) + if (_gpuFrame.buffer == NULL) { return nil; } @@ -815,7 +739,9 @@ } uint32_t *bitmapData = (uint32_t *)[imageRep bitmapData]; - RGB555ToRGBA8888Buffer((const uint16_t *)[self.frameData bytes], bitmapData, (w * h)); + pthread_rwlock_rdlock(self.rwlockProducer); + RGB555ToRGBA8888Buffer((const uint16_t *)_gpuFrame.buffer, bitmapData, (w * h)); + pthread_rwlock_unlock(self.rwlockProducer); #ifdef __BIG_ENDIAN__ uint32_t *bitmapDataEnd = bitmapData + (w * h); @@ -867,10 +793,6 @@ switch (message) { - case MESSAGE_EMU_FRAME_PROCESSED: - [self handleEmuFrameProcessed:[messageComponents objectAtIndex:0] attributes:[messageComponents objectAtIndex:1]]; - break; - case MESSAGE_REPROCESS_AND_REDRAW: [self handleReprocessAndRedraw]; break; @@ -905,60 +827,18 @@ } } -- (void) handleEmuFrameProcessed:(NSData *)mainData attributes:(NSData *)attributesData +- (void) handleEmuFrameProcessed { - if (mainData == nil || attributesData == nil) - { - return; - } + [super handleEmuFrameProcessed]; - NSData *newVideoFrame = mainData; - DisplaySrcPixelAttributes attr = *(DisplaySrcPixelAttributes *)[attributesData bytes]; - const NSInteger frameDisplayMode = attr.displayModeID; - const NSInteger frameSource = attr.videoSourceID; - const NSInteger frameWidth = attr.width; - const NSInteger frameHeight = attr.height; + pthread_rwlock_rdlock(self.rwlockProducer); + [(id)delegate doLoadVideoFrame:_gpuFrame.buffer + displayMode:_gpuFrame.displayModeID + width:_gpuFrame.width + height:_gpuFrame.height]; + pthread_rwlock_unlock(self.rwlockProducer); - if (frameSource == VIDEO_SOURCE_EMULATOR) - { - // Note that we simply received the attributes of the video data, not the actual - // video data itself. So from here, we need to pull the video data from the - // emulator and copy it to this thread. - // - // The video data contains the pixels from both the main and touch screens. So - // depending on the display mode, we copy only the pixels from the respective - // screen. - - pthread_rwlock_rdlock(self.rwlockProducer); - - switch (frameDisplayMode) - { - case DS_DISPLAY_TYPE_MAIN: - newVideoFrame = [NSData dataWithBytes:GPU_screen length:GPU_SCREEN_SIZE_BYTES]; - break; - - case DS_DISPLAY_TYPE_TOUCH: - newVideoFrame = [NSData dataWithBytes:(GPU_screen + GPU_SCREEN_SIZE_BYTES) length:GPU_SCREEN_SIZE_BYTES]; - break; - - case DS_DISPLAY_TYPE_DUAL: - newVideoFrame = [NSData dataWithBytes:GPU_screen length:GPU_SCREEN_SIZE_BYTES*2]; - break; - - default: - break; - } - - pthread_rwlock_unlock(self.rwlockProducer); - } - - [(id)delegate doProcessVideoFrame:[newVideoFrame bytes] displayMode:frameDisplayMode width:frameWidth height:frameHeight]; - - // If we need to use our saved frame data, make sure that we don't pull from the - // emulation thread again. - attr.videoSourceID = VIDEO_SOURCE_INTERNAL; - NSData *savedAttributesData = [NSData dataWithBytes:&attr length:sizeof(DisplaySrcPixelAttributes)]; - [super handleEmuFrameProcessed:newVideoFrame attributes:savedAttributesData]; + [(id)delegate doProcessVideoFrame]; } - (void) handleResizeView:(NSData *)rectData @@ -994,7 +874,7 @@ - (void) handleReprocessAndRedraw { - [self handleEmuFrameProcessed:self.frameData attributes:self.frameAttributesData]; + [self handleEmuFrameProcessed]; } - (void) handleChangeDisplayOrientation:(NSData *)displayOrientationIdData