Merge branch 'team-teaching' of https://github.com/highfidelity/hifi into punk

This commit is contained in:
Sam Gateau 2015-05-22 14:40:00 -07:00
commit a28c99bb40
14 changed files with 145 additions and 119 deletions

View file

@ -392,7 +392,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background
// downloads.
QSharedPointer<GeometryCache> geometryCacheP = DependencyManager::get<GeometryCache>();
ResourceCache *geometryCache = geometryCacheP.data();
ResourceCache* geometryCache = geometryCacheP.data();
connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets);
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
@ -3292,7 +3292,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
gpu::Batch batch;
model::Skybox::render(batch, _viewFrustum, *skybox);
gpu::GLBackend::renderBatch(batch);
gpu::GLBackend::renderBatch(batch, true);
glUseProgram(0);
}
}

View file

@ -126,8 +126,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
} else {
glScalef(dimensions.x, dimensions.y, dimensions.z);
// FIXME Remove non Batch version of renderWireCube once we use the render pipeline
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(1.0f, cubeColor);
DependencyManager::get<GeometryCache>()->renderWireCube(1.0f, cubeColor);
}
}
glPopMatrix();

View file

@ -510,7 +510,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode,
_tree->unlock();
glPushMatrix();
gpu::GLBackend::renderBatch(batch);
gpu::GLBackend::renderBatch(batch, true);
glPopMatrix();
// stats...

View file

@ -51,9 +51,9 @@ void RenderableTextEntityItem::render(RenderArgs* args) {
// TODO: Determine if we want these entities to have the deferred lighting effect? I think we do, so that the color
// used for a sphere, or box have the same look as those used on a text entity.
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram();
//DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram();
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, glm::vec4(toGlm(getBackgroundColorX()), alpha));
DependencyManager::get<DeferredLightingEffect>()->releaseSimpleProgram();
//DependencyManager::get<DeferredLightingEffect>()->releaseSimpleProgram();
glTranslatef(-(halfDimensions.x - leftMargin), halfDimensions.y - topMargin, 0.0f);
glm::vec4 textColor(toGlm(getTextColorX()), alpha);

View file

@ -76,12 +76,10 @@ GLBackend::GLBackend() :
_output()
{
initTransform();
initInput();
}
GLBackend::~GLBackend() {
killTransform();
killInput();
}
void GLBackend::render(Batch& batch) {
@ -98,8 +96,11 @@ void GLBackend::render(Batch& batch) {
}
}
void GLBackend::renderBatch(Batch& batch) {
void GLBackend::renderBatch(Batch& batch, bool syncCache) {
GLBackend backend;
if (syncCache) {
backend.syncCache();
}
backend.render(batch);
}
@ -136,6 +137,13 @@ bool GLBackend::checkGLError(const char* name) {
}
}
void GLBackend::syncCache() {
syncTransformStateCache();
syncPipelineStateCache();
syncInputStateCache();
}
void GLBackend::do_draw(Batch& batch, uint32 paramOffset) {
updateInput();
updateTransform();
@ -549,4 +557,3 @@ void GLBackend::fetchMatrix(GLenum target, glm::mat4 & m) {
}

View file

@ -24,12 +24,20 @@ namespace gpu {
class GLBackend : public Backend {
public:
explicit GLBackend(bool syncCache);
GLBackend();
~GLBackend();
void render(Batch& batch);
static void renderBatch(Batch& batch);
// Render Batch create a local Context and execute the batch with it
// WARNING:
// if syncCache is true, then the gpu::GLBackend will synchornize
// its cache with the current gl state and it's BAD
// If you know you don't rely on any state changed by naked gl calls then
// leave to false where it belongs
// if true, the needed resync IS EXPENSIVE
static void renderBatch(Batch& batch, bool syncCache = false);
static bool checkGLError(const char* name = nullptr);
@ -79,6 +87,7 @@ public:
static GLShader* syncGPUObject(const Shader& shader);
static GLuint getShaderID(const ShaderPointer& shader);
// FIXME: Please remove these 2 calls once the text renderer doesn't use naked gl calls anymore
static void loadMatrix(GLenum target, const glm::mat4 & m);
static void fetchMatrix(GLenum target, glm::mat4 & m);
@ -186,6 +195,12 @@ public:
void do_setStateColorWriteMask(uint32 mask);
// This call synchronize the Full Backend cache with the current GLState
// THis is only intended to be used when mixing raw gl calls with the gpu api usage in order to sync
// the gpu::Backend state with the true gl state which has probably been messed up by these ugly naked gl calls
// Let's try to avoid to do that as much as possible!
void syncCache();
protected:
// Draw Stage
@ -201,8 +216,8 @@ protected:
void do_setInputBuffer(Batch& batch, uint32 paramOffset);
void do_setIndexBuffer(Batch& batch, uint32 paramOffset);
void initInput();
void killInput();
// Synchronize the state cache of this Backend with the actual real state of the GL Context
void syncInputStateCache();
void updateInput();
struct InputStageState {
bool _invalidFormat;
@ -243,6 +258,8 @@ protected:
void initTransform();
void killTransform();
// Synchronize the state cache of this Backend with the actual real state of the GL Context
void syncTransformStateCache();
void updateTransform();
struct TransformStageState {
TransformObject _transformObject;
@ -299,7 +316,6 @@ protected:
GLState* _state;
bool _invalidState = false;
bool _needStateSync = true;
PipelineStageState() :
_pipeline(),
@ -308,8 +324,7 @@ protected:
_stateCache(State::DEFAULT),
_stateSignatureCache(0),
_state(nullptr),
_invalidState(false),
_needStateSync(true)
_invalidState(false)
{}
} _pipeline;

View file

@ -46,24 +46,12 @@ static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = {
};
#endif
void GLBackend::initInput() {
glPushClientAttrib(GL_VERTEX_ARRAY);
glPushClientAttrib(GL_NORMAL_ARRAY);
glPushClientAttrib(GL_COLOR_ARRAY);
glPushClientAttrib(GL_TEXTURE_COORD_ARRAY);
void GLBackend::syncInputStateCache() {
for (int i = 0; i < NUM_CLASSIC_ATTRIBS; i++) {
_input._attributeActivation[i] = glIsEnabled(attributeSlotToClassicAttribName[i]);
}
}
void GLBackend::killInput() {
glPopClientAttrib(); // GL_VERTEX_ARRAY
glPopClientAttrib(); // GL_NORMAL_ARRAY
glPopClientAttrib(); // GL_COLOR_ARRAY
glPopClientAttrib(); // GL_TEXTURE_COORD_ARRAY
}
void GLBackend::updateInput() {
if (_input._invalidFormat || _input._buffersState.any()) {
@ -164,9 +152,6 @@ void GLBackend::updateInput() {
}
}
}
} else {
glBindBuffer(GL_ARRAY_BUFFER, 0);
(void) CHECK_GL_ERROR();
}
// everything format related should be in sync now
_input._invalidFormat = false;

View file

@ -63,11 +63,6 @@ void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) {
if (_pipeline._pipeline == pipeline) {
return;
}
if (_pipeline._needStateSync) {
syncPipelineStateCache();
_pipeline._needStateSync = false;
}
// null pipeline == reset
if (!pipeline) {
@ -108,17 +103,7 @@ void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) {
}
}
#define DEBUG_GLSTATE
void GLBackend::updatePipeline() {
#ifdef DEBUG_GLSTATE
if (_pipeline._needStateSync) {
State::Data state;
getCurrentGLState(state);
State::Signature signature = State::evalSignature(state);
(void) signature; // quiet compiler
}
#endif
if (_pipeline._invalidProgram) {
// doing it here is aproblem for calls to glUniform.... so will do it on assing...
glUseProgram(_pipeline._program);

View file

@ -55,6 +55,25 @@ void GLBackend::killTransform() {
#else
#endif
}
void GLBackend::syncTransformStateCache() {
_transform._invalidProj = true;
_transform._invalidView = true;
_transform._invalidModel = true;
GLint currentMode;
glGetIntegerv(GL_MATRIX_MODE, &currentMode);
_transform._lastMode = currentMode;
glGetFloatv(GL_PROJECTION_MATRIX, (float*) &_transform._projection);
Mat4 modelView;
glGetFloatv(GL_MODELVIEW_MATRIX, (float*) &modelView);
auto modelViewInv = glm::inverse(modelView);
_transform._view.evalFromRawMatrix(modelViewInv);
_transform._model.setIdentity();
}
void GLBackend::updateTransform() {
// Check all the dirty flags and update the state accordingly
if (_transform._invalidProj) {

View file

@ -12,7 +12,6 @@
// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL
#include <gpu/GPUConfig.h>
#include <GLMHelpers.h>
#include <PathUtils.h>
#include <ViewFrustum.h>
@ -48,16 +47,26 @@
#include "point_light_frag.h"
#include "spot_light_frag.h"
static const std::string glowIntensityShaderHandle = "glowIntensity";
void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
auto vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert)));
auto pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_frag)));
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(glowIntensityShaderHandle, 0));
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(false,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
_viewState = viewState;
_simpleProgram.addShaderFromSourceCode(QGLShader::Vertex, simple_vert);
_simpleProgram.addShaderFromSourceCode(QGLShader::Fragment, simple_frag);
_simpleProgram.link();
_simpleProgram.bind();
_glowIntensityLocation = _simpleProgram.uniformLocation("glowIntensity");
_simpleProgram.release();
loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations);
loadLightProgram(directional_light_shadow_map_frag, false, _directionalLightShadowMap,
_directionalLightShadowMapLocations);
@ -92,29 +101,12 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET));
}
void DeferredLightingEffect::bindSimpleProgram() {
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(true, true, true);
_simpleProgram.bind();
_simpleProgram.setUniformValue(_glowIntensityLocation, DependencyManager::get<GlowEffect>()->getIntensity());
glDisable(GL_BLEND);
}
void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch) {
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, true, true);
batch._glUseProgram(_simpleProgram.programId());
batch._glUniform1f(_glowIntensityLocation, DependencyManager::get<GlowEffect>()->getIntensity());
batch._glDisable(GL_BLEND);
}
void DeferredLightingEffect::releaseSimpleProgram() {
glEnable(GL_BLEND);
_simpleProgram.release();
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(true, false, false);
batch.setPipeline(_simpleProgram);
}
void DeferredLightingEffect::releaseSimpleProgram(gpu::Batch& batch) {
batch._glEnable(GL_BLEND);
batch._glUseProgram(0);
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, false, false);
}
@ -136,12 +128,6 @@ void DeferredLightingEffect::renderSolidCube(gpu::Batch& batch, float size, cons
releaseSimpleProgram(batch);
}
void DeferredLightingEffect::renderWireCube(float size, const glm::vec4& color) {
gpu::Batch batch;
renderWireCube(batch, size, color);
gpu::GLBackend::renderBatch(batch);
}
void DeferredLightingEffect::renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color) {
bindSimpleProgram(batch);
DependencyManager::get<GeometryCache>()->renderWireCube(batch, size, color);

View file

@ -33,15 +33,10 @@ public:
void init(AbstractViewStateInterface* viewState);
/// Returns a reference to a simple program suitable for rendering static untextured geometry
ProgramObject& getSimpleProgram() { return _simpleProgram; }
/// Sets up the state necessary to render static untextured geometry with the simple program.
void bindSimpleProgram();
void bindSimpleProgram(gpu::Batch& batch);
/// Tears down the state necessary to render static untextured geometry with the simple program.
void releaseSimpleProgram();
void releaseSimpleProgram(gpu::Batch& batch);
//// Renders a solid sphere with the simple program.
@ -54,8 +49,6 @@ public:
void renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color);
//// Renders a wireframe cube with the simple program.
// FIXME Remove non Batch version once Cube3DOverlay uses the render pipeline
void renderWireCube(float size, const glm::vec4& color);
void renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color);
//// Renders a quad with the simple program.
@ -105,10 +98,9 @@ private:
};
static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations);
ProgramObject _simpleProgram;
int _glowIntensityLocation;
gpu::PipelinePointer _simpleProgram;
ProgramObject _directionalSkyboxLight;
LightLocations _directionalSkyboxLightLocations;
ProgramObject _directionalSkyboxLightShadowMap;

View file

@ -946,8 +946,8 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
glPushMatrix();
#endif
::gpu::GLBackend::renderBatch(batch);
::gpu::GLBackend::renderBatch(batch, true); // force sync with gl state here
#if defined(ANDROID)
#else
glPopMatrix();
@ -1859,6 +1859,7 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
}
gpu::GLBackend backend;
backend.syncCache(); // force sync with gl state here
if (args) {
glm::mat4 proj;

View file

@ -12,16 +12,22 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
// the interpolated normal
varying vec4 interpolatedNormal;
void main(void) {
// transform and store the normal for interpolation
interpolatedNormal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
// pass along the diffuse color
gl_FrontColor = gl_Color;
// use standard pipeline transform
gl_Position = ftransform();
}
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$>
<$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$>
interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0);
}

View file

@ -22,6 +22,18 @@
#include <memory>
inline bool isValidScale(glm::vec3 scale) {
bool result = scale.x != 0.0f && scale.y != 0.0f && scale.z != 0.0f;
assert(result);
return result;
}
inline bool isValidScale(float scale) {
bool result = scale != 0.0f;
assert(result);
return result;
}
class Transform {
public:
typedef glm::mat4 Mat4;
@ -32,7 +44,7 @@ public:
typedef glm::quat Quat;
Transform() :
_rotation(1.0f, 0, 0, 0),
_rotation(1.0f, 0.0f, 0.0f, 0.0f),
_scale(1.0f),
_translation(0.0f),
_flags(FLAG_CACHE_INVALID_BITSET) // invalid cache
@ -44,6 +56,9 @@ public:
_translation(translation),
_flags(FLAG_CACHE_INVALID_BITSET) // invalid cache
{
if (!isValidScale(_scale)) {
_scale = Vec3(1.0f);
}
}
Transform(const Transform& transform) :
_rotation(transform._rotation),
@ -166,8 +181,8 @@ protected:
};
inline void Transform::setIdentity() {
_translation = Vec3(0);
_rotation = Quat(1.0f, 0, 0, 0);
_translation = Vec3(0.0f);
_rotation = Quat(1.0f, 0.0f, 0.0f, 0.0f);
_scale = Vec3(1.0f);
_flags = Flags(FLAG_CACHE_INVALID_BITSET);
}
@ -187,19 +202,25 @@ inline void Transform::setTranslation(const Vec3& translation) {
}
inline void Transform::preTranslate(const Vec3& translation) {
if (translation == Vec3() ) return;
if (translation == Vec3()) {
return;
}
invalidCache();
flagTranslation();
_translation += translation;
}
inline void Transform::postTranslate(const Vec3& translation) {
if (translation == Vec3() ) return;
if (translation == Vec3()) {
return;
}
invalidCache();
flagTranslation();
Vec3 scaledT = translation;
if (isScaling()) scaledT *= _scale;
if (isScaling()) {
scaledT *= _scale;
}
if (isRotating()) {
_translation += glm::rotate(_rotation, scaledT);
@ -223,7 +244,9 @@ inline void Transform::setRotation(const Quat& rotation) {
}
inline void Transform::preRotate(const Quat& rotation) {
if (rotation == Quat()) return;
if (rotation == Quat()) {
return;
}
invalidCache();
if (isRotating()) {
_rotation = rotation * _rotation;
@ -236,7 +259,9 @@ inline void Transform::preRotate(const Quat& rotation) {
}
inline void Transform::postRotate(const Quat& rotation) {
if (rotation == Quat()) return;
if (rotation == Quat()) {
return;
}
invalidCache();
if (isNonUniform()) {
@ -269,8 +294,12 @@ inline const Transform::Vec3& Transform::getScale() const {
}
inline void Transform::setScale(float scale) {
if (!isValidScale(scale)) {
return;
}
invalidCache();
flagUniform();
if (scale == 1.0f) {
unflagScaling();
} else {
@ -280,6 +309,9 @@ inline void Transform::setScale(float scale) {
}
inline void Transform::setScale(const Vec3& scale) {
if (!isValidScale(scale)) {
return;
}
if ((scale.x == scale.y) && (scale.x == scale.z)) {
setScale(scale.x);
} else {
@ -291,9 +323,11 @@ inline void Transform::setScale(const Vec3& scale) {
}
inline void Transform::postScale(float scale) {
if (scale == 1.0f) return;
if (isValidScale(scale) || scale == 1.0f) {
return;
}
if (isScaling()) {
// if already scaling, just invalid cache and aply uniform scale
// if already scaling, just invalid cache and apply uniform scale
invalidCache();
_scale *= scale;
} else {
@ -302,6 +336,9 @@ inline void Transform::postScale(float scale) {
}
inline void Transform::postScale(const Vec3& scale) {
if (!isValidScale(scale)) {
return;
}
invalidCache();
if (isScaling()) {
_scale *= scale;
@ -360,7 +397,7 @@ inline Transform::Mat4& Transform::getRotationScaleMatrixInverse(Mat4& result) c
inline void Transform::evalFromRawMatrix(const Mat4& matrix) {
// for now works only in the case of TRS transformation
if ((matrix[0][3] == 0) && (matrix[1][3] == 0) && (matrix[2][3] == 0) && (matrix[3][3] == 1.0f)) {
if ((matrix[0][3] == 0.0f) && (matrix[1][3] == 0.0f) && (matrix[2][3] == 0.0f) && (matrix[3][3] == 1.0f)) {
setTranslation(Vec3(matrix[3]));
evalFromRawMatrix(Mat3(matrix));
}
@ -377,15 +414,10 @@ inline void Transform::evalFromRawMatrix(const Mat3& rotationScaleMatrix) {
inline Transform& Transform::evalInverse(Transform& inverse) const {
inverse.setIdentity();
if (isScaling()) {
// TODO: At some point we will face the case when scale is 0 and so 1/0 will blow up...
// WHat should we do for this one?
assert(_scale.x != 0);
assert(_scale.y != 0);
assert(_scale.z != 0);
if (isNonUniform()) {
inverse.setScale(Vec3(1.0f/_scale.x, 1.0f/_scale.y, 1.0f/_scale.z));
inverse.setScale(Vec3(1.0f) / _scale);
} else {
inverse.setScale(1.0f/_scale.x);
inverse.setScale(1.0f / _scale.x);
}
}
if (isRotating()) {
@ -421,8 +453,7 @@ inline Transform& Transform::inverseMult( Transform& result, const Transform& le
result.setIdentity();
if (left.isScaling()) {
const Vec3& s = left.getScale();
result.setScale(Vec3(1.0f / s.x, 1.0f / s.y, 1.0f / s.z));
result.setScale(Vec3(1.0f) / left.getScale());
}
if (left.isRotating()) {
result.postRotate(glm::conjugate(left.getRotation()));