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; 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. // Do nothing. This is implementation dependent.
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -1140,7 +1140,7 @@
- (void) handleCopyToPasteboard - (void) handleCopyToPasteboard
{ {
NSImage *screenshot = [self image]; NSImage *screenshot = [self copyImageFromView];
if (screenshot == nil) if (screenshot == nil)
{ {
return; return;
@ -1188,6 +1188,44 @@
OSSpinLockUnlock(&spinlockNDSFrameInfo); 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 - (NSImage *) image
{ {
pthread_rwlock_rdlock(self.rwlockProducer); pthread_rwlock_rdlock(self.rwlockProducer);

View File

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

View File

@ -27,6 +27,7 @@
@synthesize deposterizePipeline; @synthesize deposterizePipeline;
@synthesize hudPipeline; @synthesize hudPipeline;
@synthesize hudRGBAPipeline;
@synthesize samplerHUDBox; @synthesize samplerHUDBox;
@synthesize samplerHUDText; @synthesize samplerHUDText;
@ -109,20 +110,24 @@
deposterizeThreadGroupsPerGrid = fetchThreadGroupsPerGridNative; deposterizeThreadGroupsPerGrid = fetchThreadGroupsPerGridNative;
MTLRenderPipelineDescriptor *hudPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init]; MTLRenderPipelineDescriptor *hudPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatBGRA8Unorm];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setBlendingEnabled:YES]; [[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setBlendingEnabled:YES];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setRgbBlendOperation:MTLBlendOperationAdd]; [[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setRgbBlendOperation:MTLBlendOperationAdd];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setAlphaBlendOperation:MTLBlendOperationAdd]; [[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setAlphaBlendOperation:MTLBlendOperationAdd];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setSourceRGBBlendFactor:MTLBlendFactorSourceAlpha]; [[[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] setDestinationRGBBlendFactor:MTLBlendFactorOneMinusSourceAlpha];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setDestinationAlphaBlendFactor:MTLBlendFactorOneMinusSourceAlpha]; [[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setDestinationAlphaBlendFactor:MTLBlendFactorOne];
id<MTLFunction> hudFragmentFunction = [defaultLibrary newFunctionWithName:@"hud_fragment"]; id<MTLFunction> hudFragmentFunction = [defaultLibrary newFunctionWithName:@"hud_fragment"];
[hudPipelineDesc setVertexFunction:[defaultLibrary newFunctionWithName:@"hud_vertex"]]; [hudPipelineDesc setVertexFunction:[defaultLibrary newFunctionWithName:@"hud_vertex"]];
[hudPipelineDesc setFragmentFunction:hudFragmentFunction]; [hudPipelineDesc setFragmentFunction:hudFragmentFunction];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatBGRA8Unorm];
hudPipeline = [[device newRenderPipelineStateWithDescriptor:hudPipelineDesc error:nil] retain]; hudPipeline = [[device newRenderPipelineStateWithDescriptor:hudPipelineDesc error:nil] retain];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatRGBA8Unorm];
hudRGBAPipeline = [[device newRenderPipelineStateWithDescriptor:hudPipelineDesc error:nil] retain];
[hudPipelineDesc release]; [hudPipelineDesc release];
hudIndexBuffer = [[device newBufferWithLength:(sizeof(uint16_t) * HUD_TOTAL_ELEMENTS * 6) options:MTLResourceStorageModeManaged] retain]; hudIndexBuffer = [[device newBufferWithLength:(sizeof(uint16_t) * HUD_TOTAL_ELEMENTS * 6) options:MTLResourceStorageModeManaged] retain];
@ -274,6 +279,7 @@
[_fetch888Pipeline release]; [_fetch888Pipeline release];
[deposterizePipeline release]; [deposterizePipeline release];
[hudPipeline release]; [hudPipeline release];
[hudRGBAPipeline release];
[hudIndexBuffer release]; [hudIndexBuffer release];
[_bufMasterBrightMode[NDSDisplayID_Main] release]; [_bufMasterBrightMode[NDSDisplayID_Main] release];
@ -728,6 +734,7 @@
@synthesize colorAttachment0Desc; @synthesize colorAttachment0Desc;
@synthesize pixelScalePipeline; @synthesize pixelScalePipeline;
@synthesize displayOutputPipeline; @synthesize displayOutputPipeline;
@synthesize displayRGBAOutputPipeline;
@synthesize bufCPUFilterSrcMain; @synthesize bufCPUFilterSrcMain;
@synthesize bufCPUFilterSrcTouch; @synthesize bufCPUFilterSrcTouch;
@synthesize bufCPUFilterDstMain; @synthesize bufCPUFilterDstMain;
@ -764,6 +771,7 @@
pixelScalePipeline = nil; pixelScalePipeline = nil;
displayOutputPipeline = nil; displayOutputPipeline = nil;
displayRGBAOutputPipeline = nil;
_cdvPropertiesBuffer = nil; _cdvPropertiesBuffer = nil;
_displayVtxPositionBuffer = nil; _displayVtxPositionBuffer = nil;
@ -828,6 +836,7 @@
[[self colorAttachment0Desc] setTexture:nil]; [[self colorAttachment0Desc] setTexture:nil];
[self setPixelScalePipeline:nil]; [self setPixelScalePipeline:nil];
[self setDisplayOutputPipeline:nil]; [self setDisplayOutputPipeline:nil];
[self setDisplayRGBAOutputPipeline:nil];
[self setTexHUDCharMap:nil]; [self setTexHUDCharMap:nil];
[self setSharedData:nil]; [self setSharedData:nil];
@ -996,7 +1005,6 @@
- (void) setOutputFilter:(OutputFilterTypeID)filterID - (void) setOutputFilter:(OutputFilterTypeID)filterID
{ {
MTLRenderPipelineDescriptor *outputPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init]; MTLRenderPipelineDescriptor *outputPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:[self pixelFormat]];
[outputPipelineDesc setAlphaToOneEnabled:YES]; [outputPipelineDesc setAlphaToOneEnabled:YES];
switch (filterID) switch (filterID)
@ -1033,7 +1041,12 @@
break; break;
} }
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:[self pixelFormat]];
[self setDisplayOutputPipeline:[[self device] newRenderPipelineStateWithDescriptor:outputPipelineDesc error:nil]]; [self setDisplayOutputPipeline:[[self device] newRenderPipelineStateWithDescriptor:outputPipelineDesc error:nil]];
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatRGBA8Unorm];
[self setDisplayRGBAOutputPipeline:[[self device] newRenderPipelineStateWithDescriptor:outputPipelineDesc error:nil]];
[outputPipelineDesc release]; [outputPipelineDesc release];
} }
@ -1047,12 +1060,16 @@
[self setDevice:[sharedData device]]; [self setDevice:[sharedData device]];
MTLRenderPipelineDescriptor *outputPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init]; MTLRenderPipelineDescriptor *outputPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:[self pixelFormat]];
[outputPipelineDesc setAlphaToOneEnabled:YES]; [outputPipelineDesc setAlphaToOneEnabled:YES];
[outputPipelineDesc setVertexFunction:[[sharedData defaultLibrary] newFunctionWithName:@"display_output_vertex"]]; [outputPipelineDesc setVertexFunction:[[sharedData defaultLibrary] newFunctionWithName:@"display_output_vertex"]];
[outputPipelineDesc setFragmentFunction:[[sharedData defaultLibrary] newFunctionWithName:@"output_filter_bilinear"]]; [outputPipelineDesc setFragmentFunction:[[sharedData defaultLibrary] newFunctionWithName:@"output_filter_bilinear"]];
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:[self pixelFormat]];
displayOutputPipeline = [[[self device] newRenderPipelineStateWithDescriptor:outputPipelineDesc error:nil] retain]; displayOutputPipeline = [[[self device] newRenderPipelineStateWithDescriptor:outputPipelineDesc error:nil] retain];
[[[outputPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatRGBA8Unorm];
displayRGBAOutputPipeline = [[[self device] newRenderPipelineStateWithDescriptor:outputPipelineDesc error:nil] retain];
[outputPipelineDesc release]; [outputPipelineDesc release];
_cdvPropertiesBuffer = [[[self device] newBufferWithLength:sizeof(DisplayViewShaderProperties) options:MTLResourceStorageModeManaged] retain]; _cdvPropertiesBuffer = [[[self device] newBufferWithLength:sizeof(DisplayViewShaderProperties) options:MTLResourceStorageModeManaged] retain];
@ -1581,31 +1598,24 @@
pthread_mutex_unlock(&_mutexBufferUpdate); pthread_mutex_unlock(&_mutexBufferUpdate);
} }
- (void) renderAndFlushDrawable - (void) renderForCommandBuffer:(id<MTLCommandBuffer>)cb
displayPipelineState:(id<MTLRenderPipelineState>)displayPipelineState
hudPipelineState:(id<MTLRenderPipelineState>)hudPipelineState
{ {
@autoreleasepool id<MTLRenderCommandEncoder> rce = [cb renderCommandEncoderWithDescriptor:_outputRenderPassDesc];
{
pthread_mutex_lock(&_mutexDisplayTextureUpdate);
pthread_mutex_lock(&_mutexBufferUpdate);
// Now that everything is set up, go ahead and draw everything.
id<CAMetalDrawable> layerDrawable = [self nextDrawable];
[colorAttachment0Desc setTexture:[layerDrawable texture]];
id<MTLCommandBuffer> cb = [self newCommandBuffer];
id<MTLRenderCommandEncoder> ce = [cb renderCommandEncoderWithDescriptor:_outputRenderPassDesc];
if (_needEncodeViewport) if (_needEncodeViewport)
{ {
[ce setViewport:_newViewport]; [rce setViewport:_newViewport];
} }
// Draw the NDS displays. // Draw the NDS displays.
if (_willDrawDisplays) if (_willDrawDisplays)
{ {
[ce setRenderPipelineState:[self displayOutputPipeline]]; [rce setRenderPipelineState:displayPipelineState];
[ce setVertexBuffer:_displayVtxPositionBuffer offset:0 atIndex:0]; [rce setVertexBuffer:_displayVtxPositionBuffer offset:0 atIndex:0];
[ce setVertexBuffer:_displayTexCoordBuffer offset:0 atIndex:1]; [rce setVertexBuffer:_displayTexCoordBuffer offset:0 atIndex:1];
[ce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:2]; [rce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:2];
switch (_cdv->GetViewProperties().mode) switch (_cdv->GetViewProperties().mode)
{ {
@ -1613,8 +1623,8 @@
{ {
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main)) if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main))
{ {
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0]; [rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0];
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
} }
break; break;
} }
@ -1623,8 +1633,8 @@
{ {
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch)) if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch))
{ {
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0]; [rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0];
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4]; [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4];
} }
break; break;
} }
@ -1642,8 +1652,8 @@
{ {
if (_cdv->IsSelectedDisplayEnabled(majorDisplayID)) if (_cdv->IsSelectedDisplayEnabled(majorDisplayID))
{ {
[ce setFragmentTexture:_texDisplayOutput[majorDisplayID] atIndex:0]; [rce setFragmentTexture:_texDisplayOutput[majorDisplayID] atIndex:0];
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:majorDisplayVtx vertexCount:4]; [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:majorDisplayVtx vertexCount:4];
} }
break; break;
} }
@ -1654,14 +1664,14 @@
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main)) if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main))
{ {
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0]; [rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0];
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
} }
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch)) if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch))
{ {
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0]; [rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0];
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4]; [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4];
} }
} }
@ -1675,29 +1685,29 @@
{ {
uint8_t isScreenOverlay = 0; uint8_t isScreenOverlay = 0;
[ce setRenderPipelineState:[sharedData hudPipeline]]; [rce setRenderPipelineState:hudPipelineState];
[ce setVertexBuffer:_hudVtxPositionBuffer offset:0 atIndex:0]; [rce setVertexBuffer:_hudVtxPositionBuffer offset:0 atIndex:0];
[ce setVertexBuffer:_hudVtxColorBuffer offset:0 atIndex:1]; [rce setVertexBuffer:_hudVtxColorBuffer offset:0 atIndex:1];
[ce setVertexBuffer:_hudTexCoordBuffer offset:0 atIndex:2]; [rce setVertexBuffer:_hudTexCoordBuffer offset:0 atIndex:2];
[ce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:3]; [rce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:3];
[ce setFragmentTexture:[self texHUDCharMap] atIndex:0]; [rce setFragmentTexture:[self texHUDCharMap] atIndex:0];
// First, draw the inputs. // First, draw the inputs.
if (_willDrawHUDInput) if (_willDrawHUDInput)
{ {
isScreenOverlay = 1; isScreenOverlay = 1;
[ce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4]; [rce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
[ce setFragmentSamplerState:[sharedData samplerHUDBox] atIndex:0]; [rce setFragmentSamplerState:[sharedData samplerHUDBox] atIndex:0];
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle [rce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:_hudTouchLineLength * 6 indexCount:_hudTouchLineLength * 6
indexType:MTLIndexTypeUInt16 indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer] indexBuffer:[sharedData hudIndexBuffer]
indexBufferOffset:(_hudStringLength + HUD_INPUT_ELEMENT_LENGTH) * 6 * sizeof(uint16_t)]; indexBufferOffset:(_hudStringLength + HUD_INPUT_ELEMENT_LENGTH) * 6 * sizeof(uint16_t)];
isScreenOverlay = 0; isScreenOverlay = 0;
[ce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4]; [rce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
[ce setFragmentSamplerState:[sharedData samplerHUDText] atIndex:0]; [rce setFragmentSamplerState:[sharedData samplerHUDText] atIndex:0];
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle [rce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:HUD_INPUT_ELEMENT_LENGTH * 6 indexCount:HUD_INPUT_ELEMENT_LENGTH * 6
indexType:MTLIndexTypeUInt16 indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer] indexBuffer:[sharedData hudIndexBuffer]
@ -1705,24 +1715,96 @@
} }
// Next, draw the backing text box. // Next, draw the backing text box.
[ce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4]; [rce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
[ce setFragmentSamplerState:[sharedData samplerHUDBox] atIndex:0]; [rce setFragmentSamplerState:[sharedData samplerHUDBox] atIndex:0];
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle [rce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:6 indexCount:6
indexType:MTLIndexTypeUInt16 indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer] indexBuffer:[sharedData hudIndexBuffer]
indexBufferOffset:0]; indexBufferOffset:0];
// Finally, draw each character inside the box. // Finally, draw each character inside the box.
[ce setFragmentSamplerState:[sharedData samplerHUDText] atIndex:0]; [rce setFragmentSamplerState:[sharedData samplerHUDText] atIndex:0];
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle [rce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:(_hudStringLength - 1) * 6 indexCount:(_hudStringLength - 1) * 6
indexType:MTLIndexTypeUInt16 indexType:MTLIndexTypeUInt16
indexBuffer:[sharedData hudIndexBuffer] indexBuffer:[sharedData hudIndexBuffer]
indexBufferOffset:6 * sizeof(uint16_t)]; indexBufferOffset:6 * sizeof(uint16_t)];
} }
[ce endEncoding]; [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
{
pthread_mutex_lock(&_mutexDisplayTextureUpdate);
pthread_mutex_lock(&_mutexBufferUpdate);
// Now that everything is set up, go ahead and draw everything.
id<CAMetalDrawable> layerDrawable = [self nextDrawable];
[colorAttachment0Desc setTexture:[layerDrawable texture]];
id<MTLCommandBuffer> cb = [self newCommandBuffer];
[self renderForCommandBuffer:cb displayPipelineState:[self displayOutputPipeline] hudPipelineState:[sharedData hudPipeline]];
[cb presentDrawable:layerDrawable]; [cb presentDrawable:layerDrawable];
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) { [cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
@ -1999,6 +2081,11 @@ void MacMetalDisplayView::FlushView()
[(DisplayViewMetalLayer *)this->GetFrontendLayer() renderAndFlushDrawable]; [(DisplayViewMetalLayer *)this->GetFrontendLayer() renderAndFlushDrawable];
} }
void MacMetalDisplayView::CopyFrameToBuffer(uint32_t *dstBuffer)
{
[(DisplayViewMetalLayer *)this->GetFrontendLayer() renderAndDownloadToBuffer:dstBuffer];
}
#pragma mark - #pragma mark -
void SetupHQnxLUTs_Metal(id<MTLDevice> &device, id<MTLTexture> &texLQ2xLUT, id<MTLTexture> &texHQ2xLUT, id<MTLTexture> &texHQ3xLUT, id<MTLTexture> &texHQ4xLUT) 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 ProcessDisplays();
virtual void UpdateView(); virtual void UpdateView();
virtual void FlushView(); 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 LockDisplayTextures();
virtual void UnlockDisplayTextures(); virtual void UnlockDisplayTextures();
}; };

View File

@ -75,7 +75,7 @@
{ {
CGLSetCurrentContext(glContext); CGLSetCurrentContext(glContext);
CGLLockContext(glContext); CGLLockContext(glContext);
_cdv->RenderViewOGL(); _cdv->RenderFrameOGL(false);
[super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp];
CGLUnlockContext(glContext); CGLUnlockContext(glContext);
} }
@ -447,12 +447,20 @@ void MacOGLDisplayView::FlushView()
CGLLockContext(this->_context); CGLLockContext(this->_context);
CGLSetCurrentContext(this->_context); CGLSetCurrentContext(this->_context);
this->RenderViewOGL(); this->RenderFrameOGL(false);
CGLFlushDrawable(this->_context); CGLFlushDrawable(this->_context);
CGLUnlockContext(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); CGLLockContext(this->_context);
CGLSetCurrentContext(this->_context); CGLSetCurrentContext(this->_context);