blob: 60a8ae282f02889f30177ee784caf9e13a064153 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "CoreProfileEngine.h"
#include "CoreProfileEngineShaders.h"
#include "GLcommon/GLEScontext.h"
#include "GLcommon/GLESpointer.h"
#include "GLEScmContext.h"
#include "aemu/base/containers/Lookup.h"
#include "host-common/crash_reporter.h"
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <glm/gtc/matrix_inverse.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
CoreProfileEngine::CoreProfileEngine(GLEScmContext* ctx, bool onGles) :
mCtx(ctx),
mOnGles(onGles) {
getGeometryDrawState();
}
CoreProfileEngine::~CoreProfileEngine() {
teardown();
}
static const uint32_t sDrawTexIbo[] = {
0, 1, 2, 0, 2, 3,
};
const CoreProfileEngine::DrawTexOESCoreState& CoreProfileEngine::getDrawTexOESCoreState() {
if (!m_drawTexOESCoreState.program) {
m_drawTexOESCoreState.vshader =
GLEScontext::compileAndValidateCoreShader(
GL_VERTEX_SHADER,
mOnGles ? kDrawTexOESGles2_vshader : kDrawTexOESCore_vshader);
m_drawTexOESCoreState.fshader =
GLEScontext::compileAndValidateCoreShader(
GL_FRAGMENT_SHADER,
mOnGles ? kDrawTexOESGles2_fshader : kDrawTexOESCore_fshader);
m_drawTexOESCoreState.program =
GLEScontext::linkAndValidateProgram(m_drawTexOESCoreState.vshader,
m_drawTexOESCoreState.fshader);
}
if (!m_drawTexOESCoreState.vao) {
GLDispatch& gl = GLEScontext::dispatcher();
gl.glGenVertexArrays(1, &m_drawTexOESCoreState.vao);
gl.glBindVertexArray(m_drawTexOESCoreState.vao);
// Initialize VBO
// Save IBO, attrib arrays/pointers to VAO
gl.glGenBuffers(1, &m_drawTexOESCoreState.ibo);
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_drawTexOESCoreState.ibo);
gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(sDrawTexIbo), sDrawTexIbo, GL_STATIC_DRAW);
gl.glGenBuffers(1, &m_drawTexOESCoreState.vbo);
gl.glBindBuffer(GL_ARRAY_BUFFER, m_drawTexOESCoreState.vbo);
gl.glEnableVertexAttribArray(0); // pos
gl.glEnableVertexAttribArray(1); // texcoord
gl.glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (GLvoid*)0);
gl.glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
(GLvoid*)(uintptr_t)(3 * sizeof(float)));
gl.glBindVertexArray(0);
gl.glBindBuffer(GL_ARRAY_BUFFER, 0);
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
return m_drawTexOESCoreState;
}
void CoreProfileEngine::teardown() {
GLDispatch& gl = GLEScontext::dispatcher();
if (m_drawTexOESCoreState.program) {
gl.glDeleteProgram(m_drawTexOESCoreState.program);
m_drawTexOESCoreState.program = 0;
}
if (m_drawTexOESCoreState.vao) {
gl.glBindVertexArray(0);
gl.glDeleteVertexArrays(1, &m_drawTexOESCoreState.vao);
gl.glDeleteBuffers(1, &m_drawTexOESCoreState.ibo);
gl.glDeleteBuffers(1, &m_drawTexOESCoreState.vbo);
m_drawTexOESCoreState.vao = 0;
m_drawTexOESCoreState.vbo = 0;
m_drawTexOESCoreState.ibo = 0;
}
if (m_geometryDrawState.program) {
gl.glDeleteProgram(m_geometryDrawState.program);
m_geometryDrawState.program = 0;
}
if (m_geometryDrawState.programFlat) {
gl.glDeleteProgram(m_geometryDrawState.programFlat);
m_geometryDrawState.programFlat = 0;
}
if (m_geometryDrawState.vao) {
gl.glDeleteVertexArrays(1, &m_geometryDrawState.vao);
m_geometryDrawState.vao = 0;
}
if (m_geometryDrawState.posVbo) {
gl.glDeleteBuffers(1, &m_geometryDrawState.posVbo);
m_geometryDrawState.posVbo = 0;
}
if (m_geometryDrawState.normalVbo) {
gl.glDeleteBuffers(1, &m_geometryDrawState.normalVbo);
m_geometryDrawState.normalVbo = 0;
}
if (m_geometryDrawState.colorVbo) {
gl.glDeleteBuffers(1, &m_geometryDrawState.colorVbo);
m_geometryDrawState.colorVbo = 0;
}
if (m_geometryDrawState.pointsizeVbo) {
gl.glDeleteBuffers(1, &m_geometryDrawState.pointsizeVbo);
m_geometryDrawState.pointsizeVbo = 0;
}
if (m_geometryDrawState.texcoordVbo) {
gl.glDeleteBuffers(1, &m_geometryDrawState.texcoordVbo);
m_geometryDrawState.texcoordVbo = 0;
}
if (m_geometryDrawState.ibo) {
gl.glDeleteBuffers(1, &m_geometryDrawState.ibo);
m_geometryDrawState.ibo = 0;
}
}
// Match attribute locations in the shader below.
static GLint arrayTypeToCoreAttrib(GLenum type) {
switch (type) {
case GL_VERTEX_ARRAY:
return 0;
case GL_NORMAL_ARRAY:
return 1;
case GL_COLOR_ARRAY:
return 2;
case GL_POINT_SIZE_ARRAY_OES:
return 3;
case GL_TEXTURE_COORD_ARRAY:
return 4;
}
fprintf(stderr, "%s: error: unsupported array type 0x%x\n",
__func__, type);
return 0;
}
static std::string sMakeGeometryDrawShader(bool isGles, GLenum shaderType, bool flat) {
// Set up a std::string to hold the result of
// interpolating the template. We will require some extra padding
// in the result string depending on how many characters
// we could potentially insert.
// For now it's just 10 chars and for a
// single interpolation qualifier |flat|.
static const char versionPartEssl300[] = "#version 300 es\n";
static const char versionPart330Core[] = "#version 330 core\n";
static const char flatKeyword[] = "flat";
size_t extraStringLengthRequired = 10 +
sizeof(versionPartEssl300) +
sizeof(versionPart330Core) +
sizeof(flatKeyword);
size_t reservation = extraStringLengthRequired;
std::string res;
const char* shaderTemplate = nullptr;
switch (shaderType) {
case GL_VERTEX_SHADER:
reservation += sizeof(kGeometryDrawVShaderSrcTemplateCore);
shaderTemplate = kGeometryDrawVShaderSrcTemplateCore;
break;
case GL_FRAGMENT_SHADER:
reservation += sizeof(kGeometryDrawFShaderSrcTemplateCore);
shaderTemplate = kGeometryDrawFShaderSrcTemplateCore;
break;
default:
break;
// emugl_crash_reporter(
// "%s: unknown shader type 0x%x (memory corrupt)\n", __func__,
// shaderType);
}
if (shaderTemplate) {
res.resize(reservation);
snprintf(&res[0], res.size(), shaderTemplate,
isGles ? versionPartEssl300 : versionPart330Core,
flat ? flatKeyword : "");
}
return res;
}
const CoreProfileEngine::GeometryDrawState& CoreProfileEngine::getGeometryDrawState() {
auto& gl = GLEScontext::dispatcher();
if (!m_geometryDrawState.program) {
// Non-flat shader
m_geometryDrawState.vshader =
GLEScontext::compileAndValidateCoreShader(
GL_VERTEX_SHADER,
sMakeGeometryDrawShader(mOnGles, GL_VERTEX_SHADER, false /* no flat shading */).c_str());
m_geometryDrawState.fshader =
GLEScontext::compileAndValidateCoreShader(
GL_FRAGMENT_SHADER,
sMakeGeometryDrawShader(mOnGles, GL_FRAGMENT_SHADER, false /* no flat shading */).c_str());
m_geometryDrawState.program =
GLEScontext::linkAndValidateProgram(m_geometryDrawState.vshader,
m_geometryDrawState.fshader);
m_geometryDrawState.vshaderFlat =
GLEScontext::compileAndValidateCoreShader(
GL_VERTEX_SHADER,
sMakeGeometryDrawShader(mOnGles, GL_VERTEX_SHADER, true /* flat shading */).c_str());
m_geometryDrawState.fshaderFlat =
GLEScontext::compileAndValidateCoreShader(
GL_FRAGMENT_SHADER,
sMakeGeometryDrawShader(mOnGles, GL_FRAGMENT_SHADER, true /* flat shading */).c_str());
m_geometryDrawState.programFlat =
GLEScontext::linkAndValidateProgram(m_geometryDrawState.vshaderFlat,
m_geometryDrawState.fshaderFlat);
m_geometryDrawState.projMatrixLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "projection");
m_geometryDrawState.modelviewMatrixLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "modelview");
m_geometryDrawState.modelviewInvTrLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "modelview_invtr");
m_geometryDrawState.textureMatrixLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "texture_matrix");
m_geometryDrawState.textureSamplerLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "tex_sampler");
m_geometryDrawState.textureCubeSamplerLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "tex_cube_sampler");
m_geometryDrawState.enableTextureLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "enable_textures");
m_geometryDrawState.enableLightingLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "enable_lighting");
m_geometryDrawState.enableRescaleNormalLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "enable_rescale_normal");
m_geometryDrawState.enableNormalizeLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "enable_normalize");
m_geometryDrawState.enableColorMaterialLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "enable_color_material");
m_geometryDrawState.enableFogLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "enable_fog");
m_geometryDrawState.enableReflectionMapLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "enable_reflection_map");
m_geometryDrawState.textureEnvModeLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "texture_env_mode");
m_geometryDrawState.textureFormatLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "texture_format");
m_geometryDrawState.materialAmbientLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "material_ambient");
m_geometryDrawState.materialDiffuseLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "material_diffuse");
m_geometryDrawState.materialSpecularLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "material_specular");
m_geometryDrawState.materialEmissiveLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "material_emissive");
m_geometryDrawState.materialSpecularExponentLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "material_specular_exponent");
m_geometryDrawState.lightModelSceneAmbientLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_model_scene_ambient");
m_geometryDrawState.lightModelTwoSidedLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_model_two_sided");
m_geometryDrawState.lightEnablesLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_enables");
m_geometryDrawState.lightAmbientsLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_ambients");
m_geometryDrawState.lightDiffusesLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_diffuses");
m_geometryDrawState.lightSpecularsLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_speculars");
m_geometryDrawState.lightPositionsLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_positions");
m_geometryDrawState.lightDirectionsLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_directions");
m_geometryDrawState.lightSpotlightExponentsLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_spotlight_exponents");
m_geometryDrawState.lightSpotlightCutoffAnglesLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_spotlight_cutoff_angles");
m_geometryDrawState.lightAttenuationConstsLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_attenuation_consts");
m_geometryDrawState.lightAttenuationLinearsLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_attenuation_linears");
m_geometryDrawState.lightAttenuationQuadraticsLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "light_attenuation_quadratics");
m_geometryDrawState.fogModeLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "fog_mode");
m_geometryDrawState.fogDensityLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "fog_density");
m_geometryDrawState.fogStartLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "fog_start");
m_geometryDrawState.fogEndLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "fog_end");
m_geometryDrawState.fogColorLoc =
gl.glGetUniformLocation(m_geometryDrawState.program, "fog_color");
}
if (!m_geometryDrawState.vao) {
gl.glGenBuffers(1, &m_geometryDrawState.posVbo);
gl.glGenBuffers(1, &m_geometryDrawState.normalVbo);
gl.glGenBuffers(1, &m_geometryDrawState.colorVbo);
gl.glGenBuffers(1, &m_geometryDrawState.pointsizeVbo);
gl.glGenBuffers(1, &m_geometryDrawState.texcoordVbo);
gl.glGenVertexArrays(1, &m_geometryDrawState.vao);
gl.glBindVertexArray(m_geometryDrawState.vao);
gl.glGenBuffers(1, &m_geometryDrawState.ibo);
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_geometryDrawState.ibo);
gl.glBindVertexArray(0);
gl.glBindBuffer(GL_ARRAY_BUFFER, 0);
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
return m_geometryDrawState;
}
GLuint CoreProfileEngine::getVboFor(GLenum type) {
switch (type) {
case GL_VERTEX_ARRAY:
return m_geometryDrawState.posVbo;
case GL_NORMAL_ARRAY:
return m_geometryDrawState.normalVbo;
case GL_COLOR_ARRAY:
return m_geometryDrawState.colorVbo;
case GL_POINT_SIZE_ARRAY_OES:
return m_geometryDrawState.pointsizeVbo;
case GL_TEXTURE_COORD_ARRAY:
return m_geometryDrawState.texcoordVbo;
}
return 0;
}
size_t CoreProfileEngine::sizeOfType(GLenum type) {
switch (type) {
case GL_BYTE:
case GL_UNSIGNED_BYTE:
return 1;
case GL_SHORT:
case GL_UNSIGNED_SHORT:
case GL_HALF_FLOAT_OES:
return 2;
case GL_INT:
case GL_UNSIGNED_INT:
case GL_FLOAT:
return 4;
}
return 4;
}
template <class T>
static GLsizei sNeededVboCount(GLsizei indicesCount, const T* indices) {
T maxIndex = 0;
for (GLsizei i = 0; i < indicesCount; i++) {
T index = indices[i];
maxIndex = (index > maxIndex) ? index : maxIndex;
}
return (GLsizei)maxIndex + 1;
}
void CoreProfileEngine::setupArrayForDraw(
GLenum arrayType,
GLESpointer* p,
GLint first, GLsizei count,
bool isIndexed, GLenum indicesType, const GLvoid* indices) {
auto& gl = GLEScontext::dispatcher();
GLint attribNum = -1;
gl.glBindVertexArray(m_geometryDrawState.vao);
attribNum = arrayTypeToCoreAttrib(arrayType);
GLsizei vboCount = 0;
if (isIndexed) {
GLsizei indexSize = 4;
GLsizei indicesCount = count;
switch (indicesType) {
case GL_UNSIGNED_BYTE:
indexSize = 1;
vboCount = sNeededVboCount(indicesCount, (unsigned char*)indices);
break;
case GL_UNSIGNED_SHORT:
indexSize = 2;
vboCount = sNeededVboCount(indicesCount, (uint16_t*)indices);
break;
case GL_UNSIGNED_INT:
default:
indexSize = 4;
vboCount = sNeededVboCount(indicesCount, (uint32_t*)indices);
}
// And send the indices
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_geometryDrawState.ibo);
gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexSize * indicesCount, indices, GL_STREAM_DRAW);
} else {
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
vboCount = count;
}
if (p->isEnable()) {
gl.glEnableVertexAttribArray(attribNum);
gl.glBindBuffer(GL_ARRAY_BUFFER, getVboFor(arrayType));
GLESConversionArrays arrs;
bool convert = mCtx->doConvert(arrs, first, count, indicesType, indices, !isIndexed, p, arrayType);
ArrayData currentArr = arrs.getCurrentArray();
GLint size = p->getSize();
GLenum dataType = convert ? currentArr.type : p->getType();
GLsizei stride = convert ? currentArr.stride : p->getStride();
GLsizei effectiveStride =
stride ? stride :
(size * sizeOfType(dataType));
char* bufData = convert ? (char*)currentArr.data : (char*)p->getData();
uint32_t offset = first * effectiveStride;
uint32_t bufSize = offset + vboCount * effectiveStride;
gl.glBufferData(GL_ARRAY_BUFFER, bufSize, bufData, GL_STREAM_DRAW);
gl.glVertexAttribDivisor(attribNum, 0);
GLboolean shouldNormalize = false;
if (arrayType == GL_COLOR_ARRAY &&
(dataType == GL_BYTE ||
dataType == GL_UNSIGNED_BYTE ||
dataType == GL_INT ||
dataType == GL_UNSIGNED_INT ||
dataType == GL_FIXED))
shouldNormalize = true;
gl.glVertexAttribPointer(attribNum, size, dataType,
shouldNormalize ? GL_TRUE : GL_FALSE /* normalized */,
effectiveStride, nullptr /* no offset into vbo */);
gl.glBindBuffer(GL_ARRAY_BUFFER, 0);
} else {
if (arrayType == GL_COLOR_ARRAY ||
arrayType == GL_NORMAL_ARRAY ||
arrayType == GL_TEXTURE_COORD_ARRAY) {
gl.glEnableVertexAttribArray(attribNum);
gl.glBindBuffer(GL_ARRAY_BUFFER, getVboFor(arrayType));
GLint size;
std::vector<float> buffer;
switch (arrayType) {
case GL_COLOR_ARRAY:
size = 4;
mCtx->getColor(count, buffer);
break;
case GL_NORMAL_ARRAY:
size = 3;
mCtx->getNormal(count, buffer);
break;
case GL_TEXTURE_COORD_ARRAY:
size = 4;
mCtx->getMultiTexCoord(count, mCtx->getActiveTextureUnit(), buffer);
break;
default:
fprintf(stderr, "Error: Invalid array type %d.\n", arrayType);
mCtx->setGLerror(GL_INVALID_OPERATION);
return;
}
// We need a buffer large enough to hold `count` copies of the vertex attributes provided
// above.
GLsizei bufSize = count * size * sizeof(float);
gl.glBufferData(GL_ARRAY_BUFFER, bufSize, buffer.data(), GL_STREAM_DRAW);
// Stride is set to 0 to indicate that our values are tightly packed -- the driver will
// do the calculation.
gl.glVertexAttribPointer(attribNum, size, GL_FLOAT, GL_FALSE, 0, nullptr);
gl.glBindBuffer(GL_ARRAY_BUFFER, 0);
} else {
gl.glDisableVertexAttribArray(attribNum);
}
}
gl.glBindVertexArray(0);
}
// API
void CoreProfileEngine::enable(GLenum cap) {
switch (cap) {
case GL_TEXTURE_2D:
case GL_TEXTURE_CUBE_MAP_OES:
case GL_TEXTURE_GEN_STR_OES:
case GL_RESCALE_NORMAL:
case GL_NORMALIZE:
case GL_LIGHTING:
case GL_LIGHT0:
case GL_LIGHT1:
case GL_LIGHT2:
case GL_LIGHT3:
case GL_LIGHT4:
case GL_LIGHT5:
case GL_LIGHT6:
case GL_LIGHT7:
case GL_COLOR_MATERIAL:
case GL_FOG:
case GL_POINT_SMOOTH:
case GL_ALPHA_TEST:
return;
default:
break;
}
auto& gl = GLEScontext::dispatcher();
gl.glEnable(cap);
}
void CoreProfileEngine::disable(GLenum cap) {
switch (cap) {
case GL_TEXTURE_2D:
case GL_TEXTURE_CUBE_MAP_OES:
case GL_TEXTURE_GEN_STR_OES:
case GL_RESCALE_NORMAL:
case GL_NORMALIZE:
case GL_LIGHTING:
case GL_LIGHT0:
case GL_LIGHT1:
case GL_LIGHT2:
case GL_LIGHT3:
case GL_LIGHT4:
case GL_LIGHT5:
case GL_LIGHT6:
case GL_LIGHT7:
case GL_COLOR_MATERIAL:
case GL_FOG:
case GL_POINT_SMOOTH:
case GL_ALPHA_TEST:
return;
default:
break;
}
auto& gl = GLEScontext::dispatcher();
gl.glDisable(cap);
}
void CoreProfileEngine::shadeModel(GLenum mode) {
// no-op
}
void CoreProfileEngine::matrixMode(GLenum mode) {
// no-op
}
void CoreProfileEngine::loadIdentity() {
// no-op
}
void CoreProfileEngine::loadMatrixf(const GLfloat* m) {
// no-op
}
void CoreProfileEngine::pushMatrix() {
// no-op
}
void CoreProfileEngine::popMatrix() {
// no-op
}
void CoreProfileEngine::multMatrixf(const GLfloat* m) {
// no-op
}
void CoreProfileEngine::orthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) {
// no-op
}
void CoreProfileEngine::frustumf(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) {
// no-op
}
void CoreProfileEngine::texEnvf(GLenum target, GLenum pname, GLfloat param) {
// no-op
}
void CoreProfileEngine::texEnvfv(GLenum target, GLenum pname, const GLfloat* params) {
// no-op
}
void CoreProfileEngine::texEnvi(GLenum target, GLenum pname, GLint param) {
// no-op
}
void CoreProfileEngine::texEnviv(GLenum target, GLenum pname, const GLint* params) {
// no-op
}
void CoreProfileEngine::getTexEnvfv(GLenum env, GLenum pname, GLfloat* params) {
// no-op
}
void CoreProfileEngine::getTexEnviv(GLenum env, GLenum pname, GLint* params) {
// no-op
}
void CoreProfileEngine::texGenf(GLenum coord, GLenum pname, GLfloat param) {
// no-op
}
void CoreProfileEngine::texGenfv(GLenum coord, GLenum pname, const GLfloat* params) {
// no-op
}
void CoreProfileEngine::texGeni(GLenum coord, GLenum pname, GLint param) {
// no-op
}
void CoreProfileEngine::texGeniv(GLenum coord, GLenum pname, const GLint* params) {
// no-op
}
void CoreProfileEngine::getTexGeniv(GLenum coord, GLenum pname, GLint* params) {
// no-op
}
void CoreProfileEngine::getTexGenfv(GLenum coord, GLenum pname, GLfloat* params) {
// no-op
}
void CoreProfileEngine::enableClientState(GLenum clientState) {
// no-op
}
void CoreProfileEngine::disableClientState(GLenum clientState) {
// no-op
}
void CoreProfileEngine::drawTexOES(float x, float y, float z, float width, float height) {
auto& gl = GLEScontext::dispatcher();
// get viewport
GLint viewport[4] = {};
gl.glGetIntegerv(GL_VIEWPORT,viewport);
// track previous vbo/ibo
GLuint prev_vbo;
GLuint prev_ibo;
gl.glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&prev_vbo);
gl.glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, (GLint*)&prev_ibo);
// compile shaders, generate vbo/ibo if not done already
CoreProfileEngine::DrawTexOESCoreState drawTexState =
getDrawTexOESCoreState();
GLuint prog = drawTexState.program;
GLuint vbo = drawTexState.vbo;
GLuint vao = drawTexState.vao;
gl.glUseProgram(prog);
gl.glBindVertexArray(vao);
// This is not strictly needed, but Swiftshader indirect VAO
// can forget its ELEMENT_ARRAY_BUFFER binding.
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_drawTexOESCoreState.ibo);
GLint samplerLoc = gl.glGetUniformLocation(prog, "tex_sampler");
// Compute screen coordinates for our texture.
// Recenter, rescale. (e.g., [0, 0, 1080, 1920] -> [-1, -1, 1, 1])
float xNdc = 2.0f * (float)(x - viewport[0] - viewport[2] / 2) / (float)viewport[2];
float yNdc = 2.0f * (float)(y - viewport[1] - viewport[3] / 2) / (float)viewport[3];
float wNdc = 2.0f * (float)width / (float)viewport[2];
float hNdc = 2.0f * (float)height / (float)viewport[3];
z = z >= 1.0f ? 1.0f : z;
z = z <= 0.0f ? 0.0f : z;
float zNdc = z * 2.0f - 1.0f;
for (int i = 0; i < mCtx->getMaxTexUnits(); i++) {
if (mCtx->isTextureUnitEnabled(GL_TEXTURE0 + i)) {
GLuint bindedTex = mCtx->getBindedTexture(GL_TEXTURE0 + i, GL_TEXTURE_2D);
ObjectLocalName tex = mCtx->getTextureLocalName(GL_TEXTURE_2D, bindedTex);
auto objData = mCtx->shareGroup()->getObjectData(NamedObjectType::TEXTURE, tex);
if (objData) {
TextureData* texData = (TextureData*)objData;
float texCropX = (float)(texData->crop_rect[0]);
float texCropY = (float)(texData->crop_rect[1]);
float texCropW = (float)(texData->crop_rect[2]);
float texCropH = (float)(texData->crop_rect[3]);
float texW = (float)(texData->width);
float texH = (float)(texData->height);
// Now we know the vertex attributes (pos, texcoord).
// Our vertex attributes are formatted with interleaved
// position and texture coordinate:
float vertexAttrs[] = {
xNdc, yNdc, zNdc,
texCropX / texW, texCropY / texH,
xNdc + wNdc, yNdc, zNdc,
(texCropX + texCropW) / texW, texCropY / texH,
xNdc + wNdc, yNdc + hNdc, zNdc,
(texCropX + texCropW) / texW, (texCropY + texCropH) / texH,
xNdc, yNdc + hNdc, zNdc,
texCropX / texW, (texCropY + texCropH) / texH,
};
gl.glBindBuffer(GL_ARRAY_BUFFER, vbo);
gl.glBufferData(GL_ARRAY_BUFFER, sizeof(vertexAttrs),
vertexAttrs, GL_STREAM_DRAW);
}
gl.glActiveTexture(GL_TEXTURE0 + i);
gl.glUniform1i(samplerLoc, i);
gl.glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
}
gl.glBindVertexArray(0);
gl.glUseProgram(0);
gl.glBindBuffer(GL_ARRAY_BUFFER, prev_vbo);
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prev_ibo);
}
void CoreProfileEngine::rotatef(float angle, float x, float y, float z) {
// no-op
}
void CoreProfileEngine::scalef(float x, float y, float z) {
// no-op
}
void CoreProfileEngine::translatef(float x, float y, float z) {
// no-op
}
void CoreProfileEngine::color4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
// no-op
}
void CoreProfileEngine::color4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) {
// no-op
}
void CoreProfileEngine::activeTexture(GLenum unit) {
// Use 2 texture image units for each texture unit of GLES1.
// This allows us to simultaneously use GL_TEXTURE_2D
// and GL_TEXTURE_CUBE_MAP with the same texture unit through
// using different samplers for the image units.
GLEScontext::dispatcher().glActiveTexture(
GL_TEXTURE0 + mCtx->getActiveTextureUnit() * 2);
}
void CoreProfileEngine::clientActiveTexture(GLenum unit) {
GLEScontext::dispatcher().glActiveTexture(
GL_TEXTURE0 + mCtx->getActiveTextureUnit() * 2);
}
void CoreProfileEngine::preDrawTextureUnitEmulation() {
auto& gl = GLEScontext::dispatcher();
unsigned int currTextureUnit = mCtx->getActiveTextureUnit();
gl.glUniform1i(m_geometryDrawState.enableTextureLoc,
mCtx->isEnabled(GL_TEXTURE_2D) &&
mCtx->isArrEnabled(GL_TEXTURE_COORD_ARRAY));
gl.glUniform1i(m_geometryDrawState.textureSamplerLoc, currTextureUnit * 2);
gl.glUniform1i(m_geometryDrawState.textureCubeSamplerLoc, currTextureUnit * 2 + 1);
if (auto cubeMapTex = mCtx->getBindedTexture(currTextureUnit + GL_TEXTURE0, GL_TEXTURE_CUBE_MAP)) {
GLuint cubeMapTexGlobal = mCtx->shareGroup()->getGlobalName(
NamedObjectType::TEXTURE, cubeMapTex);
gl.glActiveTexture(GL_TEXTURE0 + currTextureUnit * 2);
gl.glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
gl.glActiveTexture(GL_TEXTURE0 + currTextureUnit * 2 + 1);
gl.glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMapTexGlobal);
gl.glActiveTexture(GL_TEXTURE0 + currTextureUnit * 2);
}
GLenum textureGenMode = mCtx->getTextureGenMode();
if (textureGenMode == GL_REFLECTION_MAP_OES) {
gl.glUniform1i(m_geometryDrawState.enableTextureLoc, 1);
gl.glUniform1i(m_geometryDrawState.enableReflectionMapLoc, 1);
} else {
gl.glUniform1i(m_geometryDrawState.enableReflectionMapLoc, 0);
}
auto bindedTex = mCtx->getBindedTexture(GL_TEXTURE_2D);
ObjectLocalName tex = mCtx->getTextureLocalName(GL_TEXTURE_2D, bindedTex);
auto objData = mCtx->shareGroup()->getObjectData(NamedObjectType::TEXTURE, tex);
if (objData) {
TextureData* texData = (TextureData*)objData;
gl.glUniform1i(m_geometryDrawState.textureFormatLoc, texData->internalFormat);
} else {
gl.glUniform1i(m_geometryDrawState.textureFormatLoc, GL_RGBA);
}
gl.glUniform1i(m_geometryDrawState.enableLightingLoc, 0);
gl.glUniform1i(m_geometryDrawState.textureEnvModeLoc, mCtx->getTextureEnvMode());
}
void CoreProfileEngine::postDrawTextureUnitEmulation() {
auto& gl = GLEScontext::dispatcher();
unsigned int currTextureUnit = mCtx->getActiveTextureUnit();
GLuint cubeMapTex = mCtx->getBindedTexture(currTextureUnit + GL_TEXTURE0, GL_TEXTURE_CUBE_MAP);
if (cubeMapTex) {
GLuint cubeMapTexGlobal = mCtx->shareGroup()->getGlobalName(
NamedObjectType::TEXTURE, cubeMapTex);
gl.glActiveTexture(GL_TEXTURE0 + currTextureUnit * 2);
gl.glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMapTexGlobal);
gl.glActiveTexture(GL_TEXTURE0 + currTextureUnit * 2 + 1);
gl.glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
gl.glActiveTexture(GL_TEXTURE0 + currTextureUnit * 2);
}
}
void CoreProfileEngine::preDrawVertexSetup() {
auto& gl = GLEScontext::dispatcher();
glm::mat4 currProjMatrix = mCtx->getProjMatrix();
glm::mat4 currModelviewMatrix = mCtx->getModelviewMatrix();
glm::mat4 currTextureMatrix = mCtx->getTextureMatrix();
glm::mat4 currModelviewMatrixInvTr = glm::inverseTranspose(currModelviewMatrix);
gl.glBindVertexArray(m_geometryDrawState.vao);
gl.glUseProgram(mCtx->getShadeModel() == GL_FLAT ?
m_geometryDrawState.programFlat :
m_geometryDrawState.program);
gl.glUniformMatrix4fv(m_geometryDrawState.projMatrixLoc, 1, GL_FALSE, glm::value_ptr(currProjMatrix));
gl.glUniformMatrix4fv(m_geometryDrawState.modelviewMatrixLoc, 1, GL_FALSE, glm::value_ptr(currModelviewMatrix));
gl.glUniformMatrix4fv(m_geometryDrawState.modelviewInvTrLoc, 1, GL_FALSE, glm::value_ptr(currModelviewMatrixInvTr));
gl.glUniformMatrix4fv(m_geometryDrawState.textureMatrixLoc, 1, GL_FALSE, glm::value_ptr(currTextureMatrix));
}
void CoreProfileEngine::postDrawVertexSetup() {
auto& gl = GLEScontext::dispatcher();
gl.glBindVertexArray(0);
}
void CoreProfileEngine::setupLighting() {
auto& gl = GLEScontext::dispatcher();
gl.glUniform1i(m_geometryDrawState.enableLightingLoc,
mCtx->isEnabled(GL_LIGHTING));
gl.glUniform1i(m_geometryDrawState.enableRescaleNormalLoc,
mCtx->isEnabled(GL_RESCALE_NORMAL));
gl.glUniform1i(m_geometryDrawState.enableNormalizeLoc,
mCtx->isEnabled(GL_NORMALIZE));
gl.glUniform1i(m_geometryDrawState.enableColorMaterialLoc,
mCtx->isEnabled(GL_COLOR_MATERIAL));
const auto& material = mCtx->getMaterialInfo();
gl.glUniform4fv(m_geometryDrawState.materialAmbientLoc, 1, material.ambient);
gl.glUniform4fv(m_geometryDrawState.materialDiffuseLoc, 1, material.diffuse);
gl.glUniform4fv(m_geometryDrawState.materialSpecularLoc, 1, material.specular);
gl.glUniform4fv(m_geometryDrawState.materialEmissiveLoc, 1, material.emissive);
gl.glUniform1f(m_geometryDrawState.materialSpecularExponentLoc, material.specularExponent);
const auto& lightModel = mCtx->getLightModelInfo();
gl.glUniform4fv(m_geometryDrawState.lightModelSceneAmbientLoc, 1, lightModel.color);
gl.glUniform1i(m_geometryDrawState.lightModelTwoSidedLoc, lightModel.twoSided);
assert(kMaxLights == GLEScmContext::kMaxLights);
for (int i = 0; i < GLEScmContext::kMaxLights; i++) {
m_lightingBuffer.lightEnables[i] = mCtx->isEnabled(GL_LIGHT0 + i);
const auto& light = mCtx->getLightInfo(i);
memcpy(m_lightingBuffer.lightAmbients + 4 * i, &light.ambient, 4 * sizeof(GLfloat));
memcpy(m_lightingBuffer.lightDiffuses + 4 * i, &light.diffuse, 4 * sizeof(GLfloat));
memcpy(m_lightingBuffer.lightSpeculars + 4 * i, &light.specular, 4 * sizeof(GLfloat));
memcpy(m_lightingBuffer.lightPositions + 4 * i, &light.position, 4 * sizeof(GLfloat));
memcpy(m_lightingBuffer.lightDirections + 3 * i, &light.direction, 3 * sizeof(GLfloat));
m_lightingBuffer.spotlightExponents[i] = light.spotlightExponent;
m_lightingBuffer.spotlightCutoffAngles[i] = light.spotlightCutoffAngle;
m_lightingBuffer.attenuationConsts[i] = light.attenuationConst;
m_lightingBuffer.attenuationLinears[i] = light.attenuationLinear;
m_lightingBuffer.attenuationQuadratics[i] = light.attenuationQuadratic;
}
gl.glUniform1iv(m_geometryDrawState.lightEnablesLoc, GLEScmContext::kMaxLights, m_lightingBuffer.lightEnables);
gl.glUniform4fv(m_geometryDrawState.lightAmbientsLoc, GLEScmContext::kMaxLights, m_lightingBuffer.lightAmbients);
gl.glUniform4fv(m_geometryDrawState.lightDiffusesLoc, GLEScmContext::kMaxLights, m_lightingBuffer.lightDiffuses);
gl.glUniform4fv(m_geometryDrawState.lightSpecularsLoc, GLEScmContext::kMaxLights, m_lightingBuffer.lightSpeculars);
gl.glUniform4fv(m_geometryDrawState.lightPositionsLoc, GLEScmContext::kMaxLights, m_lightingBuffer.lightPositions);
gl.glUniform3fv(m_geometryDrawState.lightDirectionsLoc, GLEScmContext::kMaxLights, m_lightingBuffer.lightDirections);
gl.glUniform1fv(m_geometryDrawState.lightSpotlightExponentsLoc, GLEScmContext::kMaxLights, m_lightingBuffer.spotlightExponents);
gl.glUniform1fv(m_geometryDrawState.lightSpotlightCutoffAnglesLoc, GLEScmContext::kMaxLights, m_lightingBuffer.spotlightCutoffAngles);
gl.glUniform1fv(m_geometryDrawState.lightAttenuationConstsLoc, GLEScmContext::kMaxLights, m_lightingBuffer.attenuationConsts);
gl.glUniform1fv(m_geometryDrawState.lightAttenuationLinearsLoc, GLEScmContext::kMaxLights, m_lightingBuffer.attenuationLinears);
gl.glUniform1fv(m_geometryDrawState.lightAttenuationQuadraticsLoc, GLEScmContext::kMaxLights, m_lightingBuffer.attenuationQuadratics);
}
void CoreProfileEngine::setupFog() {
auto& gl = GLEScontext::dispatcher();
gl.glUniform1i(m_geometryDrawState.enableFogLoc,
mCtx->isEnabled(GL_FOG));
const auto& fogInfo = mCtx->getFogInfo();
gl.glUniform1i(m_geometryDrawState.fogModeLoc, fogInfo.mode);
gl.glUniform1f(m_geometryDrawState.fogDensityLoc, fogInfo.density);
gl.glUniform1f(m_geometryDrawState.fogStartLoc, fogInfo.start);
gl.glUniform1f(m_geometryDrawState.fogEndLoc, fogInfo.end);
gl.glUniform4fv(m_geometryDrawState.fogColorLoc, 1, fogInfo.color);
}
void CoreProfileEngine::drawArrays(GLenum type, GLint first, GLsizei count) {
auto& gl = GLEScontext::dispatcher();
preDrawVertexSetup();
preDrawTextureUnitEmulation();
setupLighting();
setupFog();
gl.glDrawArrays(type, first, count);
postDrawVertexSetup();
postDrawTextureUnitEmulation();
}
void CoreProfileEngine::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) {
auto& gl = GLEScontext::dispatcher();
preDrawVertexSetup();
preDrawTextureUnitEmulation();
setupLighting();
setupFog();
gl.glDrawElements(mode, count, type, (GLvoid*)0);
postDrawVertexSetup();
postDrawTextureUnitEmulation();
}