Cocoa Port:
- Fix the behavior of the Display Preferences filter preview. - Fix an intermittent crash that sometimes occurs when creating a new display window. - Fix a rare and mysterious crashing bug that sometimes occurs when initializing the HQ4x LUT.
This commit is contained in:
parent
afa4d57545
commit
782447e115
|
@ -3712,7 +3712,7 @@ static void InitHQnxLUTs()
|
|||
|
||||
_LQ2xLUT = (LUTValues *)malloc(256*(2*2)*16 * sizeof(LUTValues));
|
||||
_HQ2xLUT = (LUTValues *)malloc(256*(2*2)*16 * sizeof(LUTValues));
|
||||
_HQ4xLUT = (LUTValues *)malloc(256*(4*4)*16 * sizeof(LUTValues));
|
||||
_HQ4xLUT = (LUTValues *)malloc(256*(4*4)*16 * sizeof(LUTValues) + 4); // The bytes fix a mysterious crash that intermittently occurs. Don't know why this works... it just does.
|
||||
|
||||
#define MUR (compare & 0x01) // top-right
|
||||
#define MDR (compare & 0x02) // bottom-right
|
||||
|
@ -4621,6 +4621,770 @@ GLuint OGLFilterDeposterize::RunFilterOGL(GLuint srcTexID, GLsizei viewportWidth
|
|||
|
||||
#pragma mark -
|
||||
|
||||
OGLImage::OGLImage(OGLInfo *oglInfo, GLsizei imageWidth, GLsizei imageHeight, GLsizei viewportWidth, GLsizei viewportHeight)
|
||||
{
|
||||
_needUploadVertices = true;
|
||||
_useDeposterize = false;
|
||||
|
||||
_vtxElementPointer = 0;
|
||||
|
||||
_normalWidth = imageWidth;
|
||||
_normalHeight = imageHeight;
|
||||
_viewportWidth = viewportWidth;
|
||||
_viewportHeight = viewportHeight;
|
||||
|
||||
_vf = new VideoFilter(_normalWidth, _normalHeight, VideoFilterTypeID_None, 0);
|
||||
|
||||
_vfMasterDstBuffer = (uint32_t *)calloc(_vf->GetDstWidth() * _vf->GetDstHeight(), sizeof(uint32_t));
|
||||
_vf->SetDstBufferPtr(_vfMasterDstBuffer);
|
||||
|
||||
_displayTexFilter = GL_NEAREST;
|
||||
glViewport(0, 0, _viewportWidth, _viewportHeight);
|
||||
|
||||
UpdateVertices();
|
||||
UpdateTexCoords(_vf->GetDstWidth(), _vf->GetDstHeight());
|
||||
|
||||
// Set up textures
|
||||
glGenTextures(1, &_texCPUFilterDstID);
|
||||
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);
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
|
||||
glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, _vf->GetDstWidth() * _vf->GetDstHeight() * sizeof(uint32_t), _vfMasterDstBuffer);
|
||||
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, _vf->GetSrcWidth(), _vf->GetSrcHeight(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, _vf->GetSrcBufferPtr());
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
|
||||
// Set up VBOs
|
||||
glGenBuffersARB(1, &_vboVertexID);
|
||||
glGenBuffersARB(1, &_vboTexCoordID);
|
||||
glGenBuffersARB(1, &_vboElementID);
|
||||
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboVertexID);
|
||||
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(_vtxBuffer), _vtxBuffer, GL_STATIC_DRAW_ARB);
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboTexCoordID);
|
||||
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(_texCoordBuffer), _texCoordBuffer, GL_STATIC_DRAW_ARB);
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
|
||||
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _vboElementID);
|
||||
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(GLubyte) * 6, outputElementBuffer, GL_STATIC_DRAW_ARB);
|
||||
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
|
||||
|
||||
// Set up VAO
|
||||
glGenVertexArraysDESMUME(1, &_vaoMainStatesID);
|
||||
glBindVertexArrayDESMUME(_vaoMainStatesID);
|
||||
|
||||
if (oglInfo->IsShaderSupported())
|
||||
{
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboVertexID);
|
||||
glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_INT, GL_FALSE, 0, 0);
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboTexCoordID);
|
||||
glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _vboElementID);
|
||||
|
||||
glEnableVertexAttribArray(OGLVertexAttributeID_Position);
|
||||
glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboVertexID);
|
||||
glVertexPointer(2, GL_INT, 0, 0);
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboTexCoordID);
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, 0);
|
||||
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _vboElementID);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
glBindVertexArrayDESMUME(0);
|
||||
_isVAOPresent = true;
|
||||
|
||||
_pixelScaler = VideoFilterTypeID_None;
|
||||
_useShader150 = oglInfo->IsUsingShader150();
|
||||
_shaderSupport = oglInfo->GetShaderSupport();
|
||||
_canUseShaderOutput = oglInfo->IsShaderSupported();
|
||||
if (_canUseShaderOutput)
|
||||
{
|
||||
_finalOutputProgram = new OGLShaderProgram;
|
||||
_finalOutputProgram->SetShaderSupport(_shaderSupport);
|
||||
_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
|
||||
|
||||
const GLuint finalOutputProgramID = _finalOutputProgram->GetProgramID();
|
||||
glUseProgram(finalOutputProgramID);
|
||||
_uniformFinalOutputAngleDegrees = glGetUniformLocation(finalOutputProgramID, "angleDegrees");
|
||||
_uniformFinalOutputScalar = glGetUniformLocation(finalOutputProgramID, "scalar");
|
||||
_uniformFinalOutputViewSize = glGetUniformLocation(finalOutputProgramID, "viewSize");
|
||||
glUseProgram(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
_finalOutputProgram = NULL;
|
||||
}
|
||||
|
||||
_canUseShaderBasedFilters = (_canUseShaderOutput && oglInfo->IsFBOSupported());
|
||||
if (_canUseShaderBasedFilters)
|
||||
{
|
||||
_filterDeposterize = new OGLFilterDeposterize(_vf->GetSrcWidth(), _vf->GetSrcHeight(), _shaderSupport, _useShader150);
|
||||
|
||||
_shaderFilter = new OGLFilter(_vf->GetSrcWidth(), _vf->GetSrcHeight(), 1);
|
||||
OGLShaderProgram *shaderFilterProgram = _shaderFilter->GetProgram();
|
||||
shaderFilterProgram->SetShaderSupport(_shaderSupport);
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, PassthroughFragShader_110, _useShader150);
|
||||
|
||||
UploadHQnxLUTs();
|
||||
}
|
||||
else
|
||||
{
|
||||
_filterDeposterize = NULL;
|
||||
_shaderFilter = NULL;
|
||||
}
|
||||
|
||||
_useShaderBasedPixelScaler = false;
|
||||
_filtersPreferGPU = true;
|
||||
_outputFilter = OutputFilterTypeID_Bilinear;
|
||||
}
|
||||
|
||||
OGLImage::~OGLImage()
|
||||
{
|
||||
if (_isVAOPresent)
|
||||
{
|
||||
glDeleteVertexArraysDESMUME(1, &this->_vaoMainStatesID);
|
||||
_isVAOPresent = false;
|
||||
}
|
||||
|
||||
glDeleteBuffersARB(1, &this->_vboVertexID);
|
||||
glDeleteBuffersARB(1, &this->_vboTexCoordID);
|
||||
glDeleteBuffersARB(1, &this->_vboElementID);
|
||||
glDeleteTextures(1, &this->_texCPUFilterDstID);
|
||||
glDeleteTextures(1, &this->_texVideoInputDataID);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_3D, 0);
|
||||
glDeleteTextures(1, &this->_texLQ2xLUT);
|
||||
glDeleteTextures(1, &this->_texHQ2xLUT);
|
||||
glDeleteTextures(1, &this->_texHQ4xLUT);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
if (_canUseShaderOutput)
|
||||
{
|
||||
glUseProgram(0);
|
||||
delete this->_finalOutputProgram;
|
||||
}
|
||||
|
||||
if (_canUseShaderBasedFilters)
|
||||
{
|
||||
delete this->_filterDeposterize;
|
||||
delete this->_shaderFilter;
|
||||
}
|
||||
|
||||
delete this->_vf;
|
||||
free(_vfMasterDstBuffer);
|
||||
}
|
||||
|
||||
void OGLImage::UploadHQnxLUTs()
|
||||
{
|
||||
InitHQnxLUTs();
|
||||
|
||||
glGenTextures(1, &_texLQ2xLUT);
|
||||
glGenTextures(1, &_texHQ2xLUT);
|
||||
glGenTextures(1, &_texHQ4xLUT);
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
|
||||
glBindTexture(GL_TEXTURE_3D, _texLQ2xLUT);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 256*2, 4, 16, 0, GL_BGR, GL_UNSIGNED_BYTE, _LQ2xLUT);
|
||||
|
||||
glBindTexture(GL_TEXTURE_3D, _texHQ2xLUT);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 256*2, 4, 16, 0, GL_BGR, GL_UNSIGNED_BYTE, _HQ2xLUT);
|
||||
|
||||
glBindTexture(GL_TEXTURE_3D, _texHQ4xLUT);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 256*2, 16, 16, 0, GL_BGR, GL_UNSIGNED_BYTE, _HQ4xLUT);
|
||||
|
||||
glBindTexture(GL_TEXTURE_3D, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
bool OGLImage::GetFiltersPreferGPU()
|
||||
{
|
||||
return this->_filtersPreferGPU;
|
||||
}
|
||||
|
||||
void OGLImage::SetFiltersPreferGPUOGL(bool preferGPU)
|
||||
{
|
||||
this->_filtersPreferGPU = preferGPU;
|
||||
this->_useShaderBasedPixelScaler = (preferGPU) ? this->SetGPUPixelScalerOGL(this->_pixelScaler) : false;
|
||||
}
|
||||
|
||||
bool OGLImage::GetSourceDeposterize()
|
||||
{
|
||||
return this->_useDeposterize;
|
||||
}
|
||||
|
||||
void OGLImage::SetSourceDeposterize(bool useDeposterize)
|
||||
{
|
||||
this->_useDeposterize = (this->_canUseShaderBasedFilters) ? useDeposterize : false;
|
||||
}
|
||||
|
||||
void OGLImage::UpdateVertices()
|
||||
{
|
||||
const GLint w = this->_normalWidth;
|
||||
const GLint h = this->_normalHeight;
|
||||
|
||||
_vtxBuffer[0] = -w/2; _vtxBuffer[1] = h/2;
|
||||
_vtxBuffer[2] = w/2; _vtxBuffer[3] = h/2;
|
||||
_vtxBuffer[4] = w/2; _vtxBuffer[5] = -h/2;
|
||||
_vtxBuffer[6] = -w/2; _vtxBuffer[7] = -h/2;
|
||||
|
||||
this->_needUploadVertices = true;
|
||||
}
|
||||
|
||||
void OGLImage::UpdateTexCoords(GLfloat s, GLfloat t)
|
||||
{
|
||||
_texCoordBuffer[0] = 0.0f; _texCoordBuffer[1] = 0.0f;
|
||||
_texCoordBuffer[2] = s; _texCoordBuffer[3] = 0.0f;
|
||||
_texCoordBuffer[4] = s; _texCoordBuffer[5] = t;
|
||||
_texCoordBuffer[6] = 0.0f; _texCoordBuffer[7] = t;
|
||||
}
|
||||
|
||||
bool OGLImage::CanUseShaderBasedFilters()
|
||||
{
|
||||
return this->_canUseShaderBasedFilters;
|
||||
}
|
||||
|
||||
void OGLImage::GetNormalSize(double *w, double *h)
|
||||
{
|
||||
if (w == NULL || h == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*w = this->_normalWidth;
|
||||
*h = this->_normalHeight;
|
||||
}
|
||||
|
||||
void OGLImage::UploadVerticesOGL()
|
||||
{
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboVertexID);
|
||||
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(this->_vtxBuffer), this->_vtxBuffer);
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
this->_needUploadVertices = false;
|
||||
}
|
||||
|
||||
void OGLImage::UploadTexCoordsOGL()
|
||||
{
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboTexCoordID);
|
||||
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(this->_texCoordBuffer), this->_texCoordBuffer);
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
}
|
||||
|
||||
void OGLImage::UploadTransformationOGL()
|
||||
{
|
||||
const double w = this->_viewportWidth;
|
||||
const double h = this->_viewportHeight;
|
||||
const GLdouble s = GetMaxScalarInBounds(this->_normalWidth, this->_normalHeight, w, h);
|
||||
|
||||
if (this->_canUseShaderOutput)
|
||||
{
|
||||
glUniform2f(this->_uniformFinalOutputViewSize, w, h);
|
||||
glUniform1f(this->_uniformFinalOutputAngleDegrees, 0.0f);
|
||||
glUniform1f(this->_uniformFinalOutputScalar, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(-w/2.0, -w/2.0 + w, -h/2.0, -h/2.0 + h, -1.0, 1.0);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glRotatef(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glScalef(s, s, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
int OGLImage::GetOutputFilter()
|
||||
{
|
||||
return this->_outputFilter;
|
||||
}
|
||||
|
||||
void OGLImage::SetOutputFilterOGL(const int filterID)
|
||||
{
|
||||
this->_displayTexFilter = GL_NEAREST;
|
||||
|
||||
if (this->_canUseShaderBasedFilters)
|
||||
{
|
||||
this->_outputFilter = filterID;
|
||||
|
||||
switch (filterID)
|
||||
{
|
||||
case OutputFilterTypeID_NearestNeighbor:
|
||||
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case OutputFilterTypeID_Bilinear:
|
||||
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
|
||||
this->_displayTexFilter = GL_LINEAR;
|
||||
break;
|
||||
|
||||
case OutputFilterTypeID_BicubicBSpline:
|
||||
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterBicubicBSplineFragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case OutputFilterTypeID_BicubicMitchell:
|
||||
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterBicubicMitchellNetravaliFragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case OutputFilterTypeID_Lanczos2:
|
||||
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterLanczos2FragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case OutputFilterTypeID_Lanczos3:
|
||||
{
|
||||
if (this->_shaderSupport >= ShaderSupport_HighTier)
|
||||
{
|
||||
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample6x6Output_VertShader_110, FilterLanczos3FragShader_110, _useShader150);
|
||||
}
|
||||
else if (this->_shaderSupport >= ShaderSupport_MidTier)
|
||||
{
|
||||
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample5x5Output_VertShader_110, FilterLanczos3FragShader_110, _useShader150);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterLanczos3FragShader_110, _useShader150);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
|
||||
this->_outputFilter = OutputFilterTypeID_NearestNeighbor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filterID == OutputFilterTypeID_Bilinear)
|
||||
{
|
||||
this->_displayTexFilter = GL_LINEAR;
|
||||
this->_outputFilter = filterID;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_outputFilter = OutputFilterTypeID_NearestNeighbor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int OGLImage::GetPixelScaler()
|
||||
{
|
||||
return (int)this->_pixelScaler;
|
||||
}
|
||||
|
||||
void OGLImage::SetPixelScalerOGL(const int filterID)
|
||||
{
|
||||
std::string cpuTypeIDString = std::string( VideoFilter::GetTypeStringByID((VideoFilterTypeID)filterID) );
|
||||
const VideoFilterTypeID newFilterID = (cpuTypeIDString != std::string(VIDEOFILTERTYPE_UNKNOWN_STRING)) ? (VideoFilterTypeID)filterID : VideoFilterTypeID_None;
|
||||
|
||||
this->SetCPUPixelScalerOGL(newFilterID);
|
||||
this->_useShaderBasedPixelScaler = (this->GetFiltersPreferGPU()) ? this->SetGPUPixelScalerOGL(newFilterID) : false;
|
||||
this->_pixelScaler = newFilterID;
|
||||
}
|
||||
|
||||
bool OGLImage::SetGPUPixelScalerOGL(const VideoFilterTypeID filterID)
|
||||
{
|
||||
bool willUseShaderBasedPixelScaler = true;
|
||||
|
||||
if (!this->_canUseShaderBasedFilters || filterID == VideoFilterTypeID_None)
|
||||
{
|
||||
willUseShaderBasedPixelScaler = false;
|
||||
return willUseShaderBasedPixelScaler;
|
||||
}
|
||||
|
||||
OGLShaderProgram *shaderFilterProgram = _shaderFilter->GetProgram();
|
||||
VideoFilterAttributes vfAttr = VideoFilter::GetAttributesByID((VideoFilterTypeID)filterID);
|
||||
GLfloat vfScale = (GLfloat)vfAttr.scaleMultiply / (GLfloat)vfAttr.scaleDivide;
|
||||
|
||||
switch (filterID)
|
||||
{
|
||||
case VideoFilterTypeID_Nearest1_5X:
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, PassthroughFragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case VideoFilterTypeID_Nearest2X:
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, PassthroughFragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case VideoFilterTypeID_Scanline:
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, Scalar2xScanlineFragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case VideoFilterTypeID_EPX:
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, Scalar2xEPXFragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case VideoFilterTypeID_EPXPlus:
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, Scalar2xEPXPlusFragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case VideoFilterTypeID_2xSaI:
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scalar2xSaIFragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case VideoFilterTypeID_Super2xSaI:
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, ScalarSuper2xSaIFragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case VideoFilterTypeID_SuperEagle:
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, ScalarSuperEagle2xFragShader_110, _useShader150);
|
||||
break;
|
||||
|
||||
case VideoFilterTypeID_LQ2X:
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_3D, this->_texLQ2xLUT);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerLQ2xFragShader_110, _useShader150);
|
||||
|
||||
glUseProgram(shaderFilterProgram->GetProgramID());
|
||||
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
|
||||
glUniform1i(uniformTexSampler, 0);
|
||||
|
||||
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
|
||||
glUniform1i(uniformTexSampler, 1);
|
||||
glUseProgram(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case VideoFilterTypeID_LQ2XS:
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_3D, this->_texLQ2xLUT);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerLQ2xSFragShader_110, _useShader150);
|
||||
|
||||
glUseProgram(shaderFilterProgram->GetProgramID());
|
||||
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
|
||||
glUniform1i(uniformTexSampler, 0);
|
||||
|
||||
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
|
||||
glUniform1i(uniformTexSampler, 1);
|
||||
glUseProgram(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case VideoFilterTypeID_HQ2X:
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_3D, this->_texHQ2xLUT);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ2xFragShader_110, _useShader150);
|
||||
|
||||
glUseProgram(shaderFilterProgram->GetProgramID());
|
||||
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
|
||||
glUniform1i(uniformTexSampler, 0);
|
||||
|
||||
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
|
||||
glUniform1i(uniformTexSampler, 1);
|
||||
glUseProgram(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case VideoFilterTypeID_HQ2XS:
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_3D, this->_texHQ2xLUT);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ2xSFragShader_110, _useShader150);
|
||||
|
||||
glUseProgram(shaderFilterProgram->GetProgramID());
|
||||
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
|
||||
glUniform1i(uniformTexSampler, 0);
|
||||
|
||||
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
|
||||
glUniform1i(uniformTexSampler, 1);
|
||||
glUseProgram(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case VideoFilterTypeID_HQ4X:
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_3D, this->_texHQ4xLUT);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ4xFragShader_110, _useShader150);
|
||||
|
||||
glUseProgram(shaderFilterProgram->GetProgramID());
|
||||
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
|
||||
glUniform1i(uniformTexSampler, 0);
|
||||
|
||||
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
|
||||
glUniform1i(uniformTexSampler, 1);
|
||||
glUseProgram(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case VideoFilterTypeID_HQ4XS:
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_3D, this->_texHQ4xLUT);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ4xSFragShader_110, _useShader150);
|
||||
|
||||
glUseProgram(shaderFilterProgram->GetProgramID());
|
||||
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
|
||||
glUniform1i(uniformTexSampler, 0);
|
||||
|
||||
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
|
||||
glUniform1i(uniformTexSampler, 1);
|
||||
glUseProgram(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case VideoFilterTypeID_2xBRZ:
|
||||
{
|
||||
if (this->_shaderSupport >= ShaderSupport_MidTier)
|
||||
{
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler2xBRZFragShader_110, _useShader150);
|
||||
}
|
||||
else if (this->_shaderSupport >= ShaderSupport_LowTier)
|
||||
{
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scaler2xBRZFragShader_110, _useShader150);
|
||||
}
|
||||
else
|
||||
{
|
||||
willUseShaderBasedPixelScaler = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VideoFilterTypeID_3xBRZ:
|
||||
{
|
||||
if (this->_shaderSupport >= ShaderSupport_MidTier)
|
||||
{
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler3xBRZFragShader_110, _useShader150);
|
||||
}
|
||||
else if (this->_shaderSupport >= ShaderSupport_LowTier)
|
||||
{
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scaler3xBRZFragShader_110, _useShader150);
|
||||
}
|
||||
else
|
||||
{
|
||||
willUseShaderBasedPixelScaler = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VideoFilterTypeID_4xBRZ:
|
||||
{
|
||||
if (this->_shaderSupport >= ShaderSupport_MidTier)
|
||||
{
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler4xBRZFragShader_110, _useShader150);
|
||||
}
|
||||
else if (this->_shaderSupport >= ShaderSupport_LowTier)
|
||||
{
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scaler4xBRZFragShader_110, _useShader150);
|
||||
}
|
||||
else
|
||||
{
|
||||
willUseShaderBasedPixelScaler = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case VideoFilterTypeID_5xBRZ:
|
||||
{
|
||||
if (this->_shaderSupport >= ShaderSupport_MidTier)
|
||||
{
|
||||
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler5xBRZFragShader_110, _useShader150);
|
||||
}
|
||||
else
|
||||
{
|
||||
willUseShaderBasedPixelScaler = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
willUseShaderBasedPixelScaler = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (willUseShaderBasedPixelScaler)
|
||||
{
|
||||
_shaderFilter->SetScaleOGL(vfScale);
|
||||
}
|
||||
|
||||
return willUseShaderBasedPixelScaler;
|
||||
}
|
||||
|
||||
void OGLImage::SetCPUPixelScalerOGL(const VideoFilterTypeID filterID)
|
||||
{
|
||||
bool needResizeTexture = false;
|
||||
const VideoFilterAttributes newFilterAttr = VideoFilter::GetAttributesByID(filterID);
|
||||
const GLsizei oldDstBufferWidth = this->_vf->GetDstWidth();
|
||||
const GLsizei oldDstBufferHeight = this->_vf->GetDstHeight();
|
||||
const GLsizei newDstBufferWidth = this->_vf->GetSrcWidth() * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide;
|
||||
const GLsizei newDstBufferHeight = this->_vf->GetSrcHeight() * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide;
|
||||
|
||||
if (oldDstBufferWidth != newDstBufferWidth || oldDstBufferHeight != newDstBufferHeight)
|
||||
{
|
||||
needResizeTexture = true;
|
||||
}
|
||||
|
||||
if (needResizeTexture)
|
||||
{
|
||||
uint32_t *oldMasterBuffer = _vfMasterDstBuffer;
|
||||
uint32_t *newMasterBuffer = (uint32_t *)calloc(newDstBufferWidth * newDstBufferHeight, sizeof(uint32_t));
|
||||
this->_vf->SetDstBufferPtr(newMasterBuffer);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texCPUFilterDstID);
|
||||
glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, newDstBufferWidth * newDstBufferHeight * sizeof(uint32_t), newMasterBuffer);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
|
||||
|
||||
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, newDstBufferWidth, newDstBufferHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, newMasterBuffer);
|
||||
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
|
||||
_vfMasterDstBuffer = newMasterBuffer;
|
||||
free(oldMasterBuffer);
|
||||
}
|
||||
|
||||
this->_vf->ChangeFilterByID(filterID);
|
||||
}
|
||||
|
||||
void OGLImage::LoadFrameOGL(const uint32_t *frameData, GLsizei w, GLsizei h)
|
||||
{
|
||||
const bool isUsingCPUPixelScaler = this->_pixelScaler != VideoFilterTypeID_None && !this->_useShaderBasedPixelScaler;
|
||||
|
||||
if (!isUsingCPUPixelScaler || this->_useDeposterize)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoInputDataID);
|
||||
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, frameData);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(this->_vf->GetSrcBufferPtr(), frameData, w * h * sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
void OGLImage::ProcessOGL()
|
||||
{
|
||||
VideoFilter *currentFilter = this->_vf;
|
||||
const bool isUsingCPUPixelScaler = this->_pixelScaler != VideoFilterTypeID_None && !this->_useShaderBasedPixelScaler;
|
||||
|
||||
// Source
|
||||
if (this->_useDeposterize)
|
||||
{
|
||||
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)
|
||||
{
|
||||
this->_filterDeposterize->DownloadDstBufferOGL(currentFilter->GetSrcBufferPtr(), 0, this->_normalHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_texVideoSourceID = this->_texVideoInputDataID;
|
||||
}
|
||||
|
||||
// Pixel scaler
|
||||
if (!isUsingCPUPixelScaler)
|
||||
{
|
||||
if (this->_useShaderBasedPixelScaler)
|
||||
{
|
||||
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->_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(this->_normalWidth, this->_normalHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t *texData = currentFilter->RunFilter();
|
||||
|
||||
const GLfloat w = currentFilter->GetDstWidth();
|
||||
const GLfloat h = currentFilter->GetDstHeight();
|
||||
this->_texVideoPixelScalerID = this->_texCPUFilterDstID;
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoPixelScalerID);
|
||||
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texData);
|
||||
this->UpdateTexCoords(w, h);
|
||||
}
|
||||
|
||||
// Output
|
||||
this->_texVideoOutputID = this->_texVideoPixelScalerID;
|
||||
this->UploadTexCoordsOGL();
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
|
||||
void OGLImage::RenderOGL()
|
||||
{
|
||||
glUseProgram(this->_finalOutputProgram->GetProgramID());
|
||||
this->UploadTransformationOGL();
|
||||
|
||||
if (this->_needUploadVertices)
|
||||
{
|
||||
this->UploadVerticesOGL();
|
||||
}
|
||||
|
||||
// Enable vertex attributes
|
||||
glBindVertexArrayDESMUME(this->_vaoMainStatesID);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
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, 6, GL_UNSIGNED_BYTE, this->_vtxElementPointer);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
|
||||
// Disable vertex attributes
|
||||
glBindVertexArrayDESMUME(0);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO)
|
||||
{
|
||||
_output = oglVO;
|
||||
|
@ -4720,6 +5484,7 @@ OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO)
|
|||
glBindVertexArrayDESMUME(0);
|
||||
_isVAOPresent = true;
|
||||
|
||||
_pixelScaler = VideoFilterTypeID_None;
|
||||
_useShader150 = this->_output->GetInfo()->IsUsingShader150();
|
||||
_shaderSupport = this->_output->GetInfo()->GetShaderSupport();
|
||||
_canUseShaderOutput = this->_output->GetInfo()->IsShaderSupported();
|
||||
|
|
|
@ -189,6 +189,93 @@ public:
|
|||
virtual void RenderOGL() {};
|
||||
};
|
||||
|
||||
class OGLImage
|
||||
{
|
||||
protected:
|
||||
bool _isVAOPresent;
|
||||
bool _canUseShaderBasedFilters;
|
||||
bool _canUseShaderOutput;
|
||||
bool _useShader150;
|
||||
ShaderSupportTier _shaderSupport;
|
||||
|
||||
bool _needUploadVertices;
|
||||
bool _useDeposterize;
|
||||
bool _useShaderBasedPixelScaler;
|
||||
bool _filtersPreferGPU;
|
||||
int _outputFilter;
|
||||
VideoFilterTypeID _pixelScaler;
|
||||
|
||||
OGLFilter *_filterDeposterize;
|
||||
OGLFilter *_shaderFilter;
|
||||
OGLShaderProgram *_finalOutputProgram;
|
||||
|
||||
VideoFilter *_vf;
|
||||
uint32_t *_vfMasterDstBuffer;
|
||||
|
||||
double _normalWidth;
|
||||
double _normalHeight;
|
||||
GLsizei _viewportWidth;
|
||||
GLsizei _viewportHeight;
|
||||
|
||||
GLubyte *_vtxElementPointer;
|
||||
|
||||
GLint _displayTexFilter;
|
||||
GLuint _texCPUFilterDstID;
|
||||
|
||||
GLuint _texLQ2xLUT;
|
||||
GLuint _texHQ2xLUT;
|
||||
GLuint _texHQ4xLUT;
|
||||
|
||||
GLint _vtxBuffer[8];
|
||||
GLfloat _texCoordBuffer[8];
|
||||
|
||||
GLuint _texVideoInputDataID;
|
||||
GLuint _texVideoSourceID;
|
||||
GLuint _texVideoPixelScalerID;
|
||||
GLuint _texVideoOutputID;
|
||||
GLuint _vaoMainStatesID;
|
||||
GLuint _vboVertexID;
|
||||
GLuint _vboTexCoordID;
|
||||
GLuint _vboElementID;
|
||||
|
||||
GLint _uniformFinalOutputAngleDegrees;
|
||||
GLint _uniformFinalOutputScalar;
|
||||
GLint _uniformFinalOutputViewSize;
|
||||
|
||||
void UploadHQnxLUTs();
|
||||
|
||||
virtual void UploadVerticesOGL();
|
||||
virtual void UploadTexCoordsOGL();
|
||||
virtual void UploadTransformationOGL();
|
||||
|
||||
void UpdateVertices();
|
||||
void UpdateTexCoords(GLfloat s, GLfloat t);
|
||||
|
||||
public:
|
||||
OGLImage() {};
|
||||
OGLImage(OGLInfo *oglInfo, GLsizei imageWidth, GLsizei imageHeight, GLsizei viewportWidth, GLsizei viewportHeight);
|
||||
virtual ~OGLImage();
|
||||
|
||||
bool GetFiltersPreferGPU();
|
||||
void SetFiltersPreferGPUOGL(bool preferGPU);
|
||||
|
||||
bool GetSourceDeposterize();
|
||||
void SetSourceDeposterize(bool useDeposterize);
|
||||
|
||||
bool CanUseShaderBasedFilters();
|
||||
void GetNormalSize(double *w, double *h);
|
||||
|
||||
int GetOutputFilter();
|
||||
virtual void SetOutputFilterOGL(const int filterID);
|
||||
int GetPixelScaler();
|
||||
virtual void SetPixelScalerOGL(const int filterID);
|
||||
virtual bool SetGPUPixelScalerOGL(const VideoFilterTypeID filterID);
|
||||
virtual void SetCPUPixelScalerOGL(const VideoFilterTypeID filterID);
|
||||
virtual void LoadFrameOGL(const uint32_t *frameData, GLsizei w, GLsizei h);
|
||||
virtual void ProcessOGL();
|
||||
virtual void RenderOGL();
|
||||
};
|
||||
|
||||
class OGLDisplayLayer : public OGLVideoLayer
|
||||
{
|
||||
protected:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,10 +17,29 @@
|
|||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#import "inputPrefsView.h"
|
||||
|
||||
@class CocoaVideoFilter;
|
||||
class OGLImage;
|
||||
|
||||
@interface DisplayPreviewView : NSView
|
||||
{
|
||||
OGLImage *oglImage;
|
||||
NSOpenGLContext *context;
|
||||
CGLContextObj cglDisplayContext;
|
||||
|
||||
bool isPreviewImageLoaded;
|
||||
}
|
||||
|
||||
@property (assign) BOOL filtersPreferGPU;
|
||||
@property (assign) BOOL sourceDeposterize;
|
||||
@property (assign) NSInteger pixelScaler;
|
||||
@property (assign) NSInteger outputFilter;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
|
||||
@interface PreferencesWindowDelegate : NSObject <NSWindowDelegate>
|
||||
|
@ -55,9 +74,7 @@
|
|||
NSImage *iconVolumeMute;
|
||||
NSPopUpButton *spuSyncMethodMenu;
|
||||
|
||||
NSImageView *previewImageView;
|
||||
CocoaVideoFilter *videoFilter;
|
||||
CocoaVideoFilter *bilinearVideoFilter;
|
||||
DisplayPreviewView *previewView;
|
||||
|
||||
NSMutableDictionary *bindings;
|
||||
}
|
||||
|
@ -82,7 +99,7 @@
|
|||
@property (readonly) IBOutlet NSTextField *displayRotationField;
|
||||
@property (readonly) IBOutlet NSPopUpButton *spuSyncMethodMenu;
|
||||
|
||||
@property (readonly) IBOutlet NSImageView *previewImageView;
|
||||
@property (readonly) IBOutlet DisplayPreviewView *previewView;
|
||||
|
||||
@property (readonly) NSMutableDictionary *bindings;
|
||||
|
||||
|
@ -98,8 +115,10 @@
|
|||
- (IBAction) selectDisplayRotation:(id)sender;
|
||||
- (void) updateDisplayRotationMenu:(double)displayRotation;
|
||||
|
||||
- (IBAction) setUseBilinear:(id)sender;
|
||||
- (IBAction) selectVideoFilterType:(id)sender;
|
||||
- (IBAction) updateFiltersPreferGPU:(id)sender;
|
||||
- (IBAction) updateSourceDeposterize:(id)sender;
|
||||
- (IBAction) selectOutputFilter:(id)sender;
|
||||
- (IBAction) selectPixelScaler:(id)sender;
|
||||
|
||||
- (IBAction) updateVolumeIcon:(id)sender;
|
||||
- (IBAction) selectSPUSyncMode:(id)sender;
|
||||
|
@ -116,8 +135,6 @@
|
|||
- (void) didEndFirmwareConfigSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo;
|
||||
|
||||
- (void) switchContentView:(NSView *)theView;
|
||||
- (void) updateVideoFilterPreview:(const NSInteger)vfType;
|
||||
- (void) updateBilinearPreview:(const BOOL)useBilinear;
|
||||
- (void) setupUserDefaults;
|
||||
|
||||
@end
|
||||
|
|
|
@ -27,6 +27,191 @@
|
|||
#import "cocoa_videofilter.h"
|
||||
#import "cocoa_util.h"
|
||||
|
||||
#ifdef MAC_OS_X_VERSION_10_7
|
||||
#include "../OGLDisplayOutput_3_2.h"
|
||||
#else
|
||||
#include "../OGLDisplayOutput.h"
|
||||
#endif
|
||||
|
||||
|
||||
#pragma mark -
|
||||
@implementation DisplayPreviewView
|
||||
|
||||
@dynamic filtersPreferGPU;
|
||||
@dynamic sourceDeposterize;
|
||||
@dynamic pixelScaler;
|
||||
@dynamic outputFilter;
|
||||
|
||||
- (id)initWithFrame:(NSRect)frameRect
|
||||
{
|
||||
self = [super initWithFrame:frameRect];
|
||||
if (self == nil)
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
isPreviewImageLoaded = false;
|
||||
|
||||
// Initialize the OpenGL context
|
||||
NSOpenGLPixelFormatAttribute attributes[] = {
|
||||
NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24,
|
||||
NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)8,
|
||||
NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)0,
|
||||
NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute)0,
|
||||
NSOpenGLPFADoubleBuffer,
|
||||
(NSOpenGLPixelFormatAttribute)0, (NSOpenGLPixelFormatAttribute)0,
|
||||
(NSOpenGLPixelFormatAttribute)0 };
|
||||
|
||||
#ifdef _OGLDISPLAYOUTPUT_3_2_H_
|
||||
// If we can support a 3.2 Core Profile context, then request that in our
|
||||
// pixel format attributes.
|
||||
if (IsOSXVersionSupported(10, 7, 0))
|
||||
{
|
||||
attributes[9] = kCGLPFAOpenGLProfile;
|
||||
attributes[10] = (CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core;
|
||||
|
||||
OGLInfoCreate_Func = &OGLInfoCreate_3_2;
|
||||
}
|
||||
#endif
|
||||
|
||||
NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
|
||||
context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:nil];
|
||||
[format release];
|
||||
cglDisplayContext = (CGLContextObj)[context CGLContextObj];
|
||||
|
||||
CGLContextObj prevContext = CGLGetCurrentContext();
|
||||
CGLSetCurrentContext(cglDisplayContext);
|
||||
|
||||
OGLInfo *oglInfo = OGLInfoCreate_Func();
|
||||
oglImage = new OGLImage(oglInfo, 64, 64, frameRect.size.width, frameRect.size.height);
|
||||
oglImage->SetFiltersPreferGPUOGL(true);
|
||||
oglImage->SetSourceDeposterize(false);
|
||||
oglImage->SetOutputFilterOGL(OutputFilterTypeID_Bilinear);
|
||||
oglImage->SetPixelScalerOGL(VideoFilterTypeID_None);
|
||||
|
||||
CGLSetCurrentContext(prevContext);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CGLContextObj prevContext = CGLGetCurrentContext();
|
||||
CGLSetCurrentContext(cglDisplayContext);
|
||||
delete oglImage;
|
||||
CGLSetCurrentContext(prevContext);
|
||||
|
||||
[context clearDrawable];
|
||||
[context release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) setFiltersPreferGPU:(BOOL)theState
|
||||
{
|
||||
CGLContextObj prevContext = CGLGetCurrentContext();
|
||||
CGLSetCurrentContext(cglDisplayContext);
|
||||
oglImage->SetFiltersPreferGPUOGL(theState ? true : false);
|
||||
oglImage->ProcessOGL();
|
||||
CGLSetCurrentContext(prevContext);
|
||||
}
|
||||
|
||||
- (BOOL) filtersPreferGPU
|
||||
{
|
||||
return (oglImage->GetFiltersPreferGPU() ? YES : NO);
|
||||
}
|
||||
|
||||
- (void) setSourceDeposterize:(BOOL)theState
|
||||
{
|
||||
CGLContextObj prevContext = CGLGetCurrentContext();
|
||||
CGLSetCurrentContext(cglDisplayContext);
|
||||
oglImage->SetSourceDeposterize(theState ? true : false);
|
||||
oglImage->ProcessOGL();
|
||||
CGLSetCurrentContext(prevContext);
|
||||
}
|
||||
|
||||
- (BOOL) sourceDeposterize
|
||||
{
|
||||
return (oglImage->GetSourceDeposterize() ? YES : NO);
|
||||
}
|
||||
|
||||
- (void) setPixelScaler:(NSInteger)scalerID
|
||||
{
|
||||
CGLContextObj prevContext = CGLGetCurrentContext();
|
||||
CGLSetCurrentContext(cglDisplayContext);
|
||||
oglImage->SetPixelScalerOGL(scalerID);
|
||||
oglImage->ProcessOGL();
|
||||
CGLSetCurrentContext(prevContext);
|
||||
}
|
||||
|
||||
- (NSInteger) pixelScaler
|
||||
{
|
||||
return (NSInteger)oglImage->GetPixelScaler();
|
||||
}
|
||||
|
||||
- (void) setOutputFilter:(NSInteger)outputFilterID
|
||||
{
|
||||
CGLContextObj prevContext = CGLGetCurrentContext();
|
||||
CGLSetCurrentContext(cglDisplayContext);
|
||||
oglImage->SetOutputFilterOGL(outputFilterID);
|
||||
CGLSetCurrentContext(prevContext);
|
||||
}
|
||||
|
||||
- (NSInteger) outputFilter
|
||||
{
|
||||
return (NSInteger)oglImage->GetOutputFilter();
|
||||
}
|
||||
|
||||
- (void) loadPreviewImage:(NSImage *)previewImage
|
||||
{
|
||||
NSArray *imageRepArray = [previewImage representations];
|
||||
const NSBitmapImageRep *imageRep = [imageRepArray objectAtIndex:0];
|
||||
const NSSize previewImageSize = [previewImage size];
|
||||
|
||||
CGLContextObj prevContext = CGLGetCurrentContext();
|
||||
CGLSetCurrentContext(cglDisplayContext);
|
||||
oglImage->LoadFrameOGL((const uint32_t *)[imageRep bitmapData], previewImageSize.width, previewImageSize.height);
|
||||
oglImage->ProcessOGL();
|
||||
CGLSetCurrentContext(prevContext);
|
||||
}
|
||||
|
||||
- (BOOL)isOpaque
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)lockFocus
|
||||
{
|
||||
[super lockFocus];
|
||||
|
||||
if ([context view] != self)
|
||||
{
|
||||
[context setView:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
if (!isPreviewImageLoaded)
|
||||
{
|
||||
// Load the preview image.
|
||||
NSImage *previewImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"VideoFilterPreview_64x64" ofType:@"png"]];
|
||||
[self loadPreviewImage:previewImage];
|
||||
[previewImage release];
|
||||
|
||||
isPreviewImageLoaded = true;
|
||||
}
|
||||
|
||||
CGLContextObj prevContext = CGLGetCurrentContext();
|
||||
CGLSetCurrentContext(cglDisplayContext);
|
||||
oglImage->RenderOGL();
|
||||
CGLFlushDrawable(cglDisplayContext);
|
||||
CGLSetCurrentContext(prevContext);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation PreferencesWindowDelegate
|
||||
|
||||
|
@ -51,7 +236,7 @@
|
|||
@synthesize displayRotationField;
|
||||
@synthesize spuSyncMethodMenu;
|
||||
|
||||
@synthesize previewImageView;
|
||||
@synthesize previewView;
|
||||
|
||||
@synthesize bindings;
|
||||
|
||||
|
@ -71,21 +256,6 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
// Load the preview image.
|
||||
NSImage *previewImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"VideoFilterPreview_64x64" ofType:@"png"]];
|
||||
NSArray *imageRepArray = [previewImage representations];
|
||||
const NSBitmapImageRep *imageRep = [imageRepArray objectAtIndex:0];
|
||||
const NSSize previewImageSize = [previewImage size];
|
||||
|
||||
// Create our video filters for preview.
|
||||
videoFilter = [[CocoaVideoFilter alloc] initWithSize:previewImageSize typeID:VideoFilterTypeID_Nearest2X];
|
||||
bilinearVideoFilter = [[CocoaVideoFilter alloc] initWithSize:[videoFilter destSize] typeID:VideoFilterTypeID_Nearest2X];
|
||||
|
||||
// Copy the preview image data into the video filter source buffer, then release it.
|
||||
RGBA8888ForceOpaqueBuffer((const uint32_t *)[imageRep bitmapData], (uint32_t *)[videoFilter srcBufferPtr], (size_t)previewImageSize.width * (size_t)previewImageSize.height);
|
||||
[self updateVideoFilterPreview:VideoFilterTypeID_None];
|
||||
[previewImage release];
|
||||
|
||||
// Load the volume icons.
|
||||
iconVolumeFull = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_VolumeFull_16x16" ofType:@"png"]];
|
||||
iconVolumeTwoThird = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Icon_VolumeTwoThird_16x16" ofType:@"png"]];
|
||||
|
@ -105,8 +275,6 @@
|
|||
[iconVolumeOneThird release];
|
||||
[iconVolumeMute release];
|
||||
[bindings release];
|
||||
[videoFilter release];
|
||||
[bilinearVideoFilter release];
|
||||
[prefViewDict release];
|
||||
|
||||
[super dealloc];
|
||||
|
@ -362,20 +530,34 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (IBAction) setUseBilinear:(id)sender
|
||||
- (IBAction) updateFiltersPreferGPU:(id)sender
|
||||
{
|
||||
const BOOL useBilinear = [[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayView_UseBilinearOutput"];
|
||||
[self updateBilinearPreview:useBilinear];
|
||||
[previewImageView setNeedsDisplay:YES];
|
||||
const BOOL theState = [CocoaDSUtil getIBActionSenderButtonStateBool:sender];
|
||||
[[self previewView] setFiltersPreferGPU:theState];
|
||||
[previewView setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (IBAction) selectVideoFilterType:(id)sender
|
||||
- (IBAction) updateSourceDeposterize:(id)sender
|
||||
{
|
||||
const NSInteger vfType = [CocoaDSUtil getIBActionSenderTag:sender];
|
||||
[[NSUserDefaults standardUserDefaults] setInteger:vfType forKey:@"DisplayView_VideoFilter"];
|
||||
|
||||
[self updateVideoFilterPreview:vfType];
|
||||
[previewImageView setNeedsDisplay:YES];
|
||||
const BOOL theState = [CocoaDSUtil getIBActionSenderButtonStateBool:sender];
|
||||
[[self previewView] setSourceDeposterize:theState];
|
||||
[previewView setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (IBAction) selectOutputFilter:(id)sender
|
||||
{
|
||||
const NSInteger filterID = [CocoaDSUtil getIBActionSenderTag:sender];
|
||||
[[NSUserDefaults standardUserDefaults] setInteger:filterID forKey:@"DisplayView_OutputFilter"];
|
||||
[[self previewView] setOutputFilter:filterID];
|
||||
[previewView setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (IBAction) selectPixelScaler:(id)sender
|
||||
{
|
||||
const NSInteger filterID = [CocoaDSUtil getIBActionSenderTag:sender];
|
||||
[[NSUserDefaults standardUserDefaults] setInteger:filterID forKey:@"DisplayView_VideoFilter"];
|
||||
[[self previewView] setPixelScaler:filterID];
|
||||
[previewView setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (IBAction) updateVolumeIcon:(id)sender
|
||||
|
@ -651,42 +833,6 @@
|
|||
[tempView release];
|
||||
}
|
||||
|
||||
- (void) updateVideoFilterPreview:(const NSInteger)vfType
|
||||
{
|
||||
const BOOL useBilinear = [[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayView_UseBilinearOutput"];
|
||||
|
||||
[videoFilter changeFilter:(VideoFilterTypeID)vfType];
|
||||
const NSUInteger previewWidth = (NSUInteger)[videoFilter destSize].width;
|
||||
const NSUInteger previewHeight = (NSUInteger)[videoFilter destSize].height;
|
||||
|
||||
if (previewWidth <= 64 || previewHeight <= 64)
|
||||
{
|
||||
[videoFilter changeFilter:VideoFilterTypeID_Nearest2X];
|
||||
}
|
||||
|
||||
[videoFilter runFilter];
|
||||
[self updateBilinearPreview:useBilinear];
|
||||
}
|
||||
|
||||
- (void) updateBilinearPreview:(const BOOL)useBilinear
|
||||
{
|
||||
const NSUInteger previewWidth = (NSUInteger)[videoFilter destSize].width;
|
||||
const NSUInteger previewHeight = (NSUInteger)[videoFilter destSize].height;
|
||||
|
||||
if (previewWidth <= 128 || previewHeight <= 128)
|
||||
{
|
||||
[bilinearVideoFilter changeFilter:(useBilinear) ? VideoFilterTypeID_Bilinear : VideoFilterTypeID_Nearest2X];
|
||||
}
|
||||
else
|
||||
{
|
||||
[bilinearVideoFilter changeFilter:VideoFilterTypeID_None];
|
||||
}
|
||||
|
||||
[bilinearVideoFilter setSourceSize:[videoFilter destSize]];
|
||||
memcpy([bilinearVideoFilter srcBufferPtr], [videoFilter dstBufferPtr], previewWidth * previewHeight * sizeof(uint32_t));
|
||||
[bindings setObject:[bilinearVideoFilter image] forKey:@"VideoFilterPreviewImage"];
|
||||
}
|
||||
|
||||
- (void) setupUserDefaults
|
||||
{
|
||||
// Update input preferences.
|
||||
|
@ -709,9 +855,18 @@
|
|||
// Set the default sound volume per user preferences.
|
||||
[self updateVolumeIcon:nil];
|
||||
|
||||
// Set the default video filter per user preferences.
|
||||
const NSInteger vfType = [[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayView_VideoFilter"];
|
||||
[self updateVideoFilterPreview:vfType];
|
||||
// Set the default video settings per user preferences.
|
||||
const BOOL filtersPreferGPU = [[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayView_FiltersPreferGPU"];
|
||||
[[self previewView] setFiltersPreferGPU:filtersPreferGPU];
|
||||
|
||||
const BOOL sourceDeposterize = [[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayView_Deposterize"];
|
||||
[[self previewView] setSourceDeposterize:sourceDeposterize];
|
||||
|
||||
const NSInteger pixelScalerID = [[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayView_VideoFilter"];
|
||||
[[self previewView] setPixelScaler:pixelScalerID];
|
||||
|
||||
const NSInteger outputFilterID = [[NSUserDefaults standardUserDefaults] integerForKey:@"DisplayView_OutputFilter"];
|
||||
[[self previewView] setOutputFilter:outputFilterID];
|
||||
|
||||
// Set up file paths.
|
||||
NSString *arm7BiosImagePath = [[NSUserDefaults standardUserDefaults] stringForKey:@"BIOS_ARM7ImagePath"];
|
||||
|
|
Loading…
Reference in New Issue