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:
rogerman 2015-02-11 12:03:47 +00:00
parent afa4d57545
commit 782447e115
5 changed files with 61435 additions and 60494 deletions

View File

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

View File

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

View File

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

View File

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