diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b35a7bb690..6356902d9d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2750,7 +2750,7 @@ void Application::updateShadowMap() { { PerformanceTimer perfTimer("avatarManager"); - DependencyManager::get()->renderAvatars(Avatar::SHADOW_RENDER_MODE); + DependencyManager::get()->renderAvatars(RenderArgs::SHADOW_RENDER_MODE); } { @@ -2997,6 +2997,8 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs "Application::displaySide() ... entities..."); if (renderCollisionHulls) { _entities.render(RenderArgs::DEBUG_RENDER_MODE, renderSide); + } else if (theCamera.getMode() == CAMERA_MODE_MIRROR) { + _entities.render(RenderArgs::MIRROR_RENDER_MODE, renderSide); } else { _entities.render(RenderArgs::DEFAULT_RENDER_MODE, renderSide); } @@ -3021,8 +3023,8 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs { PerformanceTimer perfTimer("avatars"); - DependencyManager::get()->renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, - false, selfAvatarOnly); + DependencyManager::get()->renderAvatars(mirrorMode ? RenderArgs::MIRROR_RENDER_MODE : RenderArgs::NORMAL_RENDER_MODE, + false, selfAvatarOnly); } { @@ -3038,7 +3040,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs { PerformanceTimer perfTimer("avatarsPostLighting"); - DependencyManager::get()->renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, + DependencyManager::get()->renderAvatars(mirrorMode ? RenderArgs::MIRROR_RENDER_MODE : RenderArgs::NORMAL_RENDER_MODE, true, selfAvatarOnly); } diff --git a/interface/src/Environment.cpp b/interface/src/Environment.cpp index 2531ee736a..a08abfc920 100644 --- a/interface/src/Environment.cpp +++ b/interface/src/Environment.cpp @@ -261,9 +261,11 @@ void Environment::renderAtmosphere(Camera& camera, const EnvironmentData& data) (1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius())) / 0.25f); program->setUniformValue(locations[G_LOCATION], -0.990f); program->setUniformValue(locations[G2_LOCATION], -0.990f * -0.990f); - + glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glEnable(GL_BLEND); DependencyManager::get()->renderSphere(1.0f, 100, 50, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); //Draw a unit sphere glDepthMask(GL_TRUE); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 29ff28631c..63dd884bc6 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -268,7 +268,7 @@ static TextRenderer* textRenderer(TextRendererType type) { return displayNameRenderer; } -void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool postLighting) { +void Avatar::render(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode, bool postLighting) { if (_referential) { _referential->update(); } @@ -338,13 +338,13 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool // simple frustum check float boundingRadius = getBillboardSize(); - ViewFrustum* frustum = nullptr; - if (renderMode == Avatar::SHADOW_RENDER_MODE) { + if (renderMode == RenderArgs::SHADOW_RENDER_MODE) { frustum = Application::getInstance()->getShadowViewFrustum(); } else { frustum = Application::getInstance()->getDisplayViewFrustum(); } + if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) { return; } @@ -365,14 +365,14 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool GLOW_FROM_AVERAGE_LOUDNESS = 0.0f; } - float glowLevel = _moving && distanceToTarget > GLOW_DISTANCE && renderMode == NORMAL_RENDER_MODE + float glowLevel = _moving && distanceToTarget > GLOW_DISTANCE && renderMode == RenderArgs::NORMAL_RENDER_MODE ? 1.0f : GLOW_FROM_AVERAGE_LOUDNESS; // render body renderBody(frustum, renderMode, postLighting, glowLevel); - if (!postLighting && renderMode != SHADOW_RENDER_MODE) { + if (!postLighting && renderMode != RenderArgs::SHADOW_RENDER_MODE) { // add local lights const float BASE_LIGHT_DISTANCE = 2.0f; const float LIGHT_EXPONENT = 1.0f; @@ -436,7 +436,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool float angle = abs(angleBetween(toTarget + delta, toTarget - delta)); float sphereRadius = getHead()->getAverageLoudness() * SPHERE_LOUDNESS_SCALING; - if (renderMode == NORMAL_RENDER_MODE && (sphereRadius > MIN_SPHERE_SIZE) && + if (renderMode == RenderArgs::NORMAL_RENDER_MODE && (sphereRadius > MIN_SPHERE_SIZE) && (angle < MAX_SPHERE_ANGLE) && (angle > MIN_SPHERE_ANGLE)) { glPushMatrix(); glTranslatef(_position.x, _position.y, _position.z); @@ -455,8 +455,8 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool } const float DISPLAYNAME_DISTANCE = 20.0f; - setShowDisplayName(renderMode == NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE); - if (!postLighting || renderMode != NORMAL_RENDER_MODE || (isMyAvatar() && + setShowDisplayName(renderMode == RenderArgs::NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE); + if (!postLighting || renderMode != RenderArgs::NORMAL_RENDER_MODE || (isMyAvatar() && Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) { return; } @@ -479,14 +479,13 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { return glm::angleAxis(angle * proportion, axis); } -void Avatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel) { - Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? - Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; +void Avatar::renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode renderMode, bool postLighting, float glowLevel) { + Model::RenderMode modelRenderMode = renderMode; { Glower glower(glowLevel); if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { - if (postLighting || renderMode == SHADOW_RENDER_MODE) { + if (postLighting || renderMode == RenderArgs::SHADOW_RENDER_MODE) { // render the billboard until both models are loaded renderBillboard(); } @@ -505,7 +504,7 @@ void Avatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool getHead()->render(1.0f, renderFrustum, modelRenderMode, postLighting); } -bool Avatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const { +bool Avatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode) const { return true; } @@ -529,11 +528,11 @@ void Avatar::simulateAttachments(float deltaTime) { } } -void Avatar::renderAttachments(RenderMode renderMode, RenderArgs* args) { - Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? - Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; +void Avatar::renderAttachments(RenderArgs::RenderMode renderMode, RenderArgs* args) { + // RenderArgs::RenderMode modelRenderMode = (renderMode == RenderArgs::SHADOW_RENDER_MODE) ? + // RenderArgs::SHADOW_RENDER_MODE : RenderArgs::DEFAULT_RENDER_MODE; foreach (Model* model, _attachmentModels) { - model->render(1.0f, modelRenderMode, args); + model->render(1.0f, renderMode, args); } } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 0cde800be0..032fe25c7d 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -67,10 +67,8 @@ public: void init(); void simulate(float deltaTime); - - enum RenderMode { NORMAL_RENDER_MODE, SHADOW_RENDER_MODE, MIRROR_RENDER_MODE }; - - virtual void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE, + + virtual void render(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode = RenderArgs::NORMAL_RENDER_MODE, bool postLighting = false); //setters @@ -208,11 +206,11 @@ protected: float calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD); void renderDisplayName(); - virtual void renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel = 0.0f); - virtual bool shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const; + virtual void renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode renderMode, bool postLighting, float glowLevel = 0.0f); + virtual bool shouldRenderHead(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode) const; void simulateAttachments(float deltaTime); - virtual void renderAttachments(RenderMode renderMode, RenderArgs* args); + virtual void renderAttachments(RenderArgs::RenderMode renderMode, RenderArgs* args); virtual void updateJointMappings(); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index b689c11800..5ee09ba1cf 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -115,7 +115,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { simulateAvatarFades(deltaTime); } -void AvatarManager::renderAvatars(Avatar::RenderMode renderMode, bool postLighting, bool selfAvatarOnly) { +void AvatarManager::renderAvatars(RenderArgs::RenderMode renderMode, bool postLighting, bool selfAvatarOnly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::renderAvatars()"); bool renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderLookAtVectors); @@ -159,9 +159,9 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { } } -void AvatarManager::renderAvatarFades(const glm::vec3& cameraPosition, Avatar::RenderMode renderMode) { +void AvatarManager::renderAvatarFades(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode) { // render avatar fades - Glower glower(renderMode == Avatar::NORMAL_RENDER_MODE ? 1.0f : 0.0f); + Glower glower(renderMode == RenderArgs::NORMAL_RENDER_MODE ? 1.0f : 0.0f); foreach(const AvatarSharedPointer& fadingAvatar, _avatarFades) { Avatar* avatar = static_cast(fadingAvatar.data()); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index ae6fbe5fc2..4912fabd33 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -37,7 +37,7 @@ public: void updateMyAvatar(float deltaTime); void updateOtherAvatars(float deltaTime); - void renderAvatars(Avatar::RenderMode renderMode, bool postLighting = false, bool selfAvatarOnly = false); + void renderAvatars(RenderArgs::RenderMode renderMode, bool postLighting = false, bool selfAvatarOnly = false); void clearOtherAvatars(); @@ -55,7 +55,7 @@ private: AvatarManager(const AvatarManager& other); void simulateAvatarFades(float deltaTime); - void renderAvatarFades(const glm::vec3& cameraPosition, Avatar::RenderMode renderMode); + void renderAvatarFades(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode); AvatarSharedPointer newSharedAvatar(); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index b51264b955..e67ed15b67 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -103,7 +103,7 @@ void Hand::resolvePenetrations() { } void Hand::render(bool isMine, Model::RenderMode renderMode) { - if (renderMode != Model::SHADOW_RENDER_MODE && + if (renderMode != RenderArgs::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) { // draw a green sphere at hand joint location, which is actually near the wrist) for (size_t i = 0; i < getNumPalms(); i++) { @@ -119,7 +119,7 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) { } } - if (renderMode != Model::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) { + if (renderMode != RenderArgs::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) { renderHandTargets(isMine); } diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 688af151b4..e19f5674b4 100644 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -52,7 +52,7 @@ public: }; void simulate(float deltaTime, bool isMine); - void render(bool isMine, Model::RenderMode renderMode = Model::DEFAULT_RENDER_MODE); + void render(bool isMine, Model::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE); void collideAgainstAvatar(Avatar* avatar, bool isMyHand); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 25803e5c36..e6048b86dc 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -327,7 +327,7 @@ void MyAvatar::renderDebugBodyPoints() { } // virtual -void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool postLighting) { +void MyAvatar::render(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode, bool postLighting) { // don't render if we've been asked to disable local rendering if (!_shouldRender) { return; // exit early @@ -998,7 +998,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); } -void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel) { +void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode renderMode, bool postLighting, float glowLevel) { if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { return; // wait until both models are loaded } @@ -1007,7 +1007,7 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, boo const glm::vec3 cameraPos = camera->getPosition(); // Only tweak the frustum near far if it's not shadow - if (renderMode != SHADOW_RENDER_MODE) { + if (renderMode != RenderArgs::SHADOW_RENDER_MODE) { // Set near clip distance according to skeleton model dimensions if first person and there is no separate head model. if (shouldRenderHead(cameraPos, renderMode) || !getHead()->getFaceModel().getURL().isEmpty()) { renderFrustum->setNearClip(DEFAULT_NEAR_CLIP); @@ -1028,8 +1028,7 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, boo } // Render the body's voxels and head - Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? - Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + RenderArgs::RenderMode modelRenderMode = renderMode; if (!postLighting) { RenderArgs args; args._viewFrustum = renderFrustum; @@ -1048,9 +1047,9 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, boo const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; -bool MyAvatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const { +bool MyAvatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode) const { const Head* head = getHead(); - return (renderMode != NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) || + return (renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) || (glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale); } @@ -1396,19 +1395,19 @@ void MyAvatar::updateMotionBehavior() { _feetTouchFloor = menu->isOptionChecked(MenuOption::ShiftHipsForIdleAnimations); } -void MyAvatar::renderAttachments(RenderMode renderMode, RenderArgs* args) { - if (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON || renderMode == MIRROR_RENDER_MODE) { +void MyAvatar::renderAttachments(RenderArgs::RenderMode renderMode, RenderArgs* args) { + if (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON || renderMode == RenderArgs::MIRROR_RENDER_MODE) { Avatar::renderAttachments(renderMode, args); return; } const FBXGeometry& geometry = _skeletonModel.getGeometry()->getFBXGeometry(); QString headJointName = (geometry.headJointIndex == -1) ? QString() : geometry.joints.at(geometry.headJointIndex).name; - Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? - Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + // RenderArgs::RenderMode modelRenderMode = (renderMode == RenderArgs::SHADOW_RENDER_MODE) ? + // RenderArgs::SHADOW_RENDER_MODE : RenderArgs::DEFAULT_RENDER_MODE; for (int i = 0; i < _attachmentData.size(); i++) { const QString& jointName = _attachmentData.at(i).jointName; if (jointName != headJointName && jointName != "Head") { - _attachmentModels.at(i)->render(1.0f, modelRenderMode, args); + _attachmentModels.at(i)->render(1.0f, renderMode, args); } } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 2bc3a4e4ba..fe7d394aa9 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -37,9 +37,9 @@ public: void simulate(float deltaTime); void updateFromTrackers(float deltaTime); - void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE, bool postLighting = false); - void renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel = 0.0f); - bool shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const; + void render(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode = RenderArgs::NORMAL_RENDER_MODE, bool postLighting = false); + void renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode renderMode, bool postLighting, float glowLevel = 0.0f); + bool shouldRenderHead(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode) const; void renderDebugBodyPoints(); // setters @@ -182,7 +182,7 @@ signals: void transformChanged(); protected: - virtual void renderAttachments(RenderMode renderMode, RenderArgs* args); + virtual void renderAttachments(RenderArgs::RenderMode renderMode, RenderArgs* args); private: float _turningKeyPressTime; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 58d42598f2..29d7c20f09 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -68,7 +68,7 @@ void ModelOverlay::render(RenderArgs* args) { if (glowLevel > 0.0f) { glower = new Glower(glowLevel); } - _model.render(getAlpha(), Model::DEFAULT_RENDER_MODE, args); + _model.render(getAlpha(), RenderArgs::DEFAULT_RENDER_MODE, args); if (glower) { delete glower; } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index b108c5a95b..da972b3843 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -395,12 +395,12 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::R _tree->lockForRead(); _tree->recurseTreeWithOperation(renderOperation, &args); - Model::RenderMode modelRenderMode = renderMode == RenderArgs::SHADOW_RENDER_MODE - ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; +// Model::RenderMode modelRenderMode = renderMode == RenderArgs::SHADOW_RENDER_MODE + // ? RenderArgs::SHADOW_RENDER_MODE : RenderArgs::DEFAULT_RENDER_MODE; // we must call endScene while we still have the tree locked so that no one deletes a model // on us while rendering the scene - Model::endScene(modelRenderMode, &args); + Model::endScene(renderMode, &args); _tree->unlock(); // stats... diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 9ca0eeaebf..9eb9648478 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -20,7 +20,6 @@ Batch::Batch() : _commands(), _commandOffsets(), _params(), - _resources(), _data(), _buffers(), _textures(), @@ -37,7 +36,6 @@ void Batch::clear() { _commands.clear(); _commandOffsets.clear(); _params.clear(); - _resources.clear(); _data.clear(); _buffers.clear(); _textures.clear(); @@ -46,20 +44,6 @@ void Batch::clear() { _pipelines.clear(); } -uint32 Batch::cacheResource(Resource* res) { - uint32 offset = _resources.size(); - _resources.push_back(ResourceCache(res)); - - return offset; -} - -uint32 Batch::cacheResource(const void* pointer) { - uint32 offset = _resources.size(); - _resources.push_back(ResourceCache(pointer)); - - return offset; -} - uint32 Batch::cacheData(uint32 size, const void* data) { uint32 offset = _data.size(); uint32 nbBytes = size; @@ -167,6 +151,16 @@ void Batch::setPipeline(const PipelinePointer& pipeline) { _params.push_back(_pipelines.cache(pipeline)); } +void Batch::setStateBlendFactor(const Vec4& factor) { + ADD_COMMAND(setStateBlendFactor); + + _params.push_back(factor.x); + _params.push_back(factor.y); + _params.push_back(factor.z); + _params.push_back(factor.w); +} + + void Batch::setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size) { ADD_COMMAND(setUniformBuffer); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 3468e75738..6e8a2d1da6 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -104,6 +104,8 @@ public: // Pipeline Stage void setPipeline(const PipelinePointer& pipeline); + void setStateBlendFactor(const Vec4& factor); + void setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size); void setUniformBuffer(uint32 slot, const BufferView& view); // not a command, just a shortcut from a BufferView @@ -128,7 +130,7 @@ public: void _glDepthFunc(GLenum func); void _glDepthMask(GLboolean flag); - void _glDepthRange(GLclampd zNear, GLclampd zFar); + void _glDepthRange(GLfloat zNear, GLfloat zFar); void _glBindBuffer(GLenum target, GLuint buffer); @@ -143,15 +145,6 @@ public: void _glUniform4fv(GLint location, GLsizei count, const GLfloat* value); void _glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); - void _glDrawArrays(GLenum mode, GLint first, GLsizei count); - void _glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); - - void _glColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); - void _glNormalPointer(GLenum type, GLsizei stride, const void *pointer); - void _glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); - void _glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); - - void _glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); void _glEnableVertexAttribArray(GLint location); void _glDisableVertexAttribArray(GLint location); @@ -172,6 +165,8 @@ public: COMMAND_setProjectionTransform, COMMAND_setPipeline, + COMMAND_setStateBlendFactor, + COMMAND_setUniformBuffer, COMMAND_setUniformTexture, @@ -204,15 +199,6 @@ public: COMMAND_glUniform4fv, COMMAND_glUniformMatrix4fv, - COMMAND_glDrawArrays, - COMMAND_glDrawRangeElements, - - COMMAND_glColorPointer, - COMMAND_glNormalPointer, - COMMAND_glTexCoordPointer, - COMMAND_glVertexPointer, - - COMMAND_glVertexAttribPointer, COMMAND_glEnableVertexAttribArray, COMMAND_glDisableVertexAttribArray, @@ -233,28 +219,18 @@ public: uint32 _uint; float _float; char _chars[4]; - double _double; }; Param(int32 val) : _int(val) {} Param(uint32 val) : _uint(val) {} Param(float val) : _float(val) {} - Param(double val) : _double(val) {} }; typedef std::vector Params; const Params& getParams() const { return _params; } - class ResourceCache { - public: - union { - Resource* _resource; - const void* _pointer; - }; - ResourceCache(Resource* res) : _resource(res) {} - ResourceCache(const void* pointer) : _pointer(pointer) {} - }; - typedef std::vector Resources; - + // The template cache mechanism for the gpu::Object passed to the gpu::Batch + // this allow us to have one cache container for each different types and eventually + // be smarter how we manage them template class Cache { public: @@ -291,26 +267,10 @@ public: typedef Cache::Vector TransformCaches; typedef Cache::Vector PipelineCaches; + // Cache Data in a byte array if too big to fit in Param + // FOr example Mat4s are going there typedef unsigned char Byte; typedef std::vector Bytes; - - uint32 cacheResource(Resource* res); - uint32 cacheResource(const void* pointer); - ResourceCache* editResource(uint32 offset) { - if (offset >= _resources.size()) { - return 0; - } - return (_resources.data() + offset); - } - - template - T* editResourcePointer(uint32 offset) { - if (offset >= _resources.size()) { - return 0; - } - return reinterpret_cast((_resources.data() + offset)->_pointer); - } - uint32 cacheData(uint32 size, const void* data); Byte* editData(uint32 offset) { if (offset >= _data.size()) { @@ -322,7 +282,6 @@ public: Commands _commands; CommandOffsets _commandOffsets; Params _params; - Resources _resources; Bytes _data; BufferCaches _buffers; diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 1e239f0c56..8276ff5f95 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -82,6 +82,15 @@ public: return reinterpret_cast(pipeline.getGPUObject()); } + template< typename T > + static void setGPUObject(const State& state, T* so) { + state.setGPUObject(so); + } + template< typename T > + static T* getGPUObject(const State& state) { + return reinterpret_cast(state.getGPUObject()); + } + protected: }; diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 8a754bb564..7f36797374 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -16,6 +16,10 @@ namespace gpu { +class GPUObject; + +typedef int Stamp; + typedef unsigned int uint32; typedef int int32; typedef unsigned short uint16; diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 1c4534c6f6..e1eff5f3cd 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -27,6 +27,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_setProjectionTransform), (&::gpu::GLBackend::do_setPipeline), + (&::gpu::GLBackend::do_setStateBlendFactor), + (&::gpu::GLBackend::do_setUniformBuffer), (&::gpu::GLBackend::do_setUniformTexture), @@ -56,15 +58,6 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_glUniform4fv), (&::gpu::GLBackend::do_glUniformMatrix4fv), - (&::gpu::GLBackend::do_glDrawArrays), - (&::gpu::GLBackend::do_glDrawRangeElements), - - (&::gpu::GLBackend::do_glColorPointer), - (&::gpu::GLBackend::do_glNormalPointer), - (&::gpu::GLBackend::do_glTexCoordPointer), - (&::gpu::GLBackend::do_glVertexPointer), - - (&::gpu::GLBackend::do_glVertexAttribPointer), (&::gpu::GLBackend::do_glEnableVertexAttribArray), (&::gpu::GLBackend::do_glDisableVertexAttribArray), @@ -281,7 +274,7 @@ void GLBackend::do_glDepthMask(Batch& batch, uint32 paramOffset) { CHECK_GL_ERROR(); } -void Batch::_glDepthRange(GLclampd zNear, GLclampd zFar) { +void Batch::_glDepthRange(GLfloat zNear, GLfloat zFar) { ADD_COMMAND_GL(glDepthRange); _params.push_back(zFar); @@ -291,8 +284,8 @@ void Batch::_glDepthRange(GLclampd zNear, GLclampd zFar) { } void GLBackend::do_glDepthRange(Batch& batch, uint32 paramOffset) { glDepthRange( - batch._params[paramOffset + 1]._double, - batch._params[paramOffset + 0]._double); + batch._params[paramOffset + 1]._float, + batch._params[paramOffset + 0]._float); CHECK_GL_ERROR(); } @@ -371,14 +364,19 @@ void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) { } void Batch::_glUniform1f(GLint location, GLfloat v0) { + if (location < 0) { + return; + } ADD_COMMAND_GL(glUniform1f); - _params.push_back(v0); _params.push_back(location); DO_IT_NOW(_glUniform1f, 1); } void GLBackend::do_glUniform1f(Batch& batch, uint32 paramOffset) { + if (_pipeline._program == 0) { + return; + } glUniform1f( batch._params[paramOffset + 1]._int, batch._params[paramOffset + 0]._float); @@ -441,144 +439,6 @@ void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) { CHECK_GL_ERROR(); } -void Batch::_glDrawArrays(GLenum mode, GLint first, GLsizei count) { - ADD_COMMAND_GL(glDrawArrays); - - _params.push_back(count); - _params.push_back(first); - _params.push_back(mode); - - DO_IT_NOW(_glDrawArrays, 3); -} -void GLBackend::do_glDrawArrays(Batch& batch, uint32 paramOffset) { - glDrawArrays( - batch._params[paramOffset + 2]._uint, - batch._params[paramOffset + 1]._int, - batch._params[paramOffset + 0]._int); - CHECK_GL_ERROR(); -} - -void Batch::_glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices) { - ADD_COMMAND_GL(glDrawRangeElements); - - _params.push_back(cacheResource(indices)); - _params.push_back(type); - _params.push_back(count); - _params.push_back(end); - _params.push_back(start); - _params.push_back(mode); - - DO_IT_NOW(_glDrawRangeElements, 6); -} -void GLBackend::do_glDrawRangeElements(Batch& batch, uint32 paramOffset) { - glDrawRangeElements( - batch._params[paramOffset + 5]._uint, - batch._params[paramOffset + 4]._uint, - batch._params[paramOffset + 3]._uint, - batch._params[paramOffset + 2]._int, - batch._params[paramOffset + 1]._uint, - batch.editResource(batch._params[paramOffset + 0]._uint)->_pointer); - CHECK_GL_ERROR(); -} - -void Batch::_glColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) { - ADD_COMMAND_GL(glColorPointer); - - _params.push_back(cacheResource(pointer)); - _params.push_back(stride); - _params.push_back(type); - _params.push_back(size); - - DO_IT_NOW(_glColorPointer, 4); -} -void GLBackend::do_glColorPointer(Batch& batch, uint32 paramOffset) { - glColorPointer( - batch._params[paramOffset + 3]._int, - batch._params[paramOffset + 2]._uint, - batch._params[paramOffset + 1]._int, - batch.editResource(batch._params[paramOffset + 0]._uint)->_pointer); - CHECK_GL_ERROR(); -} - -void Batch::_glNormalPointer(GLenum type, GLsizei stride, const void *pointer) { - ADD_COMMAND_GL(glNormalPointer); - - _params.push_back(cacheResource(pointer)); - _params.push_back(stride); - _params.push_back(type); - - DO_IT_NOW(_glNormalPointer, 3); -} -void GLBackend::do_glNormalPointer(Batch& batch, uint32 paramOffset) { - glNormalPointer( - batch._params[paramOffset + 2]._uint, - batch._params[paramOffset + 1]._int, - batch.editResource(batch._params[paramOffset + 0]._uint)->_pointer); - CHECK_GL_ERROR(); -} - -void Batch::_glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) { - ADD_COMMAND_GL(glTexCoordPointer); - - _params.push_back(cacheResource(pointer)); - _params.push_back(stride); - _params.push_back(type); - _params.push_back(size); - - DO_IT_NOW(_glTexCoordPointer, 4); -} -void GLBackend::do_glTexCoordPointer(Batch& batch, uint32 paramOffset) { - glTexCoordPointer( - batch._params[paramOffset + 3]._int, - batch._params[paramOffset + 2]._uint, - batch._params[paramOffset + 1]._int, - batch.editResource(batch._params[paramOffset + 0]._uint)->_pointer); - CHECK_GL_ERROR(); -} - -void Batch::_glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) { - ADD_COMMAND_GL(glVertexPointer); - - _params.push_back(cacheResource(pointer)); - _params.push_back(stride); - _params.push_back(type); - _params.push_back(size); - - DO_IT_NOW(_glVertexPointer, 4); -} -void GLBackend::do_glVertexPointer(Batch& batch, uint32 paramOffset) { - glVertexPointer( - batch._params[paramOffset + 3]._int, - batch._params[paramOffset + 2]._uint, - batch._params[paramOffset + 1]._int, - batch.editResource(batch._params[paramOffset + 0]._uint)->_pointer); - CHECK_GL_ERROR(); -} - - -void Batch::_glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) { - ADD_COMMAND_GL(glVertexAttribPointer); - - _params.push_back(cacheResource(pointer)); - _params.push_back(stride); - _params.push_back(normalized); - _params.push_back(type); - _params.push_back(size); - _params.push_back(index); - - DO_IT_NOW(_glVertexAttribPointer, 6); -} -void GLBackend::do_glVertexAttribPointer(Batch& batch, uint32 paramOffset) { - glVertexAttribPointer( - batch._params[paramOffset + 5]._uint, - batch._params[paramOffset + 4]._int, - batch._params[paramOffset + 3]._uint, - batch._params[paramOffset + 2]._uint, - batch._params[paramOffset + 1]._int, - batch.editResource(batch._params[paramOffset + 0]._uint)->_pointer); - CHECK_GL_ERROR(); -} - void Batch::_glEnableVertexAttribArray(GLint location) { ADD_COMMAND_GL(glEnableVertexAttribArray); diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 2fd27862f9..71e44ddfda 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -75,10 +75,66 @@ public: static GLShader* syncGPUObject(const Shader& shader); static GLuint getShaderID(const ShaderPointer& shader); + class GLState : public GPUObject { + public: + class Command { + public: + virtual void run(GLBackend* backend) = 0; + Command() {} + virtual ~Command() {}; + }; + + template class Command1 : public Command { + public: + typedef void (GLBackend::*GLFunction)(T); + void run(GLBackend* backend) { (backend->*(_func))(_param); } + Command1(GLFunction func, T param) : _func(func), _param(param) {}; + GLFunction _func; + T _param; + }; + template class Command2 : public Command { + public: + typedef void (GLBackend::*GLFunction)(T, U); + void run(GLBackend* backend) { (backend->*(_func))(_param0, _param1); } + Command2(GLFunction func, T param0, U param1) : _func(func), _param0(param0), _param1(param1) {}; + GLFunction _func; + T _param0; + U _param1; + }; + + template class Command3 : public Command { + public: + typedef void (GLBackend::*GLFunction)(T, U, V); + void run(GLBackend* backend) { (backend->*(_func))(_param0, _param1, _param2); } + Command3(GLFunction func, T param0, U param1, V param2) : _func(func), _param0(param0), _param1(param1), _param2(param2) {}; + GLFunction _func; + T _param0; + U _param1; + V _param2; + }; + + typedef std::shared_ptr< Command > CommandPointer; + typedef std::vector< CommandPointer > Commands; + + Commands _commands; + Stamp _stamp; + State::Signature _signature; + + GLState(); + ~GLState(); + + // The state commands to reset to default, + // WARNING depending on the order of the State::Field enum + static const Commands _resetStateCommands; + + friend class GLBackend; + }; + static GLState* syncGPUObject(const State& state); class GLPipeline : public GPUObject { public: GLShader* _program; + GLState* _state; GLPipeline(); ~GLPipeline(); @@ -90,21 +146,43 @@ public: uint32 getNumInputBuffers() const { return _input._buffersState.size(); } + + // The State setters called by the GLState::Commands when a new state is assigned + void do_setStateFillMode(int32 mode); + void do_setStateCullMode(int32 mode); + void do_setStateFrontFaceClockwise(bool isClockwise); + void do_setStateDepthClipEnable(bool enable); + void do_setStateScissorEnable(bool enable); + void do_setStateMultisampleEnable(bool enable); + void do_setStateAntialiasedLineEnable(bool enable); + + void do_setStateDepthBias(Vec2 bias); + void do_setStateDepthTest(State::DepthTest test); + + void do_setStateStencil(State::StencilActivation activation, State::StencilTest frontTest, State::StencilTest backTest); + + void do_setStateAlphaToCoverageEnable(bool enable); + void do_setStateSampleMask(uint32 mask); + + void do_setStateBlend(State::BlendFunction blendFunction); + + void do_setStateColorWriteMask(uint32 mask); + protected: // Draw Stage - void do_draw(Batch& batch, uint32 paramOffset); + void do_draw(Batch& batch, uint32 paramOffset); void do_drawIndexed(Batch& batch, uint32 paramOffset); - void do_drawInstanced(Batch& batch, uint32 paramOffset); + void do_drawInstanced(Batch& batch, uint32 paramOffset); void do_drawIndexedInstanced(Batch& batch, uint32 paramOffset); // Input Stage - void do_setInputFormat(Batch& batch, uint32 paramOffset); - void do_setInputBuffer(Batch& batch, uint32 paramOffset); + void do_setInputFormat(Batch& batch, uint32 paramOffset); + void do_setInputBuffer(Batch& batch, uint32 paramOffset); void do_setIndexBuffer(Batch& batch, uint32 paramOffset); void updateInput(); - struct InputStageState { + struct InputStageState { bool _invalidFormat; Stream::FormatPointer _format; @@ -137,18 +215,18 @@ protected: } _input; // Transform Stage - void do_setModelTransform(Batch& batch, uint32 paramOffset); - void do_setViewTransform(Batch& batch, uint32 paramOffset); + void do_setModelTransform(Batch& batch, uint32 paramOffset); + void do_setViewTransform(Batch& batch, uint32 paramOffset); void do_setProjectionTransform(Batch& batch, uint32 paramOffset); void initTransform(); void killTransform(); - void updateTransform(); - struct TransformStageState { - TransformObject _transformObject; - TransformCamera _transformCamera; - GLuint _transformObjectBuffer; - GLuint _transformCameraBuffer; + void updateTransform(); + struct TransformStageState { + TransformObject _transformObject; + TransformCamera _transformCamera; + GLuint _transformObjectBuffer; + GLuint _transformCameraBuffer; Transform _model; Transform _view; Mat4 _projection; @@ -172,38 +250,61 @@ protected: // Pipeline Stage void do_setPipeline(Batch& batch, uint32 paramOffset); - void do_setUniformBuffer(Batch& batch, uint32 paramOffset); - void do_setUniformTexture(Batch& batch, uint32 paramOffset); + + void do_setStateBlendFactor(Batch& batch, uint32 paramOffset); + + void do_setUniformBuffer(Batch& batch, uint32 paramOffset); + void do_setUniformTexture(Batch& batch, uint32 paramOffset); - void updatePipeline(); + // Standard update pipeline check that the current Program and current State or good to go for a + void updatePipeline(); + // Force to reset all the state fields indicated by the 'toBeReset" signature + void resetPipelineState(State::Signature toBeReset); + // Synchronize the state cache of this Backend with the actual real state of the GL Context + void syncPipelineStateCache(); + // Grab the actual gl state into it's gpu::State equivalent. THis is used by the above call syncPipleineStateCache() + void getCurrentGLState(State::Data& state); + struct PipelineStageState { PipelinePointer _pipeline; + GLuint _program; bool _invalidProgram; + State::Data _stateCache; + State::Signature _stateSignatureCache; + + GLState* _state; + bool _invalidState; + bool _needStateSync; + PipelineStageState() : _pipeline(), _program(0), - _invalidProgram(false) + _invalidProgram(false), + _stateCache(State::DEFAULT), + _stateSignatureCache(0), + _state(nullptr), + _invalidState(false), + _needStateSync(true) {} } _pipeline; - // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API - void do_glEnable(Batch& batch, uint32 paramOffset); + void do_glEnable(Batch& batch, uint32 paramOffset); void do_glDisable(Batch& batch, uint32 paramOffset); - + void do_glEnableClientState(Batch& batch, uint32 paramOffset); void do_glDisableClientState(Batch& batch, uint32 paramOffset); void do_glCullFace(Batch& batch, uint32 paramOffset); void do_glAlphaFunc(Batch& batch, uint32 paramOffset); - void do_glDepthFunc(Batch& batch, uint32 paramOffset); - void do_glDepthMask(Batch& batch, uint32 paramOffset); + void do_glDepthFunc(Batch& batch, uint32 paramOffset); + void do_glDepthMask(Batch& batch, uint32 paramOffset); void do_glDepthRange(Batch& batch, uint32 paramOffset); void do_glBindBuffer(Batch& batch, uint32 paramOffset); @@ -217,17 +318,8 @@ protected: void do_glUniform1f(Batch& batch, uint32 paramOffset); void do_glUniform2f(Batch& batch, uint32 paramOffset); void do_glUniform4fv(Batch& batch, uint32 paramOffset); - void do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset); + void do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset); - void do_glDrawArrays(Batch& batch, uint32 paramOffset); - void do_glDrawRangeElements(Batch& batch, uint32 paramOffset); - - void do_glColorPointer(Batch& batch, uint32 paramOffset); - void do_glNormalPointer(Batch& batch, uint32 paramOffset); - void do_glTexCoordPointer(Batch& batch, uint32 paramOffset); - void do_glVertexPointer(Batch& batch, uint32 paramOffset); - - void do_glVertexAttribPointer(Batch& batch, uint32 paramOffset); void do_glEnableVertexAttribArray(Batch& batch, uint32 paramOffset); void do_glDisableVertexAttribArray(Batch& batch, uint32 paramOffset); diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index aee3f009d1..0f7d3d6db8 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -15,11 +15,13 @@ using namespace gpu; GLBackend::GLPipeline::GLPipeline() : - _program(nullptr) + _program(nullptr), + _state(nullptr) {} GLBackend::GLPipeline::~GLPipeline() { _program = nullptr; + _state = nullptr; } GLBackend::GLPipeline* GLBackend::syncGPUObject(const Pipeline& pipeline) { @@ -30,24 +32,118 @@ GLBackend::GLPipeline* GLBackend::syncGPUObject(const Pipeline& pipeline) { return object; } - return nullptr; + // No object allocated yet, let's see if it's worth it... + ShaderPointer shader = pipeline.getProgram(); + GLShader* programObject = GLBackend::syncGPUObject((*shader)); + if (programObject == nullptr) { + return nullptr; + } + + StatePointer state = pipeline.getState(); + GLState* stateObject = GLBackend::syncGPUObject((*state)); + if (stateObject == nullptr) { + return nullptr; + } + + // Program and state are valid, we can create the pipeline object + if (!object) { + object = new GLPipeline(); + Backend::setGPUObject(pipeline, object); + } + + object->_program = programObject; + object->_state = stateObject; + + return object; } void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) { PipelinePointer pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint); - if (pipeline == _pipeline._pipeline) { + if (_pipeline._pipeline == pipeline) { return; } - auto pipelineObject = syncGPUObject((*pipeline)); - if (!pipelineObject) { - return; + if (_pipeline._needStateSync) { + syncPipelineStateCache(); + _pipeline._needStateSync = false; + } + + // null pipeline == reset + if (!pipeline) { + _pipeline._pipeline.reset(); + + _pipeline._program = 0; + _pipeline._invalidProgram = true; + + _pipeline._state = nullptr; + _pipeline._invalidState = true; + } else { + auto pipelineObject = syncGPUObject((*pipeline)); + if (!pipelineObject) { + return; + } + + // check the program cache + if (_pipeline._program != pipelineObject->_program->_program) { + _pipeline._program = pipelineObject->_program->_program; + _pipeline._invalidProgram = true; + } + + // Now for the state + if (_pipeline._state != pipelineObject->_state) { + _pipeline._state = pipelineObject->_state; + _pipeline._invalidState = true; + } + + // Remember the new pipeline + _pipeline._pipeline = pipeline; + } + + // THis should be done on Pipeline::update... + if (_pipeline._invalidProgram) { + glUseProgram(_pipeline._program); + CHECK_GL_ERROR(); + _pipeline._invalidProgram = false; + } +} + +#define DEBUG_GLSTATE +void GLBackend::updatePipeline() { +#ifdef DEBUG_GLSTATE + if (_pipeline._needStateSync) { + State::Data state; + getCurrentGLState(state); + State::Signature signature = State::evalSignature(state); + } +#endif + + if (_pipeline._invalidProgram) { + // doing it here is aproblem for calls to glUniform.... so will do it on assing... + glUseProgram(_pipeline._program); + CHECK_GL_ERROR(); + _pipeline._invalidProgram = false; + } + + if (_pipeline._invalidState) { + if (_pipeline._state) { + // first reset to default what should be + // the fields which were not to default and are default now + resetPipelineState(_pipeline._state->_signature); + + // Update the signature cache with what's going to be touched + _pipeline._stateSignatureCache |= _pipeline._state->_signature; + + // And perform + for (auto command: _pipeline._state->_commands) { + command->run(this); + } + } else { + // No state ? anyway just reset everything + resetPipelineState(0); + } + _pipeline._invalidState = false; } - - _pipeline._pipeline = pipeline; - _pipeline._program = pipelineObject->_program->_program; - _pipeline._invalidProgram = true; } void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { @@ -81,13 +177,3 @@ void GLBackend::do_setUniformTexture(Batch& batch, uint32 paramOffset) { CHECK_GL_ERROR(); } - -void GLBackend::updatePipeline() { - if (_pipeline._invalidProgram) { - glUseProgram(_pipeline._program); - CHECK_GL_ERROR(); - - _pipeline._invalidProgram = true; - } -} - diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp new file mode 100644 index 0000000000..fba40ca77f --- /dev/null +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -0,0 +1,735 @@ +// +// GLBackendState.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/22/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLBackendShared.h" + +#include "Format.h" + +using namespace gpu; + +GLBackend::GLState::GLState() +{} + +GLBackend::GLState::~GLState() { +} + + +typedef GLBackend::GLState::Command Command; +typedef GLBackend::GLState::CommandPointer CommandPointer; +typedef GLBackend::GLState::Command1 Command1U; +typedef GLBackend::GLState::Command1 Command1I; +typedef GLBackend::GLState::Command1 Command1B; +typedef GLBackend::GLState::Command1 CommandDepthBias; +typedef GLBackend::GLState::Command1 CommandDepthTest; +typedef GLBackend::GLState::Command3 CommandStencil; +typedef GLBackend::GLState::Command1 CommandBlend; + +// The state commands to reset to default, +// WARNING depending on the order of the State::Field enum +const GLBackend::GLState::Commands GLBackend::GLState::_resetStateCommands = { + CommandPointer(new Command1I(&GLBackend::do_setStateFillMode, State::DEFAULT.fillMode)), + CommandPointer(new Command1I(&GLBackend::do_setStateCullMode, State::DEFAULT.cullMode)), + CommandPointer(new Command1B(&GLBackend::do_setStateFrontFaceClockwise, State::DEFAULT.frontFaceClockwise)), + CommandPointer(new Command1B(&GLBackend::do_setStateDepthClipEnable, State::DEFAULT.depthClipEnable)), + CommandPointer(new Command1B(&GLBackend::do_setStateScissorEnable, State::DEFAULT.scissorEnable)), + CommandPointer(new Command1B(&GLBackend::do_setStateMultisampleEnable, State::DEFAULT.multisampleEnable)), + CommandPointer(new Command1B(&GLBackend::do_setStateAntialiasedLineEnable, State::DEFAULT.antialisedLineEnable)), + + // Depth bias has 2 fields in State but really one call in GLBackend + CommandPointer(new CommandDepthBias(&GLBackend::do_setStateDepthBias, Vec2(State::DEFAULT.depthBias, State::DEFAULT.depthBiasSlopeScale))), + CommandPointer(new CommandDepthBias(&GLBackend::do_setStateDepthBias, Vec2(State::DEFAULT.depthBias, State::DEFAULT.depthBiasSlopeScale))), + + CommandPointer(new CommandDepthTest(&GLBackend::do_setStateDepthTest, State::DEFAULT.depthTest)), + + // Depth bias has 3 fields in State but really one call in GLBackend + CommandPointer(new CommandStencil(&GLBackend::do_setStateStencil, State::DEFAULT.stencilActivation, State::DEFAULT.stencilTestFront, State::DEFAULT.stencilTestBack)), + CommandPointer(new CommandStencil(&GLBackend::do_setStateStencil, State::DEFAULT.stencilActivation, State::DEFAULT.stencilTestFront, State::DEFAULT.stencilTestBack)), + CommandPointer(new CommandStencil(&GLBackend::do_setStateStencil, State::DEFAULT.stencilActivation, State::DEFAULT.stencilTestFront, State::DEFAULT.stencilTestBack)), + + CommandPointer(new Command1B(&GLBackend::do_setStateAlphaToCoverageEnable, State::DEFAULT.alphaToCoverageEnable)), + + CommandPointer(new Command1U(&GLBackend::do_setStateSampleMask, State::DEFAULT.sampleMask)), + + CommandPointer(new CommandBlend(&GLBackend::do_setStateBlend, State::DEFAULT.blendFunction)), + + CommandPointer(new Command1U(&GLBackend::do_setStateColorWriteMask, State::DEFAULT.colorWriteMask)) +}; + +void generateFillMode(GLBackend::GLState::Commands& commands, State::FillMode fillMode) { + commands.push_back(CommandPointer(new Command1I(&GLBackend::do_setStateFillMode, int32(fillMode)))); +} + +void generateCullMode(GLBackend::GLState::Commands& commands, State::CullMode cullMode) { + commands.push_back(CommandPointer(new Command1I(&GLBackend::do_setStateCullMode, int32(cullMode)))); +} + +void generateFrontFaceClockwise(GLBackend::GLState::Commands& commands, bool isClockwise) { + commands.push_back(CommandPointer(new Command1B(&GLBackend::do_setStateFrontFaceClockwise, isClockwise))); +} + +void generateDepthClipEnable(GLBackend::GLState::Commands& commands, bool enable) { + commands.push_back(CommandPointer(new Command1B(&GLBackend::do_setStateDepthClipEnable, enable))); +} + +void generateScissorEnable(GLBackend::GLState::Commands& commands, bool enable) { + commands.push_back(CommandPointer(new Command1B(&GLBackend::do_setStateScissorEnable, enable))); +} + +void generateMultisampleEnable(GLBackend::GLState::Commands& commands, bool enable) { + commands.push_back(CommandPointer(new Command1B(&GLBackend::do_setStateMultisampleEnable, enable))); +} + +void generateAntialiasedLineEnable(GLBackend::GLState::Commands& commands, bool enable) { + commands.push_back(CommandPointer(new Command1B(&GLBackend::do_setStateAntialiasedLineEnable, enable))); +} + +void generateDepthBias(GLBackend::GLState::Commands& commands, const State& state) { + commands.push_back(CommandPointer(new CommandDepthBias(&GLBackend::do_setStateDepthBias, Vec2(state.getDepthBias(), state.getDepthBiasSlopeScale())))); +} + +void generateDepthTest(GLBackend::GLState::Commands& commands, const State::DepthTest& test) { + commands.push_back(CommandPointer(new CommandDepthTest(&GLBackend::do_setStateDepthTest, int32(test.getRaw())))); +} + +void generateStencil(GLBackend::GLState::Commands& commands, const State& state) { + commands.push_back(CommandPointer(new CommandStencil(&GLBackend::do_setStateStencil, state.getStencilActivation(), state.getStencilTestFront(), state.getStencilTestBack()))); +} + +void generateAlphaToCoverageEnable(GLBackend::GLState::Commands& commands, bool enable) { + commands.push_back(CommandPointer(new Command1B(&GLBackend::do_setStateAlphaToCoverageEnable, enable))); +} + +void generateSampleMask(GLBackend::GLState::Commands& commands, uint32 mask) { + commands.push_back(CommandPointer(new Command1U(&GLBackend::do_setStateSampleMask, mask))); +} + +void generateBlend(GLBackend::GLState::Commands& commands, const State& state) { + commands.push_back(CommandPointer(new CommandBlend(&GLBackend::do_setStateBlend, state.getBlendFunction()))); +} + +void generateColorWriteMask(GLBackend::GLState::Commands& commands, uint32 mask) { + commands.push_back(CommandPointer(new Command1U(&GLBackend::do_setStateColorWriteMask, mask))); +} + +GLBackend::GLState* GLBackend::syncGPUObject(const State& state) { + GLState* object = Backend::getGPUObject(state); + + // If GPU object already created then good + if (object) { + return object; + } + + // Else allocate and create the GLState + if (!object) { + object = new GLState(); + Backend::setGPUObject(state, object); + } + + // here, we need to regenerate something so let's do it all + object->_commands.clear(); + object->_stamp = state.getStamp(); + object->_signature = state.getSignature(); + + bool depthBias = false; + bool stencilState = false; + bool blendState = false; + + // go thorugh the list of state fields in the State and record the corresponding gl command + for (int i = 0; i < State::NUM_FIELDS; i++) { + if (state.getSignature()[i]) { + switch(i) { + case State::FILL_MODE: { + generateFillMode(object->_commands, state.getFillMode()); + break; + } + case State::CULL_MODE: { + generateCullMode(object->_commands, state.getCullMode()); + break; + } + case State::DEPTH_BIAS: + case State::DEPTH_BIAS_SLOPE_SCALE: { + depthBias = true; + break; + } + case State::FRONT_FACE_CLOCKWISE: { + generateFrontFaceClockwise(object->_commands, state.isFrontFaceClockwise()); + break; + } + case State::DEPTH_CLIP_ENABLE: { + generateDepthClipEnable(object->_commands, state.isDepthClipEnable()); + break; + } + case State::SCISSOR_ENABLE: { + generateScissorEnable(object->_commands, state.isScissorEnable()); + break; + } + case State::MULTISAMPLE_ENABLE: { + generateMultisampleEnable(object->_commands, state.isMultisampleEnable()); + break; + } + case State::ANTIALISED_LINE_ENABLE: { + generateAntialiasedLineEnable(object->_commands, state.isAntialiasedLineEnable()); + break; + } + case State::DEPTH_TEST: { + generateDepthTest(object->_commands, state.getDepthTest()); + break; + } + + case State::STENCIL_ACTIVATION: + case State::STENCIL_TEST_FRONT: + case State::STENCIL_TEST_BACK: { + stencilState = true; + break; + } + + case State::SAMPLE_MASK: { + generateSampleMask(object->_commands, state.getSampleMask()); + break; + } + case State::ALPHA_TO_COVERAGE_ENABLE: { + generateAlphaToCoverageEnable(object->_commands, state.isAlphaToCoverageEnabled()); + break; + } + + case State::BLEND_FUNCTION: { + generateBlend(object->_commands, state); + break; + } + + case State::COLOR_WRITE_MASK: { + generateColorWriteMask(object->_commands, state.getColorWriteMask()); + break; + } + } + } + } + + if (depthBias) { + generateDepthBias(object->_commands, state); + } + + if (stencilState) { + generateStencil(object->_commands, state); + } + + return object; +} + + +void GLBackend::resetPipelineState(State::Signature nextSignature) { + auto currentNotSignature = ~_pipeline._stateSignatureCache; + auto nextNotSignature = ~nextSignature; + auto fieldsToBeReset = currentNotSignature ^ (currentNotSignature | nextNotSignature); + if (fieldsToBeReset.any()) { + for (auto i = 0; i < State::NUM_FIELDS; i++) { + if (fieldsToBeReset[i]) { + GLState::_resetStateCommands[i]->run(this); + _pipeline._stateSignatureCache.reset(i); + } + } + } +} + +State::ComparisonFunction comparisonFuncFromGL(GLenum func) { + if (func == GL_NEVER) { + return State::NEVER; + } else if (func == GL_LESS) { + return State::LESS; + } else if (func == GL_EQUAL) { + return State::EQUAL; + } else if (func == GL_LEQUAL) { + return State::LESS_EQUAL; + } else if (func == GL_GREATER) { + return State::GREATER; + } else if (func == GL_NOTEQUAL) { + return State::NOT_EQUAL; + } else if (func == GL_GEQUAL) { + return State::GREATER_EQUAL; + } else if (func == GL_ALWAYS) { + return State::ALWAYS; + } + + return State::ALWAYS; +} + +State::StencilOp stencilOpFromGL(GLenum stencilOp) { + if (stencilOp == GL_KEEP) { + return State::STENCIL_OP_KEEP; + } else if (stencilOp == GL_ZERO) { + return State::STENCIL_OP_ZERO; + } else if (stencilOp == GL_REPLACE) { + return State::STENCIL_OP_REPLACE; + } else if (stencilOp == GL_INCR_WRAP) { + return State::STENCIL_OP_INCR_SAT; + } else if (stencilOp == GL_DECR_WRAP) { + return State::STENCIL_OP_DECR_SAT; + } else if (stencilOp == GL_INVERT) { + return State::STENCIL_OP_INVERT; + } else if (stencilOp == GL_INCR) { + return State::STENCIL_OP_INCR; + } else if (stencilOp == GL_DECR) { + return State::STENCIL_OP_DECR; + } + + return State::STENCIL_OP_KEEP; +} + +State::BlendOp blendOpFromGL(GLenum blendOp) { + if (blendOp == GL_FUNC_ADD) { + return State::BLEND_OP_ADD; + } else if (blendOp == GL_FUNC_SUBTRACT) { + return State::BLEND_OP_SUBTRACT; + } else if (blendOp == GL_FUNC_REVERSE_SUBTRACT) { + return State::BLEND_OP_REV_SUBTRACT; + } else if (blendOp == GL_MIN) { + return State::BLEND_OP_MIN; + } else if (blendOp == GL_MAX) { + return State::BLEND_OP_MAX; + } + + return State::BLEND_OP_ADD; +} + +State::BlendArg blendArgFromGL(GLenum blendArg) { + if (blendArg == GL_ZERO) { + return State::ZERO; + } else if (blendArg == GL_ONE) { + return State::ONE; + } else if (blendArg == GL_SRC_COLOR) { + return State::SRC_COLOR; + } else if (blendArg == GL_ONE_MINUS_SRC_COLOR) { + return State::INV_SRC_COLOR; + } else if (blendArg == GL_DST_COLOR) { + return State::DEST_COLOR; + } else if (blendArg == GL_ONE_MINUS_DST_COLOR) { + return State::INV_DEST_COLOR; + } else if (blendArg == GL_SRC_ALPHA) { + return State::SRC_ALPHA; + } else if (blendArg == GL_ONE_MINUS_SRC_ALPHA) { + return State::INV_SRC_ALPHA; + } else if (blendArg == GL_DST_ALPHA) { + return State::DEST_ALPHA; + } else if (blendArg == GL_ONE_MINUS_DST_ALPHA) { + return State::INV_DEST_ALPHA; + } else if (blendArg == GL_CONSTANT_COLOR) { + return State::FACTOR_COLOR; + } else if (blendArg == GL_ONE_MINUS_CONSTANT_COLOR) { + return State::INV_FACTOR_COLOR; + } else if (blendArg == GL_CONSTANT_ALPHA) { + return State::FACTOR_ALPHA; + } else if (blendArg == GL_ONE_MINUS_CONSTANT_ALPHA) { + return State::INV_FACTOR_ALPHA; + } + + return State::ONE; +} + +void GLBackend::getCurrentGLState(State::Data& state) { + { + GLint modes[2]; + glGetIntegerv(GL_POLYGON_MODE, modes); + if (modes[0] == GL_FILL) { + state.fillMode = State::FILL_FACE; + } else { + if (modes[0] == GL_LINE) { + state.fillMode = State::FILL_LINE; + } else { + state.fillMode = State::FILL_POINT; + } + } + } + { + if (glIsEnabled(GL_CULL_FACE)) { + GLint mode; + glGetIntegerv(GL_CULL_FACE_MODE, &mode); + state.cullMode = (mode == GL_FRONT ? State::CULL_FRONT : State::CULL_BACK); + } else { + state.cullMode = State::CULL_NONE; + } + } + { + GLint winding; + glGetIntegerv(GL_FRONT_FACE, &winding); + state.frontFaceClockwise = (winding == GL_CW); + state.depthClipEnable = glIsEnabled(GL_DEPTH_CLAMP); + state.scissorEnable = glIsEnabled(GL_SCISSOR_TEST); + state.multisampleEnable = glIsEnabled(GL_MULTISAMPLE); + state.antialisedLineEnable = glIsEnabled(GL_LINE_SMOOTH); + } + { + if (glIsEnabled(GL_POLYGON_OFFSET_FILL)) { + glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &state.depthBiasSlopeScale); + glGetFloatv(GL_POLYGON_OFFSET_UNITS, &state.depthBias); + } + } + { + GLboolean isEnabled = glIsEnabled(GL_DEPTH_TEST); + GLboolean writeMask; + glGetBooleanv(GL_DEPTH_WRITEMASK, &writeMask); + GLint func; + glGetIntegerv(GL_DEPTH_FUNC, &func); + + state.depthTest = State::DepthTest(isEnabled, writeMask, comparisonFuncFromGL(func)); + } + { + GLboolean isEnabled = glIsEnabled(GL_STENCIL_TEST); + + GLint frontWriteMask; + GLint frontReadMask; + GLint frontRef; + GLint frontFail; + GLint frontDepthFail; + GLint frontPass; + GLint frontFunc; + glGetIntegerv(GL_STENCIL_WRITEMASK, &frontWriteMask); + glGetIntegerv(GL_STENCIL_VALUE_MASK, &frontReadMask); + glGetIntegerv(GL_STENCIL_REF, &frontRef); + glGetIntegerv(GL_STENCIL_FAIL, &frontFail); + glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &frontDepthFail); + glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &frontPass); + glGetIntegerv(GL_STENCIL_FUNC, &frontFunc); + + GLint backWriteMask; + GLint backReadMask; + GLint backRef; + GLint backFail; + GLint backDepthFail; + GLint backPass; + GLint backFunc; + glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &backWriteMask); + glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &backReadMask); + glGetIntegerv(GL_STENCIL_BACK_REF, &backRef); + glGetIntegerv(GL_STENCIL_BACK_FAIL, &backFail); + glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &backDepthFail); + glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &backPass); + glGetIntegerv(GL_STENCIL_BACK_FUNC, &backFunc); + + state.stencilActivation = State::StencilActivation(isEnabled, frontWriteMask, backWriteMask); + state.stencilTestFront = State::StencilTest(frontRef, frontReadMask, comparisonFuncFromGL(frontFunc), stencilOpFromGL(frontFail), stencilOpFromGL(frontDepthFail), stencilOpFromGL(frontPass)); + state.stencilTestBack = State::StencilTest(backRef, backReadMask, comparisonFuncFromGL(backFunc), stencilOpFromGL(backFail), stencilOpFromGL(backDepthFail), stencilOpFromGL(backPass)); + } + { + GLint mask = 0xFFFFFFFF; + +#ifdef GPU_PROFILE_CORE + if (glIsEnabled(GL_SAMPLE_MASK)) { + glGetIntegerv(GL_SAMPLE_MASK, &mask); + state.sampleMask = mask; + } +#endif + state.sampleMask = mask; + } + { + state.alphaToCoverageEnable = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); + } + { + GLboolean isEnabled = glIsEnabled(GL_BLEND); + GLint srcRGB; + GLint srcA; + GLint dstRGB; + GLint dstA; + glGetIntegerv(GL_BLEND_SRC_RGB, &srcRGB); + glGetIntegerv(GL_BLEND_SRC_ALPHA, &srcA); + glGetIntegerv(GL_BLEND_DST_RGB, &dstRGB); + glGetIntegerv(GL_BLEND_DST_ALPHA, &dstA); + + GLint opRGB; + GLint opA; + glGetIntegerv(GL_BLEND_EQUATION_RGB, &opRGB); + glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &opA); + + state.blendFunction = State::BlendFunction(isEnabled, + blendArgFromGL(srcRGB), blendOpFromGL(opRGB), blendArgFromGL(dstRGB), + blendArgFromGL(srcA), blendOpFromGL(opA), blendArgFromGL(dstA)); + } + { + GLboolean mask[4]; + glGetBooleanv(GL_COLOR_WRITEMASK, mask); + state.colorWriteMask = (mask[0] ? State::WRITE_RED : 0) + | (mask[1] ? State::WRITE_GREEN : 0) + | (mask[2] ? State::WRITE_BLUE : 0) + | (mask[3] ? State::WRITE_ALPHA : 0); + } + + CHECK_GL_ERROR(); +} + +void GLBackend::syncPipelineStateCache() { + State::Data state; + + getCurrentGLState(state); + State::Signature signature = State::evalSignature(state); + + _pipeline._stateCache = state; + _pipeline._stateSignatureCache = signature; +} + +static GLenum GL_COMPARISON_FUNCTIONS[] = { + GL_NEVER, + GL_LESS, + GL_EQUAL, + GL_LEQUAL, + GL_GREATER, + GL_NOTEQUAL, + GL_GEQUAL, + GL_ALWAYS }; + +void GLBackend::do_setStateFillMode(int32 mode) { + if (_pipeline._stateCache.fillMode != mode) { + static GLenum GL_FILL_MODES[] = { GL_POINT, GL_LINE, GL_FILL }; + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_MODES[mode]); + CHECK_GL_ERROR(); + + _pipeline._stateCache.fillMode = State::FillMode(mode); + } +} + +void GLBackend::do_setStateCullMode(int32 mode) { + if (_pipeline._stateCache.cullMode != mode) { + static GLenum GL_CULL_MODES[] = { GL_FRONT_AND_BACK, GL_FRONT, GL_BACK }; + if (mode == State::CULL_NONE) { + glDisable(GL_CULL_FACE); + glCullFace(GL_FRONT_AND_BACK); + } else { + glEnable(GL_CULL_FACE); + glCullFace(GL_CULL_MODES[mode]); + } + CHECK_GL_ERROR(); + + _pipeline._stateCache.cullMode = State::CullMode(mode); + } +} + +void GLBackend::do_setStateFrontFaceClockwise(bool isClockwise) { + if (_pipeline._stateCache.frontFaceClockwise != isClockwise) { + static GLenum GL_FRONT_FACES[] = { GL_CCW, GL_CW }; + glFrontFace(GL_FRONT_FACES[isClockwise]); + CHECK_GL_ERROR(); + + _pipeline._stateCache.frontFaceClockwise = isClockwise; + } +} + +void GLBackend::do_setStateDepthClipEnable(bool enable) { + if (_pipeline._stateCache.depthClipEnable != enable) { + if (enable) { + glEnable(GL_DEPTH_CLAMP); + } else { + glDisable(GL_DEPTH_CLAMP); + } + CHECK_GL_ERROR(); + + _pipeline._stateCache.depthClipEnable = enable; + } +} + +void GLBackend::do_setStateScissorEnable(bool enable) { + if (_pipeline._stateCache.scissorEnable != enable) { + if (enable) { + glEnable(GL_SCISSOR_TEST); + } else { + glDisable(GL_SCISSOR_TEST); + } + CHECK_GL_ERROR(); + + _pipeline._stateCache.scissorEnable = enable; + } +} + +void GLBackend::do_setStateMultisampleEnable(bool enable) { + if (_pipeline._stateCache.multisampleEnable != enable) { + if (enable) { + glEnable(GL_MULTISAMPLE); + } else { + glDisable(GL_MULTISAMPLE); + } + CHECK_GL_ERROR(); + + _pipeline._stateCache.multisampleEnable = enable; + } +} + +void GLBackend::do_setStateAntialiasedLineEnable(bool enable) { + if (_pipeline._stateCache.antialisedLineEnable != enable) { + if (enable) { + glEnable(GL_POINT_SMOOTH); + glEnable(GL_LINE_SMOOTH); + } else { + glDisable(GL_POINT_SMOOTH); + glDisable(GL_LINE_SMOOTH); + } + CHECK_GL_ERROR(); + + _pipeline._stateCache.antialisedLineEnable = enable; + } +} + +void GLBackend::do_setStateDepthBias(Vec2 bias) { + if ( (bias.x != _pipeline._stateCache.depthBias) || (bias.y != _pipeline._stateCache.depthBiasSlopeScale)) { + if ((bias.x != 0.f) || (bias.y != 0.f)) { + glEnable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_POLYGON_OFFSET_LINE); + glEnable(GL_POLYGON_OFFSET_POINT); + glPolygonOffset(bias.x, bias.y); + } else { + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_POLYGON_OFFSET_LINE); + glDisable(GL_POLYGON_OFFSET_POINT); + } + _pipeline._stateCache.depthBias = bias.x; + _pipeline._stateCache.depthBiasSlopeScale = bias.y; + } +} + +void GLBackend::do_setStateDepthTest(State::DepthTest test) { + if (_pipeline._stateCache.depthTest != test) { + if (test.isEnabled()) { + glEnable(GL_DEPTH_TEST); + glDepthMask(test.getWriteMask()); + glDepthFunc(GL_COMPARISON_FUNCTIONS[test.getFunction()]); + } else { + glDisable(GL_DEPTH_TEST); + } + CHECK_GL_ERROR(); + + _pipeline._stateCache.depthTest = test; + } +} + +void GLBackend::do_setStateStencil(State::StencilActivation activation, State::StencilTest frontTest, State::StencilTest backTest) { + + if ((_pipeline._stateCache.stencilActivation != activation) + || (_pipeline._stateCache.stencilTestFront != frontTest) + || (_pipeline._stateCache.stencilTestBack != backTest)) { + + if (activation.isEnabled()) { + glEnable(GL_STENCIL_TEST); + glStencilMaskSeparate(GL_FRONT, activation.getWriteMaskFront()); + glStencilMaskSeparate(GL_BACK, activation.getWriteMaskBack()); + + static GLenum STENCIL_OPS[] = { + GL_KEEP, + GL_ZERO, + GL_REPLACE, + GL_INCR_WRAP, + GL_DECR_WRAP, + GL_INVERT, + GL_INCR, + GL_DECR }; + + glStencilFuncSeparate(GL_FRONT, STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]); + glStencilFuncSeparate(GL_FRONT, GL_COMPARISON_FUNCTIONS[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask()); + + glStencilFuncSeparate(GL_BACK, STENCIL_OPS[backTest.getFailOp()], STENCIL_OPS[backTest.getPassOp()], STENCIL_OPS[backTest.getDepthFailOp()]); + glStencilFuncSeparate(GL_BACK, GL_COMPARISON_FUNCTIONS[backTest.getFunction()], backTest.getReference(), backTest.getReadMask()); + } else { + glDisable(GL_STENCIL_TEST); + } + CHECK_GL_ERROR(); + + _pipeline._stateCache.stencilActivation = activation; + _pipeline._stateCache.stencilTestFront = frontTest; + _pipeline._stateCache.stencilTestBack = backTest; + } +} + +void GLBackend::do_setStateAlphaToCoverageEnable(bool enable) { + if (_pipeline._stateCache.alphaToCoverageEnable != enable) { + if (enable) { + glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); + } else { + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); + } + CHECK_GL_ERROR(); + _pipeline._stateCache.alphaToCoverageEnable = enable; + } +} + +void GLBackend::do_setStateSampleMask(uint32 mask) { + if (_pipeline._stateCache.sampleMask != mask) { +#ifdef GPU_CORE_PROFILE + if (mask == 0xFFFFFFFF) { + glDisable(GL_SAMPLE_MASK); + } else { + glEnable(GL_SAMPLE_MASK); + glSampleMaski(0, mask); + } +#endif + _pipeline._stateCache.sampleMask = mask; + } +} + +void GLBackend::do_setStateBlend(State::BlendFunction function) { + if (_pipeline._stateCache.blendFunction != function) { + if (function.isEnabled()) { + glEnable(GL_BLEND); + + static GLenum GL_BLEND_OPS[] = { + GL_FUNC_ADD, + GL_FUNC_SUBTRACT, + GL_FUNC_REVERSE_SUBTRACT, + GL_MIN, + GL_MAX }; + + glBlendEquationSeparate(GL_BLEND_OPS[function.getOperationColor()], GL_BLEND_OPS[function.getOperationAlpha()]); + CHECK_GL_ERROR(); + + static GLenum BLEND_ARGS[] = { + GL_ZERO, + GL_ONE, + GL_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA_SATURATE, + GL_CONSTANT_COLOR, + GL_ONE_MINUS_CONSTANT_COLOR, + GL_CONSTANT_ALPHA, + GL_ONE_MINUS_CONSTANT_ALPHA, + }; + + glBlendFuncSeparate(BLEND_ARGS[function.getSourceColor()], BLEND_ARGS[function.getDestinationColor()], + BLEND_ARGS[function.getSourceAlpha()], BLEND_ARGS[function.getDestinationAlpha()]); + CHECK_GL_ERROR(); + } else { + glDisable(GL_BLEND); + } + + _pipeline._stateCache.blendFunction = function; + } +} + +void GLBackend::do_setStateColorWriteMask(uint32 mask) { + if (_pipeline._stateCache.colorWriteMask = mask) { + glColorMask(mask & State::ColorMask::WRITE_RED, + mask & State::ColorMask::WRITE_GREEN, + mask & State::ColorMask::WRITE_BLUE, + mask & State::ColorMask::WRITE_ALPHA ); + + _pipeline._stateCache.colorWriteMask = mask; + } +} + + +void GLBackend::do_setStateBlendFactor(Batch& batch, uint32 paramOffset) { + + Vec4 factor(batch._params[paramOffset + 0]._float, + batch._params[paramOffset + 1]._float, + batch._params[paramOffset + 2]._float, + batch._params[paramOffset + 3]._float); + + glBlendColor(factor.x, factor.y, factor.z, factor.w); + CHECK_GL_ERROR(); +} \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Pipeline.cpp b/libraries/gpu/src/gpu/Pipeline.cpp index 931d330c2b..237932b07d 100755 --- a/libraries/gpu/src/gpu/Pipeline.cpp +++ b/libraries/gpu/src/gpu/Pipeline.cpp @@ -17,7 +17,7 @@ using namespace gpu; Pipeline::Pipeline(): _program(), - _states() + _state() { } @@ -25,10 +25,10 @@ Pipeline::~Pipeline() { } -Pipeline* Pipeline::create(const ShaderPointer& program, const States& states) { +Pipeline* Pipeline::create(const ShaderPointer& program, const StatePointer& state) { Pipeline* pipeline = new Pipeline(); pipeline->_program = program; - pipeline->_states = states; + pipeline->_state = state; return pipeline; } diff --git a/libraries/gpu/src/gpu/Pipeline.h b/libraries/gpu/src/gpu/Pipeline.h index faa671c30f..73e9a29913 100755 --- a/libraries/gpu/src/gpu/Pipeline.h +++ b/libraries/gpu/src/gpu/Pipeline.h @@ -22,23 +22,23 @@ namespace gpu { class Pipeline { public: - static Pipeline* create(const ShaderPointer& program, const States& states); + static Pipeline* create(const ShaderPointer& program, const StatePointer& state); ~Pipeline(); const ShaderPointer& getProgram() const { return _program; } - const States& getStates() const { return _states; } + const StatePointer& getState() const { return _state; } protected: ShaderPointer _program; - States _states; + StatePointer _state; Pipeline(); Pipeline(const Pipeline& pipeline); // deep copy of the sysmem shader Pipeline& operator=(const Pipeline& pipeline); // deep copy of the sysmem texture // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = NULL; + mutable GPUObject* _gpuObject = nullptr; void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } GPUObject* getGPUObject() const { return _gpuObject; } friend class Backend; diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index 3da25ae78f..96b961ffd7 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -24,10 +24,6 @@ namespace gpu { -class GPUObject; - -typedef int Stamp; - class Resource { public: typedef unsigned char Byte; diff --git a/libraries/gpu/src/gpu/State.cpp b/libraries/gpu/src/gpu/State.cpp index 0b8edb7cd2..76a444a2e6 100755 --- a/libraries/gpu/src/gpu/State.cpp +++ b/libraries/gpu/src/gpu/State.cpp @@ -14,7 +14,73 @@ using namespace gpu; - -State::~State() -{ +State::State() { } + +State::~State() { +} + +const State::Data State::DEFAULT = State::Data(); + +State::Signature State::evalSignature(const Data& state) { + Signature signature(0); + + if (state.fillMode != State::DEFAULT.fillMode) { + signature.set(State::FILL_MODE); + } + if (state.cullMode != State::DEFAULT.cullMode) { + signature.set(State::CULL_MODE); + } + if (state.frontFaceClockwise != State::DEFAULT.frontFaceClockwise) { + signature.set(State::FRONT_FACE_CLOCKWISE); + } + if (state.depthClipEnable != State::DEFAULT.depthClipEnable) { + signature.set(State::DEPTH_CLIP_ENABLE); + } + if (state.scissorEnable != State::DEFAULT.scissorEnable) { + signature.set(State::SCISSOR_ENABLE); + } + if (state.multisampleEnable != State::DEFAULT.multisampleEnable) { + signature.set(State::MULTISAMPLE_ENABLE); + } + if (state.antialisedLineEnable != State::DEFAULT.antialisedLineEnable) { + signature.set(State::ANTIALISED_LINE_ENABLE); + } + if (state.depthBias != State::DEFAULT.depthBias) { + signature.set(State::DEPTH_BIAS); + } + if (state.depthBiasSlopeScale != State::DEFAULT.depthBiasSlopeScale) { + signature.set(State::DEPTH_BIAS_SLOPE_SCALE); + } + if (state.depthTest != State::DEFAULT.depthTest) { + signature.set(State::DEPTH_TEST); + } + if (state.stencilActivation != State::DEFAULT.stencilActivation) { + signature.set(State::STENCIL_ACTIVATION); + } + if (state.stencilTestFront != State::DEFAULT.stencilTestFront) { + signature.set(State::STENCIL_TEST_FRONT); + } + if (state.stencilTestBack != State::DEFAULT.stencilTestBack) { + signature.set(State::STENCIL_TEST_BACK); + } + if (state.sampleMask != State::DEFAULT.sampleMask) { + signature.set(State::SAMPLE_MASK); + } + if (state.alphaToCoverageEnable != State::DEFAULT.alphaToCoverageEnable) { + signature.set(State::ALPHA_TO_COVERAGE_ENABLE); + } + if (state.blendFunction != State::DEFAULT.blendFunction) { + signature.set(State::BLEND_FUNCTION); + } + if (state.colorWriteMask != State::DEFAULT.colorWriteMask) { + signature.set(State::COLOR_WRITE_MASK); + } + + return signature; +} + +State::State(const Data& values) : + _values(values) { + _signature = evalSignature(_values); +} diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 92ef4c1c8d..56bc472cac 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -1,88 +1,418 @@ -// -// Pipeline.h -// libraries/gpu/src/gpu -// -// Created by Sam Gateau on 3/8/2015. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#ifndef hifi_gpu_State_h -#define hifi_gpu_State_h - -#include "Format.h" -#include -#include - - -namespace gpu { - -class GPUObject; - -class State { -public: - State() {} - virtual ~State(); - - // Work in progress, not used - /* - enum Field { - FILL_MODE, - CULL_MODE, - DEPTH_BIAS, - DEPTH_BIAS_CLAMP, - DEPTH_BIASSLOPE_SCALE, - - FRONT_CLOCKWISE, - DEPTH_CLIP_ENABLE, - SCISSR_ENABLE, - MULTISAMPLE_ENABLE, - ANTIALISED_LINE_ENABLE, - - DEPTH_ENABLE, - DEPTH_WRITE_MASK, - DEPTH_FUNCTION, - - STENCIL_ENABLE, - STENCIL_READ_MASK, - STENCIL_WRITE_MASK, - STENCIL_FUNCTION_FRONT, - STENCIL_FUNCTION_BACK, - STENCIL_REFERENCE, - - BLEND_INDEPENDANT_ENABLE, - BLEND_ENABLE, - BLEND_SOURCE, - BLEND_DESTINATION, - BLEND_OPERATION, - BLEND_SOURCE_ALPHA, - BLEND_DESTINATION_ALPHA, - BLEND_OPERATION_ALPHA, - BLEND_WRITE_MASK, - BLEND_FACTOR, - - SAMPLE_MASK, - - ALPHA_TO_COVERAGE_ENABLE, - }; - */ - -protected: - State(const State& state); - State& operator=(const State& state); - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = NULL; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; -}; - -typedef QSharedPointer< State > StatePointer; -typedef std::vector< StatePointer > States; - -}; - - -#endif +// +// State +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_State_h +#define hifi_gpu_State_h + +#include "Format.h" + +#include +#include +#include +#include + +// Why a macro and not a fancy template you will ask me ? +// Because some of the fields are bool packed tightly in the State::Cache class +// and it s just not good anymore for template T& variable manipulation... +#define SET_FIELD(field, defaultValue, value, dest) {\ + dest = value;\ + if (value == defaultValue) {\ + _signature.reset(field);\ + } else {\ + _signature.set(field);\ + }\ + _stamp++;\ +}\ + + +namespace gpu { + +class GPUObject; + +class State { +public: + State(); + virtual ~State(); + + const Stamp getStamp() const { return _stamp; } + + enum ComparisonFunction { + NEVER = 0, + LESS, + EQUAL, + LESS_EQUAL, + GREATER, + NOT_EQUAL, + GREATER_EQUAL, + ALWAYS, + + NUM_COMPARISON_FUNCS, + }; + + enum FillMode { + FILL_POINT = 0, + FILL_LINE, + FILL_FACE, + + NUM_FILL_MODES, + }; + + enum CullMode { + CULL_NONE = 0, + CULL_FRONT, + CULL_BACK, + + NUM_CULL_MODES, + }; + + enum StencilOp { + STENCIL_OP_KEEP = 0, + STENCIL_OP_ZERO, + STENCIL_OP_REPLACE, + STENCIL_OP_INCR_SAT, + STENCIL_OP_DECR_SAT, + STENCIL_OP_INVERT, + STENCIL_OP_INCR, + STENCIL_OP_DECR, + + NUM_STENCIL_OPS, + }; + + enum BlendArg { + ZERO = 0, + ONE, + SRC_COLOR, + INV_SRC_COLOR, + SRC_ALPHA, + INV_SRC_ALPHA, + DEST_ALPHA, + INV_DEST_ALPHA, + DEST_COLOR, + INV_DEST_COLOR, + SRC_ALPHA_SAT, + FACTOR_COLOR, + INV_FACTOR_COLOR, + FACTOR_ALPHA, + INV_FACTOR_ALPHA, + + NUM_BLEND_ARGS, + }; + + enum BlendOp { + BLEND_OP_ADD = 0, + BLEND_OP_SUBTRACT, + BLEND_OP_REV_SUBTRACT, + BLEND_OP_MIN, + BLEND_OP_MAX, + + NUM_BLEND_OPS, + }; + + enum ColorMask + { + WRITE_NONE = 0, + WRITE_RED = 1, + WRITE_GREEN = 2, + WRITE_BLUE = 4, + WRITE_ALPHA = 8, + WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA ), + }; + + class DepthTest { + uint8 _function = LESS; + bool _writeMask = true; + bool _enabled = false; + public: + DepthTest(bool enabled, bool writeMask, ComparisonFunction func) : + _function(func), _writeMask(writeMask), _enabled(enabled) {} + + bool isEnabled() const { return _enabled; } + ComparisonFunction getFunction() const { return ComparisonFunction(_function); } + bool getWriteMask() const { return _writeMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const DepthTest& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const DepthTest& right) const { return getRaw() != right.getRaw(); } + }; + + class StencilTest { + static const int FUNC_MASK = 0x000f; + static const int FAIL_OP_MASK = 0x00f0; + static const int DEPTH_FAIL_OP_MASK = 0x0f00; + static const int PASS_OP_MASK = 0xf000; + static const int FAIL_OP_OFFSET = 4; + static const int DEPTH_FAIL_OP_OFFSET = 8; + static const int PASS_OP_OFFSET = 12; + + uint16 _functionAndOperations; + uint8 _reference = 0; + uint8 _readMask = 0xff; + public: + + StencilTest(uint8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) : + _functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)), + _reference(reference), _readMask(readMask) + {} + + ComparisonFunction getFunction() const { return ComparisonFunction(_functionAndOperations & FUNC_MASK); } + StencilOp getFailOp() const { return StencilOp((_functionAndOperations & FAIL_OP_MASK) >> FAIL_OP_OFFSET); } + StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); } + StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); } + + uint8 getReference() const { return _reference; } + uint8 getReadMask() const { return _readMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + StencilTest(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); } + }; + + class StencilActivation { + uint8 _frontWriteMask = 0xFF; + uint8 _backWriteMask = 0xFF; + uint16 _enabled = 0; + public: + + StencilActivation(bool enabled, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) : + _frontWriteMask(frontWriteMask), _backWriteMask(backWriteMask), _enabled(enabled) {} + + bool isEnabled() const { return (_enabled != 0); } + uint8 getWriteMaskFront() const { return _frontWriteMask; } + uint8 getWriteMaskBack() const { return _backWriteMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + StencilActivation(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const StencilActivation& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const StencilActivation& right) const { return getRaw() != right.getRaw(); } + }; + + class BlendFunction { + static const int COLOR_MASK = 0x0f; + static const int ALPHA_MASK = 0xf0; + static const int ALPHA_OFFSET = 4; + + uint8 _enabled; + uint8 _source; + uint8 _destination; + uint8 _operation; + public: + + BlendFunction(bool enabled, + BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, + BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) : + _enabled(enabled), + _source(sourceColor | (sourceAlpha << ALPHA_OFFSET)), + _destination(destinationColor | (destinationAlpha << ALPHA_OFFSET)), + _operation(operationColor | (operationAlpha << ALPHA_OFFSET)) {} + + BlendFunction(bool enabled, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) : + _enabled(enabled), + _source(source | (source << ALPHA_OFFSET)), + _destination(destination | (destination << ALPHA_OFFSET)), + _operation(operation | (operation << ALPHA_OFFSET)) {} + + bool isEnabled() const { return (_enabled != 0); } + + BlendArg getSourceColor() const { return BlendArg(_source & COLOR_MASK); } + BlendArg getDestinationColor() const { return BlendArg(_destination & COLOR_MASK); } + BlendOp getOperationColor() const { return BlendOp(_operation & COLOR_MASK); } + + BlendArg getSourceAlpha() const { return BlendArg((_source & ALPHA_MASK) >> ALPHA_OFFSET); } + BlendArg getDestinationAlpha() const { return BlendArg((_destination & ALPHA_MASK) >> ALPHA_OFFSET); } + BlendOp getOperationAlpha() const { return BlendOp((_operation & ALPHA_MASK) >> ALPHA_OFFSET); } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + BlendFunction(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const BlendFunction& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const BlendFunction& right) const { return getRaw() != right.getRaw(); } + }; + + // The Data class is the full explicit description of the State class fields value. + // Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value + class Data { + public: + float depthBias = 0.0f; + float depthBiasSlopeScale = 0.0f; + + DepthTest depthTest = DepthTest(false, true, LESS); + + StencilActivation stencilActivation = StencilActivation(false); + StencilTest stencilTestFront = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + StencilTest stencilTestBack = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + + uint32 sampleMask = 0xFFFFFFFF; + + BlendFunction blendFunction = BlendFunction(false); + + uint8 fillMode = FILL_FACE; + uint8 cullMode = CULL_NONE; + + uint8 colorWriteMask = WRITE_ALL; + + bool frontFaceClockwise : 1; + bool depthClipEnable : 1; + bool scissorEnable : 1; + bool multisampleEnable : 1; + bool antialisedLineEnable : 1; + bool alphaToCoverageEnable : 1; + + Data() : + frontFaceClockwise(false), + depthClipEnable(false), + scissorEnable(false), + multisampleEnable(false), + antialisedLineEnable(false), + alphaToCoverageEnable(false) + {} + }; + + // The unique default values for all the fields + static const Data DEFAULT; + void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, DEFAULT.fillMode, fill, _values.fillMode); } + FillMode getFillMode() const { return FillMode(_values.fillMode); } + + void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, DEFAULT.cullMode, cull, _values.cullMode); } + CullMode getCullMode() const { return CullMode(_values.cullMode); } + + void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, DEFAULT.frontFaceClockwise, isClockwise, _values.frontFaceClockwise); } + bool isFrontFaceClockwise() const { return _values.frontFaceClockwise; } + + void setDepthClipEnable(bool enable) { SET_FIELD(DEPTH_CLIP_ENABLE, DEFAULT.depthClipEnable, enable, _values.depthClipEnable); } + bool isDepthClipEnable() const { return _values.depthClipEnable; } + + void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, DEFAULT.scissorEnable, enable, _values.scissorEnable); } + bool isScissorEnable() const { return _values.scissorEnable; } + + void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, DEFAULT.multisampleEnable, enable, _values.multisampleEnable); } + bool isMultisampleEnable() const { return _values.multisampleEnable; } + + void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, DEFAULT.antialisedLineEnable, enable, _values.antialisedLineEnable); } + bool isAntialiasedLineEnable() const { return _values.antialisedLineEnable; } + + // Depth Bias + void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, DEFAULT.depthBias, bias, _values.depthBias); } + float getDepthBias() const { return _values.depthBias; } + + void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, DEFAULT.depthBiasSlopeScale, scale, _values.depthBiasSlopeScale); } + float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; } + + // Depth Test + void setDepthTest(DepthTest depthTest) { SET_FIELD(DEPTH_TEST, DEFAULT.depthTest, depthTest, _values.depthTest); } + void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) { setDepthTest(DepthTest(enable, writeMask, func)); } + DepthTest getDepthTest() const { return _values.depthTest; } + + bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); } + bool getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } + ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); } + + // Stencil test + void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) { + SET_FIELD(STENCIL_ACTIVATION, DEFAULT.stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask), _values.stencilActivation); + SET_FIELD(STENCIL_TEST_FRONT, DEFAULT.stencilTestFront, frontTest, _values.stencilTestFront); + SET_FIELD(STENCIL_TEST_BACK, DEFAULT.stencilTestBack, backTest, _values.stencilTestBack); } + void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) { + setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest); } + + StencilActivation getStencilActivation() const { return _values.stencilActivation; } + StencilTest getStencilTestFront() const { return _values.stencilTestFront; } + StencilTest getStencilTestBack() const { return _values.stencilTestBack; } + + bool isStencilEnabled() const { return getStencilActivation().isEnabled(); } + uint8 getStencilWriteMaskFront() const { return getStencilActivation().getWriteMaskFront(); } + uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); } + + // Alpha to coverage + void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, DEFAULT.alphaToCoverageEnable, enable, _values.alphaToCoverageEnable); } + bool isAlphaToCoverageEnabled() const { return _values.alphaToCoverageEnable; } + + // Sample mask + void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, DEFAULT.sampleMask, mask, _values.sampleMask); } + uint32 getSampleMask() const { return _values.sampleMask; } + + // Blend Function + void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, DEFAULT.blendFunction, function, _values.blendFunction); } + BlendFunction getBlendFunction() const { return _values.blendFunction; } + + void setBlendFunction(bool enabled, BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) { + setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha, destinationAlpha)); } + void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) { + setBlendFunction(BlendFunction(enabled, source, operation, destination)); } + + bool isBlendEnabled() const { return getBlendFunction().isEnabled(); } + + // Color write mask + void setColorWriteMask(uint8 mask) { SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, mask, _values.colorWriteMask); } + uint8 getColorWriteMask() const { return _values.colorWriteMask; } + + // All the possible fields + enum Field { + FILL_MODE, + CULL_MODE, + FRONT_FACE_CLOCKWISE, + DEPTH_CLIP_ENABLE, + SCISSOR_ENABLE, + MULTISAMPLE_ENABLE, + ANTIALISED_LINE_ENABLE, + + DEPTH_BIAS, + DEPTH_BIAS_SLOPE_SCALE, + + DEPTH_TEST, + + STENCIL_ACTIVATION, + STENCIL_TEST_FRONT, + STENCIL_TEST_BACK, + + SAMPLE_MASK, + ALPHA_TO_COVERAGE_ENABLE, + + BLEND_FUNCTION, + + COLOR_WRITE_MASK, + + NUM_FIELDS, // not a valid field, just the count + }; + + // The signature of the state tells which fields of the state are not default + // this way during rendering the Backend can compare it's current state and try to minimize the job to do + typedef std::bitset Signature; + + Signature getSignature() const { return _signature; } + + static Signature evalSignature(const Data& state); + + // For convenience, create a State from the values directly + State(const Data& values); + const Data& getValues() const { return _values; } + +protected: + State(const State& state); + State& operator=(const State& state); + + Data _values; + Signature _signature{0}; + Stamp _stamp{0}; + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = nullptr; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; +}; + +typedef std::shared_ptr< State > StatePointer; +typedef std::vector< StatePointer > States; + +}; + + +#endif diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 096ec273eb..b72aa16497 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -184,6 +184,14 @@ void Atmosphere::setInnerOuterRadiuses(float inner, float outer) { data._scales.z = data._scales.x / data._scales.y; } +Skybox::Skybox() { +} + +void Skybox::setCubemap(const gpu::TexturePointer& cubemap) { + _cubemap = cubemap; +} + + const int NUM_DAYS_PER_YEAR = 365; const float NUM_HOURS_PER_DAY = 24.0f; @@ -207,7 +215,12 @@ SunSkyStage::SunSkyStage() : auto skyFromAtmosphereVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(SkyFromAtmosphere_vert))); auto skyFromAtmosphereFragment = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(SkyFromAtmosphere_frag))); auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyFromAtmosphereVertex, skyFromAtmosphereFragment)); - _skyPipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, gpu::States())); + + auto skyState = gpu::StatePointer(new gpu::State()); + // skyState->setStencilEnable(false); + // skyState->setBlendEnable(false); + + _skyPipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState)); } @@ -273,3 +286,7 @@ void SunSkyStage::updateGraphicsObject() const { } +void SunSkyStage::setSkybox(const SkyboxPointer& skybox) { + _skybox = skybox; + invalidate(); +} \ No newline at end of file diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index 3cc8b4a6e9..30c96259ca 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -160,6 +160,21 @@ protected: }; typedef QSharedPointer< Atmosphere > AtmospherePointer; + +class Skybox { +public: + Skybox(); + Skybox& operator= (const Atmosphere& Skybox); + virtual ~Skybox() {}; + + void setCubemap(const gpu::TexturePointer& cubemap); + const gpu::TexturePointer& getCubemap() const { return _cubemap; } + +protected: + gpu::TexturePointer _cubemap; +}; +typedef QSharedPointer< Skybox > SkyboxPointer; + // Sun sky stage generates the rendering primitives to display a scene realistically // at the specified location and time around earth class SunSkyStage { @@ -197,9 +212,14 @@ public: LightPointer getSunLight() const { valid(); return _sunLight; } AtmospherePointer getAtmosphere() const { valid(); return _atmosphere; } + // Skybox + void setSkybox(const SkyboxPointer& skybox); + const SkyboxPointer& getSkybox() const { valid(); return _skybox; } + protected: LightPointer _sunLight; AtmospherePointer _atmosphere; + SkyboxPointer _skybox; gpu::PipelinePointer _skyPipeline; diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index 066e0198b1..a7f4055bba 100755 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -22,12 +22,19 @@ float evalOpaqueFinalAlpha(float alpha, float mapAlpha) { } void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) { + if (alpha != glowIntensity) { + discard; + } gl_FragData[0] = vec4(diffuse.rgb, alpha); gl_FragData[1] = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); gl_FragData[2] = vec4(specular, shininess / 128.0); } void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess, vec3 emissive) { + if (alpha != glowIntensity) { + discard; + } + gl_FragData[0] = vec4(diffuse.rgb, alpha); //gl_FragData[1] = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); gl_FragData[1] = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5); @@ -35,6 +42,10 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 s } void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) { + if (alpha <= alphaThreshold) { + discard; + } + gl_FragData[0] = vec4(diffuse.rgb, alpha); // gl_FragData[1] = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); // gl_FragData[2] = vec4(specular, shininess / 128.0); diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 556e7421af..ecb1f503c7 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -28,21 +28,23 @@ struct SphericalHarmonics { vec4 evalSphericalLight(SphericalHarmonics sh, vec3 direction ) { + vec3 dir = direction.xzy; // we don;t understand why yet but we need to use z as vertical axis? + const float C1 = 0.429043; const float C2 = 0.511664; const float C3 = 0.743125; const float C4 = 0.886227; const float C5 = 0.247708; - vec4 value = C1 * sh.L22 * (direction.x * direction.x - direction.y * direction.y) + - C3 * sh.L20 * direction.z * direction.z + + vec4 value = C1 * sh.L22 * (dir.x * dir.x - dir.y * dir.y) + + C3 * sh.L20 * dir.z * dir.z + C4 * sh.L00 - C5 * sh.L20 + - 2.0 * C1 * ( sh.L2m2 * direction.x * direction.y + - sh.L21 * direction.x * direction.z + - sh.L2m1 * direction.y * direction.z ) + - 2.0 * C2 * ( sh.L11 * direction.x + - sh.L1m1 * direction.y + - sh.L10 * direction.z ) ; + 2.0 * C1 * ( sh.L2m2 * dir.x * dir.y + + sh.L21 * dir.x * dir.z + + sh.L2m1 * dir.y * dir.z ) + + 2.0 * C2 * ( sh.L11 * dir.x + + sh.L1m1 * dir.y + + sh.L10 * dir.z ) ; return value; } @@ -75,15 +77,12 @@ vec3 evalAmbienGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 evalAmbienSphereGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { // Need the light now Light light = getLight(); - - vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0)); + + vec3 fragNormal = normalize(vec3(invViewMat * vec4(normal, 0.0))); vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - - // TODO: The world space normal doesn;t seem to work properly with the current SH definitions - // FoOr now, we use the normal in view space - vec3 ambientNormal = normal; - + + vec3 ambientNormal = fragNormal.xyz; vec3 color = diffuse.rgb * 0.5 * evalSphericalLight(ambientSphere, ambientNormal).xyz; vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index f46bd689d4..a4f45802a4 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -551,3 +551,7 @@ void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const gl light->setColor(diffuse); light->setIntensity(intensity); } + +void DeferredLightingEffect::setGlobalSkybox(const model::SkyboxPointer& skybox) { + _skybox = skybox; +} \ No newline at end of file diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 900c5243cb..6d0d131029 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -76,6 +76,7 @@ public: void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity); void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; } + void setGlobalSkybox(const model::SkyboxPointer& skybox); private: DeferredLightingEffect() {} virtual ~DeferredLightingEffect() { } @@ -150,6 +151,7 @@ private: int _ambientLightMode = 0; model::AtmospherePointer _atmosphere; + model::SkyboxPointer _skybox; }; /// Simple interface for objects that require something to be rendered after deferred lighting. diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index e89479331b..5dea546bbe 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -96,50 +96,89 @@ Model::~Model() { deleteGeometry(); } -gpu::ShaderPointer Model::_program; -gpu::ShaderPointer Model::_normalMapProgram; -gpu::ShaderPointer Model::_specularMapProgram; -gpu::ShaderPointer Model::_normalSpecularMapProgram; -gpu::ShaderPointer Model::_translucentProgram; +Model::RenderPipelineLib Model::_renderPipelineLib; +const GLint MATERIAL_GPU_SLOT = 3; -gpu::ShaderPointer Model::_lightmapProgram; -gpu::ShaderPointer Model::_lightmapNormalMapProgram; -gpu::ShaderPointer Model::_lightmapSpecularMapProgram; -gpu::ShaderPointer Model::_lightmapNormalSpecularMapProgram; +void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, + gpu::ShaderPointer& vertexShader, + gpu::ShaderPointer& pixelShader ) { -gpu::ShaderPointer Model::_shadowProgram; + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); + slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3)); -gpu::ShaderPointer Model::_skinProgram; -gpu::ShaderPointer Model::_skinNormalMapProgram; -gpu::ShaderPointer Model::_skinSpecularMapProgram; -gpu::ShaderPointer Model::_skinNormalSpecularMapProgram; -gpu::ShaderPointer Model::_skinTranslucentProgram; + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); + bool makeResult = gpu::Shader::makeProgram(*program, slotBindings); + + + auto locations = std::shared_ptr(new Locations()); + initLocations(program, *locations); -gpu::ShaderPointer Model::_skinShadowProgram; + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); -Model::Locations Model::_locations; -Model::Locations Model::_normalMapLocations; -Model::Locations Model::_specularMapLocations; -Model::Locations Model::_normalSpecularMapLocations; -Model::Locations Model::_translucentLocations; -Model::Locations Model::_shadowLocations; + // Backface on shadow + if (key.isShadow()) { + state->setCullMode(gpu::State::CULL_FRONT); + state->setDepthBias(1.0f); + state->setDepthBiasSlopeScale(4.0f); + } else { + state->setCullMode(gpu::State::CULL_BACK); + } -Model::Locations Model::_lightmapLocations; -Model::Locations Model::_lightmapNormalMapLocations; -Model::Locations Model::_lightmapSpecularMapLocations; -Model::Locations Model::_lightmapNormalSpecularMapLocations; + // Z test depends if transparent or not + state->setDepthTest(true, !key.isTranslucent(), gpu::State::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(key.isTranslucent(), + 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); + + // Good to go add the brand new pipeline + auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + auto it = insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); + + // If not a shadow pass, create the mirror version from the same state, just change the FrontFace + if (!key.isShadow()) { + + RenderKey mirrorKey(key.getRaw() | RenderKey::IS_MIRROR); + gpu::StatePointer mirrorState = gpu::StatePointer(new gpu::State(state->getValues())); + + mirrorState->setFrontFaceClockwise(true); + + // create a new RenderPipeline with the same shader side and the mirrorState + auto mirrorPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, mirrorState)); + auto it = insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations))); + } +} -Model::SkinLocations Model::_skinLocations; -Model::SkinLocations Model::_skinNormalMapLocations; -Model::SkinLocations Model::_skinSpecularMapLocations; -Model::SkinLocations Model::_skinNormalSpecularMapLocations; -Model::SkinLocations Model::_skinTranslucentLocations; -Model::SkinLocations Model::_skinShadowLocations; +void Model::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, Model::Locations& locations) { + locations.alphaThreshold = program->getUniforms().findLocation("alphaThreshold"); + locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices"); + locations.emissiveParams = program->getUniforms().findLocation("emissiveParams"); + locations.glowIntensity = program->getUniforms().findLocation("glowIntensity"); + + locations.specularTextureUnit = program->getTextures().findLocation("specularMap"); + locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); + +#if (GPU_FEATURE_PROFILE == GPU_CORE) + locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); +#else + locations.materialBufferUnit = program->getUniforms().findLocation("materialBuffer"); +#endif + locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices"); + + locations.clusterIndices = program->getInputs().findLocation("clusterIndices");; + locations.clusterWeights = program->getInputs().findLocation("clusterWeights");; + +} AbstractViewStateInterface* Model::_viewState = NULL; -const GLint MATERIAL_GPU_SLOT = 3; void Model::setScale(const glm::vec3& scale) { setScaleInternal(scale); @@ -171,33 +210,6 @@ void Model::setOffset(const glm::vec3& offset) { _snappedToRegistrationPoint = false; } -void Model::initProgram(gpu::ShaderPointer& program, Model::Locations& locations) { - locations.alphaThreshold = program->getUniforms().findLocation("alphaThreshold"); - locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices"); - locations.emissiveParams = program->getUniforms().findLocation("emissiveParams"); - locations.glowIntensity = program->getUniforms().findLocation("glowIntensity"); - - locations.specularTextureUnit = program->getTextures().findLocation("specularMap"); - locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); - -#if (GPU_FEATURE_PROFILE == GPU_CORE) - locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); -#else - locations.materialBufferUnit = program->getUniforms().findLocation("materialBuffer"); -#endif - -} - -void Model::initSkinProgram(gpu::ShaderPointer& program, Model::SkinLocations& locations) { - - initProgram(program, locations); - - locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices"); - - locations.clusterIndices = program->getInputs().findLocation("clusterIndices");; - locations.clusterWeights = program->getInputs().findLocation("clusterWeights");; -} - QVector Model::createJointStates(const FBXGeometry& geometry) { QVector jointStates; for (int i = 0; i < geometry.joints.size(); ++i) { @@ -231,7 +243,7 @@ void Model::initJointTransforms() { } void Model::init() { - if (_program.isNull()) { + if (_renderPipelineLib.empty()) { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); @@ -261,75 +273,71 @@ void Model::init() { auto modelLightmapSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag))); auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag))); - - bool makeResult = false; - - // Programs - _program = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelPixel)); - makeResult = gpu::Shader::makeProgram(*_program, slotBindings); - initProgram(_program, _locations); - - _normalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalMapPixel)); - makeResult = gpu::Shader::makeProgram(*_normalMapProgram, slotBindings); - initProgram(_normalMapProgram, _normalMapLocations); - - _specularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*_specularMapProgram, slotBindings); - initProgram(_specularMapProgram, _specularMapLocations); - - _normalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*_normalSpecularMapProgram, slotBindings); - initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations); - - _translucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelTranslucentPixel)); - makeResult = gpu::Shader::makeProgram(*_translucentProgram, slotBindings); - initProgram(_translucentProgram, _translucentLocations); + // Fill the renderPipelineLib - _shadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelShadowVertex, modelShadowPixel)); - makeResult = gpu::Shader::makeProgram(*_shadowProgram, slotBindings); - initProgram(_shadowProgram, _shadowLocations); + _renderPipelineLib.addRenderPipeline( + RenderKey(0), + modelVertex, modelPixel); - _lightmapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapPixel)); - makeResult = gpu::Shader::makeProgram(*_lightmapProgram, slotBindings); - initProgram(_lightmapProgram, _lightmapLocations); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_TANGENTS), + modelNormalMapVertex, modelNormalMapPixel); - _lightmapNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalMapPixel)); - makeResult = gpu::Shader::makeProgram(*_lightmapNormalMapProgram, slotBindings); - initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_SPECULAR), + modelVertex, modelSpecularMapPixel); - _lightmapSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*_lightmapSpecularMapProgram, slotBindings); - initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + modelNormalMapVertex, modelNormalSpecularMapPixel); - _lightmapNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*_lightmapNormalSpecularMapProgram, slotBindings); - initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_TRANSLUCENT), + modelVertex, modelTranslucentPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP), + modelLightmapVertex, modelLightmapPixel); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS), + modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); - _skinProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelPixel)); - makeResult = gpu::Shader::makeProgram(*_skinProgram, slotBindings); - initSkinProgram(_skinProgram, _skinLocations); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_SPECULAR), + modelLightmapVertex, modelLightmapSpecularMapPixel); - _skinNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalMapPixel)); - makeResult = gpu::Shader::makeProgram(*_skinNormalMapProgram, slotBindings); - initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); - _skinSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*_skinSpecularMapProgram, slotBindings); - initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED), + skinModelVertex, modelPixel); - _skinNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*_skinNormalSpecularMapProgram, slotBindings); - initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations); - - _skinShadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelShadowVertex, modelShadowPixel)); - makeResult = gpu::Shader::makeProgram(*_skinShadowProgram, slotBindings); - initSkinProgram(_skinShadowProgram, _skinShadowLocations); - - _skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel)); - makeResult = gpu::Shader::makeProgram(*_skinTranslucentProgram, slotBindings); - initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS), + skinModelNormalMapVertex, modelNormalMapPixel); - (void) makeResult; // quiet compiler + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR), + skinModelVertex, modelSpecularMapPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + skinModelNormalMapVertex, modelNormalSpecularMapPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_TRANSLUCENT), + skinModelVertex, modelTranslucentPixel); + + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), + modelShadowVertex, modelShadowPixel); + + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), + skinModelShadowVertex, modelShadowPixel); } } @@ -665,6 +673,8 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { return false; } + // auto glowEffectIntensity = DependencyManager::get()->getIntensity(); + // Let's introduce a gpu::Batch to capture all the calls to the graphics api _renderBatch.clear(); gpu::Batch& batch = _renderBatch; @@ -693,42 +703,48 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { batch.setViewTransform(_transforms[0]); - GLBATCH(glDisable)(GL_COLOR_MATERIAL); + // GLBATCH(glDisable)(GL_COLOR_MATERIAL); - if (mode == DIFFUSE_RENDER_MODE || mode == NORMAL_RENDER_MODE) { + // taking care of by the state? + /* if (mode == RenderArgs::DIFFUSE_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE) { GLBATCH(glDisable)(GL_CULL_FACE); } else { GLBATCH(glEnable)(GL_CULL_FACE); - if (mode == SHADOW_RENDER_MODE) { + if (mode == RenderArgs::SHADOW_RENDER_MODE) { GLBATCH(glCullFace)(GL_FRONT); } } - + */ + // render opaque meshes with alpha testing - GLBATCH(glDisable)(GL_BLEND); - GLBATCH(glEnable)(GL_ALPHA_TEST); - - if (mode == SHADOW_RENDER_MODE) { +// GLBATCH(glDisable)(GL_BLEND); +// GLBATCH(glEnable)(GL_ALPHA_TEST); + + /* if (mode == RenderArgs::SHADOW_RENDER_MODE) { GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f); } - + */ /*DependencyManager::get()->setPrimaryDrawBuffers( - mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE, - mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE, - mode == DEFAULT_RENDER_MODE); + mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE, + mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE, + mode == RenderArgs::DEFAULT_RENDER_MODE); */ { GLenum buffers[3]; int bufferCount = 0; - if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE || mode == DEBUG_RENDER_MODE) { + + // if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE) { + if (mode != RenderArgs::SHADOW_RENDER_MODE) { buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; } - if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE || mode == DEBUG_RENDER_MODE) { + // if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE) { + if (mode != RenderArgs::SHADOW_RENDER_MODE) { buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; } - if (mode == DEFAULT_RENDER_MODE || mode == DEBUG_RENDER_MODE) { + // if (mode == RenderArgs::DEFAULT_RENDER_MODE) { + if (mode != RenderArgs::SHADOW_RENDER_MODE) { buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; } GLBATCH(glDrawBuffers)(bufferCount, buffers); @@ -774,11 +790,11 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args, true); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args, true); - GLBATCH(glDisable)(GL_ALPHA_TEST); - GLBATCH(glEnable)(GL_BLEND); + // GLBATCH(glDisable)(GL_ALPHA_TEST); + /* GLBATCH(glEnable)(GL_BLEND); GLBATCH(glDepthMask)(false); GLBATCH(glDepthFunc)(GL_LEQUAL); - + */ //DependencyManager::get()->setPrimaryDrawBuffers(true); { GLenum buffers[1]; @@ -787,7 +803,8 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { GLBATCH(glDrawBuffers)(bufferCount, buffers); } - if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE || mode == DEBUG_RENDER_MODE) { + // if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE) { + if (mode != RenderArgs::SHADOW_RENDER_MODE) { const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args, true); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args, true); @@ -803,7 +820,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { GLBATCH(glDepthFunc)(GL_LESS); GLBATCH(glDisable)(GL_CULL_FACE); - if (mode == SHADOW_RENDER_MODE) { + if (mode == RenderArgs::SHADOW_RENDER_MODE) { GLBATCH(glCullFace)(GL_BACK); } @@ -830,6 +847,9 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, 0); GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); + // Back to no program + GLBATCH(glUseProgram)(0); + // Render! { PROFILE_RANGE("render Batch"); @@ -1738,6 +1758,9 @@ void Model::setupBatchTransform(gpu::Batch& batch, RenderArgs* args) { void Model::endScene(RenderMode mode, RenderArgs* args) { PROFILE_RANGE(__FUNCTION__); + // auto glowEffectIntensity = DependencyManager::get()->getIntensity(); + + #if defined(ANDROID) #else glPushMatrix(); @@ -1769,42 +1792,45 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { _sceneRenderBatch.clear(); gpu::Batch& batch = _sceneRenderBatch; - GLBATCH(glDisable)(GL_COLOR_MATERIAL); + // GLBATCH(glDisable)(GL_COLOR_MATERIAL); - if (mode == DIFFUSE_RENDER_MODE || mode == NORMAL_RENDER_MODE) { + /* if (mode == RenderArgs::DIFFUSE_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE) { GLBATCH(glDisable)(GL_CULL_FACE); } else { GLBATCH(glEnable)(GL_CULL_FACE); - if (mode == SHADOW_RENDER_MODE) { + if (mode == RenderArgs::SHADOW_RENDER_MODE) { GLBATCH(glCullFace)(GL_FRONT); } - } + }*/ // render opaque meshes with alpha testing - GLBATCH(glDisable)(GL_BLEND); - GLBATCH(glEnable)(GL_ALPHA_TEST); + // GLBATCH(glDisable)(GL_BLEND); + // GLBATCH(glEnable)(GL_ALPHA_TEST); - if (mode == SHADOW_RENDER_MODE) { + /* if (mode == RenderArgs::SHADOW_RENDER_MODE) { GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f); } - +*/ /*DependencyManager::get()->setPrimaryDrawBuffers( - mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE, - mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE, - mode == DEFAULT_RENDER_MODE); + mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE, + mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE, + mode == RenderArgs::DEFAULT_RENDER_MODE); */ { GLenum buffers[3]; int bufferCount = 0; - if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE || mode == DEBUG_RENDER_MODE) { + // if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE) { + if (mode != RenderArgs::SHADOW_RENDER_MODE) { buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; } - if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE || mode == DEBUG_RENDER_MODE) { + //if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::NORMAL_RENDER_MODE) { + if (mode != RenderArgs::SHADOW_RENDER_MODE) { buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; } - if (mode == DEFAULT_RENDER_MODE || mode == DEBUG_RENDER_MODE) { + // if (mode == RenderArgs::DEFAULT_RENDER_MODE) { + if (mode != RenderArgs::SHADOW_RENDER_MODE) { buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; } GLBATCH(glDrawBuffers)(bufferCount, buffers); @@ -1850,11 +1876,11 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args); translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args); - GLBATCH(glDisable)(GL_ALPHA_TEST); - GLBATCH(glEnable)(GL_BLEND); + // GLBATCH(glDisable)(GL_ALPHA_TEST); + /* GLBATCH(glEnable)(GL_BLEND); GLBATCH(glDepthMask)(false); GLBATCH(glDepthFunc)(GL_LEQUAL); - + */ //DependencyManager::get()->setPrimaryDrawBuffers(true); { GLenum buffers[1]; @@ -1863,7 +1889,8 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { GLBATCH(glDrawBuffers)(bufferCount, buffers); } - if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE || mode == DEBUG_RENDER_MODE) { + // if (mode == RenderArgs::DEFAULT_RENDER_MODE || mode == RenderArgs::DIFFUSE_RENDER_MODE) { + if (mode != RenderArgs::SHADOW_RENDER_MODE) { const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args); translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args); @@ -1879,7 +1906,7 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { GLBATCH(glDepthFunc)(GL_LESS); GLBATCH(glDisable)(GL_CULL_FACE); - if (mode == SHADOW_RENDER_MODE) { + if (mode == RenderArgs::SHADOW_RENDER_MODE) { GLBATCH(glCullFace)(GL_BACK); } @@ -1907,6 +1934,10 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, 0); GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, 0); GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); + + // Back to no program + GLBATCH(glUseProgram)(0); + if (args) { args->_translucentMeshPartsRendered = translucentParts; args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered; @@ -2298,83 +2329,34 @@ QVector* Model::pickMeshList(bool translucent, float alphaThreshold, bool h void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, - Locations*& locations, SkinLocations*& skinLocations) { - gpu::ShaderPointer program = _program; - locations = &_locations; - gpu::ShaderPointer skinProgram = _skinProgram; - skinLocations = &_skinLocations; - if (mode == SHADOW_RENDER_MODE) { - program = _shadowProgram; - locations = &_shadowLocations; - skinProgram = _skinShadowProgram; - skinLocations = &_skinShadowLocations; - } else if (translucent && alphaThreshold == 0.0f) { - program = _translucentProgram; - locations = &_translucentLocations; - skinProgram = _skinTranslucentProgram; - skinLocations = &_skinTranslucentLocations; - - } else if (hasLightmap) { - if (hasTangents) { - if (hasSpecular) { - program = _lightmapNormalSpecularMapProgram; - locations = &_lightmapNormalSpecularMapLocations; - skinProgram.reset(); - skinLocations = NULL; - } else { - program = _lightmapNormalMapProgram; - locations = &_lightmapNormalMapLocations; - skinProgram.reset(); - skinLocations = NULL; - } - } else if (hasSpecular) { - program = _lightmapSpecularMapProgram; - locations = &_lightmapSpecularMapLocations; - skinProgram.reset(); - skinLocations = NULL; - } else { - program = _lightmapProgram; - locations = &_lightmapLocations; - skinProgram.reset(); - skinLocations = NULL; - } - } else { - if (hasTangents) { - if (hasSpecular) { - program = _normalSpecularMapProgram; - locations = &_normalSpecularMapLocations; - skinProgram = _skinNormalSpecularMapProgram; - skinLocations = &_skinNormalSpecularMapLocations; - } else { - program = _normalMapProgram; - locations = &_normalMapLocations; - skinProgram = _skinNormalMapProgram; - skinLocations = &_skinNormalMapLocations; - } - } else if (hasSpecular) { - program = _specularMapProgram; - locations = &_specularMapLocations; - skinProgram = _skinSpecularMapProgram; - skinLocations = &_skinSpecularMapLocations; - } - } + Locations*& locations) { - gpu::ShaderPointer activeProgram = program; - Locations* activeLocations = locations; - - if (isSkinned) { - activeProgram = skinProgram; - activeLocations = skinLocations; - locations = skinLocations; + RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned); + auto pipeline = _renderPipelineLib.find(key.getRaw()); + if (pipeline == _renderPipelineLib.end()) { + qDebug() << "No good, couldn;t find a pipeline from the key ?" << key.getRaw(); + return; } - GLuint glprogram = gpu::GLBackend::getShaderID(activeProgram); - GLBATCH(glUseProgram)(glprogram); + gpu::ShaderPointer program = (*pipeline).second._pipeline->getProgram(); + locations = (*pipeline).second._locations.get(); + + //GLuint glprogram = gpu::GLBackend::getShaderID(program); + //GLBATCH(glUseProgram)(glprogram); + // dare! + batch.setPipeline((*pipeline).second._pipeline); - if ((activeLocations->alphaThreshold > -1) && (mode != SHADOW_RENDER_MODE)) { - GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold); + if ((locations->alphaThreshold > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { + GLBATCH(glUniform1f)(locations->alphaThreshold, alphaThreshold); } + + if ((locations->glowIntensity > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { + GLBATCH(glUniform1f)(locations->glowIntensity, DependencyManager::get()->getIntensity()); + } + // if (!(translucent && alphaThreshold == 0.0f) && (mode != RenderArgs::SHADOW_RENDER_MODE)) { + // GLBATCH(glAlphaFunc)(GL_EQUAL, DependencyManager::get()->getIntensity()); + // } } int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, @@ -2385,7 +2367,6 @@ int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool bool pickProgramsNeeded = true; Locations* locations; - SkinLocations* skinLocations; foreach(Model* model, _modelsInScene) { QVector* whichList = model->pickMeshList(translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned); @@ -2393,24 +2374,25 @@ int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool QVector& list = *whichList; if (list.size() > 0) { if (pickProgramsNeeded) { - pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, args, locations, skinLocations); + pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, args, locations); pickProgramsNeeded = false; } + model->setupBatchTransform(batch, args); - meshPartsRendered += model->renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, args, locations, skinLocations); + meshPartsRendered += model->renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, args, locations); } } } // if we selected a program, then unselect it if (!pickProgramsNeeded) { - GLBATCH(glUseProgram)(0); + // GLBATCH(glUseProgram)(0); } return meshPartsRendered; } int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, - bool forceRenderMeshes) { + bool forceRenderSomeMeshes) { PROFILE_RANGE(__FUNCTION__); int meshPartsRendered = 0; @@ -2429,24 +2411,23 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl } Locations* locations; - SkinLocations* skinLocations; pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, - args, locations, skinLocations); + args, locations); meshPartsRendered = renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, - args, locations, skinLocations, forceRenderMeshes); - GLBATCH(glUseProgram)(0); + args, locations, forceRenderSomeMeshes); + // GLBATCH(glUseProgram)(0); + return meshPartsRendered; } -int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMode mode, bool translucent, - float alphaThreshold, RenderArgs* args, Locations* locations, SkinLocations* skinLocations, - bool forceRenderMeshes) { +int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args, + Locations* locations, bool forceRenderMeshes) { PROFILE_RANGE(__FUNCTION__); auto textureCache = DependencyManager::get(); - auto glowEffect = DependencyManager::get(); + // auto glowEffect = DependencyManager::get(); QString lastMaterialID; int meshPartsRendered = 0; updateVisibleJointStates(); @@ -2506,7 +2487,7 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod const MeshState& state = _meshStates.at(i); if (state.clusterMatrices.size() > 1) { - GLBATCH(glUniformMatrix4fv)(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, + GLBATCH(glUniformMatrix4fv)(locations->clusterMatrices, state.clusterMatrices.size(), false, (const float*)state.clusterMatrices.constData()); batch.setModelTransform(Transform()); } else { @@ -2524,7 +2505,7 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod } if (mesh.colors.isEmpty()) { - GLBATCH(glColor4f)(1.0f, 1.0f, 1.0f, 1.0f); + GLBATCH(glColor4f)(0.0f, 1.0f, 0.0f, 1.0f); } qint64 offset = 0; @@ -2538,7 +2519,7 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod } // apply material properties - if (mode == SHADOW_RENDER_MODE) { + if (mode == RenderArgs::SHADOW_RENDER_MODE) { /// GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); } else { @@ -2550,13 +2531,13 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod qCDebug(renderutils) << "NEW part.materialID:" << part.materialID; } - if (locations->glowIntensity >= 0) { +/* if (locations->glowIntensity >= 0) { GLBATCH(glUniform1f)(locations->glowIntensity, glowEffect->getIntensity()); } if (!(translucent && alphaThreshold == 0.0f)) { GLBATCH(glAlphaFunc)(GL_EQUAL, glowEffect->getIntensity()); } - +*/ if (locations->materialBufferUnit >= 0) { batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer()); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index f1bbf151cd..fce5629b8d 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -18,12 +18,16 @@ #include #include +#include +#include + #include #include #include #include #include #include +#include #include "PhysicsEntity.h" #include @@ -47,6 +51,8 @@ class Model : public QObject, public PhysicsEntity { public: + typedef RenderArgs::RenderMode RenderMode; + static void setAbstractViewStateInterface(AbstractViewStateInterface* viewState) { _viewState = viewState; } Model(QObject* parent = NULL); @@ -90,15 +96,13 @@ public: void init(); void reset(); virtual void simulate(float deltaTime, bool fullUpdate = true); - - enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, DEBUG_RENDER_MODE }; - - bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); + + bool render(float alpha = 1.0f, RenderArgs::RenderMode mode = RenderArgs::DEFAULT_RENDER_MODE, RenderArgs* args = NULL); // Scene rendering support static void startScene(RenderArgs::RenderSide renderSide); bool renderInScene(float alpha = 1.0f, RenderArgs* args = NULL); - static void endScene(RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); + static void endScene(RenderArgs::RenderMode mode = RenderArgs::DEFAULT_RENDER_MODE, RenderArgs* args = NULL); /// Sets the URL of the model to render. /// \param fallback the URL of a fallback model to render if the requested model fails to load @@ -319,27 +323,6 @@ private: int _blendNumber; int _appliedBlendNumber; - static gpu::ShaderPointer _program; - static gpu::ShaderPointer _normalMapProgram; - static gpu::ShaderPointer _specularMapProgram; - static gpu::ShaderPointer _normalSpecularMapProgram; - static gpu::ShaderPointer _translucentProgram; - - static gpu::ShaderPointer _lightmapProgram; - static gpu::ShaderPointer _lightmapNormalMapProgram; - static gpu::ShaderPointer _lightmapSpecularMapProgram; - static gpu::ShaderPointer _lightmapNormalSpecularMapProgram; - - static gpu::ShaderPointer _shadowProgram; - - static gpu::ShaderPointer _skinProgram; - static gpu::ShaderPointer _skinNormalMapProgram; - static gpu::ShaderPointer _skinSpecularMapProgram; - static gpu::ShaderPointer _skinNormalSpecularMapProgram; - static gpu::ShaderPointer _skinTranslucentProgram; - - static gpu::ShaderPointer _skinShadowProgram; - class Locations { public: int tangent; @@ -350,40 +333,10 @@ private: int emissiveParams; int glowIntensity; int materialBufferUnit; - }; - - static Locations _locations; - static Locations _normalMapLocations; - static Locations _specularMapLocations; - static Locations _normalSpecularMapLocations; - static Locations _translucentLocations; - static Locations _shadowLocations; - - static Locations _lightmapLocations; - static Locations _lightmapNormalMapLocations; - static Locations _lightmapSpecularMapLocations; - static Locations _lightmapNormalSpecularMapLocations; - - static void initProgram(ProgramObject& program, Locations& locations, bool link = true); - static void initProgram(gpu::ShaderPointer& program, Locations& locations); - - class SkinLocations : public Locations { - public: int clusterMatrices; int clusterIndices; int clusterWeights; }; - - static SkinLocations _skinLocations; - static SkinLocations _skinNormalMapLocations; - static SkinLocations _skinSpecularMapLocations; - static SkinLocations _skinNormalSpecularMapLocations; - static SkinLocations _skinTranslucentLocations; - static SkinLocations _skinShadowLocations; - - - static void initSkinProgram(ProgramObject& program, SkinLocations& locations); - static void initSkinProgram(gpu::ShaderPointer& program, SkinLocations& locations); QVector _calculatedMeshBoxes; // world coordinate AABoxes for all sub mesh boxes bool _calculatedMeshBoxesValid; @@ -421,6 +374,9 @@ private: QMap _unsortedMeshesOpaqueLightmapTangents; QMap _unsortedMeshesOpaqueLightmapTangentsSpecular; QMap _unsortedMeshesOpaqueLightmapSpecular; + + typedef std::unordered_map> MeshListMap; + MeshListMap _sortedMeshes; QVector _meshesTranslucent; QVector _meshesTranslucentTangents; @@ -455,33 +411,122 @@ private: static QVector _modelsInScene; static gpu::Batch _sceneRenderBatch; - static void endSceneSimple(RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); - static void endSceneSplitPass(RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); + static void endSceneSimple(RenderArgs::RenderMode mode = RenderArgs::DEFAULT_RENDER_MODE, RenderArgs* args = NULL); + static void endSceneSplitPass(RenderArgs::RenderMode mode = RenderArgs::DEFAULT_RENDER_MODE, RenderArgs* args = NULL); // helper functions used by render() or renderInScene() void renderSetup(RenderArgs* args); - bool renderCore(float alpha, RenderMode mode, RenderArgs* args); - int renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, + bool renderCore(float alpha, RenderArgs::RenderMode mode, RenderArgs* args); + int renderMeshes(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL, bool forceRenderMeshes = false); void setupBatchTransform(gpu::Batch& batch, RenderArgs* args); QVector* pickMeshList(bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned); - int renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, - RenderArgs* args, Locations* locations, SkinLocations* skinLocations, - bool forceRenderMeshes = false); + int renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, + RenderArgs* args, Locations* locations, + bool forceRenderSomeMeshes = false); - static void pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, + static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, - Locations*& locations, SkinLocations*& skinLocations); + Locations*& locations); - static int renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, + static int renderMeshesForModelsInScene(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args); static AbstractViewStateInterface* _viewState; + class RenderKey { + public: + enum FlagBit { + IS_TRANSLUCENT_FLAG = 0, + HAS_LIGHTMAP_FLAG, + HAS_TANGENTS_FLAG, + HAS_SPECULAR_FLAG, + HAS_EMISSIVE_FLAG, + IS_SKINNED_FLAG, + IS_STEREO_FLAG, + IS_DEPTH_ONLY_FLAG, + IS_SHADOW_FLAG, + IS_MIRROR_FLAG, //THis means that the mesh is rendered mirrored, not the same as "Rear view mirror" + + NUM_FLAGS, + }; + + enum Flag { + IS_TRANSLUCENT = (1 << IS_TRANSLUCENT_FLAG), + HAS_LIGHTMAP = (1 << HAS_LIGHTMAP_FLAG), + HAS_TANGENTS = (1 << HAS_TANGENTS_FLAG), + HAS_SPECULAR = (1 << HAS_SPECULAR_FLAG), + HAS_EMISSIVE = (1 << HAS_EMISSIVE_FLAG), + IS_SKINNED = (1 << IS_SKINNED_FLAG), + IS_STEREO = (1 << IS_STEREO_FLAG), + IS_DEPTH_ONLY = (1 << IS_DEPTH_ONLY_FLAG), + IS_SHADOW = (1 << IS_SHADOW_FLAG), + IS_MIRROR = (1 << IS_MIRROR_FLAG), + + }; + typedef unsigned short Flags; + + + + bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); } + + bool isTranslucent() const { return isFlag(IS_TRANSLUCENT); } + bool hasLightmap() const { return isFlag(HAS_LIGHTMAP); } + bool hasTangents() const { return isFlag(HAS_TANGENTS); } + bool hasSpecular() const { return isFlag(HAS_SPECULAR); } + bool hasEmissive() const { return isFlag(HAS_EMISSIVE); } + bool isSkinned() const { return isFlag(IS_SKINNED); } + bool isStereo() const { return isFlag(IS_STEREO); } + bool isDepthOnly() const { return isFlag(IS_DEPTH_ONLY); } + bool isShadow() const { return isFlag(IS_SHADOW); } // = depth only but with back facing + bool isMirror() const { return isFlag(IS_MIRROR); } + + Flags _flags = 0; + short _spare = 0; + + int getRaw() { return *reinterpret_cast(this); } + + RenderKey(RenderArgs::RenderMode mode, + bool translucent, float alphaThreshold, bool hasLightmap, + bool hasTangents, bool hasSpecular, bool isSkinned) : + RenderKey( ((translucent && (alphaThreshold == 0.0f) && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0) + | (hasLightmap && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_LIGHTMAP : 0) // Lightmap, tangents and specular don't matter for depthOnly + | (hasTangents && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_TANGENTS : 0) + | (hasSpecular && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_SPECULAR : 0) + | (isSkinned ? IS_SKINNED : 0) + | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_DEPTH_ONLY : 0) + | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_SHADOW : 0) + | ((mode == RenderArgs::MIRROR_RENDER_MODE) ? IS_MIRROR :0) + ) {} + + RenderKey(int bitmask) : _flags(bitmask) {} + }; + + + class RenderPipeline { + public: + gpu::PipelinePointer _pipeline; + std::shared_ptr _locations; + RenderPipeline(gpu::PipelinePointer pipeline, std::shared_ptr locations) : + _pipeline(pipeline), _locations(locations) {} + }; + + typedef std::unordered_map BaseRenderPipelineMap; + class RenderPipelineLib : public BaseRenderPipelineMap { + public: + typedef RenderKey Key; + + + void addRenderPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); + + void initLocations(gpu::ShaderPointer& program, Locations& locations); + }; + static RenderPipelineLib _renderPipelineLib; + bool _renderCollisionHull; }; diff --git a/libraries/render-utils/src/model_normal_map.slf b/libraries/render-utils/src/model_normal_map.slf index 5ad0bfb50d..6a74ddaca0 100755 --- a/libraries/render-utils/src/model_normal_map.slf +++ b/libraries/render-utils/src/model_normal_map.slf @@ -33,7 +33,7 @@ void main(void) { vec3 normalizedNormal = normalize(vec3(interpolatedNormal)); vec3 normalizedTangent = normalize(vec3(interpolatedTangent)); vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); - vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) - vec3(0.5, 0.5, 0.5); + vec3 localNormal = normalize(vec3(texture2D(normalMap, gl_TexCoord[0].st)) - vec3(0.5, 0.5, 0.5)); vec4 viewNormal = vec4(normalizedTangent * localNormal.x + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); diff --git a/libraries/render-utils/src/model_normal_specular_map.slf b/libraries/render-utils/src/model_normal_specular_map.slf index 5c272d0c6b..4d70e659e6 100755 --- a/libraries/render-utils/src/model_normal_specular_map.slf +++ b/libraries/render-utils/src/model_normal_specular_map.slf @@ -36,7 +36,7 @@ void main(void) { vec3 normalizedNormal = normalize(vec3(interpolatedNormal)); vec3 normalizedTangent = normalize(vec3(interpolatedTangent)); vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); - vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) - vec3(0.5, 0.5, 0.5); + vec3 localNormal = normalize(vec3(texture2D(normalMap, gl_TexCoord[0].st)) - vec3(0.5, 0.5, 0.5)); vec4 viewNormal = vec4(normalizedTangent * localNormal.x + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); diff --git a/libraries/render-utils/src/skin_model_normal_map.slv b/libraries/render-utils/src/skin_model_normal_map.slv index 6a4170152d..19e0c041f0 100755 --- a/libraries/render-utils/src/skin_model_normal_map.slv +++ b/libraries/render-utils/src/skin_model_normal_map.slv @@ -52,12 +52,15 @@ void main(void) { // and the texture coordinates gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0); + interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); + interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0); + // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); <$transformModelToClipPos(cam, obj, interpolatedPosition, gl_Position)$> - <$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$> - <$transformModelToEyeDir(cam, obj, tangent, interpolatedTangent.xyz)$> + <$transformModelToEyeDir(cam, obj, interpolatedNormal.xyz, interpolatedNormal.xyz)$> + <$transformModelToEyeDir(cam, obj, interpolatedTangent.xyz, interpolatedTangent.xyz)$> interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0); diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index c7386f9f6b..116fc430c2 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -17,7 +17,8 @@ class OctreeRenderer; class RenderArgs { public: - enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, DEBUG_RENDER_MODE }; + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, DEBUG_RENDER_MODE }; + enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT }; OctreeRenderer* _renderer;