summaryrefslogtreecommitdiff
path: root/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp')
-rw-r--r--Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp308
1 files changed, 212 insertions, 96 deletions
diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp
index ee918ee6c0..b0bc682f29 100644
--- a/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp
+++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp
@@ -42,7 +42,7 @@
#include "HW/Memmap.h"
#include "ImageWrite.h"
#include "MemoryUtil.h"
-#include "PixelShaderCache.h"
+#include "ProgramShaderCache.h"
#include "PixelShaderManager.h"
#include "Render.h"
#include "Statistics.h"
@@ -56,6 +56,24 @@
namespace OGL
{
+static SHADER s_ColorMatrixProgram;
+static SHADER s_DepthMatrixProgram;
+static GLuint s_ColorMatrixUniform;
+static GLuint s_DepthMatrixUniform;
+static u32 s_ColorCbufid;
+static u32 s_DepthCbufid;
+
+static u32 s_Textures[8];
+static u32 s_ActiveTexture;
+static u32 s_NextStage;
+
+struct VBOCache {
+ GLuint vbo;
+ GLuint vao;
+ TargetRectangle targetSource;
+};
+static std::map<u64,VBOCache> s_VBO;
+
static u32 s_TempFramebuffer = 0;
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level)
@@ -63,8 +81,11 @@ bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width
int width = std::max(virtual_width >> level, 1);
int height = std::max(virtual_height >> level, 1);
std::vector<u32> data(width * height);
+ glActiveTexture(GL_TEXTURE0+9);
glBindTexture(textarget, tex);
glGetTexImage(textarget, level, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]);
+ glBindTexture(textarget, 0);
+ TextureCache::SetStage();
const GLenum err = GL_REPORT_ERROR();
if (GL_NO_ERROR != err)
@@ -80,6 +101,9 @@ TextureCache::TCacheEntry::~TCacheEntry()
{
if (texture)
{
+ for(int i=0; i<8; i++)
+ if(s_Textures[i] == texture)
+ s_Textures[i] = 0;
glDeleteTextures(1, &texture);
texture = 0;
}
@@ -93,14 +117,17 @@ TextureCache::TCacheEntry::TCacheEntry()
void TextureCache::TCacheEntry::Bind(unsigned int stage)
{
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, texture);
- GL_REPORT_ERRORD();
-
- // TODO: is this already done somewhere else?
- TexMode0 &tm0 = bpmem.tex[stage >> 2].texMode0[stage & 3];
- TexMode1 &tm1 = bpmem.tex[stage >> 2].texMode1[stage & 3];
- SetTextureParameters(tm0, tm1);
+ if (s_Textures[stage] != texture)
+ {
+ if (s_ActiveTexture != stage)
+ {
+ glActiveTexture(GL_TEXTURE0 + stage);
+ s_ActiveTexture = stage;
+ }
+
+ glBindTexture(GL_TEXTURE_2D, texture);
+ s_Textures[stage] = texture;
+ }
}
bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
@@ -129,13 +156,13 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
PanicAlert("Invalid PC texture format %i", pcfmt);
case PC_TEX_FMT_BGRA32:
gl_format = GL_BGRA;
- gl_iformat = 4;
+ gl_iformat = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
break;
case PC_TEX_FMT_RGBA32:
gl_format = GL_RGBA;
- gl_iformat = 4;
+ gl_iformat = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
break;
@@ -177,7 +204,7 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
entry.gl_type = gl_type;
entry.pcfmt = pcfmt;
- entry.bHaveMipMaps = tex_levels != 1;
+ entry.m_tex_levels = tex_levels;
entry.Load(width, height, expanded_width, 0);
@@ -187,19 +214,33 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level)
{
- //glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, texture);
- //GL_REPORT_ERRORD();
+ if (s_ActiveTexture != s_NextStage)
+ {
+ glActiveTexture(GL_TEXTURE0 + s_NextStage);
+ s_ActiveTexture = s_NextStage;
+ }
+
+ if (s_Textures[s_NextStage] != texture)
+ {
+ glBindTexture(GL_TEXTURE_2D, texture);
+ s_Textures[s_NextStage] = texture;
+ }
+
+ // TODO: sloppy, just do this on creation?
+ if (level == 0)
+ {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, m_tex_levels - 1);
+ }
if (pcfmt != PC_TEX_FMT_DXT1)
{
if (expanded_width != width)
- glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
if (expanded_width != width)
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
else
{
@@ -214,31 +255,26 @@ TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(
unsigned int scaled_tex_w, unsigned int scaled_tex_h)
{
TCacheEntry *const entry = new TCacheEntry;
+ glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D, entry->texture);
GL_REPORT_ERRORD();
const GLenum
gl_format = GL_RGBA,
- gl_iformat = 4,
+ gl_iformat = GL_RGBA,
gl_type = GL_UNSIGNED_BYTE;
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ entry->m_tex_levels = 1;
glTexImage2D(GL_TEXTURE_2D, 0, gl_iformat, scaled_tex_w, scaled_tex_h, 0, gl_format, gl_type, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ SetStage();
+
GL_REPORT_ERRORD();
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- if (GL_REPORT_ERROR() != GL_NO_ERROR)
- {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
- GL_REPORT_ERRORD();
- }
-
return entry;
}
@@ -247,8 +283,8 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
const float *colmat)
{
- glBindTexture(GL_TEXTURE_2D, texture);
-
+ g_renderer->ResetAPIState(); // reset any game specific settings
+
// Make sure to resolve anything we need to read from.
const GLuint read_texture = (srcFormat == PIXELFMT_Z24) ?
FramebufferManager::ResolveAndGetDepthTarget(srcRect) :
@@ -259,38 +295,85 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
{
if (s_TempFramebuffer == 0)
- glGenFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer);
+ glGenFramebuffers(1, (GLuint*)&s_TempFramebuffer);
FramebufferManager::SetFramebuffer(s_TempFramebuffer);
// Bind texture to temporary framebuffer
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
GL_REPORT_FBO_ERROR();
GL_REPORT_ERRORD();
-
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
- glActiveTexture(GL_TEXTURE0);
- glEnable(GL_TEXTURE_RECTANGLE_ARB);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, read_texture);
+
+ glActiveTexture(GL_TEXTURE0+9);
+ glBindTexture(GL_TEXTURE_RECTANGLE, read_texture);
glViewport(0, 0, virtual_width, virtual_height);
- PixelShaderCache::SetCurrentShader((srcFormat == PIXELFMT_Z24) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram());
- PixelShaderManager::SetColorMatrix(colmat); // set transformation
+ if(srcFormat == PIXELFMT_Z24) {
+ s_DepthMatrixProgram.Bind();
+ if(s_DepthCbufid != cbufid)
+ glUniform4fv(s_DepthMatrixUniform, 5, colmat);
+ s_DepthCbufid = cbufid;
+ } else {
+ s_ColorMatrixProgram.Bind();
+ if(s_ColorCbufid != cbufid)
+ glUniform4fv(s_ColorMatrixUniform, 7, colmat);
+ s_ColorCbufid = cbufid;
+ }
GL_REPORT_ERRORD();
TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect);
-
- glBegin(GL_QUADS);
- glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.bottom); glVertex2f(-1, 1);
- glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.top ); glVertex2f(-1, -1);
- glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.top ); glVertex2f( 1, -1);
- glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.bottom); glVertex2f( 1, 1);
- glEnd();
+ GL_REPORT_ERRORD();
+
+ // should be unique enough, if not, vbo will "only" be uploaded to much
+ u64 targetSourceHash = u64(targetSource.left)<<48 | u64(targetSource.top)<<32 | u64(targetSource.right)<<16 | u64(targetSource.bottom);
+ std::map<u64, VBOCache>::iterator vbo_it = s_VBO.find(targetSourceHash);
+
+ if(vbo_it == s_VBO.end()) {
+ VBOCache item;
+ item.targetSource.bottom = -1;
+ item.targetSource.top = -1;
+ item.targetSource.left = -1;
+ item.targetSource.right = -1;
+ glGenBuffers(1, &item.vbo);
+ glGenVertexArrays(1, &item.vao);
+
+ glBindBuffer(GL_ARRAY_BUFFER, item.vbo);
+ glBindVertexArray(item.vao);
+
+ glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
+ glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL);
+ glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
+ glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
+
+ vbo_it = s_VBO.insert(std::pair<u64,VBOCache>(targetSourceHash, item)).first;
+ }
+ if(!(vbo_it->second.targetSource == targetSource)) {
+ GLfloat vertices[] = {
+ -1.f, 1.f,
+ (GLfloat)targetSource.left, (GLfloat)targetSource.bottom,
+ -1.f, -1.f,
+ (GLfloat)targetSource.left, (GLfloat)targetSource.top,
+ 1.f, -1.f,
+ (GLfloat)targetSource.right, (GLfloat)targetSource.top,
+ 1.f, 1.f,
+ (GLfloat)targetSource.right, (GLfloat)targetSource.bottom
+ };
+
+ glBindBuffer(GL_ARRAY_BUFFER, vbo_it->second.vbo);
+ glBufferData(GL_ARRAY_BUFFER, 4*4*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
+
+ vbo_it->second.targetSource = targetSource;
+ }
+
+ glBindVertexArray(vbo_it->second.vao);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
GL_REPORT_ERRORD();
// Unbind texture from temporary framebuffer
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
}
if (false == g_ActiveConfig.bCopyEFBToTexture)
@@ -318,7 +401,6 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
FramebufferManager::SetFramebuffer(0);
VertexShaderManager::SetViewportChanged();
- DisableStage(0);
GL_REPORT_ERRORD();
@@ -328,63 +410,97 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
SaveTexture(StringFromFormat("%sefb_frame_%i.tga", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
count++).c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height, 0);
}
+
+ g_renderer->RestoreAPIState();
}
-void TextureCache::TCacheEntry::SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1)
+TextureCache::TextureCache()
{
- const GLint c_MinLinearFilter[8] =
- {
- GL_NEAREST,
- GL_NEAREST_MIPMAP_NEAREST,
- GL_NEAREST_MIPMAP_LINEAR,
- GL_NEAREST,
- GL_LINEAR,
- GL_LINEAR_MIPMAP_NEAREST,
- GL_LINEAR_MIPMAP_LINEAR,
- GL_LINEAR,
- };
- const GLint c_WrapSettings[4] =
- {
- GL_CLAMP_TO_EDGE,
- GL_REPEAT,
- GL_MIRRORED_REPEAT,
- GL_REPEAT,
- };
-
- int filt = newmode.min_filter;
- if (g_ActiveConfig.bForceFiltering && newmode.min_filter < 4)
- filt += 4; // take equivalent forced linear
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c_MinLinearFilter[filt & 7]);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (newmode.mag_filter || g_Config.bForceFiltering) ? GL_LINEAR : GL_NEAREST);
-
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, newmode1.min_lod / 16.f);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, newmode1.max_lod / 16.f);
- glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, (s32)newmode.lod_bias / 32.0f);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, c_WrapSettings[newmode.wrap_s]);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, c_WrapSettings[newmode.wrap_t]);
-
- // TODO: Reset anisotrop when changed to 1
- if (g_Config.iMaxAnisotropy >= 1)
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
- (float)(1 << g_ActiveConfig.iMaxAnisotropy));
+ const char *pColorMatrixProg =
+ "uniform sampler2DRect samp9;\n"
+ "uniform vec4 colmat[7];\n"
+ "in vec2 uv0;\n"
+ "out vec4 ocol0;\n"
+ "\n"
+ "void main(){\n"
+ " vec4 texcol = texture2DRect(samp9, uv0);\n"
+ " texcol = round(texcol * colmat[5]) * colmat[6];\n"
+ " ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];\n"
+ "}\n";
+
+ const char *pDepthMatrixProg =
+ "uniform sampler2DRect samp9;\n"
+ "uniform vec4 colmat[5];\n"
+ "in vec2 uv0;\n"
+ "out vec4 ocol0;\n"
+ "\n"
+ "void main(){\n"
+ " vec4 texcol = texture2DRect(samp9, uv0);\n"
+ " vec4 EncodedDepth = fract((texcol.r * (16777215.0f/16777216.0f)) * vec4(1.0f,256.0f,256.0f*256.0f,1.0f));\n"
+ " texcol = round(EncodedDepth * (16777216.0f/16777215.0f) * vec4(255.0f,255.0f,255.0f,15.0f)) / vec4(255.0f,255.0f,255.0f,15.0f);\n"
+ " ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];"
+ "}\n";
+
+
+ const char *VProgram =
+ "in vec2 rawpos;\n"
+ "in vec2 tex0;\n"
+ "out vec2 uv0;\n"
+ "void main()\n"
+ "{\n"
+ " uv0 = tex0;\n"
+ " gl_Position = vec4(rawpos,0,1);\n"
+ "}\n";
+
+ ProgramShaderCache::CompileShader(s_ColorMatrixProgram, VProgram, pColorMatrixProg);
+ ProgramShaderCache::CompileShader(s_DepthMatrixProgram, VProgram, pDepthMatrixProg);
+
+ s_ColorMatrixUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "colmat");
+ s_DepthMatrixUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "colmat");
+ s_ColorCbufid = -1;
+ s_DepthCbufid = -1;
+
+ s_ActiveTexture = -1;
+ s_NextStage = -1;
+ for(int i=0; i<8; i++)
+ s_Textures[i] = -1;
}
+
TextureCache::~TextureCache()
{
- if (s_TempFramebuffer)
+ s_ColorMatrixProgram.Destroy();
+ s_DepthMatrixProgram.Destroy();
+
+ for(std::map<u64, VBOCache>::iterator it = s_VBO.begin(); it != s_VBO.end(); it++) {
+ glDeleteBuffers(1, &it->second.vbo);
+ glDeleteVertexArrays(1, &it->second.vao);
+ }
+ s_VBO.clear();
+
+ if (s_TempFramebuffer)
{
- glDeleteFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer);
- s_TempFramebuffer = 0;
- }
+ glDeleteFramebuffers(1, (GLuint*)&s_TempFramebuffer);
+ s_TempFramebuffer = 0;
+ }
}
void TextureCache::DisableStage(unsigned int stage)
{
- glActiveTexture(GL_TEXTURE0 + stage);
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_TEXTURE_RECTANGLE_ARB);
}
+void TextureCache::SetStage ()
+{
+ // -1 is the initial value as we don't know which testure should be bound
+ if(s_ActiveTexture != (u32)-1)
+ glActiveTexture(GL_TEXTURE0 + s_ActiveTexture);
+}
+
+void TextureCache::SetNextStage ( unsigned int stage )
+{
+ s_NextStage = stage;
+}
+
+
+
}