dolphin/Source/Plugins/Plugin_VideoSoftware/Src/SWRenderer.cpp

282 lines
8.3 KiB
C++
Raw Normal View History

// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "Common.h"
#include <math.h>
#include "Core.h"
#include "../../Plugin_VideoOGL/Src/GLUtil.h"
#include "RasterFont.h"
#include "SWRenderer.h"
#include "SWStatistics.h"
#include "SWCommandProcessor.h"
#include "OnScreenDisplay.h"
static GLuint s_RenderTarget = 0;
static GLint attr_pos = -1, attr_tex = -1;
static GLint uni_tex = -1;
static GLuint program;
static u8 s_xfbColorTexture[2][EFB_WIDTH*EFB_HEIGHT*4];
static int s_currentColorTexture = 0;
// Rasterfont isn't compatible with GLES
// degasus: I think it does, but I can't test it
#ifndef USE_GLES
RasterFont* s_pfont = NULL;
#endif
void SWRenderer::Init()
{
GLInterface->SetBackBufferDimensions(EFB_WIDTH, EFB_HEIGHT);
}
void SWRenderer::Shutdown()
{
glDeleteProgram(program);
2012-12-26 16:33:45 +00:00
glDeleteTextures(1, &s_RenderTarget);
#ifndef USE_GLES
delete s_pfont;
s_pfont = 0;
#endif
}
void CreateShaders()
{
static const char *fragShaderText =
"varying " PREC " vec2 TexCoordOut;\n"
"uniform sampler2D Texture;\n"
"void main() {\n"
" " PREC " vec4 tmpcolor;\n"
" tmpcolor = texture2D(Texture, TexCoordOut);\n"
" gl_FragColor = tmpcolor;\n"
"}\n";
static const char *vertShaderText =
"attribute vec4 pos;\n"
"attribute vec2 TexCoordIn;\n "
"varying vec2 TexCoordOut;\n "
"void main() {\n"
" gl_Position = pos;\n"
" TexCoordOut = TexCoordIn;\n"
"}\n";
program = OpenGL_CompileProgram(vertShaderText, fragShaderText);
glUseProgram(program);
uni_tex = glGetUniformLocation(program, "Texture");
attr_pos = glGetAttribLocation(program, "pos");
attr_tex = glGetAttribLocation(program, "TexCoordIn");
}
void SWRenderer::Prepare()
{
memset(s_xfbColorTexture, 0, sizeof(s_xfbColorTexture));
s_currentColorTexture = 0;
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
2012-12-26 16:33:45 +00:00
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
glGenTextures(1, &s_RenderTarget);
CreateShaders();
2012-12-26 18:54:58 +00:00
// TODO: Enable for GLES once RasterFont supports GLES
#ifndef USE_GLES
s_pfont = new RasterFont();
glEnable(GL_TEXTURE_2D);
#endif
GL_REPORT_ERRORD();
}
void SWRenderer::RenderText(const char* pstr, int left, int top, u32 color)
{
#ifndef USE_GLES
int nBackbufferWidth = (int)GLInterface->GetBackBufferWidth();
int nBackbufferHeight = (int)GLInterface->GetBackBufferHeight();
glColor4f(((color>>16) & 0xff)/255.0f, ((color>> 8) & 0xff)/255.0f,
((color>> 0) & 0xff)/255.0f, ((color>>24) & 0xFF)/255.0f);
s_pfont->printMultilineText(pstr,
left * 2.0f / (float)nBackbufferWidth - 1,
1 - top * 2.0f / (float)nBackbufferHeight,
0, nBackbufferWidth, nBackbufferHeight);
#endif
}
void SWRenderer::DrawDebugText()
{
2012-12-26 16:33:45 +00:00
char debugtext_buffer[8192];
char *p = debugtext_buffer;
p[0] = 0;
if (g_SWVideoConfig.bShowStats)
{
p+=sprintf(p,"Objects: %i\n",swstats.thisFrame.numDrawnObjects);
p+=sprintf(p,"Primitives: %i\n",swstats.thisFrame.numPrimatives);
p+=sprintf(p,"Vertices Loaded: %i\n",swstats.thisFrame.numVerticesLoaded);
p+=sprintf(p,"Triangles Input: %i\n",swstats.thisFrame.numTrianglesIn);
p+=sprintf(p,"Triangles Rejected: %i\n",swstats.thisFrame.numTrianglesRejected);
p+=sprintf(p,"Triangles Culled: %i\n",swstats.thisFrame.numTrianglesCulled);
p+=sprintf(p,"Triangles Clipped: %i\n",swstats.thisFrame.numTrianglesClipped);
p+=sprintf(p,"Triangles Drawn: %i\n",swstats.thisFrame.numTrianglesDrawn);
p+=sprintf(p,"Rasterized Pix: %i\n",swstats.thisFrame.rasterizedPixels);
p+=sprintf(p,"TEV Pix In: %i\n",swstats.thisFrame.tevPixelsIn);
p+=sprintf(p,"TEV Pix Out: %i\n",swstats.thisFrame.tevPixelsOut);
}
// Render a shadow, and then the text.
SWRenderer::RenderText(debugtext_buffer, 21, 21, 0xDD000000);
SWRenderer::RenderText(debugtext_buffer, 20, 20, 0xFFFFFF00);
}
#ifdef ANDROID
// XXX: This /really/ shouldn't be here
// But for now, we don't have a generic way for all backends to draw the buttons on screen.
// Once that is implemented, we can remove this
void DrawButton(GLuint tex, float *coords)
{
//Texture rectangle uses pixel coordinates
2013-03-20 02:53:09 +00:00
#ifndef USE_GLES
GLfloat u_max = (GLfloat)width;
GLfloat v_max = (GLfloat)height;
static const GLfloat texverts[4][2] = {
{0, v_max},
{0, 0},
{u_max, 0},
{u_max, v_max}
};
2013-03-20 02:53:09 +00:00
#else
static const GLfloat texverts[4][2] = {
{0, 1},
{0, 0},
{1, 0},
{1, 1}
};
2013-03-20 02:53:09 +00:00
#endif
glBindTexture(TEX2D, tex);
glVertexAttribPointer(attr_pos, 2, GL_FLOAT, GL_FALSE, 0, coords);
glVertexAttribPointer(attr_tex, 2, GL_FLOAT, GL_FALSE, 0, texverts);
glEnableVertexAttribArray(attr_pos);
glEnableVertexAttribArray(attr_tex);
glActiveTexture(GL_TEXTURE0);
glUniform1i(uni_tex, 0);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableVertexAttribArray(attr_pos);
glDisableVertexAttribArray(attr_tex);
glBindTexture(TEX2D, 0);
2013-03-20 02:53:09 +00:00
}
#endif
void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidth, u32 fbHeight)
{
u32 offset = 0;
u8 *TexturePointer = s_xfbColorTexture[!s_currentColorTexture];
for (u16 y = 0; y < fbHeight; y++)
{
for (u16 x = 0; x < fbWidth; x+=2)
{
// We do this one color sample (aka 2 RGB pixles) at a time
int Y1 = xfb[x].Y - 16;
int Y2 = xfb[x+1].Y - 16;
int U = int(xfb[x].UV) - 128;
int V = int(xfb[x+1].UV) - 128;
// We do the inverse BT.601 conversion for YCbCr to RGB
// http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion
TexturePointer[offset++] = min(255.0f, max(0.0f, 1.164f * Y1 + 1.596f * V));
TexturePointer[offset++] = min(255.0f, max(0.0f, 1.164f * Y1 - 0.392f * U - 0.813f * V));
TexturePointer[offset++] = min(255.0f, max(0.0f, 1.164f * Y1 + 2.017f * U ));
TexturePointer[offset++] = 255;
TexturePointer[offset++] = min(255.0f, max(0.0f, 1.164f * Y2 + 1.596f * V));
TexturePointer[offset++] = min(255.0f, max(0.0f, 1.164f * Y2 - 0.392f * U - 0.813f * V));
TexturePointer[offset++] = min(255.0f, max(0.0f, 1.164f * Y2 + 2.017f * U ));
TexturePointer[offset++] = 255;
}
xfb += fbWidth;
}
s_currentColorTexture = !s_currentColorTexture;
}
// Called on the GPU thread
void SWRenderer::Swap(u32 fbWidth, u32 fbHeight)
{
GLInterface->Update(); // just updates the render window position and the backbuffer size
if (!g_SWVideoConfig.bHwRasterizer)
SWRenderer::DrawTexture(s_xfbColorTexture[s_currentColorTexture], fbWidth, fbHeight);
swstats.frameCount++;
SWRenderer::SwapBuffer();
Core::Callback_VideoCopiedToXFB(true); // FIXME: should this function be called FrameRendered?
}
void SWRenderer::DrawTexture(u8 *texture, int width, int height)
{
// FIXME: This should add black bars when the game has set the VI to render less than the full xfb.
2012-12-26 16:33:45 +00:00
GLsizei glWidth = (GLsizei)GLInterface->GetBackBufferWidth();
GLsizei glHeight = (GLsizei)GLInterface->GetBackBufferHeight();
// Update GLViewPort
glViewport(0, 0, glWidth, glHeight);
2012-12-26 16:33:45 +00:00
glScissor(0, 0, glWidth, glHeight);
glBindTexture(GL_TEXTURE_2D, s_RenderTarget);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glUseProgram(program);
static const GLfloat verts[4][2] = {
{ -1, -1}, // Left top
{ -1, 1}, // left bottom
{ 1, 1}, // right bottom
{ 1, -1} // right top
};
static const GLfloat texverts[4][2] = {
{0, 1},
{0, 0},
{1, 0},
{1, 1}
};
glVertexAttribPointer(attr_pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
glVertexAttribPointer(attr_tex, 2, GL_FLOAT, GL_FALSE, 0, texverts);
2012-12-26 16:33:45 +00:00
glEnableVertexAttribArray(attr_pos);
glEnableVertexAttribArray(attr_tex);
glUniform1i(uni_tex, 0);
glActiveTexture(GL_TEXTURE0);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
2012-12-26 16:33:45 +00:00
glDisableVertexAttribArray(attr_pos);
glDisableVertexAttribArray(attr_tex);
glBindTexture(GL_TEXTURE_2D, 0);
GL_REPORT_ERRORD();
}
void SWRenderer::SwapBuffer()
{
// Do our OSD callbacks
OSD::DoCallbacks(OSD::OSD_ONFRAME);
2012-12-26 16:33:45 +00:00
DrawDebugText();
2012-12-26 16:33:45 +00:00
glFlush();
2012-12-26 06:34:09 +00:00
GLInterface->Swap();
swstats.ResetFrame();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GL_REPORT_ERRORD();
}