doom3quest/Projects/Android/jni/d3es-multithread-master/neo/renderer/framebuffer.cpp
Simon b2b8f43c9d Initial Commit
Builds, runs, no stereo or much else is working, menus work ok though
2020-09-08 23:10:45 +01:00

360 lines
9.3 KiB
C++

/*
Emile Belanger
GPL3
*/
#include "renderer/tr_local.h"
#include "renderer/VertexCache.h"
idCVar r_framebufferFilter( "r_framebufferFilter", "0", CVAR_RENDERER | CVAR_BOOL, "Image filter when using the framebuffer. 0 = Nearest, 1 = Linear" );
static GLuint m_framebuffer = -1;
static GLuint m_depthbuffer;
static GLuint m_stencilbuffer;
static int m_framebuffer_width, m_framebuffer_height;
static GLuint m_framebuffer_texture;
static GLuint m_positionLoc;
static GLuint m_texCoordLoc;
static GLuint m_samplerLoc;
static GLuint r_program;
static int fixNpot(int v)
{
int ret = 1;
while(ret < v)
ret <<= 1;
return ret;
}
#define ALOGE(...) __android_log_print( ANDROID_LOG_ERROR, "FRAMEBUFFER", __VA_ARGS__ )
static const char * GlErrorString( GLenum error )
{
switch ( error )
{
case GL_NO_ERROR: return "GL_NO_ERROR";
case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION";
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
default: return "unknown";
}
}
static void GLCheckErrors( int line )
{
for ( int i = 0; i < 10; i++ )
{
const GLenum error = glGetError();
if ( error == GL_NO_ERROR )
{
break;
}
ALOGE( "GL error on line %d: %s", line, GlErrorString( error ) );
}
}
#define LOG common->Printf
int loadShader(int shaderType, const char * source)
{
int shader = qglCreateShader(shaderType);
if(shader != 0)
{
qglShaderSource(shader, 1, &source, NULL);
qglCompileShader(shader);
GLint length;
qglGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
if(length)
{
char* buffer = new char [ length ];
qglGetShaderInfoLog(shader, length, NULL, buffer);
LOG("shader = %s\n", buffer);
delete [] buffer;
GLint success;
qglGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if(success != GL_TRUE)
{
LOG("ERROR compiling shader\n");
}
}
}
else
{
LOG("FAILED to create shader");
}
return shader;
}
int createProgram(const char * vertexSource, const char * fragmentSource)
{
int vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource);
int pixelShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
int program = glCreateProgram();
if(program != 0)
{
glAttachShader(program, vertexShader);
// checkGlError("glAttachShader");
glAttachShader(program, pixelShader);
// checkGlError("glAttachShader");
glLinkProgram(program);
#define GL_LINK_STATUS 0x8B82
int linkStatus[1];
glGetProgramiv(program, GL_LINK_STATUS, linkStatus);
if(linkStatus[0] != GL_TRUE)
{
LOG("Could not link program: ");
char log[256];
GLsizei size;
glGetProgramInfoLog(program, 256, &size, log);
LOG("Log: %s", log);
//glDeleteProgram(program);
program = 0;
}
}
else
{
LOG("FAILED to create program");
}
LOG("Program linked OK %d", program);
return program;
}
static void createShaders (void)
{
const GLchar *vertSource = \
"attribute vec2 a_texCoord; \n \
attribute vec4 a_position; \n \
varying vec2 v_texCoord; \n \
void main() \n \
{ \n \
gl_Position = a_position; \n \
v_texCoord = a_texCoord; \n \
} \n \
";
const GLchar *fragSource = \
"precision mediump float; \n \
varying vec2 v_texCoord; \n \
uniform sampler2D s_texture; \n \
void main() \n \
{ \n \
gl_FragColor = texture2D( s_texture, v_texCoord ); \n \
//gl_FragColor = vec4( 0.8, 0.5, 0.9, 1.0 ); \n \
} \n \
";
r_program = createProgram(vertSource, fragSource);
glUseProgram(r_program);
// get attrib locations
m_positionLoc = glGetAttribLocation(r_program, "a_position");
m_texCoordLoc = glGetAttribLocation(r_program, "a_texCoord");
m_samplerLoc = glGetUniformLocation(r_program, "s_texture");
if(m_positionLoc == -1)
LOG("Failed to get m_positionLoc");
if(m_texCoordLoc == -1)
LOG("Failed to get m_texCoordLoc");
if(m_samplerLoc == -1)
LOG("Failed to get m_samplerLoc");
glUniform1i(m_samplerLoc, 0);
}
void R_InitFrameBuffer()
{
//LOG("R_InitFrameBuffer Real[%d, %d] -> Framebuffer[%d,%d]", glConfig.vidWidthReal, glConfig.vidHeightReal, glConfig.vidWidth, glConfig.vidHeight);
/* if(glConfig.vidWidthReal == glConfig.vidWidth && glConfig.vidHeightReal == glConfig.vidHeight)
{
LOGI("Not using framebuffer");
return;
}*/
//glConfig.npotAvailable = false;
m_framebuffer_width = glConfig.vidWidth;
m_framebuffer_height = glConfig.vidHeight;
if (!glConfig.npotAvailable)
{
m_framebuffer_width = fixNpot(m_framebuffer_width);
m_framebuffer_height = fixNpot(m_framebuffer_height);
}
LOGI("Framebuffer buffer size = [%d, %d]", m_framebuffer_width, m_framebuffer_height);
// Create texture
glGenTextures(1, &m_framebuffer_texture);
glBindTexture(GL_TEXTURE_2D, m_framebuffer_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_framebuffer_width, m_framebuffer_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
if(r_framebufferFilter.GetInteger() == 0)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
// Create framebuffer
glGenFramebuffers(1, &m_framebuffer);
// Create renderbuffer
glGenRenderbuffers(1, &m_depthbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_depthbuffer);
if(glConfig.depthStencilAvailable)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_framebuffer_width, m_framebuffer_height);
else
{
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, m_framebuffer_width, m_framebuffer_height);
// Need separate Stencil buffer
glGenRenderbuffers(1, &m_stencilbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_stencilbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, m_framebuffer_width, m_framebuffer_height);
}
createShaders();
}
void R_FrameBufferStart()
{
if(m_framebuffer == -1)
return;
// Render to framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
GLCheckErrors(__LINE__);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
GLCheckErrors(__LINE__);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_framebuffer_texture, 0);
GLCheckErrors(__LINE__);
// Attach combined depth+stencil
if(glConfig.depthStencilAvailable)
{
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthbuffer);
}
else
{
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilbuffer);
}
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(result != GL_FRAMEBUFFER_COMPLETE)
{
common->Error( "Error binding Framebuffer: %d\n", result );
}
}
void R_FrameBufferEnd()
{
if(m_framebuffer == -1)
return;
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
//glBindRenderbuffer(GL_RENDERBUFFER, 0);
// Bind the texture
glBindTexture(GL_TEXTURE_2D, m_framebuffer_texture);
GLCheckErrors(__LINE__);
// Unbind any VBOs
vertexCache.UnbindIndex();
vertexCache.UnbindVertex();
glUseProgram(r_program);
GLCheckErrors(__LINE__);
GLfloat vert[] =
{
-1.f, -1.f, 0.0f, // 0. left-bottom
-1.f, 1.f, 0.0f, // 1. left-top
1.f, 1.f, 0.0f, // 2. right-top
1.f, -1.f, 0.0f, // 3. right-bottom
};
GLfloat smax = 1;
GLfloat tmax = 1;
if (!glConfig.npotAvailable)
{
smax = (float)glConfig.vidWidth / (float)m_framebuffer_width;
tmax = (float)glConfig.vidHeight / (float)m_framebuffer_height;
}
GLfloat texVert[] =
{
0.0f, 0.0f, // TexCoord 0
0.0f, tmax, // TexCoord 1
smax, tmax, // TexCoord 2
smax, 0.0f // TexCoord 3
};
GLCheckErrors(__LINE__);
glVertexAttribPointer(m_positionLoc, 3, GL_FLOAT,
false,
3 * 4,
vert);
GLCheckErrors(__LINE__);
glVertexAttribPointer(m_texCoordLoc, 2, GL_FLOAT,
false,
2 * 4,
texVert);
GLCheckErrors(__LINE__);
glEnableVertexAttribArray(m_positionLoc);
GLCheckErrors(__LINE__);
glEnableVertexAttribArray(m_texCoordLoc);
GLCheckErrors(__LINE__);
// Set the sampler texture unit to 0
glUniform1i(m_samplerLoc, 0);
GLCheckErrors(__LINE__);
glViewport (0, 0, glConfig.vidWidth, glConfig.vidHeight );
//glViewport (0, 0, glConfig.vidWidthReal, glConfig.vidHeightReal );
GLCheckErrors(__LINE__);
glDisable(GL_BLEND);
GLCheckErrors(__LINE__);
glDisable(GL_SCISSOR_TEST);
GLCheckErrors(__LINE__);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
GLCheckErrors(__LINE__);
}