diff --git a/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj b/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj index bb2a3d56d0..4bc60b2823 100644 --- a/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj +++ b/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj @@ -1,7 +1,7 @@ + + + + diff --git a/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp b/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp index 7e3c937b75..179bc660be 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp @@ -460,7 +460,10 @@ void BPWritten(int addr, int changes, int newval) // EFB to XFB if(g_Config.bUseXFB) { - XFB_Write(Memory_GetPtr(bpmem.copyTexDest<<5), multirc, (bpmem.copyMipMapStrideChannels << 4), bpmem.copyTexSrcWH.y + 1, bpmem.dispcopyyscale / 256.0f); + // the number of lines copied is determined by the y scale * source efb height + float yScale = bpmem.dispcopyyscale / 256.0f; + float xfbLines = bpmem.copyTexSrcWH.y + 1 * yScale; + XFB_Write(Memory_GetPtr(bpmem.copyTexDest<<5), multirc, (bpmem.copyMipMapStrideChannels << 4), xfbLines); } else { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp new file mode 100644 index 0000000000..f5c864f012 --- /dev/null +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp @@ -0,0 +1,224 @@ +// Copyright (C) 2003-2008 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "TextureConverter.h" +#include "PixelShaderManager.h" +#include "VertexShaderManager.h" +#include "Globals.h" +#include "GLUtil.h" +#include "Render.h" + +namespace TextureConverter +{ + +static GLuint s_frameBuffer = 0; +static GLuint s_srcTexture = 0; // for decoding from RAM +static GLuint s_dstRenderBuffer = 0; // for encoding to RAM + +const int renderBufferWidth = 1024; +const int renderBufferHeight = 1024; + +static FRAGMENTSHADER s_rgbToYuyvProgram; +static FRAGMENTSHADER s_yuyvToRgbProgram; + +void CreateRgbToYuyvProgram() +{ + // output is BGRA because that is slightly faster than RGBA + char *FProgram = + "uniform samplerRECT samp0 : register(s0);\n" + "void main(\n" + " out float4 ocol0 : COLOR0,\n" + " in float2 uv0 : TEXCOORD0)\n" + "{\n" + " float2 uv1 = float2(uv0.x + 1.0f, uv0.y);\n" + " float3 c0 = texRECT(samp0, uv0).rgb;\n" + " float3 c1 = texRECT(samp0, uv1).rgb;\n" + + " float y0 = (0.257f * c0.r) + (0.504f * c0.g) + (0.098f * c0.b) + 0.0625f;\n" + " float u0 =-(0.148f * c0.r) - (0.291f * c0.g) + (0.439f * c0.b) + 0.5f;\n" + " float y1 = (0.257f * c1.r) + (0.504f * c1.g) + (0.098f * c1.b) + 0.0625f;\n" + " float v1 = (0.439f * c1.r) - (0.368f * c1.g) - (0.071f * c1.b) + 0.5f;\n" + + " ocol0 = float4(y1, u0, y0, v1);\n" + "}\n"; + + if (!PixelShaderMngr::CompilePixelShader(s_rgbToYuyvProgram, FProgram)) { + ERROR_LOG("Failed to create RGB to YUYV fragment program\n"); + } +} + +void CreateYuyvToRgbProgram() +{ + char *FProgram = + "uniform samplerRECT samp0 : register(s0);\n" + "void main(\n" + " out float4 ocol0 : COLOR0,\n" + " in float2 uv0 : TEXCOORD0)\n" + "{\n" + " float4 c0 = texRECT(samp0, uv0).rgba;\n" + + " float f = step(0.5, frac(uv0.x));\n" + " float y = lerp(c0.b, c0.r, f);\n" + " float yComp = 1.164f * (y - 0.0625f);\n" + " float uComp = c0.g - 0.5f;\n" + " float vComp = c0.a - 0.5f;\n" + + " ocol0 = float4(yComp + (1.596f * vComp),\n" + " yComp - (0.813f * vComp) - (0.391f * uComp),\n" + " yComp + (2.018f * uComp),\n" + " 1.0f);\n" + "}\n"; + + if (!PixelShaderMngr::CompilePixelShader(s_yuyvToRgbProgram, FProgram)) { + ERROR_LOG("Failed to create YUYV to RGB fragment program\n"); + } +} + +void Init() +{ + glGenFramebuffersEXT( 1, &s_frameBuffer); + + glGenRenderbuffersEXT(1, &s_dstRenderBuffer); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, renderBufferWidth, renderBufferHeight); + + glGenTextures(1, &s_srcTexture); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_srcTexture); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + CreateRgbToYuyvProgram(); + CreateYuyvToRgbProgram(); +} + +void Shutdown() +{ + glDeleteTextures(1, &s_srcTexture); + + glDeleteRenderbuffersEXT(1, &s_dstRenderBuffer); + + glDeleteFramebuffersEXT(1, &s_frameBuffer); +} + +void EncodeToRam(GLuint srcTexture, const TRectangle& sourceRc, + u8* destAddr, int dstWidth, int dstHeight) +{ + Renderer::SetRenderMode(Renderer::RM_Normal); + + Renderer::ResetGLState(); + + float dstFormatFactor = 0.5f; + float dstFmtWidth = dstWidth * dstFormatFactor; + + // switch to texture converter frame buffer + // attach render buffer as color destination + Renderer::SetFramebuffer(s_frameBuffer); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_dstRenderBuffer); + GL_REPORT_ERRORD(); + + // set source texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, srcTexture); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + TextureMngr::EnableTexRECT(0); + for (int i = 1; i < 8; ++i) + TextureMngr::DisableStage(i); + GL_REPORT_ERRORD(); + + glViewport(0, 0, dstFmtWidth, dstHeight); + + glEnable(GL_FRAGMENT_PROGRAM_ARB); + glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, s_rgbToYuyvProgram.glprogid); + + glBegin(GL_QUADS); + glTexCoord2f(sourceRc.left, sourceRc.top); glVertex2f(-1,-1); + glTexCoord2f(sourceRc.left, sourceRc.bottom); glVertex2f(-1,1); + glTexCoord2f(sourceRc.right, sourceRc.bottom); glVertex2f(1,1); + glTexCoord2f(sourceRc.right, sourceRc.top); glVertex2f(1,-1); + glEnd(); + GL_REPORT_ERRORD(); + + // TODO: this is real slow. try using a pixel buffer object. + glReadPixels(0, 0, dstFmtWidth, dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr); + GL_REPORT_ERRORD(); + + Renderer::SetFramebuffer(0); + Renderer::RestoreGLState(); + VertexShaderMngr::SetViewportChanged(); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + TextureMngr::DisableStage(0); + + Renderer::RestoreGLState(); + GL_REPORT_ERRORD(); +} + +void DecodeToTexture(u8* srcAddr, int srcWidth, int srcHeight, GLuint destTexture) +{ + Renderer::SetRenderMode(Renderer::RM_Normal); + + Renderer::ResetGLState(); + + float srcFormatFactor = 0.5f; + float srcFmtWidth = srcWidth * srcFormatFactor; + + // swich to texture converter frame buffer + // attach destTexture as color destination + Renderer::SetFramebuffer(s_frameBuffer); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, destTexture); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, destTexture, 0); + + // activate source texture + // set srcAddr as data for source texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_srcTexture); + + // TODO: this is slow. try using a pixel buffer object. + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, srcFmtWidth, srcHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr); + + TextureMngr::EnableTexRECT(0); + for (int i = 1; i < 8; ++i) + TextureMngr::DisableStage(i); + + glViewport(0, 0, srcWidth, srcHeight); + + glEnable(GL_FRAGMENT_PROGRAM_ARB); + glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, s_yuyvToRgbProgram.glprogid); + + GL_REPORT_ERRORD(); + + glBegin(GL_QUADS); + glTexCoord2f(srcFmtWidth, srcHeight); glVertex2f(1,-1); + glTexCoord2f(srcFmtWidth, 0); glVertex2f(1,1); + glTexCoord2f(0, 0); glVertex2f(-1,1); + glTexCoord2f(0, srcHeight); glVertex2f(-1,-1); + glEnd(); + + // reset state + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + TextureMngr::DisableStage(0); + + VertexShaderMngr::SetViewportChanged(); + + Renderer::RestoreGLState(); + GL_REPORT_ERRORD(); +} + +} \ No newline at end of file diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.h b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.h new file mode 100644 index 0000000000..c3c56089cf --- /dev/null +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.h @@ -0,0 +1,38 @@ +// Copyright (C) 2003-2008 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _TEXTURECONVERTER_H +#define _TEXTURECONVERTER_H + +#include "TextureMngr.h" + +// Converts textures between formats +// TODO: support multiple texture formats +namespace TextureConverter +{ + +void Init(); +void Shutdown(); + +void EncodeToRam(GLuint srcTexture, const TRectangle& sourceRc, + u8* destAddr, int dstWidth, int dstHeight); + +void DecodeToTexture(u8* srcAddr, int srcWidth, int srcHeight, GLuint destTexture); + +} + +#endif \ No newline at end of file diff --git a/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp b/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp index 8f5c8af21f..3f1011ee3f 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp @@ -25,6 +25,9 @@ #include "TextureMngr.h" #include "VertexShaderManager.h" #include "XFBConvert.h" +#include "TextureConverter.h" + +#define XFB_USE_SHADERS 1 enum { XFB_WIDTH = 640, @@ -33,6 +36,69 @@ enum { // TODO: figure out what to do with PAL }; + +#if XFB_USE_SHADERS + +static GLuint xfb_decoded_texture; + +void XFB_Init() +{ + glGenTextures(1, &xfb_decoded_texture); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfb_decoded_texture); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_BUF_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); +} + +void XFB_Shutdown() +{ + glDeleteTextures(1, &xfb_decoded_texture); +} + + +void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt) +{ + TRectangle renderSrcRc; + renderSrcRc.left = sourceRc.left; + renderSrcRc.right = sourceRc.right; + renderSrcRc.top = nBackbufferHeight - sourceRc.top; + renderSrcRc.bottom = nBackbufferHeight - sourceRc.bottom; + TextureConverter::EncodeToRam(Renderer::GetRenderTarget(), renderSrcRc, xfb_in_ram, dstWd, dstHt); +} + +void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset) +{ + TextureConverter::DecodeToTexture(xfb_in_ram, width, height, xfb_decoded_texture); + + OpenGL_Update(); // just updates the render window position and the backbuffer size + + Renderer::ResetGLState(); + + TextureMngr::EnableTexRECT(0); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfb_decoded_texture); + + glViewport(nXoff, nYoff, nBackbufferWidth, nBackbufferHeight); + GL_REPORT_ERRORD(); + + glBegin(GL_QUADS); + glTexCoord2f(width, 0 - yOffset); glVertex2f(1,-1); + glTexCoord2f(width, height - yOffset); glVertex2f(1,1); + glTexCoord2f(0, height - yOffset); glVertex2f(-1,1); + glTexCoord2f(0, 0 - yOffset); glVertex2f(-1,-1); + glEnd(); + + TextureMngr::DisableStage(0); + + Renderer::SwapBuffers(); + + Renderer::RestoreGLState(); + GL_REPORT_ERRORD(); +} + +#else + static GLuint xfb_texture; static u8 *xfb_buffer = 0; static u8 *efb_buffer = 0; @@ -70,7 +136,7 @@ void XFB_Shutdown() } -void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt, float yScale) +void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt) { Renderer::SetRenderMode(Renderer::RM_Normal); @@ -91,12 +157,10 @@ void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt, TextureMngr::DisableStage(i); GL_REPORT_ERRORD(); - float scaledTextureY = nBackbufferHeight - (nBackbufferHeight / yScale); - glBegin(GL_QUADS); glTexCoord2f(0, nBackbufferHeight); glVertex2f(-1,-1); - glTexCoord2f(0, scaledTextureY); glVertex2f(-1,1); - glTexCoord2f(nBackbufferWidth, scaledTextureY); glVertex2f(1,1); + glTexCoord2f(0, 0); glVertex2f(-1,1); + glTexCoord2f(nBackbufferWidth, 0); glVertex2f(1,1); glTexCoord2f(nBackbufferWidth, nBackbufferHeight); glVertex2f(1,-1); glEnd(); GL_REPORT_ERRORD(); @@ -159,3 +223,5 @@ void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset) Renderer::RestoreGLState(); GL_REPORT_ERRORD(); } + +#endif \ No newline at end of file diff --git a/Source/Plugins/Plugin_VideoOGL/Src/XFB.h b/Source/Plugins/Plugin_VideoOGL/Src/XFB.h index 29683897f8..4a68334fb2 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/XFB.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/XFB.h @@ -23,7 +23,7 @@ void XFB_Init(); // write the EFB to the XFB -void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt, float yScale); +void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt); // draw the XFB to the screen void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index a26d078151..7e91026300 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -45,6 +45,7 @@ #include "VertexShaderManager.h" #include "XFB.h" #include "XFBConvert.h" +#include "TextureConverter.h" #include "VideoState.h" #if !defined(OSX64) @@ -238,10 +239,12 @@ void Video_Prepare(void) PixelShaderMngr::Init(); GL_REPORT_ERRORD(); VertexLoaderManager::Init(); + TextureConverter::Init(); } void Video_Shutdown(void) { + TextureConverter::Shutdown(); VertexLoaderManager::Shutdown(); VertexShaderMngr::Shutdown(); PixelShaderMngr::Shutdown(); @@ -320,4 +323,4 @@ void Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset) void Video_AddMessage(const char* pstr, u32 milliseconds) { Renderer::AddMessage(pstr,milliseconds); -} +} \ No newline at end of file