mirror of
https://github.com/libretro/ppsspp.git
synced 2024-12-13 11:38:34 +00:00
Finish the shader manager (almost)
This commit is contained in:
parent
60a966c5ec
commit
9340260802
@ -576,17 +576,11 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo
|
||||
|
||||
// This is a bit of a hack as the render buffer isn't always that size
|
||||
// We always scissor on non-buffered so that clears don't spill outside the frame.
|
||||
if (useBufferedRendering && scissorX1 == 0 && scissorY1 == 0
|
||||
&& scissorX2 >= (int)gstate_c.curRTWidth
|
||||
&& scissorY2 >= (int)gstate_c.curRTHeight) {
|
||||
out.scissorEnable = false;
|
||||
} else {
|
||||
out.scissorEnable = true;
|
||||
out.scissorX = renderX + displayOffsetX + scissorX1 * renderWidthFactor;
|
||||
out.scissorY = renderY + displayOffsetY + scissorY1 * renderHeightFactor;
|
||||
out.scissorW = (scissorX2 - scissorX1) * renderWidthFactor;
|
||||
out.scissorH = (scissorY2 - scissorY1) * renderHeightFactor;
|
||||
}
|
||||
out.scissorEnable = true;
|
||||
out.scissorX = renderX + displayOffsetX + scissorX1 * renderWidthFactor;
|
||||
out.scissorY = renderY + displayOffsetY + scissorY1 * renderHeightFactor;
|
||||
out.scissorW = (scissorX2 - scissorX1) * renderWidthFactor;
|
||||
out.scissorH = (scissorY2 - scissorY1) * renderHeightFactor;
|
||||
|
||||
int curRTWidth = gstate_c.curRTWidth;
|
||||
int curRTHeight = gstate_c.curRTHeight;
|
||||
|
@ -115,7 +115,7 @@ enum {
|
||||
|
||||
enum { VAI_KILL_AGE = 120, VAI_UNRELIABLE_KILL_AGE = 240, VAI_UNRELIABLE_KILL_MAX = 4 };
|
||||
|
||||
DrawEngineGLES::DrawEngineGLES() : vai_(256) {
|
||||
DrawEngineGLES::DrawEngineGLES(Draw::DrawContext *draw) : vai_(256), draw_(draw) {
|
||||
|
||||
decOptions_.expandAllWeightsToFloat = false;
|
||||
decOptions_.expand8BitNormalsToFloat = false;
|
||||
|
@ -101,7 +101,7 @@ public:
|
||||
// Handles transform, lighting and drawing.
|
||||
class DrawEngineGLES : public DrawEngineCommon {
|
||||
public:
|
||||
DrawEngineGLES();
|
||||
DrawEngineGLES(Draw::DrawContext *draw);
|
||||
virtual ~DrawEngineGLES();
|
||||
|
||||
void SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead);
|
||||
@ -189,6 +189,7 @@ private:
|
||||
TextureCacheGLES *textureCache_ = nullptr;
|
||||
FramebufferManagerGLES *framebufferManager_ = nullptr;
|
||||
FragmentTestCacheGLES *fragmentTestCache_ = nullptr;
|
||||
Draw::DrawContext *draw_;
|
||||
|
||||
int bufferDecimationCounter_ = 0;
|
||||
|
||||
|
@ -79,11 +79,13 @@ static const GLESCommandTableEntry commandTable[] = {
|
||||
GPU_GLES::CommandInfo GPU_GLES::cmdInfo_[256];
|
||||
|
||||
GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
|
||||
: GPUCommon(gfxCtx, draw) {
|
||||
: GPUCommon(gfxCtx, draw), drawEngine_(draw) {
|
||||
UpdateVsyncInterval(true);
|
||||
CheckGPUFeatures();
|
||||
|
||||
shaderManagerGL_ = new ShaderManagerGLES();
|
||||
GLRenderManager *render = (GLRenderManager *)draw->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
|
||||
shaderManagerGL_ = new ShaderManagerGLES(render);
|
||||
framebufferManagerGL_ = new FramebufferManagerGLES(draw);
|
||||
framebufferManager_ = framebufferManagerGL_;
|
||||
textureCacheGL_ = new TextureCacheGLES(draw);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/timeutil.h"
|
||||
#include "gfx/gl_debug_log.h"
|
||||
#include "thin3d/GLRenderManager.h"
|
||||
#include "i18n/i18n.h"
|
||||
#include "math/math_util.h"
|
||||
#include "math/lin/matrix4x4.h"
|
||||
@ -43,8 +44,8 @@
|
||||
#include "GPU/GLES/DrawEngineGLES.h"
|
||||
#include "FramebufferManagerGLES.h"
|
||||
|
||||
Shader::Shader(const ShaderID &id, const char *code, uint32_t glShaderType, bool useHWTransform, uint32_t attrMask, uint64_t uniformMask)
|
||||
: failed_(false), useHWTransform_(useHWTransform), attrMask_(attrMask), uniformMask_(uniformMask) {
|
||||
Shader::Shader(GLRenderManager *render, const char *code, uint32_t glShaderType, bool useHWTransform, uint32_t attrMask, uint64_t uniformMask)
|
||||
: render_(render), failed_(false), useHWTransform_(useHWTransform), attrMask_(attrMask), uniformMask_(uniformMask) {
|
||||
PROFILE_THIS_SCOPE("shadercomp");
|
||||
isFragment_ = glShaderType == GL_FRAGMENT_SHADER;
|
||||
source_ = code;
|
||||
@ -55,218 +56,131 @@ Shader::Shader(const ShaderID &id, const char *code, uint32_t glShaderType, bool
|
||||
printf("%s\n", code);
|
||||
#endif
|
||||
#endif
|
||||
shader = glCreateShader(glShaderType);
|
||||
glShaderSource(shader, 1, &code, 0);
|
||||
glCompileShader(shader);
|
||||
GLint success = 0;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
#define MAX_INFO_LOG_SIZE 2048
|
||||
GLchar infoLog[MAX_INFO_LOG_SIZE];
|
||||
GLsizei len;
|
||||
glGetShaderInfoLog(shader, MAX_INFO_LOG_SIZE, &len, infoLog);
|
||||
infoLog[len] = '\0';
|
||||
#ifdef __ANDROID__
|
||||
ELOG("Error in shader compilation! %s\n", infoLog);
|
||||
ELOG("Shader source:\n%s\n", (const char *)code);
|
||||
#endif
|
||||
|
||||
std::string desc = GetShaderString(SHADER_STRING_SHORT_DESC, id);
|
||||
ERROR_LOG(G3D, "Error in shader compilation for: %s", desc.c_str());
|
||||
ERROR_LOG(G3D, "Info log: %s", infoLog);
|
||||
ERROR_LOG(G3D, "Shader source:\n%s\n", (const char *)code);
|
||||
Reporting::ReportMessage("Error in shader compilation: info: %s\n%s\n%s", infoLog, desc.c_str(), (const char *)code);
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugStringUTF8(infoLog);
|
||||
#endif
|
||||
failed_ = true;
|
||||
shader = 0;
|
||||
} else {
|
||||
DEBUG_LOG(G3D, "Compiled shader:\n%s\n", (const char *)code);
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
shader = render->CreateShader(glShaderType, source_);
|
||||
}
|
||||
|
||||
Shader::~Shader() {
|
||||
if (shader)
|
||||
glDeleteShader(shader);
|
||||
render_->DeleteShader(shader);
|
||||
}
|
||||
|
||||
LinkedShader::LinkedShader(VShaderID VSID, Shader *vs, FShaderID FSID, Shader *fs, bool useHWTransform, bool preloading)
|
||||
: useHWTransform_(useHWTransform) {
|
||||
LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, FShaderID FSID, Shader *fs, bool useHWTransform, bool preloading)
|
||||
: render_(render), useHWTransform_(useHWTransform) {
|
||||
PROFILE_THIS_SCOPE("shaderlink");
|
||||
|
||||
program = glCreateProgram();
|
||||
vs_ = vs;
|
||||
glAttachShader(program, vs->shader);
|
||||
glAttachShader(program, fs->shader);
|
||||
|
||||
// Bind attribute locations to fixed locations so that they're
|
||||
// the same in all shaders. We use this later to minimize the calls to
|
||||
// glEnableVertexAttribArray and glDisableVertexAttribArray.
|
||||
glBindAttribLocation(program, ATTR_POSITION, "position");
|
||||
glBindAttribLocation(program, ATTR_TEXCOORD, "texcoord");
|
||||
glBindAttribLocation(program, ATTR_NORMAL, "normal");
|
||||
glBindAttribLocation(program, ATTR_W1, "w1");
|
||||
glBindAttribLocation(program, ATTR_W2, "w2");
|
||||
glBindAttribLocation(program, ATTR_COLOR0, "color0");
|
||||
glBindAttribLocation(program, ATTR_COLOR1, "color1");
|
||||
std::vector<GLRShader *> shaders;
|
||||
shaders.push_back(vs->shader);
|
||||
shaders.push_back(fs->shader);
|
||||
|
||||
#if !defined(USING_GLES2)
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_DUALSOURCE_BLEND)) {
|
||||
// Dual source alpha
|
||||
glBindFragDataLocationIndexed(program, 0, 0, "fragColor0");
|
||||
glBindFragDataLocationIndexed(program, 0, 1, "fragColor1");
|
||||
} else if (gl_extensions.VersionGEThan(3, 3, 0)) {
|
||||
glBindFragDataLocation(program, 0, "fragColor0");
|
||||
}
|
||||
#elif !defined(IOS)
|
||||
if (gl_extensions.GLES3) {
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_DUALSOURCE_BLEND)) {
|
||||
glBindFragDataLocationIndexedEXT(program, 0, 0, "fragColor0");
|
||||
glBindFragDataLocationIndexedEXT(program, 0, 1, "fragColor1");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
glLinkProgram(program);
|
||||
std::vector<GLRProgram::Semantic> semantics;
|
||||
semantics.push_back({ ATTR_POSITION, "position" });
|
||||
semantics.push_back({ ATTR_TEXCOORD, "texcoord" });
|
||||
semantics.push_back({ ATTR_NORMAL, "normal" });
|
||||
semantics.push_back({ ATTR_W1, "w1" });
|
||||
semantics.push_back({ ATTR_W2, "w2" });
|
||||
semantics.push_back({ ATTR_COLOR0, "color0" });
|
||||
semantics.push_back({ ATTR_COLOR1, "color1" });
|
||||
|
||||
GLint linkStatus = GL_FALSE;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
||||
if (linkStatus != GL_TRUE) {
|
||||
GLint bufLength = 0;
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
|
||||
if (bufLength) {
|
||||
char* buf = new char[bufLength];
|
||||
glGetProgramInfoLog(program, bufLength, NULL, buf);
|
||||
#ifdef __ANDROID__
|
||||
ELOG("Could not link program:\n %s", buf);
|
||||
#endif
|
||||
ERROR_LOG(G3D, "Could not link program:\n %s", buf);
|
||||
std::vector<GLRProgram::UniformLocQuery> queries;
|
||||
queries.push_back({ &u_tex, "tex" });
|
||||
queries.push_back({ &u_proj, "u_proj" });
|
||||
queries.push_back({ &u_proj_through, "u_proj_through" });
|
||||
|
||||
std::string vs_desc = vs->GetShaderString(SHADER_STRING_SHORT_DESC, VSID);
|
||||
std::string fs_desc = fs->GetShaderString(SHADER_STRING_SHORT_DESC, FSID);
|
||||
std::string vs_source = vs->GetShaderString(SHADER_STRING_SOURCE_CODE, VSID);
|
||||
std::string fs_source = fs->GetShaderString(SHADER_STRING_SOURCE_CODE, FSID);
|
||||
queries.push_back({ &u_proj, "u_proj" });
|
||||
queries.push_back({ &u_proj_through, "u_proj_through" });
|
||||
queries.push_back({ &u_texenv, "u_texenv" });
|
||||
queries.push_back({ &u_fogcolor, "u_fogcolor" });
|
||||
queries.push_back({ &u_fogcoef, "u_fogcoef" });
|
||||
queries.push_back({ &u_alphacolorref, "u_alphacolorref" });
|
||||
queries.push_back({ &u_alphacolormask, "u_alphacolormask" });
|
||||
queries.push_back({ &u_stencilReplaceValue, "u_stencilReplaceValue" });
|
||||
queries.push_back({ &u_testtex, "testtex" });
|
||||
|
||||
ERROR_LOG(G3D, "VS desc:\n%s", vs_desc.c_str());
|
||||
ERROR_LOG(G3D, "FS desc:\n%s", fs_desc.c_str());
|
||||
ERROR_LOG(G3D, "VS:\n%s\n", vs_source.c_str());
|
||||
ERROR_LOG(G3D, "FS:\n%s\n", fs_source.c_str());
|
||||
if (preloading) {
|
||||
Reporting::ReportMessage("Error in shader program link during preload: info: %s\nfs: %s\n%s\nvs: %s\n%s", buf, fs_desc.c_str(), fs_source.c_str(), vs_desc.c_str(), vs_source.c_str());
|
||||
} else {
|
||||
Reporting::ReportMessage("Error in shader program link: info: %s\nfs: %s\n%s\nvs: %s\n%s", buf, fs_desc.c_str(), fs_source.c_str(), vs_desc.c_str(), vs_source.c_str());
|
||||
}
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugStringUTF8(buf);
|
||||
OutputDebugStringUTF8(vs_source.c_str());
|
||||
OutputDebugStringUTF8(fs_source.c_str());
|
||||
#endif
|
||||
delete [] buf; // we're dead!
|
||||
}
|
||||
// Prevent a buffer overflow.
|
||||
numBones = 0;
|
||||
// Avoid weird attribute enables.
|
||||
attrMask = 0;
|
||||
availableUniforms = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, "Linked shader: vs %i fs %i", (int)vs->shader, (int)fs->shader);
|
||||
|
||||
u_tex = glGetUniformLocation(program, "tex");
|
||||
u_proj = glGetUniformLocation(program, "u_proj");
|
||||
u_proj_through = glGetUniformLocation(program, "u_proj_through");
|
||||
u_texenv = glGetUniformLocation(program, "u_texenv");
|
||||
u_fogcolor = glGetUniformLocation(program, "u_fogcolor");
|
||||
u_fogcoef = glGetUniformLocation(program, "u_fogcoef");
|
||||
u_alphacolorref = glGetUniformLocation(program, "u_alphacolorref");
|
||||
u_alphacolormask = glGetUniformLocation(program, "u_alphacolormask");
|
||||
u_stencilReplaceValue = glGetUniformLocation(program, "u_stencilReplaceValue");
|
||||
u_testtex = glGetUniformLocation(program, "testtex");
|
||||
|
||||
u_fbotex = glGetUniformLocation(program, "fbotex");
|
||||
u_blendFixA = glGetUniformLocation(program, "u_blendFixA");
|
||||
u_blendFixB = glGetUniformLocation(program, "u_blendFixB");
|
||||
u_fbotexSize = glGetUniformLocation(program, "u_fbotexSize");
|
||||
queries.push_back({ &u_fbotex, "fbotex" });
|
||||
queries.push_back({ &u_blendFixA, "u_blendFixA" });
|
||||
queries.push_back({ &u_blendFixB, "u_blendFixB" });
|
||||
queries.push_back({ &u_fbotexSize, "u_fbotexSize" });
|
||||
|
||||
// Transform
|
||||
u_view = glGetUniformLocation(program, "u_view");
|
||||
u_world = glGetUniformLocation(program, "u_world");
|
||||
u_texmtx = glGetUniformLocation(program, "u_texmtx");
|
||||
queries.push_back({ &u_view, "u_view" });
|
||||
queries.push_back({ &u_world, "u_world" });
|
||||
queries.push_back({ &u_texmtx, "u_texmtx" });
|
||||
|
||||
if (VSID.Bit(VS_BIT_ENABLE_BONES))
|
||||
numBones = TranslateNumBones(VSID.Bits(VS_BIT_BONES, 3) + 1);
|
||||
else
|
||||
numBones = 0;
|
||||
u_depthRange = glGetUniformLocation(program, "u_depthRange");
|
||||
queries.push_back({ &u_depthRange, "u_depthRange" });
|
||||
|
||||
#ifdef USE_BONE_ARRAY
|
||||
u_bone = glGetUniformLocation(program, "u_bone");
|
||||
queries.push_back({ &u_bone, "u_bone" });
|
||||
#else
|
||||
static const char * const boneNames[8] = { "u_bone0", "u_bone1", "u_bone2", "u_bone3", "u_bone4", "u_bone5", "u_bone6", "u_bone7", };
|
||||
for (int i = 0; i < 8; i++) {
|
||||
char name[10];
|
||||
sprintf(name, "u_bone%i", i);
|
||||
u_bone[i] = glGetUniformLocation(program, name);
|
||||
queries.push_back({ &u_bone[i], boneNames[i] });
|
||||
}
|
||||
#endif
|
||||
|
||||
// Lighting, texturing
|
||||
u_ambient = glGetUniformLocation(program, "u_ambient");
|
||||
u_matambientalpha = glGetUniformLocation(program, "u_matambientalpha");
|
||||
u_matdiffuse = glGetUniformLocation(program, "u_matdiffuse");
|
||||
u_matspecular = glGetUniformLocation(program, "u_matspecular");
|
||||
u_matemissive = glGetUniformLocation(program, "u_matemissive");
|
||||
u_uvscaleoffset = glGetUniformLocation(program, "u_uvscaleoffset");
|
||||
u_texclamp = glGetUniformLocation(program, "u_texclamp");
|
||||
u_texclampoff = glGetUniformLocation(program, "u_texclampoff");
|
||||
queries.push_back({ &u_ambient, "u_ambient" });
|
||||
queries.push_back({ &u_matambientalpha, "u_matambientalpha" });
|
||||
queries.push_back({ &u_matdiffuse, "u_matdiffuse" });
|
||||
queries.push_back({ &u_matspecular, "u_matspecular" });
|
||||
queries.push_back({ &u_matemissive, "u_matemissive" });
|
||||
queries.push_back({ &u_uvscaleoffset, "u_uvscaleoffset" });
|
||||
queries.push_back({ &u_texclamp, "u_texclamp" });
|
||||
queries.push_back({ &u_texclampoff, "u_texclampoff" });
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
char temp[64];
|
||||
sprintf(temp, "u_lightpos%i", i);
|
||||
u_lightpos[i] = glGetUniformLocation(program, temp);
|
||||
sprintf(temp, "u_lightdir%i", i);
|
||||
u_lightdir[i] = glGetUniformLocation(program, temp);
|
||||
sprintf(temp, "u_lightatt%i", i);
|
||||
u_lightatt[i] = glGetUniformLocation(program, temp);
|
||||
sprintf(temp, "u_lightangle%i", i);
|
||||
u_lightangle[i] = glGetUniformLocation(program, temp);
|
||||
sprintf(temp, "u_lightspotCoef%i", i);
|
||||
u_lightspotCoef[i] = glGetUniformLocation(program, temp);
|
||||
sprintf(temp, "u_lightambient%i", i);
|
||||
u_lightambient[i] = glGetUniformLocation(program, temp);
|
||||
sprintf(temp, "u_lightdiffuse%i", i);
|
||||
u_lightdiffuse[i] = glGetUniformLocation(program, temp);
|
||||
sprintf(temp, "u_lightspecular%i", i);
|
||||
u_lightspecular[i] = glGetUniformLocation(program, temp);
|
||||
static const char * const lightPosNames[4] = { "u_lightpos0", "u_lightpos1", "u_lightpos2", "u_lightpos3", };
|
||||
queries.push_back({ &u_lightpos[i], lightPosNames[i] });
|
||||
static const char * const lightdir_names[4] = { "u_lightdir0", "u_lightdir1", "u_lightdir2", "u_lightdir3", };
|
||||
queries.push_back({ &u_lightdir[i], lightdir_names[i] });
|
||||
static const char * const lightatt_names[4] = { "u_lightatt0", "u_lightatt1", "u_lightatt2", "u_lightatt3", };
|
||||
queries.push_back({ &u_lightatt[i], lightatt_names[i] });
|
||||
static const char * const lightangle_names[4] = { "u_lightangle0", "u_lightangle1", "u_lightangle2", "u_lightangle3", };
|
||||
queries.push_back({ &u_lightangle[i], lightangle_names[i] });
|
||||
|
||||
static const char * const lightspotCoef_names[4] = { "u_lightspotCoef0", "u_lightspotCoef1", "u_lightspotCoef2", "u_lightspotCoef3", };
|
||||
queries.push_back({ &u_lightspotCoef[i], lightspotCoef_names[i] });
|
||||
static const char * const lightambient_names[4] = { "u_lightambient0", "u_lightambient1", "u_lightambient2", "u_lightambient3", };
|
||||
queries.push_back({ &u_lightambient[i], lightambient_names[i] });
|
||||
static const char * const lightdiffuse_names[4] = { "u_lightdiffuse0", "u_lightdiffuse1", "u_lightdiffuse2", "u_lightdiffuse3", };
|
||||
queries.push_back({ &u_lightdiffuse[i], lightdiffuse_names[i] });
|
||||
static const char * const lightspecular_names[4] = { "u_lightspecular0", "u_lightspecular1", "u_lightspecular2", "u_lightspecular3", };
|
||||
queries.push_back({ &u_lightspecular[i], lightspecular_names[i] });
|
||||
}
|
||||
|
||||
// We need to fetch these unconditionally, gstate_c.spline or bezier will not be set if we
|
||||
// create this shader at load time from the shader cache.
|
||||
u_tess_pos_tex = glGetUniformLocation(program, "u_tess_pos_tex");
|
||||
u_tess_tex_tex = glGetUniformLocation(program, "u_tess_tex_tex");
|
||||
u_tess_col_tex = glGetUniformLocation(program, "u_tess_col_tex");
|
||||
u_spline_count_u = glGetUniformLocation(program, "u_spline_count_u");
|
||||
u_spline_count_v = glGetUniformLocation(program, "u_spline_count_v");
|
||||
u_spline_type_u = glGetUniformLocation(program, "u_spline_type_u");
|
||||
u_spline_type_v = glGetUniformLocation(program, "u_spline_type_v");
|
||||
queries.push_back({ &u_tess_pos_tex, "u_tess_pos_tex" });
|
||||
queries.push_back({ &u_tess_tex_tex, "u_tess_tex_tex" });
|
||||
queries.push_back({ &u_tess_col_tex, "u_tess_col_tex" });
|
||||
queries.push_back({ &u_spline_count_u, "u_spline_count_u" });
|
||||
queries.push_back({ &u_spline_count_v, "u_spline_count_v" });
|
||||
queries.push_back({ &u_spline_type_u, "u_spline_type_u" });
|
||||
queries.push_back({ &u_spline_type_v, "u_spline_type_v" });
|
||||
|
||||
attrMask = vs->GetAttrMask();
|
||||
availableUniforms = vs->GetUniformMask() | fs->GetUniformMask();
|
||||
|
||||
glUseProgram(program);
|
||||
program = render->CreateProgram(shaders, semantics, queries, gstate_c.featureFlags & GPU_SUPPORTS_DUALSOURCE_BLEND);
|
||||
|
||||
render->BindProgram(program);
|
||||
|
||||
// Default uniform values
|
||||
glUniform1i(u_tex, 0);
|
||||
glUniform1i(u_fbotex, 1);
|
||||
glUniform1i(u_testtex, 2);
|
||||
render->SetUniformI1(&u_tex, 0);
|
||||
render->SetUniformI1(&u_fbotex, 1);
|
||||
render->SetUniformI1(&u_fbotex, 2);
|
||||
|
||||
if (u_tess_pos_tex != -1)
|
||||
glUniform1i(u_tess_pos_tex, 4); // Texture unit 4
|
||||
render->SetUniformI1(&u_tess_pos_tex, 4); // Texture unit 4
|
||||
if (u_tess_tex_tex != -1)
|
||||
glUniform1i(u_tess_tex_tex, 5); // Texture unit 5
|
||||
render->SetUniformI1(&u_tess_tex_tex, 5); // Texture unit 5
|
||||
if (u_tess_col_tex != -1)
|
||||
glUniform1i(u_tess_col_tex, 6); // Texture unit 6
|
||||
render->SetUniformI1(&u_tess_col_tex, 6); // Texture unit 6
|
||||
|
||||
// The rest, use the "dirty" mechanism.
|
||||
dirtyUniforms = DIRTY_ALL_UNIFORMS;
|
||||
@ -274,25 +188,28 @@ LinkedShader::LinkedShader(VShaderID VSID, Shader *vs, FShaderID FSID, Shader *f
|
||||
}
|
||||
|
||||
LinkedShader::~LinkedShader() {
|
||||
// Shaders are automatically detached by glDeleteProgram.
|
||||
glDeleteProgram(program);
|
||||
render_->DeleteProgram(program);
|
||||
}
|
||||
|
||||
// Utility
|
||||
static void SetColorUniform3(int uniform, u32 color) {
|
||||
float f[4];
|
||||
Uint8x4ToFloat4(f, color);
|
||||
glUniform3fv(uniform, 1, f);
|
||||
static inline void SetFloatUniform(GLRenderManager *render, GLint *uniform, float value) {
|
||||
render->SetUniformF(uniform, 1, &value);
|
||||
}
|
||||
|
||||
static void SetColorUniform3Alpha(int uniform, u32 color, u8 alpha) {
|
||||
static inline void SetColorUniform3(GLRenderManager *render, GLint *uniform, u32 color) {
|
||||
float f[4];
|
||||
Uint8x4ToFloat4(f, color);
|
||||
render->SetUniformF(uniform, 3, f);
|
||||
}
|
||||
|
||||
static void SetColorUniform3Alpha(GLRenderManager *render, GLint *uniform, u32 color, u8 alpha) {
|
||||
float f[4];
|
||||
Uint8x3ToFloat4_AlphaUint8(f, color, alpha);
|
||||
glUniform4fv(uniform, 1, f);
|
||||
render->SetUniformF(uniform, 4, f);
|
||||
}
|
||||
|
||||
// This passes colors unscaled (e.g. 0 - 255 not 0 - 1.)
|
||||
static void SetColorUniform3Alpha255(int uniform, u32 color, u8 alpha) {
|
||||
static void SetColorUniform3Alpha255(GLRenderManager *render, GLint *uniform, u32 color, u8 alpha) {
|
||||
if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) {
|
||||
const float col[4] = {
|
||||
(float)((color & 0xFF) >> 0) * (1.0f / 255.0f),
|
||||
@ -300,7 +217,7 @@ static void SetColorUniform3Alpha255(int uniform, u32 color, u8 alpha) {
|
||||
(float)((color & 0xFF0000) >> 16) * (1.0f / 255.0f),
|
||||
(float)alpha * (1.0f / 255.0f)
|
||||
};
|
||||
glUniform4fv(uniform, 1, col);
|
||||
render->SetUniformF(uniform, 4, col);
|
||||
} else {
|
||||
const float col[4] = {
|
||||
(float)((color & 0xFF) >> 0),
|
||||
@ -308,44 +225,44 @@ static void SetColorUniform3Alpha255(int uniform, u32 color, u8 alpha) {
|
||||
(float)((color & 0xFF0000) >> 16),
|
||||
(float)alpha
|
||||
};
|
||||
glUniform4fv(uniform, 1, col);
|
||||
render->SetUniformF(uniform, 4, col);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetColorUniform3iAlpha(int uniform, u32 color, u8 alpha) {
|
||||
static void SetColorUniform3iAlpha(GLRenderManager *render, GLint *uniform, u32 color, u8 alpha) {
|
||||
const int col[4] = {
|
||||
(int)((color & 0xFF) >> 0),
|
||||
(int)((color & 0xFF00) >> 8),
|
||||
(int)((color & 0xFF0000) >> 16),
|
||||
(int)alpha,
|
||||
};
|
||||
glUniform4iv(uniform, 1, col);
|
||||
render->SetUniformI(uniform, 4, col);
|
||||
}
|
||||
|
||||
static void SetColorUniform3ExtraFloat(int uniform, u32 color, float extra) {
|
||||
static void SetColorUniform3ExtraFloat(GLRenderManager *render, GLint *uniform, u32 color, float extra) {
|
||||
const float col[4] = {
|
||||
((color & 0xFF)) / 255.0f,
|
||||
((color & 0xFF00) >> 8) / 255.0f,
|
||||
((color & 0xFF0000) >> 16) / 255.0f,
|
||||
extra
|
||||
};
|
||||
glUniform4fv(uniform, 1, col);
|
||||
render->SetUniformF(uniform, 4, col);
|
||||
}
|
||||
|
||||
static void SetFloat24Uniform3(int uniform, const uint32_t data[3]) {
|
||||
static void SetFloat24Uniform3(GLRenderManager *render, GLint *uniform, const uint32_t data[3]) {
|
||||
float f[4];
|
||||
ExpandFloat24x3ToFloat4(f, data);
|
||||
glUniform3fv(uniform, 1, f);
|
||||
render->SetUniformF(uniform, 3, f);
|
||||
}
|
||||
|
||||
static void SetFloatUniform4(int uniform, float data[4]) {
|
||||
glUniform4fv(uniform, 1, data);
|
||||
static void SetFloatUniform4(GLRenderManager *render, GLint *uniform, float data[4]) {
|
||||
render->SetUniformF(uniform, 4, data);
|
||||
}
|
||||
|
||||
static void SetMatrix4x3(int uniform, const float *m4x3) {
|
||||
static void SetMatrix4x3(GLRenderManager *render, GLint *uniform, const float *m4x3) {
|
||||
float m4x4[16];
|
||||
ConvertMatrix4x3To4x4(m4x4, m4x3);
|
||||
glUniformMatrix4fv(uniform, 1, GL_FALSE, m4x4);
|
||||
render->SetUniformM4x4(uniform, m4x4);
|
||||
}
|
||||
|
||||
static inline void ScaleProjMatrix(Matrix4x4 &in) {
|
||||
@ -359,34 +276,12 @@ static inline void ScaleProjMatrix(Matrix4x4 &in) {
|
||||
in.translateAndScale(trans, scale);
|
||||
}
|
||||
|
||||
void LinkedShader::use(const VShaderID &VSID, LinkedShader *previous) {
|
||||
glUseProgram(program);
|
||||
int enable, disable;
|
||||
if (previous) {
|
||||
enable = attrMask & ~previous->attrMask;
|
||||
disable = (~attrMask) & previous->attrMask;
|
||||
} else {
|
||||
enable = attrMask;
|
||||
disable = ~attrMask;
|
||||
}
|
||||
for (int i = 0; i < ATTR_COUNT; i++) {
|
||||
if (enable & (1 << i))
|
||||
glEnableVertexAttribArray(i);
|
||||
else if (disable & (1 << i))
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
void LinkedShader::use(const ShaderID &VSID) {
|
||||
render_->BindProgram(program);
|
||||
// Note that we no longer track attr masks here - we do it for the input layouts instead.
|
||||
}
|
||||
|
||||
void LinkedShader::stop() {
|
||||
for (int i = 0; i < ATTR_COUNT; i++) {
|
||||
if (attrMask & (1 << i))
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
}
|
||||
|
||||
void LinkedShader::UpdateUniforms(u32 vertType, const VShaderID &vsid) {
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
|
||||
void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid) {
|
||||
u64 dirty = dirtyUniforms & availableUniforms;
|
||||
dirtyUniforms = 0;
|
||||
if (!dirty)
|
||||
@ -448,7 +343,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const VShaderID &vsid) {
|
||||
|
||||
ScaleProjMatrix(flippedMatrix);
|
||||
|
||||
glUniformMatrix4fv(u_proj, 1, GL_FALSE, flippedMatrix.m);
|
||||
render_->SetUniformM4x4(&u_proj, flippedMatrix.m);
|
||||
}
|
||||
if (dirty & DIRTY_PROJTHROUGHMATRIX)
|
||||
{
|
||||
@ -459,19 +354,19 @@ void LinkedShader::UpdateUniforms(u32 vertType, const VShaderID &vsid) {
|
||||
} else {
|
||||
proj_through.setOrtho(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
glUniformMatrix4fv(u_proj_through, 1, GL_FALSE, proj_through.getReadPtr());
|
||||
render_->SetUniformM4x4(&u_proj_through, proj_through.getReadPtr());
|
||||
}
|
||||
if (dirty & DIRTY_TEXENV) {
|
||||
SetColorUniform3(u_texenv, gstate.texenvcolor);
|
||||
SetColorUniform3(render_, &u_texenv, gstate.texenvcolor);
|
||||
}
|
||||
if (dirty & DIRTY_ALPHACOLORREF) {
|
||||
SetColorUniform3Alpha255(u_alphacolorref, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask());
|
||||
SetColorUniform3Alpha255(render_, &u_alphacolorref, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask());
|
||||
}
|
||||
if (dirty & DIRTY_ALPHACOLORMASK) {
|
||||
SetColorUniform3iAlpha(u_alphacolormask, gstate.colortestmask, gstate.getAlphaTestMask());
|
||||
SetColorUniform3iAlpha(render_, &u_alphacolormask, gstate.colortestmask, gstate.getAlphaTestMask());
|
||||
}
|
||||
if (dirty & DIRTY_FOGCOLOR) {
|
||||
SetColorUniform3(u_fogcolor, gstate.fogcolor);
|
||||
SetColorUniform3(render_, &u_fogcolor, gstate.fogcolor);
|
||||
}
|
||||
if (dirty & DIRTY_FOGCOEF) {
|
||||
float fogcoef[2] = {
|
||||
@ -494,7 +389,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const VShaderID &vsid) {
|
||||
ERROR_LOG_REPORT_ONCE(fognan, G3D, "Unhandled fog NaN/INF combo: %f %f", fogcoef[0], fogcoef[1]);
|
||||
}
|
||||
#endif
|
||||
glUniform2fv(u_fogcoef, 1, fogcoef);
|
||||
render_->SetUniformF(&u_fogcoef, 2, fogcoef);
|
||||
}
|
||||
|
||||
if (dirty & DIRTY_UVSCALEOFFSET) {
|
||||
@ -518,7 +413,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const VShaderID &vsid) {
|
||||
uvscaleoff[2] = 0.0f;
|
||||
uvscaleoff[3] = 0.0f;
|
||||
}
|
||||
glUniform4fv(u_uvscaleoffset, 1, uvscaleoff);
|
||||
render_->SetUniformF(&u_uvscaleoffset, 4, uvscaleoff);
|
||||
}
|
||||
|
||||
if ((dirty & DIRTY_TEXCLAMP) && u_texclamp != -1) {
|
||||
@ -540,21 +435,21 @@ void LinkedShader::UpdateUniforms(u32 vertType, const VShaderID &vsid) {
|
||||
gstate_c.curTextureXOffset * invW,
|
||||
gstate_c.curTextureYOffset * invH,
|
||||
};
|
||||
glUniform4fv(u_texclamp, 1, texclamp);
|
||||
render_->SetUniformF(&u_texclamp, 4, texclamp);
|
||||
if (u_texclampoff != -1) {
|
||||
glUniform2fv(u_texclampoff, 1, texclampoff);
|
||||
render_->SetUniformF(&u_texclampoff, 2, texclampoff);
|
||||
}
|
||||
}
|
||||
|
||||
// Transform
|
||||
if (dirty & DIRTY_WORLDMATRIX) {
|
||||
SetMatrix4x3(u_world, gstate.worldMatrix);
|
||||
SetMatrix4x3(render_, &u_world, gstate.worldMatrix);
|
||||
}
|
||||
if (dirty & DIRTY_VIEWMATRIX) {
|
||||
SetMatrix4x3(u_view, gstate.viewMatrix);
|
||||
SetMatrix4x3(render_, &u_view, gstate.viewMatrix);
|
||||
}
|
||||
if (dirty & DIRTY_TEXMATRIX) {
|
||||
SetMatrix4x3(u_texmtx, gstate.tgenMatrix);
|
||||
SetMatrix4x3(render_, &u_texmtx, gstate.tgenMatrix);
|
||||
}
|
||||
if ((dirty & DIRTY_DEPTHRANGE) && u_depthRange != -1) {
|
||||
// Since depth is [-1, 1] mapping to [minz, maxz], this is easyish.
|
||||
@ -580,53 +475,27 @@ void LinkedShader::UpdateUniforms(u32 vertType, const VShaderID &vsid) {
|
||||
}
|
||||
|
||||
float data[4] = { viewZScale, viewZCenter, viewZCenter, viewZInvScale };
|
||||
SetFloatUniform4(u_depthRange, data);
|
||||
SetFloatUniform4(render_, &u_depthRange, data);
|
||||
}
|
||||
|
||||
if (dirty & DIRTY_STENCILREPLACEVALUE) {
|
||||
glUniform1f(u_stencilReplaceValue, (float)gstate.getStencilTestRef() * (1.0f / 255.0f));
|
||||
float f = (float)gstate.getStencilTestRef() * (1.0f / 255.0f);
|
||||
render_->SetUniformF(&u_stencilReplaceValue, 1, &f);
|
||||
}
|
||||
// TODO: Could even set all bones in one go if they're all dirty.
|
||||
#ifdef USE_BONE_ARRAY
|
||||
if (u_bone != -1) {
|
||||
float allBones[8 * 16];
|
||||
|
||||
bool allDirty = true;
|
||||
for (int i = 0; i < numBones; i++) {
|
||||
if (dirty & (DIRTY_BONEMATRIX0 << i)) {
|
||||
ConvertMatrix4x3To4x4(allBones + 16 * i, gstate.boneMatrix + 12 * i);
|
||||
} else {
|
||||
allDirty = false;
|
||||
}
|
||||
}
|
||||
if (allDirty) {
|
||||
// Set them all with one call
|
||||
glUniformMatrix4fv(u_bone, numBones, GL_FALSE, allBones);
|
||||
} else {
|
||||
// Set them one by one. Could try to coalesce two in a row etc but too lazy.
|
||||
for (int i = 0; i < numBones; i++) {
|
||||
if (dirty & (DIRTY_BONEMATRIX0 << i)) {
|
||||
glUniformMatrix4fv(u_bone + i, 1, GL_FALSE, allBones + 16 * i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
float bonetemp[16];
|
||||
for (int i = 0; i < numBones; i++) {
|
||||
if (dirty & (DIRTY_BONEMATRIX0 << i)) {
|
||||
ConvertMatrix4x3To4x4(bonetemp, gstate.boneMatrix + 12 * i);
|
||||
glUniformMatrix4fv(u_bone[i], 1, GL_FALSE, bonetemp);
|
||||
render_->SetUniformM4x4(&u_bone[i], bonetemp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dirty & DIRTY_SHADERBLEND) {
|
||||
if (u_blendFixA != -1) {
|
||||
SetColorUniform3(u_blendFixA, gstate.getFixA());
|
||||
SetColorUniform3(render_, &u_blendFixA, gstate.getFixA());
|
||||
}
|
||||
if (u_blendFixB != -1) {
|
||||
SetColorUniform3(u_blendFixB, gstate.getFixB());
|
||||
SetColorUniform3(render_, &u_blendFixB, gstate.getFixB());
|
||||
}
|
||||
|
||||
const float fbotexSize[2] = {
|
||||
@ -634,25 +503,25 @@ void LinkedShader::UpdateUniforms(u32 vertType, const VShaderID &vsid) {
|
||||
1.0f / (float)gstate_c.curRTRenderHeight,
|
||||
};
|
||||
if (u_fbotexSize != -1) {
|
||||
glUniform2fv(u_fbotexSize, 1, fbotexSize);
|
||||
render_->SetUniformF(&u_fbotexSize, 2, fbotexSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Lighting
|
||||
if (dirty & DIRTY_AMBIENT) {
|
||||
SetColorUniform3Alpha(u_ambient, gstate.ambientcolor, gstate.getAmbientA());
|
||||
SetColorUniform3Alpha(render_, &u_ambient, gstate.ambientcolor, gstate.getAmbientA());
|
||||
}
|
||||
if (dirty & DIRTY_MATAMBIENTALPHA) {
|
||||
SetColorUniform3Alpha(u_matambientalpha, gstate.materialambient, gstate.getMaterialAmbientA());
|
||||
SetColorUniform3Alpha(render_, &u_matambientalpha, gstate.materialambient, gstate.getMaterialAmbientA());
|
||||
}
|
||||
if (dirty & DIRTY_MATDIFFUSE) {
|
||||
SetColorUniform3(u_matdiffuse, gstate.materialdiffuse);
|
||||
SetColorUniform3(render_, &u_matdiffuse, gstate.materialdiffuse);
|
||||
}
|
||||
if (dirty & DIRTY_MATEMISSIVE) {
|
||||
SetColorUniform3(u_matemissive, gstate.materialemissive);
|
||||
SetColorUniform3(render_, &u_matemissive, gstate.materialemissive);
|
||||
}
|
||||
if (dirty & DIRTY_MATSPECULAR) {
|
||||
SetColorUniform3ExtraFloat(u_matspecular, gstate.materialspecular, getFloat24(gstate.materialspecularcoef));
|
||||
SetColorUniform3ExtraFloat(render_, &u_matspecular, gstate.materialspecular, getFloat24(gstate.materialspecularcoef));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@ -668,34 +537,33 @@ void LinkedShader::UpdateUniforms(u32 vertType, const VShaderID &vsid) {
|
||||
else
|
||||
len = 1.0f / len;
|
||||
float vec[3] = { x * len, y * len, z * len };
|
||||
glUniform3fv(u_lightpos[i], 1, vec);
|
||||
render_->SetUniformF(&u_lightpos[i], 3, vec);
|
||||
} else {
|
||||
SetFloat24Uniform3(u_lightpos[i], &gstate.lpos[i * 3]);
|
||||
SetFloat24Uniform3(render_, &u_lightpos[i], &gstate.lpos[i * 3]);
|
||||
}
|
||||
if (u_lightdir[i] != -1) SetFloat24Uniform3(u_lightdir[i], &gstate.ldir[i * 3]);
|
||||
if (u_lightatt[i] != -1) SetFloat24Uniform3(u_lightatt[i], &gstate.latt[i * 3]);
|
||||
if (u_lightangle[i] != -1) glUniform1f(u_lightangle[i], getFloat24(gstate.lcutoff[i]));
|
||||
if (u_lightspotCoef[i] != -1) glUniform1f(u_lightspotCoef[i], getFloat24(gstate.lconv[i]));
|
||||
if (u_lightambient[i] != -1) SetColorUniform3(u_lightambient[i], gstate.lcolor[i * 3]);
|
||||
if (u_lightdiffuse[i] != -1) SetColorUniform3(u_lightdiffuse[i], gstate.lcolor[i * 3 + 1]);
|
||||
if (u_lightspecular[i] != -1) SetColorUniform3(u_lightspecular[i], gstate.lcolor[i * 3 + 2]);
|
||||
if (u_lightdir[i] != -1) SetFloat24Uniform3(render_, &u_lightdir[i], &gstate.ldir[i * 3]);
|
||||
if (u_lightatt[i] != -1) SetFloat24Uniform3(render_, &u_lightatt[i], &gstate.latt[i * 3]);
|
||||
if (u_lightangle[i] != -1) SetFloatUniform(render_, &u_lightangle[i], getFloat24(gstate.lcutoff[i]));
|
||||
if (u_lightspotCoef[i] != -1) SetFloatUniform(render_, &u_lightspotCoef[i], getFloat24(gstate.lconv[i]));
|
||||
if (u_lightambient[i] != -1) SetColorUniform3(render_, &u_lightambient[i], gstate.lcolor[i * 3]);
|
||||
if (u_lightdiffuse[i] != -1) SetColorUniform3(render_, &u_lightdiffuse[i], gstate.lcolor[i * 3 + 1]);
|
||||
if (u_lightspecular[i] != -1) SetColorUniform3(render_, &u_lightspecular[i], gstate.lcolor[i * 3 + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (dirty & DIRTY_BEZIERSPLINE) {
|
||||
glUniform1i(u_spline_count_u, gstate_c.spline_count_u);
|
||||
render_->SetUniformI1(&u_spline_count_u, gstate_c.spline_count_u);
|
||||
if (u_spline_count_v != -1)
|
||||
glUniform1i(u_spline_count_v, gstate_c.spline_count_v);
|
||||
render_->SetUniformI1(&u_spline_count_v, gstate_c.spline_count_v);
|
||||
if (u_spline_type_u != -1)
|
||||
glUniform1i(u_spline_type_u, gstate_c.spline_type_u);
|
||||
render_->SetUniformI1(&u_spline_type_u, gstate_c.spline_type_u);
|
||||
if (u_spline_type_v != -1)
|
||||
glUniform1i(u_spline_type_v, gstate_c.spline_type_v);
|
||||
render_->SetUniformI1(&u_spline_type_v, gstate_c.spline_type_v);
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
}
|
||||
|
||||
ShaderManagerGLES::ShaderManagerGLES()
|
||||
: lastShader_(nullptr), shaderSwitchDirtyUniforms_(0), diskCacheDirty_(false), fsCache_(16), vsCache_(16) {
|
||||
ShaderManagerGLES::ShaderManagerGLES(GLRenderManager *render)
|
||||
: render_(render), lastShader_(nullptr), shaderSwitchDirtyUniforms_(0), diskCacheDirty_(false), fsCache_(16), vsCache_(16) {
|
||||
codeBuffer_ = new char[16384];
|
||||
lastFSID_.set_invalid();
|
||||
lastVSID_.set_invalid();
|
||||
@ -737,8 +605,6 @@ void ShaderManagerGLES::DirtyShader() {
|
||||
}
|
||||
|
||||
void ShaderManagerGLES::DirtyLastShader() { // disables vertex arrays
|
||||
if (lastShader_)
|
||||
lastShader_->stop();
|
||||
lastShader_ = nullptr;
|
||||
lastVShaderSame_ = false;
|
||||
}
|
||||
@ -748,7 +614,7 @@ Shader *ShaderManagerGLES::CompileFragmentShader(FShaderID FSID) {
|
||||
if (!GenerateFragmentShader(FSID, codeBuffer_, &uniformMask)) {
|
||||
return nullptr;
|
||||
}
|
||||
return new Shader(FSID, codeBuffer_, GL_FRAGMENT_SHADER, false, 0, uniformMask);
|
||||
return new Shader(render_, codeBuffer_, GL_FRAGMENT_SHADER, false, 0, uniformMask);
|
||||
}
|
||||
|
||||
Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) {
|
||||
@ -756,7 +622,7 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) {
|
||||
uint32_t attrMask;
|
||||
uint64_t uniformMask;
|
||||
GenerateVertexShader(VSID, codeBuffer_, &attrMask, &uniformMask);
|
||||
return new Shader(VSID, codeBuffer_, GL_VERTEX_SHADER, useHWTransform, attrMask, uniformMask);
|
||||
return new Shader(render_, codeBuffer_, GL_VERTEX_SHADER, useHWTransform, attrMask, uniformMask);
|
||||
}
|
||||
|
||||
Shader *ShaderManagerGLES::ApplyVertexShader(int prim, u32 vertType, VShaderID *VSID) {
|
||||
@ -806,7 +672,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(int prim, u32 vertType, VShaderID *
|
||||
uint32_t attrMask;
|
||||
uint64_t uniformMask;
|
||||
GenerateVertexShader(vsidTemp, codeBuffer_, &attrMask, &uniformMask);
|
||||
vs = new Shader(vsidTemp, codeBuffer_, GL_VERTEX_SHADER, false, attrMask, uniformMask);
|
||||
vs = new Shader(render_, codeBuffer_, GL_VERTEX_SHADER, false, attrMask, uniformMask);
|
||||
}
|
||||
|
||||
vsCache_.Insert(*VSID, vs);
|
||||
@ -860,12 +726,12 @@ LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs,
|
||||
_dbg_assert_(G3D, FSID.Bit(FS_BIT_FLATSHADE) == VSID.Bit(VS_BIT_FLATSHADE));
|
||||
|
||||
// Check if we can link these.
|
||||
ls = new LinkedShader(VSID, vs, FSID, fs, vs->UseHWTransform());
|
||||
ls->use(VSID, lastShader_);
|
||||
ls = new LinkedShader(render_, VSID, vs, FSID, fs, vs->UseHWTransform());
|
||||
ls->use(VSID);
|
||||
const LinkedShaderCacheEntry entry(vs, fs, ls);
|
||||
linkedShaderCache_.push_back(entry);
|
||||
} else {
|
||||
ls->use(VSID, lastShader_);
|
||||
ls->use(VSID);
|
||||
}
|
||||
ls->UpdateUniforms(vertType, VSID);
|
||||
|
||||
@ -1083,7 +949,7 @@ bool ShaderManagerGLES::ContinuePrecompile(float sliceTime) {
|
||||
Shader *vs = vsCache_.Get(vsid);
|
||||
Shader *fs = fsCache_.Get(fsid);
|
||||
if (vs && fs) {
|
||||
LinkedShader *ls = new LinkedShader(vsid, vs, fsid, fs, vs->UseHWTransform(), true);
|
||||
LinkedShader *ls = new LinkedShader(render_, vsid, vs, fsid, fs, vs->UseHWTransform(), true);
|
||||
LinkedShaderCacheEntry entry(vs, fs, ls);
|
||||
linkedShaderCache_.push_back(entry);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "Common/Hashmaps.h"
|
||||
#include "thin3d/GLRenderManager.h"
|
||||
#include "GPU/Common/ShaderCommon.h"
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
#include "GPU/GLES/VertexShaderGeneratorGLES.h"
|
||||
@ -43,18 +44,18 @@ enum {
|
||||
|
||||
class LinkedShader {
|
||||
public:
|
||||
LinkedShader(VShaderID VSID, Shader *vs, FShaderID FSID, Shader *fs, bool useHWTransform, bool preloading = false);
|
||||
LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, FShaderID FSID, Shader *fs, bool useHWTransform, bool preloading = false);
|
||||
~LinkedShader();
|
||||
|
||||
void use(const VShaderID &VSID, LinkedShader *previous);
|
||||
void stop();
|
||||
void UpdateUniforms(u32 vertType, const VShaderID &VSID);
|
||||
void use(const ShaderID &VSID);
|
||||
void UpdateUniforms(u32 vertType, const ShaderID &VSID);
|
||||
|
||||
GLRenderManager *render_;
|
||||
Shader *vs_;
|
||||
// Set to false if the VS failed, happens on Mali-400 a lot for complex shaders.
|
||||
bool useHWTransform_;
|
||||
|
||||
uint32_t program = 0;
|
||||
GLRProgram *program;
|
||||
uint64_t availableUniforms;
|
||||
uint64_t dirtyUniforms = 0;
|
||||
|
||||
@ -124,9 +125,9 @@ public:
|
||||
|
||||
class Shader {
|
||||
public:
|
||||
Shader(const ShaderID &id, const char *code, uint32_t glShaderType, bool useHWTransform, uint32_t attrMask, uint64_t uniformMask);
|
||||
Shader(GLRenderManager *render, const char *code, uint32_t glShaderType, bool useHWTransform, uint32_t attrMask, uint64_t uniformMask);
|
||||
~Shader();
|
||||
uint32_t shader;
|
||||
GLRShader *shader;
|
||||
|
||||
bool Failed() const { return failed_; }
|
||||
bool UseHWTransform() const { return useHWTransform_; } // only relevant for vtx shaders
|
||||
@ -137,6 +138,7 @@ public:
|
||||
uint64_t GetUniformMask() const { return uniformMask_; }
|
||||
|
||||
private:
|
||||
GLRenderManager *render_;
|
||||
std::string source_;
|
||||
bool failed_;
|
||||
bool useHWTransform_;
|
||||
@ -147,7 +149,7 @@ private:
|
||||
|
||||
class ShaderManagerGLES : public ShaderManagerCommon {
|
||||
public:
|
||||
ShaderManagerGLES();
|
||||
ShaderManagerGLES(GLRenderManager *render);
|
||||
~ShaderManagerGLES();
|
||||
|
||||
void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected
|
||||
@ -186,6 +188,7 @@ private:
|
||||
};
|
||||
typedef std::vector<LinkedShaderCacheEntry> LinkedShaderCache;
|
||||
|
||||
GLRenderManager *render_;
|
||||
LinkedShaderCache linkedShaderCache_;
|
||||
|
||||
bool lastVShaderSame_;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "StateMappingGLES.h"
|
||||
#include "profiler/profiler.h"
|
||||
#include "gfx/gl_debug_log.h"
|
||||
#include "thin3d/GLRenderManager.h"
|
||||
|
||||
#include "GPU/Math3D.h"
|
||||
#include "GPU/GPUState.h"
|
||||
@ -123,14 +124,15 @@ static const GLushort logicOps[] = {
|
||||
|
||||
inline void DrawEngineGLES::ResetShaderBlending() {
|
||||
if (fboTexBound_) {
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
GLRenderManager *renderManager = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
renderManager->BindTexture(1, nullptr);
|
||||
fboTexBound_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
GLRenderManager *renderManager = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
|
||||
textureCache_->SetTexture();
|
||||
gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
@ -163,11 +165,10 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
gstate_c.SetAllowShaderBlend(!g_Config.bDisableSlowFramebufEffects);
|
||||
|
||||
if (gstate.isModeClear()) {
|
||||
glstate.blend.disable();
|
||||
// Color Test
|
||||
bool colorMask = gstate.isClearModeColorMask();
|
||||
bool alphaMask = gstate.isClearModeAlphaMask();
|
||||
glstate.colorMask.set(colorMask, colorMask, colorMask, alphaMask);
|
||||
renderManager->SetNoBlendAndMask((colorMask ? 7 : 0) | (alphaMask ? 8 : 0));
|
||||
#ifndef USING_GLES2
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
// Logic Ops
|
||||
@ -194,11 +195,6 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
}
|
||||
|
||||
if (blendState.enabled) {
|
||||
glstate.blend.enable();
|
||||
glstate.blendEquationSeparate.set(glBlendEqLookup[(size_t)blendState.eqColor], glBlendEqLookup[(size_t)blendState.eqAlpha]);
|
||||
glstate.blendFuncSeparate.set(
|
||||
glBlendFactorLookup[(size_t)blendState.srcColor], glBlendFactorLookup[(size_t)blendState.dstColor],
|
||||
glBlendFactorLookup[(size_t)blendState.srcAlpha], glBlendFactorLookup[(size_t)blendState.dstAlpha]);
|
||||
if (blendState.dirtyShaderBlend) {
|
||||
gstate_c.Dirty(DIRTY_SHADERBLEND);
|
||||
}
|
||||
@ -210,10 +206,8 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
(float)((color & 0xFF0000) >> 16) * (1.0f / 255.0f),
|
||||
(float)((color & 0xFF000000) >> 24) * (1.0f / 255.0f),
|
||||
};
|
||||
glstate.blendColor.set(col);
|
||||
renderManager->SetBlendFactor(col);
|
||||
}
|
||||
} else {
|
||||
glstate.blend.disable();
|
||||
}
|
||||
|
||||
// PSP color/alpha mask is per bit but we can only support per byte.
|
||||
@ -235,18 +229,21 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
WARN_LOG_REPORT_ONCE(amask, G3D, "Unsupported alpha/stencil mask: %02x", abits);
|
||||
}
|
||||
#endif
|
||||
|
||||
glstate.colorMask.set(rmask, gmask, bmask, amask);
|
||||
int mask = (int)rmask | ((int)gmask << 1) | ((int)bmask << 2) | ((int)amask << 3);
|
||||
renderManager->SetBlendAndMask(mask, blendState.enabled,
|
||||
glBlendFactorLookup[(size_t)blendState.srcColor], glBlendFactorLookup[(size_t)blendState.dstColor],
|
||||
glBlendFactorLookup[(size_t)blendState.srcAlpha], glBlendFactorLookup[(size_t)blendState.dstAlpha],
|
||||
glBlendEqLookup[(size_t)blendState.eqColor], glBlendEqLookup[(size_t)blendState.eqAlpha]);
|
||||
|
||||
#ifndef USING_GLES2
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
// TODO: Make this dynamic
|
||||
// Logic Ops
|
||||
if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) {
|
||||
glstate.colorLogicOp.enable();
|
||||
glstate.logicOp.set(logicOps[gstate.getLogicOp()]);
|
||||
//glstate.colorLogicOp.enable();
|
||||
//glstate.logicOp.set(logicOps[gstate.getLogicOp()]);
|
||||
} else {
|
||||
glstate.colorLogicOp.disable();
|
||||
//glstate.colorLogicOp.disable();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -257,26 +254,18 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
gstate_c.Clean(DIRTY_RASTER_STATE);
|
||||
|
||||
// Dither
|
||||
if (gstate.isDitherEnabled()) {
|
||||
glstate.dither.enable();
|
||||
glstate.dither.set(true);
|
||||
} else {
|
||||
glstate.dither.disable();
|
||||
}
|
||||
bool dither = gstate.isDitherEnabled();
|
||||
bool cullEnable;
|
||||
GLenum cullMode = cullingMode[gstate.getCullMode() ^ !useBufferedRendering];
|
||||
|
||||
if (gstate.isModeClear()) {
|
||||
// Culling
|
||||
glstate.cullFace.disable();
|
||||
cullEnable = false;
|
||||
} else {
|
||||
// Set cull
|
||||
bool cullEnabled = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
|
||||
if (cullEnabled) {
|
||||
glstate.cullFace.enable();
|
||||
glstate.cullFaceMode.set(cullingMode[gstate.getCullMode() ^ !useBufferedRendering]);
|
||||
} else {
|
||||
glstate.cullFace.disable();
|
||||
}
|
||||
cullEnable = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
|
||||
}
|
||||
renderManager->SetRaster(cullEnable, GL_CCW, cullMode, dither);
|
||||
}
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE)) {
|
||||
@ -284,51 +273,24 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
bool enableStencilTest = !g_Config.bDisableStencilTest;
|
||||
if (gstate.isModeClear()) {
|
||||
// Depth Test
|
||||
glstate.depthTest.enable();
|
||||
glstate.depthFunc.set(GL_ALWAYS);
|
||||
glstate.depthWrite.set(gstate.isClearModeDepthMask() ? GL_TRUE : GL_FALSE);
|
||||
if (gstate.isClearModeDepthMask()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
// Stencil Test
|
||||
if (gstate.isClearModeAlphaMask() && enableStencilTest) {
|
||||
glstate.stencilTest.enable();
|
||||
glstate.stencilOp.set(GL_REPLACE, GL_REPLACE, GL_REPLACE);
|
||||
// TODO: In clear mode, the stencil value is set to the alpha value of the vertex.
|
||||
// A normal clear will be 2 points, the second point has the color.
|
||||
// We should set "ref" to that value instead of 0.
|
||||
// In case of clear rectangles, we set it again once we know what the color is.
|
||||
glstate.stencilFunc.set(GL_ALWAYS, 255, 0xFF);
|
||||
glstate.stencilMask.set(0xFF);
|
||||
} else {
|
||||
glstate.stencilTest.disable();
|
||||
}
|
||||
renderManager->SetStencil(gstate.isClearModeAlphaMask() && enableStencilTest, GL_ALWAYS, GL_REPLACE, GL_REPLACE, GL_REPLACE, 0xFF, 0xFF, 0xFF);
|
||||
renderManager->SetDepth(true, gstate.isClearModeDepthMask() ? true : false, GL_ALWAYS);
|
||||
} else {
|
||||
// Depth Test
|
||||
if (gstate.isDepthTestEnabled()) {
|
||||
glstate.depthTest.enable();
|
||||
glstate.depthFunc.set(compareOps[gstate.getDepthTestFunction()]);
|
||||
glstate.depthWrite.set(gstate.isDepthWriteEnabled() ? GL_TRUE : GL_FALSE);
|
||||
if (gstate.isDepthWriteEnabled()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
} else {
|
||||
glstate.depthTest.disable();
|
||||
renderManager->SetDepth(gstate.isDepthTestEnabled(), gstate.isDepthWriteEnabled(), compareOps[gstate.getDepthTestFunction()]);
|
||||
if (gstate.isDepthTestEnabled() && gstate.isDepthWriteEnabled()) {
|
||||
framebufferManager_->SetDepthUpdated();
|
||||
}
|
||||
|
||||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
// Stencil Test
|
||||
if (stencilState.enabled) {
|
||||
glstate.stencilTest.enable();
|
||||
glstate.stencilFunc.set(compareOps[stencilState.testFunc], stencilState.testRef, stencilState.testMask);
|
||||
glstate.stencilOp.set(stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
|
||||
glstate.stencilMask.set(stencilState.writeMask);
|
||||
} else {
|
||||
glstate.stencilTest.disable();
|
||||
}
|
||||
renderManager->SetStencil(stencilState.enabled, compareOps[stencilState.testFunc],
|
||||
stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass],
|
||||
stencilState.writeMask, stencilState.testMask, stencilState.testRef);
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,21 +302,18 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
|
||||
vpAndScissor);
|
||||
|
||||
if (vpAndScissor.scissorEnable) {
|
||||
glstate.scissorTest.enable();
|
||||
if (!useBufferedRendering) {
|
||||
vpAndScissor.scissorY = PSP_CoreParameter().pixelHeight - vpAndScissor.scissorH - vpAndScissor.scissorY;
|
||||
}
|
||||
glstate.scissorRect.set(vpAndScissor.scissorX, vpAndScissor.scissorY, vpAndScissor.scissorW, vpAndScissor.scissorH);
|
||||
} else {
|
||||
glstate.scissorTest.disable();
|
||||
if (!useBufferedRendering) {
|
||||
vpAndScissor.scissorY = PSP_CoreParameter().pixelHeight - vpAndScissor.scissorH - vpAndScissor.scissorY;
|
||||
}
|
||||
renderManager->SetScissor(GLRect2D{ vpAndScissor.scissorX, vpAndScissor.scissorY, vpAndScissor.scissorW, vpAndScissor.scissorH });
|
||||
|
||||
if (!useBufferedRendering) {
|
||||
vpAndScissor.viewportY = PSP_CoreParameter().pixelHeight - vpAndScissor.viewportH - vpAndScissor.viewportY;
|
||||
}
|
||||
glstate.viewport.set(vpAndScissor.viewportX, vpAndScissor.viewportY, vpAndScissor.viewportW, vpAndScissor.viewportH);
|
||||
glstate.depthRange.set(vpAndScissor.depthRangeMin, vpAndScissor.depthRangeMax);
|
||||
renderManager->SetViewport({
|
||||
vpAndScissor.viewportX, vpAndScissor.viewportY,
|
||||
vpAndScissor.viewportW, vpAndScissor.viewportH,
|
||||
vpAndScissor.depthRangeMin, vpAndScissor.depthRangeMax });
|
||||
|
||||
if (vpAndScissor.dirtyProj) {
|
||||
gstate_c.Dirty(DIRTY_PROJMATRIX);
|
||||
@ -363,7 +322,6 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
gstate_c.Dirty(DIRTY_DEPTHRANGE);
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
}
|
||||
|
||||
void DrawEngineGLES::ApplyDrawStateLate() {
|
||||
@ -371,32 +329,20 @@ void DrawEngineGLES::ApplyDrawStateLate() {
|
||||
// TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)?
|
||||
if (!gstate.isModeClear()) {
|
||||
if (fboTexNeedBind_) {
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
// Note that this is positions, not UVs, that we need the copy from.
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
|
||||
framebufferManager_->RebindFramebuffer();
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
// If we are rendering at a higher resolution, linear is probably best for the dest color.
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
fboTexBound_ = true;
|
||||
fboTexNeedBind_ = false;
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
|
||||
// Apply the texture after the FBO tex, since it might unbind the texture.
|
||||
// TODO: Could use a separate texture unit to be safer?
|
||||
textureCache_->ApplyTexture();
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
|
||||
// Apply last, once we know the alpha params of the texture.
|
||||
if (gstate.isAlphaTestEnabled() || gstate.isColorTestEnabled()) {
|
||||
fragmentTestCache_->BindTestTexture(GL_TEXTURE2);
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
}
|
||||
}
|
||||
|
@ -164,25 +164,14 @@ void TextureCacheGLES::UpdateSamplingParams(TexCacheEntry &entry, bool force) {
|
||||
}
|
||||
}
|
||||
|
||||
if (force || entry.minFilt != minFilt) {
|
||||
if (force || entry.minFilt != minFilt || entry.magFilt != magFilt || entry.sClamp != sClamp || entry.tClamp != tClamp) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, MinFiltGL[minFilt]);
|
||||
entry.minFilt = minFilt;
|
||||
}
|
||||
if (force || entry.magFilt != magFilt) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, MagFiltGL[magFilt]);
|
||||
entry.magFilt = magFilt;
|
||||
}
|
||||
|
||||
if (entry.framebuffer) {
|
||||
WARN_LOG_REPORT_ONCE(wrongFramebufAttach, G3D, "Framebuffer still attached in UpdateSamplingParams()?");
|
||||
}
|
||||
|
||||
if (force || entry.sClamp != sClamp) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
entry.sClamp = sClamp;
|
||||
}
|
||||
if (force || entry.tClamp != tClamp) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
entry.minFilt = minFilt;
|
||||
entry.magFilt = magFilt;
|
||||
entry.sClamp = sClamp;
|
||||
entry.tClamp = tClamp;
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
@ -201,6 +190,8 @@ void TextureCacheGLES::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferH
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, MinFiltGL[minFilt]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, MagFiltGL[magFilt]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
|
||||
// Often the framebuffer will not match the texture size. We'll wrap/clamp in the shader in that case.
|
||||
// This happens whether we have OES_texture_npot or not.
|
||||
@ -209,9 +200,6 @@ void TextureCacheGLES::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferH
|
||||
if (w != bufferWidth || h != bufferHeight) {
|
||||
return;
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
}
|
||||
|
||||
static void ConvertColors(void *dstBuf, const void *srcBuf, GLuint dstFmt, int numPixels) {
|
||||
@ -336,14 +324,11 @@ bool SetDebugTexture() {
|
||||
#endif
|
||||
|
||||
void TextureCacheGLES::BindTexture(TexCacheEntry *entry) {
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
if (entry->textureName != lastBoundTexture) {
|
||||
glBindTexture(GL_TEXTURE_2D, entry->textureName);
|
||||
lastBoundTexture = entry->textureName;
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
UpdateSamplingParams(*entry, false);
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
}
|
||||
|
||||
void TextureCacheGLES::Unbind() {
|
||||
|
@ -53,6 +53,24 @@ void GLQueueRunner::RunInitSteps(const std::vector<GLRInitStep> &steps) {
|
||||
for (auto iter : program->semantics_) {
|
||||
glBindAttribLocation(program->program, iter.location, iter.attrib);
|
||||
}
|
||||
|
||||
#if !defined(USING_GLES2)
|
||||
if (step.create_program.support_dual_source) {
|
||||
// Dual source alpha
|
||||
glBindFragDataLocationIndexed(program->program, 0, 0, "fragColor0");
|
||||
glBindFragDataLocationIndexed(program->program, 0, 1, "fragColor1");
|
||||
} else if (gl_extensions.VersionGEThan(3, 3, 0)) {
|
||||
glBindFragDataLocation(program->program, 0, "fragColor0");
|
||||
}
|
||||
#elif !defined(IOS)
|
||||
if (gl_extensions.GLES3) {
|
||||
if (gstate_c.featureFlags & GPU_SUPPORTS_DUALSOURCE_BLEND) {
|
||||
glBindFragDataLocationIndexedEXT(program->program, 0, 0, "fragColor0");
|
||||
glBindFragDataLocationIndexedEXT(program->program, 0, 1, "fragColor1");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
glLinkProgram(program->program);
|
||||
|
||||
GLint linkStatus = GL_FALSE;
|
||||
@ -86,6 +104,13 @@ void GLQueueRunner::RunInitSteps(const std::vector<GLRInitStep> &steps) {
|
||||
}
|
||||
}
|
||||
|
||||
// Query all the uniforms.
|
||||
for (int i = 0; i < program->queries_.size(); i++) {
|
||||
auto &x = program->queries_[i];
|
||||
assert(x.name);
|
||||
*x.dest = glGetUniformLocation(program->program, x.name);
|
||||
}
|
||||
|
||||
// Here we could (using glGetAttribLocation) save a bitmask about which pieces of vertex data are used in the shader
|
||||
// and then AND it with the vertex format bitmask later...
|
||||
}
|
||||
@ -193,6 +218,8 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
GLRProgram *curProgram = nullptr;
|
||||
GLint activeTexture = GL_TEXTURE0;
|
||||
|
||||
int attrMask = 0;
|
||||
|
||||
auto &commands = step.commands;
|
||||
for (const auto &c : commands) {
|
||||
switch (c.cmd) {
|
||||
@ -245,7 +272,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
break;
|
||||
case GLRRenderCommand::UNIFORM4F:
|
||||
{
|
||||
int loc = c.uniform4.loc;
|
||||
int loc = c.uniform4.loc ? *c.uniform4.loc : -1;
|
||||
if (c.uniform4.name) {
|
||||
loc = curProgram->GetUniformLoc(c.uniform4.name);
|
||||
}
|
||||
@ -267,9 +294,33 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GLRRenderCommand::UNIFORM4I:
|
||||
{
|
||||
int loc = c.uniform4.loc ? *c.uniform4.loc : -1;
|
||||
if (c.uniform4.name) {
|
||||
loc = curProgram->GetUniformLoc(c.uniform4.name);
|
||||
}
|
||||
if (loc >= 0) {
|
||||
switch (c.uniform4.count) {
|
||||
case 1:
|
||||
glUniform1iv(loc, 1, (GLint *)&c.uniform4.v[0]);
|
||||
break;
|
||||
case 2:
|
||||
glUniform2iv(loc, 1, (GLint *)c.uniform4.v);
|
||||
break;
|
||||
case 3:
|
||||
glUniform3iv(loc, 1, (GLint *)c.uniform4.v);
|
||||
break;
|
||||
case 4:
|
||||
glUniform4iv(loc, 1, (GLint *)c.uniform4.v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GLRRenderCommand::UNIFORMMATRIX:
|
||||
{
|
||||
int loc = c.uniform4.loc;
|
||||
int loc = c.uniform4.loc ? *c.uniform4.loc : -1;
|
||||
if (c.uniform4.name) {
|
||||
loc = curProgram->GetUniformLoc(c.uniform4.name);
|
||||
}
|
||||
@ -302,10 +353,16 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
case GLRRenderCommand::BIND_INPUT_LAYOUT:
|
||||
{
|
||||
GLRInputLayout *layout = c.inputLayout.inputLayout;
|
||||
int enable, disable;
|
||||
enable = layout->semanticsMask_ & ~attrMask;
|
||||
disable = (~layout->semanticsMask_) & attrMask;
|
||||
for (int i = 0; i < 7; i++) { // SEM_MAX
|
||||
if (layout->semanticsMask_ & (1 << i)) {
|
||||
if (enable & (1 << i)) {
|
||||
glEnableVertexAttribArray(i);
|
||||
}
|
||||
if (disable & (1 << i)) {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < layout->entries.size(); i++) {
|
||||
auto &entry = layout->entries[i];
|
||||
@ -319,16 +376,6 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buf);
|
||||
break;
|
||||
}
|
||||
case GLRRenderCommand::UNBIND_INPUT_LAYOUT:
|
||||
{
|
||||
GLRInputLayout *layout = c.inputLayout.inputLayout;
|
||||
for (int i = 0; i < 7; i++) { // SEM_MAX
|
||||
if (layout->semanticsMask_ & (1 << i)) {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GLRRenderCommand::GENMIPS:
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
break;
|
||||
@ -354,6 +401,11 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
} else {
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
if (c.raster.ditherEnable) {
|
||||
glEnable(GL_DITHER);
|
||||
} else {
|
||||
glDisable(GL_DITHER);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Crash();
|
||||
@ -361,6 +413,12 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
if (attrMask & (1 << i)) {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (activeTexture != GL_TEXTURE0)
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
@ -31,6 +31,7 @@ enum class GLRRenderCommand : uint8_t {
|
||||
STENCIL,
|
||||
BLEND,
|
||||
BLENDCOLOR,
|
||||
UNIFORM4I,
|
||||
UNIFORM4F,
|
||||
UNIFORMMATRIX,
|
||||
TEXTURESAMPLER,
|
||||
@ -43,13 +44,14 @@ enum class GLRRenderCommand : uint8_t {
|
||||
BIND_FB_TEXTURE,
|
||||
BIND_INPUT_LAYOUT,
|
||||
BIND_VERTEX_BUFFER,
|
||||
UNBIND_INPUT_LAYOUT,
|
||||
GENMIPS,
|
||||
DRAW,
|
||||
DRAW_INDEXED,
|
||||
PUSH_CONSTANTS,
|
||||
};
|
||||
|
||||
// TODO: Bloated since the biggest struct decides the size. Will need something more efficient (separate structs with shared
|
||||
// type field, smashed right after each other?)
|
||||
struct GLRRenderData {
|
||||
GLRRenderCommand cmd;
|
||||
union {
|
||||
@ -96,13 +98,13 @@ struct GLRRenderData {
|
||||
} drawIndexed;
|
||||
struct {
|
||||
const char *name; // if null, use loc
|
||||
GLint loc;
|
||||
GLint *loc; // NOTE: This is a pointer so we can immediately use things that are "queried" during program creation.
|
||||
GLint count;
|
||||
float v[4];
|
||||
} uniform4;
|
||||
struct {
|
||||
const char *name; // if null, use loc
|
||||
GLint loc;
|
||||
GLint *loc;
|
||||
float m[16];
|
||||
} uniformMatrix4;
|
||||
struct {
|
||||
@ -146,6 +148,7 @@ struct GLRRenderData {
|
||||
GLboolean cullEnable;
|
||||
GLenum frontFace;
|
||||
GLenum cullFace;
|
||||
GLboolean ditherEnable;
|
||||
} raster;
|
||||
};
|
||||
};
|
||||
@ -185,6 +188,7 @@ struct GLRInitStep {
|
||||
GLRProgram *program;
|
||||
GLRShader *shaders[3];
|
||||
int num_shaders;
|
||||
bool support_dual_source;
|
||||
} create_program;
|
||||
struct {
|
||||
GLRBuffer *buffer;
|
||||
|
@ -83,8 +83,15 @@ public:
|
||||
int location;
|
||||
const char *attrib;
|
||||
};
|
||||
|
||||
struct UniformLocQuery {
|
||||
GLint *dest;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
GLuint program = 0;
|
||||
std::vector<Semantic> semantics_;
|
||||
std::vector<UniformLocQuery> queries_;
|
||||
|
||||
struct UniformInfo {
|
||||
int loc_;
|
||||
@ -196,10 +203,10 @@ public:
|
||||
return step.create_texture.texture;
|
||||
}
|
||||
|
||||
GLRBuffer *CreateBuffer(GLuint target, int size, GLuint usage) {
|
||||
GLRBuffer *CreateBuffer(GLuint target, size_t size, GLuint usage) {
|
||||
GLRInitStep step{ GLRInitStepType::CREATE_BUFFER };
|
||||
step.create_buffer.buffer = new GLRBuffer(target);
|
||||
step.create_buffer.size = size;
|
||||
step.create_buffer.size = (int)size;
|
||||
step.create_buffer.usage = usage;
|
||||
initSteps_.push_back(step);
|
||||
return step.create_buffer.buffer;
|
||||
@ -215,14 +222,23 @@ public:
|
||||
return step.create_shader.shader;
|
||||
}
|
||||
|
||||
GLRProgram *CreateProgram(std::vector<GLRShader *> shaders, std::vector<GLRProgram::Semantic> semantics) {
|
||||
GLRProgram *CreateProgram(std::vector<GLRShader *> shaders, std::vector<GLRProgram::Semantic> semantics, std::vector<GLRProgram::UniformLocQuery> queries, bool supportDualSource) {
|
||||
GLRInitStep step{ GLRInitStepType::CREATE_PROGRAM };
|
||||
assert(shaders.size() <= ARRAY_SIZE(step.create_program.shaders));
|
||||
step.create_program.program = new GLRProgram();
|
||||
step.create_program.program->semantics_ = semantics;
|
||||
step.create_program.program->queries_ = queries;
|
||||
for (int i = 0; i < shaders.size(); i++) {
|
||||
step.create_program.shaders[i] = shaders[i];
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
for (auto &iter : queries) {
|
||||
assert(iter.name);
|
||||
}
|
||||
for (auto &sem : semantics) {
|
||||
assert(sem.attrib);
|
||||
}
|
||||
#endif
|
||||
step.create_program.num_shaders = (int)shaders.size();
|
||||
initSteps_.push_back(step);
|
||||
return step.create_program.program;
|
||||
@ -320,14 +336,6 @@ public:
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void UnbindInputLayout(GLRInputLayout *inputLayout) {
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
assert(inputLayout);
|
||||
GLRRenderData data{ GLRRenderCommand::UNBIND_INPUT_LAYOUT };
|
||||
data.inputLayout.inputLayout = inputLayout;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void GenerateMipmap() {
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
GLRRenderData data{ GLRRenderCommand::GENMIPS };
|
||||
@ -357,7 +365,25 @@ public:
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetUniformF(int loc, int count, const float *udata) {
|
||||
void SetUniformI(GLint *loc, int count, const int *udata) {
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
GLRRenderData data{ GLRRenderCommand::UNIFORM4I };
|
||||
data.uniform4.loc = loc;
|
||||
data.uniform4.count = count;
|
||||
memcpy(data.uniform4.v, udata, sizeof(int) * count);
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetUniformI1(GLint *loc, int udata) {
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
GLRRenderData data{ GLRRenderCommand::UNIFORM4I };
|
||||
data.uniform4.loc = loc;
|
||||
data.uniform4.count = 1;
|
||||
memcpy(data.uniform4.v, &udata, sizeof(udata));
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetUniformF(GLint *loc, int count, const float *udata) {
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
GLRRenderData data{ GLRRenderCommand::UNIFORM4F };
|
||||
data.uniform4.loc = loc;
|
||||
@ -375,7 +401,7 @@ public:
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetUniformM4x4(int loc, const float *udata) {
|
||||
void SetUniformM4x4(GLint *loc, const float *udata) {
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
GLRRenderData data{ GLRRenderCommand::UNIFORM4F };
|
||||
data.uniformMatrix4.loc = loc;
|
||||
@ -405,6 +431,14 @@ public:
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetNoBlendAndMask(int colorMask) {
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
GLRRenderData data{ GLRRenderCommand::BLEND };
|
||||
data.blend.mask = colorMask;
|
||||
data.blend.enabled = false;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetStencil(bool enabled, GLenum func, GLenum sFail, GLenum zFail, GLenum pass, uint8_t writeMask, uint8_t compareMask, uint8_t refValue) {
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
GLRRenderData data{ GLRRenderCommand::STENCIL };
|
||||
@ -418,19 +452,20 @@ public:
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetBlendFactor(float color[4]) {
|
||||
void SetBlendFactor(const float color[4]) {
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
GLRRenderData data{ GLRRenderCommand::BLENDCOLOR };
|
||||
CopyFloat4(data.blendColor.color, color);
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetRaster(GLboolean cullEnable, GLenum frontFace, GLenum cullFace) {
|
||||
void SetRaster(GLboolean cullEnable, GLenum frontFace, GLenum cullFace, GLboolean ditherEnable) {
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
GLRRenderData data{ GLRRenderCommand::RASTER };
|
||||
data.raster.cullEnable = cullEnable;
|
||||
data.raster.frontFace = frontFace;
|
||||
data.raster.cullFace = cullFace;
|
||||
data.raster.ditherEnable = ditherEnable;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
|
@ -214,7 +214,7 @@ public:
|
||||
class OpenGLRasterState : public RasterState {
|
||||
public:
|
||||
void Apply(GLRenderManager *render) {
|
||||
render->SetRaster(cullEnable, frontFace, cullMode);
|
||||
render->SetRaster(cullEnable, frontFace, cullMode, false);
|
||||
}
|
||||
|
||||
GLboolean cullEnable;
|
||||
@ -1098,7 +1098,8 @@ bool OpenGLPipeline::LinkShaders() {
|
||||
semantics.push_back({ SEM_NORMAL, "Normal" });
|
||||
semantics.push_back({ SEM_TANGENT, "Tangent" });
|
||||
semantics.push_back({ SEM_BINORMAL, "Binormal" });
|
||||
program_ = render_->CreateProgram(linkShaders, semantics);
|
||||
std::vector<GLRProgram::UniformLocQuery> queries;
|
||||
program_ = render_->CreateProgram(linkShaders, semantics, queries, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1134,8 +1135,6 @@ void OpenGLContext::Draw(int vertexCount, int offset) {
|
||||
ApplySamplers();
|
||||
|
||||
renderManager_.Draw(curPipeline_->prim, offset, vertexCount);
|
||||
|
||||
renderManager_.UnbindInputLayout(curPipeline_->inputLayout->inputLayout_);
|
||||
}
|
||||
|
||||
void OpenGLContext::DrawIndexed(int vertexCount, int offset) {
|
||||
@ -1146,7 +1145,6 @@ void OpenGLContext::DrawIndexed(int vertexCount, int offset) {
|
||||
curIBuffer_->Bind(curIBufferOffset_);
|
||||
|
||||
renderManager_.DrawIndexed(curPipeline_->prim, vertexCount, GL_UNSIGNED_INT, (void *)(intptr_t)offset);
|
||||
renderManager_.UnbindInputLayout(curPipeline_->inputLayout->inputLayout_);
|
||||
}
|
||||
|
||||
void OpenGLContext::DrawUP(const void *vdata, int vertexCount) {
|
||||
@ -1165,7 +1163,6 @@ void OpenGLContext::DrawUP(const void *vdata, int vertexCount) {
|
||||
renderManager_.BindInputLayout(curPipeline_->inputLayout->inputLayout_, (void *)offset);
|
||||
|
||||
renderManager_.Draw(curPipeline_->prim, 0, vertexCount);
|
||||
renderManager_.UnbindInputLayout(curPipeline_->inputLayout->inputLayout_);
|
||||
renderManager_.BindVertexBuffer(nullptr);
|
||||
#else
|
||||
ApplySamplers();
|
||||
|
Loading…
Reference in New Issue
Block a user