Cocoa Port:

- Read the GPU_screen buffer directly and avoid making multiple copies of it. Improves performance when many display windows are used.
This commit is contained in:
rogerman 2015-01-21 02:09:59 +00:00
parent 245586a978
commit d880c58f75
8 changed files with 178 additions and 263 deletions

View File

@ -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

View File

@ -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);
};

View File

@ -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);

View File

@ -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;

View File

@ -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];

View File

@ -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,

View File

@ -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 <CocoaDSDisplayDelegate> 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;

View File

@ -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<CocoaDSDisplayVideoDelegate>)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<CocoaDSDisplayVideoDelegate>)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<CocoaDSDisplayVideoDelegate>)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