Cocoa Port: Copying the contents of the display window via Edit > Copy now copies the actual contents of the display window instead of directly copying the NDS screens with a generic vertical layout.

This commit is contained in:
rogerman 2017-09-25 21:21:51 -07:00
parent 70c69a46d3
commit d37ef1ff95
10 changed files with 395 additions and 156 deletions

View File

@ -1017,7 +1017,12 @@ void ClientDisplayView::FlushView()
this->_viewNeedsFlush = false;
}
void ClientDisplayView::FinishFrameAtIndex(const u8 bufferIndex)
void ClientDisplayView::CopyFrameToBuffer(uint32_t *dstBuffer)
{
// Do nothing. This is implementation dependent.
}
void ClientDisplayView::FinishFrameAtIndex(const uint8_t bufferIndex)
{
// Do nothing. This is implementation dependent.
}

View File

@ -320,7 +320,9 @@ public:
virtual void ProcessDisplays();
virtual void UpdateView();
virtual void FlushView();
virtual void FinishFrameAtIndex(const u8 bufferIndex);
virtual void FinishFrameAtIndex(const uint8_t bufferIndex);
virtual void CopyFrameToBuffer(uint32_t *dstBuffer);
// Emulator interface
const NDSDisplayInfo& GetEmuDisplayInfo() const;

View File

@ -34,6 +34,7 @@ static const char *HUDOutputVertShader_100 = {"\
uniform vec2 viewSize; \n\
uniform float scalar; \n\
uniform float angleDegrees; \n\
uniform bool renderFlipped; \n\
\n\
VARYING vec4 vtxColor; \n\
VARYING vec2 texCoord[1]; \n\
@ -54,6 +55,11 @@ static const char *HUDOutputVertShader_100 = {"\
vtxColor = inColor; \n\
texCoord[0] = inTexCoord0; \n\
gl_Position = vec4(projection * rotation * scale * inPosition, 0.0, 1.0);\n\
\n\
if (renderFlipped)\n\
{\n\
gl_Position.y *= -1.0;\n\
}\n\
} \n\
"};
@ -77,6 +83,7 @@ static const char *Sample1x1OutputVertShader_100 = {"\
uniform vec2 viewSize; \n\
uniform float scalar; \n\
uniform float angleDegrees; \n\
uniform bool renderFlipped; \n\
\n\
VARYING vec2 texCoord[1]; \n\
\n\
@ -95,6 +102,11 @@ static const char *Sample1x1OutputVertShader_100 = {"\
\n\
texCoord[0] = inTexCoord0; \n\
gl_Position = vec4(projection * rotation * scale * inPosition, 0.0, 1.0);\n\
\n\
if (renderFlipped)\n\
{\n\
gl_Position.y *= -1.0;\n\
}\n\
} \n\
"};
@ -111,6 +123,7 @@ static const char *BicubicSample4x4Output_VertShader_110 = {"\
uniform vec2 viewSize; \n\
uniform float scalar; \n\
uniform float angleDegrees; \n\
uniform bool renderFlipped; \n\
\n\
VARYING vec2 texCoord[16];\n\
\n\
@ -150,6 +163,11 @@ static const char *BicubicSample4x4Output_VertShader_110 = {"\
texCoord[12] = xystart + vec2( 2.0, 2.0);\n\
\n\
gl_Position = vec4(projection * rotation * scale * inPosition, 0.0, 1.0);\n\
\n\
if (renderFlipped)\n\
{\n\
gl_Position.y *= -1.0;\n\
}\n\
}\n\
"};
@ -167,6 +185,7 @@ static const char *BicubicSample5x5Output_VertShader_110 = {"\
uniform vec2 viewSize; \n\
uniform float scalar; \n\
uniform float angleDegrees; \n\
uniform bool renderFlipped; \n\
\n\
VARYING vec2 texCoord[25];\n\
\n\
@ -216,6 +235,11 @@ static const char *BicubicSample5x5Output_VertShader_110 = {"\
texCoord[12] = xystart + vec2( 2.0, 2.0);\n\
\n\
gl_Position = vec4(projection * rotation * scale * inPosition, 0.0, 1.0);\n\
\n\
if (renderFlipped)\n\
{\n\
gl_Position.y *= -1.0;\n\
}\n\
}\n\
"};
@ -234,6 +258,7 @@ static const char *BicubicSample6x6Output_VertShader_110 = {"\
uniform vec2 viewSize; \n\
uniform float scalar; \n\
uniform float angleDegrees; \n\
uniform bool renderFlipped; \n\
\n\
VARYING vec2 texCoord[36];\n\
\n\
@ -295,6 +320,11 @@ static const char *BicubicSample6x6Output_VertShader_110 = {"\
texCoord[30] = xystart + vec2( 3.0, 3.0);\n\
\n\
gl_Position = vec4(projection * rotation * scale * inPosition, 0.0, 1.0);\n\
\n\
if (renderFlipped)\n\
{\n\
gl_Position.y *= -1.0;\n\
}\n\
}\n\
"};
@ -4996,6 +5026,8 @@ OGLVideoOutput::OGLVideoOutput()
_texCPUFilterDstID[NDSDisplayID_Main] = 0;
_texCPUFilterDstID[NDSDisplayID_Touch] = 0;
_fboFrameCopyID = 0;
}
OGLVideoOutput::~OGLVideoOutput()
@ -5011,6 +5043,7 @@ OGLVideoOutput::~OGLVideoOutput()
this->_layerList = NULL;
}
glDeleteFramebuffersEXT(1, &this->_fboFrameCopyID);
glDeleteTextures(2, this->_texCPUFilterDstID);
}
@ -5118,7 +5151,7 @@ void OGLVideoOutput::Init()
glDisable(GL_DITHER);
glDisable(GL_STENCIL_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
// Set up fixed-function pipeline render states.
if (!this->_contextInfo->IsShaderSupported())
@ -5133,10 +5166,9 @@ void OGLVideoOutput::Init()
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Set up textures
glGenTextures(2, this->_texCPUFilterDstID);
glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, this->_vfMasterDstBufferSize, this->_vfMasterDstBuffer);
glGenTextures(2, this->_texCPUFilterDstID);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texCPUFilterDstID[NDSDisplayID_Main]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -5154,6 +5186,8 @@ void OGLVideoOutput::Init()
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, this->_vf[NDSDisplayID_Touch]->GetDstWidth(), this->_vf[NDSDisplayID_Touch]->GetDstHeight(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, this->_vf[NDSDisplayID_Touch]->GetDstBufferPtr());
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glGenFramebuffersEXT(1, &this->_fboFrameCopyID);
}
void OGLVideoOutput::SetOutputFilter(const OutputFilterTypeID filterID)
@ -5222,7 +5256,7 @@ void OGLVideoOutput::ProcessDisplays()
}
}
void OGLVideoOutput::FinishFrameAtIndex(const u8 bufferIndex)
void OGLVideoOutput::FinishFrameAtIndex(const uint8_t bufferIndex)
{
for (size_t i = 0; i < _layerList->size(); i++)
{
@ -5235,7 +5269,42 @@ void OGLVideoOutput::FinishFrameAtIndex(const u8 bufferIndex)
}
}
void OGLVideoOutput::RenderViewOGL()
void OGLVideoOutput::CopyFrameToBuffer(uint32_t *dstBuffer)
{
for (size_t i = 0; i < _layerList->size(); i++)
{
OGLVideoLayer *theLayer = (*_layerList)[i];
theLayer->SetNeedsUpdateViewport();
}
GLuint texFrameCopyID = 0;
glGenTextures(1, &texFrameCopyID);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texFrameCopyID);
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);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, this->_viewportWidth, this->_viewportHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, dstBuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, this->_fboFrameCopyID);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, texFrameCopyID, 0);
this->RenderFrameOGL(true);
glReadPixels(0, 0, this->_renderProperty.clientWidth, this->_renderProperty.clientHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, dstBuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glDeleteTextures(1, &texFrameCopyID);
for (size_t i = 0; i < _layerList->size(); i++)
{
OGLVideoLayer *theLayer = (*_layerList)[i];
theLayer->SetNeedsUpdateViewport();
}
}
void OGLVideoOutput::RenderFrameOGL(bool isRenderingFlipped)
{
if (this->_needUpdateViewport)
{
@ -5251,7 +5320,7 @@ void OGLVideoOutput::RenderViewOGL()
if (theLayer->IsVisible())
{
theLayer->RenderOGL();
theLayer->RenderOGL(isRenderingFlipped);
}
}
}
@ -5632,6 +5701,7 @@ OGLImage::OGLImage(OGLContextInfo *contextInfo, GLsizei imageWidth, GLsizei imag
_uniformAngleDegrees = glGetUniformLocation(finalOutputProgramID, "angleDegrees");
_uniformScalar = glGetUniformLocation(finalOutputProgramID, "scalar");
_uniformViewSize = glGetUniformLocation(finalOutputProgramID, "viewSize");
_uniformRenderFlipped = glGetUniformLocation(finalOutputProgramID, "renderFlipped");
glUseProgram(0);
}
else
@ -5771,6 +5841,7 @@ void OGLImage::UploadTransformationOGL()
glUniform2f(this->_uniformViewSize, w, h);
glUniform1f(this->_uniformAngleDegrees, 0.0f);
glUniform1f(this->_uniformScalar, s);
glUniform1i(this->_uniformRenderFlipped, GL_FALSE);
}
else
{
@ -6228,6 +6299,7 @@ OGLHUDLayer::OGLHUDLayer(OGLVideoOutput *oglVO)
_uniformAngleDegrees = glGetUniformLocation(_program->GetProgramID(), "angleDegrees");
_uniformScalar = glGetUniformLocation(_program->GetProgramID(), "scalar");
_uniformViewSize = glGetUniformLocation(_program->GetProgramID(), "viewSize");
_uniformRenderFlipped = glGetUniformLocation(_program->GetProgramID(), "renderFlipped");
glUseProgram(0);
}
else
@ -6438,7 +6510,7 @@ void OGLHUDLayer::_UpdateVerticesOGL()
this->_output->ClearHUDNeedsUpdate();
}
void OGLHUDLayer::RenderOGL()
void OGLHUDLayer::RenderOGL(bool isRenderingFlipped)
{
size_t hudLength = this->_output->GetHUDString().length();
size_t hudTouchLineLength = 0;
@ -6489,6 +6561,7 @@ void OGLHUDLayer::RenderOGL()
if (this->_needUpdateViewport)
{
glUniform2f(this->_uniformViewSize, this->_output->GetViewProperties().clientWidth, this->_output->GetViewProperties().clientHeight);
glUniform1i(this->_uniformRenderFlipped, (isRenderingFlipped) ? GL_TRUE : GL_FALSE);
this->_needUpdateViewport = false;
}
}
@ -6645,6 +6718,7 @@ OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO)
_uniformAngleDegrees = glGetUniformLocation(finalOutputProgramID, "angleDegrees");
_uniformScalar = glGetUniformLocation(finalOutputProgramID, "scalar");
_uniformViewSize = glGetUniformLocation(finalOutputProgramID, "viewSize");
_uniformRenderFlipped = glGetUniformLocation(finalOutputProgramID, "renderFlipped");
glUseProgram(0);
}
else
@ -7134,7 +7208,7 @@ void OGLDisplayLayer::ProcessOGL()
glViewport(0, 0, this->_output->GetViewportWidth(), this->_output->GetViewportHeight());
}
void OGLDisplayLayer::RenderOGL()
void OGLDisplayLayer::RenderOGL(bool isRenderingFlipped)
{
const NDSDisplayInfo &emuDisplayInfo = this->_output->GetEmuDisplayInfo();
@ -7145,6 +7219,7 @@ void OGLDisplayLayer::RenderOGL()
if (this->_needUpdateViewport)
{
glUniform2f(this->_uniformViewSize, this->_output->GetViewportWidth(), this->_output->GetViewportHeight());
glUniform1i(this->_uniformRenderFlipped, (isRenderingFlipped) ? GL_TRUE : GL_FALSE);
this->_needUpdateViewport = false;
}
}
@ -7156,7 +7231,15 @@ void OGLDisplayLayer::RenderOGL()
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-w/2.0, -w/2.0 + w, -h/2.0, -h/2.0 + h, -1.0, 1.0);
if (isRenderingFlipped)
{
glOrtho(-w/2.0, -w/2.0 + w, -h/2.0 + h, -h/2.0, -1.0, 1.0);
}
else
{
glOrtho(-w/2.0, -w/2.0 + w, -h/2.0, -h/2.0 + h, -1.0, 1.0);
}
this->_needUpdateViewport = false;
}

View File

@ -212,6 +212,7 @@ protected:
GLint _uniformAngleDegrees;
GLint _uniformScalar;
GLint _uniformViewSize;
GLint _uniformRenderFlipped;
void UploadVerticesOGL();
void UploadTexCoordsOGL();
@ -257,6 +258,7 @@ protected:
GLint _uniformAngleDegrees;
GLint _uniformScalar;
GLint _uniformViewSize;
GLint _uniformRenderFlipped;
public:
virtual ~OGLVideoLayer() {};
@ -268,7 +270,7 @@ public:
virtual bool IsVisible();
virtual void SetVisibility(const bool visibleState);
virtual void RenderOGL() = 0;
virtual void RenderOGL(bool isRenderingFlipped) = 0;
virtual void FinishOGL(const u8 bufferIndex) {};
};
@ -292,7 +294,7 @@ public:
void CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, const size_t glyphTileSize, GlyphInfo *glyphInfo);
virtual void RenderOGL();
virtual void RenderOGL(bool isRenderingFlipped);
};
class OGLDisplayLayer : public OGLVideoLayer
@ -324,7 +326,7 @@ public:
void LoadNativeDisplayByID_OGL(const NDSDisplayID displayID);
void ProcessOGL();
virtual void RenderOGL();
virtual void RenderOGL(bool isRenderingFlipped);
virtual void FinishOGL(const u8 bufferIndex);
};
@ -381,6 +383,7 @@ protected:
bool _hasOGLPixelScaler;
std::vector<OGLVideoLayer *> *_layerList;
GLuint _texCPUFilterDstID[2];
GLuint _fboFrameCopyID;
void _UpdateViewport();
@ -419,8 +422,9 @@ public:
// Client view interface
virtual void ProcessDisplays();
virtual void FinishFrameAtIndex(const u8 bufferIndex);
virtual void RenderViewOGL();
virtual void FinishFrameAtIndex(const uint8_t bufferIndex);
virtual void CopyFrameToBuffer(uint32_t *dstBuffer);;
virtual void RenderFrameOGL(bool isRenderingFlipped);
virtual void LockDisplayTextures();
virtual void UnlockDisplayTextures();
};

View File

@ -170,6 +170,7 @@
- (void) setScaleFactor:(float)theScaleFactor;
- (void) hudUpdate;
- (NSImage *) copyImageFromView;
- (NSImage *) image;
- (NSBitmapImageRep *) bitmapImageRep;

View File

@ -1140,7 +1140,7 @@
- (void) handleCopyToPasteboard
{
NSImage *screenshot = [self image];
NSImage *screenshot = [self copyImageFromView];
if (screenshot == nil)
{
return;
@ -1188,6 +1188,44 @@
OSSpinLockUnlock(&spinlockNDSFrameInfo);
}
- (NSImage *) copyImageFromView
{
NSSize viewSize = NSMakeSize(_cdv->GetViewProperties().clientWidth, _cdv->GetViewProperties().clientHeight);
NSUInteger w = viewSize.width;
NSUInteger h = viewSize.height;
NSImage *newImage = [[NSImage alloc] initWithSize:viewSize];
if (newImage == nil)
{
return newImage;
}
// Render the frame in an NSBitmapImageRep
NSBitmapImageRep *newImageRep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:w
pixelsHigh:h
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bytesPerRow:w * 4
bitsPerPixel:32] autorelease];
if (newImageRep == nil)
{
[newImage release];
newImage = nil;
return newImage;
}
_cdv->CopyFrameToBuffer((uint32_t *)[newImageRep bitmapData]);
// Attach the rendered frame to the NSImageRep
[newImage addRepresentation:newImageRep];
return [newImage autorelease];
}
- (NSImage *) image
{
pthread_rwlock_rdlock(self.rwlockProducer);

View File

@ -55,6 +55,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
id<MTLComputePipelineState> _fetch888Pipeline;
id<MTLComputePipelineState> deposterizePipeline;
id<MTLRenderPipelineState> hudPipeline;
id<MTLRenderPipelineState> hudRGBAPipeline;
id<MTLBlitCommandEncoder> _fetchEncoder;
@ -109,6 +110,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
@property (readonly, nonatomic) id<MTLComputePipelineState> deposterizePipeline;
@property (readonly, nonatomic) id<MTLRenderPipelineState> hudPipeline;
@property (readonly, nonatomic) id<MTLRenderPipelineState> hudRGBAPipeline;
@property (readonly, nonatomic) id<MTLSamplerState> samplerHUDBox;
@property (readonly, nonatomic) id<MTLSamplerState> samplerHUDText;
@ -162,6 +164,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
MTLRenderPassColorAttachmentDescriptor *colorAttachment0Desc;
id<MTLComputePipelineState> pixelScalePipeline;
id<MTLRenderPipelineState> displayOutputPipeline;
id<MTLRenderPipelineState> displayRGBAOutputPipeline;
id<MTLBuffer> _cdvPropertiesBuffer;
id<MTLBuffer> _displayVtxPositionBuffer;
@ -203,6 +206,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
@property (readonly, nonatomic) MTLRenderPassColorAttachmentDescriptor *colorAttachment0Desc;
@property (retain) id<MTLComputePipelineState> pixelScalePipeline;
@property (retain) id<MTLRenderPipelineState> displayOutputPipeline;
@property (retain) id<MTLRenderPipelineState> displayRGBAOutputPipeline;
@property (retain) id<MTLBuffer> bufCPUFilterSrcMain;
@property (retain) id<MTLBuffer> bufCPUFilterSrcTouch;
@property (retain) id<MTLBuffer> bufCPUFilterDstMain;
@ -223,6 +227,10 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
- (void) copyHUDFontUsingFace:(const FT_Face &)fontFace size:(const size_t)glyphSize tileSize:(const size_t)glyphTileSize info:(GlyphInfo *)glyphInfo;
- (void) processDisplays;
- (void) updateRenderBuffers;
- (void) renderForCommandBuffer:(id<MTLCommandBuffer>)cb
displayPipelineState:(id<MTLRenderPipelineState>)displayPipelineState
hudPipelineState:(id<MTLRenderPipelineState>)hudPipelineState;
- (void) renderAndDownloadToBuffer:(uint32_t *)dstBuffer;
- (void) renderAndFlushDrawable;
@end
@ -287,6 +295,8 @@ public:
virtual void ProcessDisplays();
virtual void UpdateView();
virtual void FlushView();
virtual void CopyFrameToBuffer(uint32_t *dstBuffer);
};
#pragma mark -

View File

@ -27,6 +27,7 @@
@synthesize deposterizePipeline;
@synthesize hudPipeline;
@synthesize hudRGBAPipeline;
@synthesize samplerHUDBox;
@synthesize samplerHUDText;
@ -109,20 +110,24 @@
deposterizeThreadGroupsPerGrid = fetchThreadGroupsPerGridNative;
MTLRenderPipelineDescriptor *hudPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatBGRA8Unorm];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setBlendingEnabled:YES];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setRgbBlendOperation:MTLBlendOperationAdd];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setAlphaBlendOperation:MTLBlendOperationAdd];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setSourceRGBBlendFactor:MTLBlendFactorSourceAlpha];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setSourceAlphaBlendFactor:MTLBlendFactorSourceAlpha];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setSourceAlphaBlendFactor:MTLBlendFactorZero];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setDestinationRGBBlendFactor:MTLBlendFactorOneMinusSourceAlpha];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setDestinationAlphaBlendFactor:MTLBlendFactorOneMinusSourceAlpha];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setDestinationAlphaBlendFactor:MTLBlendFactorOne];
id<MTLFunction> hudFragmentFunction = [defaultLibrary newFunctionWithName:@"hud_fragment"];
[hudPipelineDesc setVertexFunction:[defaultLibrary newFunctionWithName:@"hud_vertex"]];
[hudPipelineDesc setFragmentFunction:hudFragmentFunction];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatBGRA8Unorm];
hudPipeline = [[device newRenderPipelineStateWithDescriptor:hudPipelineDesc error:nil] retain];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatRGBA8Unorm];
hudRGBAPipeline = [[device newRenderPipelineStateWithDescriptor:hudPipelineDesc error:nil] retain];
[hudPipelineDesc release];
hudIndexBuffer = [[device newBufferWithLength:(sizeof(uint16_t) * HUD_TOTAL_ELEMENTS * 6) options:MTLResourceStorageModeManaged] retain];
@ -274,6 +279,7 @@
[_fetch888Pipeline release];
[deposterizePipeline release];
[hudPipeline release];
[hudRGBAPipeline release];
[hudIndexBuffer release];
[_bufMasterBrightMode[NDSDisplayID_Main] release];
@ -728,6 +734,7 @@
@synthesize colorAttachment0Desc;
@synthesize pixelScalePipeline;
@synthesize displayOutputPipeline;
@synthesize displayRGBAOutputPipeline;
@synthesize bufCPUFilterSrcMain;
@synthesize bufCPUFilterSrcTouch;
@synthesize bufCPUFilterDstMain;
@ -764,6 +771,7 @@
pixelScalePipeline = nil;
displayOutputPipeline = nil;
displayRGBAOutputPipeline = nil;
_cdvPropertiesBuffer = nil;
_displayVtxPositionBuffer = nil;
@ -828,6 +836,7 @@
[[self colorAttachment0Desc] setTexture:nil];
[self setPixelScalePipeline:nil];
[self setDisplayOutputPipeline:nil];
[self setDisplayRGBAOutputPipeline:nil];
[self setTexHUDCharMap:nil];
[self setSharedData:nil];
@ -996,7 +1005,6 @@
- (void) setOutputFilter:(OutputFilterTypeID)filterID
{
MTLRenderPipelineDescriptor *outputPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:[self pixelFormat]];
[outputPipelineDesc setAlphaToOneEnabled:YES];
switch (filterID)
@ -1033,7 +1041,12 @@
break;
}
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:[self pixelFormat]];
[self setDisplayOutputPipeline:[[self device] newRenderPipelineStateWithDescriptor:outputPipelineDesc error:nil]];
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatRGBA8Unorm];
[self setDisplayRGBAOutputPipeline:[[self device] newRenderPipelineStateWithDescriptor:outputPipelineDesc error:nil]];
[outputPipelineDesc release];
}
@ -1047,12 +1060,16 @@
[self setDevice:[sharedData device]];
MTLRenderPipelineDescriptor *outputPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:[self pixelFormat]];
[outputPipelineDesc setAlphaToOneEnabled:YES];
[outputPipelineDesc setVertexFunction:[[sharedData defaultLibrary] newFunctionWithName:@"display_output_vertex"]];
[outputPipelineDesc setFragmentFunction:[[sharedData defaultLibrary] newFunctionWithName:@"output_filter_bilinear"]];
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:[self pixelFormat]];
displayOutputPipeline = [[[self device] newRenderPipelineStateWithDescriptor:outputPipelineDesc error:nil] retain];
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatRGBA8Unorm];
displayRGBAOutputPipeline = [[[self device] newRenderPipelineStateWithDescriptor:outputPipelineDesc error:nil] retain];
[outputPipelineDesc release];
_cdvPropertiesBuffer = [[[self device] newBufferWithLength:sizeof(DisplayViewShaderProperties) options:MTLResourceStorageModeManaged] retain];
@ -1581,6 +1598,200 @@
pthread_mutex_unlock(&_mutexBufferUpdate);
}
- (void) renderForCommandBuffer:(id<MTLCommandBuffer>)cb
displayPipelineState:(id<MTLRenderPipelineState>)displayPipelineState
hudPipelineState:(id<MTLRenderPipelineState>)hudPipelineState
{
id<MTLRenderCommandEncoder> rce = [cb renderCommandEncoderWithDescriptor:_outputRenderPassDesc];
if (_needEncodeViewport)
{
[rce setViewport:_newViewport];
}
// Draw the NDS displays.
if (_willDrawDisplays)
{
[rce setRenderPipelineState:displayPipelineState];
[rce setVertexBuffer:_displayVtxPositionBuffer offset:0 atIndex:0];
[rce setVertexBuffer:_displayTexCoordBuffer offset:0 atIndex:1];
[rce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:2];
switch (_cdv->GetViewProperties().mode)
{
case ClientDisplayMode_Main:
{
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main))
{
[rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0];
[rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
}
break;
}
case ClientDisplayMode_Touch:
{
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch))
{
[rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0];
[rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4];
}
break;
}
case ClientDisplayMode_Dual:
{
const NDSDisplayID majorDisplayID = (_cdv->GetViewProperties().order == ClientDisplayOrder_MainFirst) ? NDSDisplayID_Main : NDSDisplayID_Touch;
const size_t majorDisplayVtx = (_cdv->GetViewProperties().order == ClientDisplayOrder_MainFirst) ? 8 : 12;
switch (_cdv->GetViewProperties().layout)
{
case ClientDisplayLayout_Hybrid_2_1:
case ClientDisplayLayout_Hybrid_16_9:
case ClientDisplayLayout_Hybrid_16_10:
{
if (_cdv->IsSelectedDisplayEnabled(majorDisplayID))
{
[rce setFragmentTexture:_texDisplayOutput[majorDisplayID] atIndex:0];
[rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:majorDisplayVtx vertexCount:4];
}
break;
}
default:
break;
}
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main))
{
[rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0];
[rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
}
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch))
{
[rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0];
[rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4];
}
}
default:
break;
}
}
// Draw the HUD.
if (_willDrawHUD)
{
uint8_t isScreenOverlay = 0;
[rce setRenderPipelineState:hudPipelineState];
[rce setVertexBuffer:_hudVtxPositionBuffer offset:0 atIndex:0];
[rce setVertexBuffer:_hudVtxColorBuffer offset:0 atIndex:1];
[rce setVertexBuffer:_hudTexCoordBuffer offset:0 atIndex:2];
[rce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:3];
[rce setFragmentTexture:[self texHUDCharMap] atIndex:0];
// First, draw the inputs.
if (_willDrawHUDInput)
{
isScreenOverlay = 1;
[rce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
[rce setFragmentSamplerState:[sharedData samplerHUDBox] atIndex:0];
[rce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:_hudTouchLineLength * 6
indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer]
indexBufferOffset:(_hudStringLength + HUD_INPUT_ELEMENT_LENGTH) * 6 * sizeof(uint16_t)];
isScreenOverlay = 0;
[rce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
[rce setFragmentSamplerState:[sharedData samplerHUDText] atIndex:0];
[rce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:HUD_INPUT_ELEMENT_LENGTH * 6
indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer]
indexBufferOffset:_hudStringLength * 6 * sizeof(uint16_t)];
}
// Next, draw the backing text box.
[rce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
[rce setFragmentSamplerState:[sharedData samplerHUDBox] atIndex:0];
[rce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:6
indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer]
indexBufferOffset:0];
// Finally, draw each character inside the box.
[rce setFragmentSamplerState:[sharedData samplerHUDText] atIndex:0];
[rce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:(_hudStringLength - 1) * 6
indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer]
indexBufferOffset:6 * sizeof(uint16_t)];
}
[rce endEncoding];
}
- (void) renderAndDownloadToBuffer:(uint32_t *)dstBuffer
{
const size_t clientWidth = _cdv->GetViewProperties().clientWidth;
const size_t clientHeight = _cdv->GetViewProperties().clientHeight;
@autoreleasepool
{
MTLTextureDescriptor *texRenderDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
width:clientWidth
height:clientHeight
mipmapped:NO];
[texRenderDesc setResourceOptions:MTLResourceStorageModePrivate];
[texRenderDesc setStorageMode:MTLStorageModePrivate];
[texRenderDesc setUsage:MTLTextureUsageRenderTarget];
id<MTLTexture> texRender = [[[self device] newTextureWithDescriptor:texRenderDesc] retain];
id<MTLBuffer> dstMTLBuffer = [[[self device] newBufferWithLength:clientWidth * clientHeight * sizeof(uint32_t) options:MTLResourceStorageModeManaged] retain];
pthread_mutex_lock(&_mutexDisplayTextureUpdate);
pthread_mutex_lock(&_mutexBufferUpdate);
// Now that everything is set up, go ahead and draw everything.
[colorAttachment0Desc setTexture:texRender];
id<MTLCommandBuffer> cb = [self newCommandBuffer];
[self renderForCommandBuffer:cb displayPipelineState:[self displayRGBAOutputPipeline] hudPipelineState:[sharedData hudRGBAPipeline]];
id<MTLBlitCommandEncoder> bce = [cb blitCommandEncoder];
[bce copyFromTexture:texRender
sourceSlice:0
sourceLevel:0
sourceOrigin:MTLOriginMake(0, 0, 0)
sourceSize:MTLSizeMake(clientWidth, clientHeight, 1)
toBuffer:dstMTLBuffer
destinationOffset:0
destinationBytesPerRow:clientWidth * sizeof(uint32_t)
destinationBytesPerImage:clientWidth * clientHeight * sizeof(uint32_t)];
[bce synchronizeResource:dstMTLBuffer];
[bce endEncoding];
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_mutex_unlock(&_mutexBufferUpdate);
pthread_mutex_unlock(&_mutexDisplayTextureUpdate);
memcpy(dstBuffer, [dstMTLBuffer contents], clientWidth * clientHeight * sizeof(uint32_t));
[texRender release];
[dstMTLBuffer release];
}];
[cb commit];
[cb waitUntilCompleted];
}
}
- (void) renderAndFlushDrawable
{
@autoreleasepool
@ -1592,137 +1803,8 @@
id<CAMetalDrawable> layerDrawable = [self nextDrawable];
[colorAttachment0Desc setTexture:[layerDrawable texture]];
id<MTLCommandBuffer> cb = [self newCommandBuffer];
id<MTLRenderCommandEncoder> ce = [cb renderCommandEncoderWithDescriptor:_outputRenderPassDesc];
if (_needEncodeViewport)
{
[ce setViewport:_newViewport];
}
// Draw the NDS displays.
if (_willDrawDisplays)
{
[ce setRenderPipelineState:[self displayOutputPipeline]];
[ce setVertexBuffer:_displayVtxPositionBuffer offset:0 atIndex:0];
[ce setVertexBuffer:_displayTexCoordBuffer offset:0 atIndex:1];
[ce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:2];
switch (_cdv->GetViewProperties().mode)
{
case ClientDisplayMode_Main:
{
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main))
{
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0];
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
}
break;
}
case ClientDisplayMode_Touch:
{
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch))
{
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0];
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4];
}
break;
}
case ClientDisplayMode_Dual:
{
const NDSDisplayID majorDisplayID = (_cdv->GetViewProperties().order == ClientDisplayOrder_MainFirst) ? NDSDisplayID_Main : NDSDisplayID_Touch;
const size_t majorDisplayVtx = (_cdv->GetViewProperties().order == ClientDisplayOrder_MainFirst) ? 8 : 12;
switch (_cdv->GetViewProperties().layout)
{
case ClientDisplayLayout_Hybrid_2_1:
case ClientDisplayLayout_Hybrid_16_9:
case ClientDisplayLayout_Hybrid_16_10:
{
if (_cdv->IsSelectedDisplayEnabled(majorDisplayID))
{
[ce setFragmentTexture:_texDisplayOutput[majorDisplayID] atIndex:0];
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:majorDisplayVtx vertexCount:4];
}
break;
}
default:
break;
}
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main))
{
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0];
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
}
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch))
{
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0];
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4];
}
}
default:
break;
}
}
// Draw the HUD.
if (_willDrawHUD)
{
uint8_t isScreenOverlay = 0;
[ce setRenderPipelineState:[sharedData hudPipeline]];
[ce setVertexBuffer:_hudVtxPositionBuffer offset:0 atIndex:0];
[ce setVertexBuffer:_hudVtxColorBuffer offset:0 atIndex:1];
[ce setVertexBuffer:_hudTexCoordBuffer offset:0 atIndex:2];
[ce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:3];
[ce setFragmentTexture:[self texHUDCharMap] atIndex:0];
// First, draw the inputs.
if (_willDrawHUDInput)
{
isScreenOverlay = 1;
[ce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
[ce setFragmentSamplerState:[sharedData samplerHUDBox] atIndex:0];
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:_hudTouchLineLength * 6
indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer]
indexBufferOffset:(_hudStringLength + HUD_INPUT_ELEMENT_LENGTH) * 6 * sizeof(uint16_t)];
isScreenOverlay = 0;
[ce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
[ce setFragmentSamplerState:[sharedData samplerHUDText] atIndex:0];
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:HUD_INPUT_ELEMENT_LENGTH * 6
indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer]
indexBufferOffset:_hudStringLength * 6 * sizeof(uint16_t)];
}
// Next, draw the backing text box.
[ce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
[ce setFragmentSamplerState:[sharedData samplerHUDBox] atIndex:0];
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:6
indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer]
indexBufferOffset:0];
// Finally, draw each character inside the box.
[ce setFragmentSamplerState:[sharedData samplerHUDText] atIndex:0];
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:(_hudStringLength - 1) * 6
indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer]
indexBufferOffset:6 * sizeof(uint16_t)];
}
[ce endEncoding];
[self renderForCommandBuffer:cb displayPipelineState:[self displayOutputPipeline] hudPipelineState:[sharedData hudPipeline]];
[cb presentDrawable:layerDrawable];
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
@ -1999,6 +2081,11 @@ void MacMetalDisplayView::FlushView()
[(DisplayViewMetalLayer *)this->GetFrontendLayer() renderAndFlushDrawable];
}
void MacMetalDisplayView::CopyFrameToBuffer(uint32_t *dstBuffer)
{
[(DisplayViewMetalLayer *)this->GetFrontendLayer() renderAndDownloadToBuffer:dstBuffer];
}
#pragma mark -
void SetupHQnxLUTs_Metal(id<MTLDevice> &device, id<MTLTexture> &texLQ2xLUT, id<MTLTexture> &texHQ2xLUT, id<MTLTexture> &texHQ3xLUT, id<MTLTexture> &texHQ4xLUT)
{

View File

@ -100,7 +100,8 @@ public:
virtual void ProcessDisplays();
virtual void UpdateView();
virtual void FlushView();
virtual void FinishFrameAtIndex(const u8 bufferIndex);
virtual void CopyFrameToBuffer(uint32_t *dstBuffer);
virtual void FinishFrameAtIndex(const uint8_t bufferIndex);
virtual void LockDisplayTextures();
virtual void UnlockDisplayTextures();
};

View File

@ -75,7 +75,7 @@
{
CGLSetCurrentContext(glContext);
CGLLockContext(glContext);
_cdv->RenderViewOGL();
_cdv->RenderFrameOGL(false);
[super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp];
CGLUnlockContext(glContext);
}
@ -447,12 +447,20 @@ void MacOGLDisplayView::FlushView()
CGLLockContext(this->_context);
CGLSetCurrentContext(this->_context);
this->RenderViewOGL();
this->RenderFrameOGL(false);
CGLFlushDrawable(this->_context);
CGLUnlockContext(this->_context);
}
void MacOGLDisplayView::FinishFrameAtIndex(const u8 bufferIndex)
void MacOGLDisplayView::CopyFrameToBuffer(uint32_t *dstBuffer)
{
CGLLockContext(this->_context);
CGLSetCurrentContext(this->_context);
this->OGLVideoOutput::CopyFrameToBuffer(dstBuffer);
CGLUnlockContext(this->_context);
}
void MacOGLDisplayView::FinishFrameAtIndex(const uint8_t bufferIndex)
{
CGLLockContext(this->_context);
CGLSetCurrentContext(this->_context);