From 206d1c0157c338de485cedd06a89bf6029cc9255 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sat, 29 Jun 2024 21:50:33 -0700 Subject: [PATCH 1/3] shader error fallback --- interface/resources/shaders/errorShader.frag | 30 +++++++++++++++++++ .../resources/shaders/errorSkyboxShader.frag | 7 +++++ .../procedural/src/procedural/Procedural.cpp | 19 +++++++++++- .../procedural/src/procedural/Procedural.h | 5 ++++ .../src/procedural/ProceduralSkybox.cpp | 2 ++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 interface/resources/shaders/errorShader.frag create mode 100644 interface/resources/shaders/errorSkyboxShader.frag diff --git a/interface/resources/shaders/errorShader.frag b/interface/resources/shaders/errorShader.frag new file mode 100644 index 0000000000..acfd23505e --- /dev/null +++ b/interface/resources/shaders/errorShader.frag @@ -0,0 +1,30 @@ +vec3 getErrorColor() { + vec3 positionWS = iWorldOrientation * (_positionMS.xyz * iWorldScale) + iWorldPosition; + float checkSize = 0.1; + vec3 edges = round(mod(positionWS, vec3(checkSize)) / checkSize); + float checkerboard = mod(edges.x + edges.y + edges.z, 2.0); + return mix(vec3(1, 0, 1), vec3(0.0), checkerboard); +} + +// version 1 +vec3 getProceduralColor() { + return getErrorColor(); +} + +// version 2 +float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + diffuse = getErrorColor(); + return 1.0; +} + +// version 3 +float getProceduralFragment(inout ProceduralFragment data) { + data.emissive = getErrorColor(); + return 1.0; +} + +// version 4 +float getProceduralFragmentWithPosition(inout ProceduralFragmentWithPosition data) { + data.emissive = getErrorColor(); + return 1.0; +} diff --git a/interface/resources/shaders/errorSkyboxShader.frag b/interface/resources/shaders/errorSkyboxShader.frag new file mode 100644 index 0000000000..1c9b333ae5 --- /dev/null +++ b/interface/resources/shaders/errorSkyboxShader.frag @@ -0,0 +1,7 @@ +vec3 getSkyboxColor() { + vec3 normal = normalize(_normal); + float checkSize = 0.1; + vec3 edges = round(mod(normal, vec3(checkSize)) / checkSize); + float checkerboard = mod(edges.x + edges.y + edges.z, 2.0); + return mix(vec3(1, 0, 1), vec3(0.0), checkerboard); +} diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 66dde1ca56..91b949e280 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -377,6 +377,16 @@ void Procedural::prepare(gpu::Batch& batch, _proceduralPipelines[key] = gpu::Pipeline::create(program, key.isTransparent() ? _transparentState : _opaqueState); + if (_errorFallbackFragmentSource.isEmpty()) { + QFile file(_errorFallbackFragmentPath); + file.open(QIODevice::ReadOnly); + _errorFallbackFragmentSource = QTextStream(&file).readAll(); + } + fragmentSource.replacements[PROCEDURAL_BLOCK] = _errorFallbackFragmentSource.toStdString(); + gpu::ShaderPointer errorFragmentShader = gpu::Shader::createPixel(fragmentSource); + gpu::ShaderPointer errorProgram = gpu::Shader::createProgram(vertexShader, errorFragmentShader); + _errorPipelines[key] = gpu::Pipeline::create(errorProgram, _opaqueState); + _lastCompile = usecTimestampNow(); if (_firstCompile == 0) { _firstCompile = _lastCompile; @@ -385,8 +395,13 @@ void Procedural::prepare(gpu::Batch& batch, recompiledShader = true; } + gpu::PipelinePointer finalPipeline = recompiledShader ? _proceduralPipelines[key] : pipeline->second; + if (!finalPipeline || finalPipeline->getProgram()->compilationHasFailed()) { + finalPipeline = _errorPipelines[key]; + } + // FIXME: need to handle forward rendering - batch.setPipeline(recompiledShader ? _proceduralPipelines[key] : pipeline->second); + batch.setPipeline(finalPipeline); bool recreateUniforms = _shaderDirty || _uniformsDirty || recompiledShader || _prevKey != key; if (recreateUniforms) { @@ -533,4 +548,6 @@ void graphics::ProceduralMaterial::initializeProcedural() { // FIXME: Setup proper uniform slots and use correct pipelines for forward rendering _procedural._opaqueFragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_procedural); _procedural._transparentFragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_procedural_translucent); + + _procedural._errorFallbackFragmentPath = ":" + QUrl("qrc:///shaders/errorShader.frag").path(); } \ No newline at end of file diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 39c619c687..3b78563b40 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -124,6 +124,8 @@ public: gpu::Shader::Source _opaqueFragmentSource; gpu::Shader::Source _transparentFragmentSource; + QString _errorFallbackFragmentSource; + gpu::StatePointer _opaqueState { std::make_shared() }; gpu::StatePointer _transparentState { std::make_shared() }; @@ -176,11 +178,14 @@ protected: bool _shaderDirty { true }; bool _uniformsDirty { true }; + QString _errorFallbackFragmentPath; + // Rendering objects UniformLambdas _uniforms; NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS]; std::unordered_map _proceduralPipelines; + std::unordered_map _errorPipelines; StandardInputs _standardInputs; gpu::BufferPointer _standardInputsBuffer; diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 432e02fe10..5cbf11f298 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -22,6 +22,8 @@ ProceduralSkybox::ProceduralSkybox(uint64_t created) : graphics::Skybox(), _crea _procedural._vertexSource = shader::Source::get(shader::graphics::vertex::skybox); _procedural._opaqueFragmentSource = shader::Source::get(shader::procedural::fragment::proceduralSkybox); + _procedural._errorFallbackFragmentPath = ":" + QUrl("qrc:///shaders/errorSkyboxShader.frag").path(); + _procedural.setDoesFade(false); // Adjust the pipeline state for background using the stencil test From 2a3d1c639c73b55285f30f6ace4801632bbe134a Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sat, 29 Jun 2024 22:49:55 -0700 Subject: [PATCH 2/3] disabled fallback --- interface/src/Menu.cpp | 2 +- .../procedural/src/procedural/Procedural.cpp | 19 +++++++++++++++++-- .../procedural/src/procedural/Procedural.h | 7 +++++-- .../render-utils/src/MeshPartPayload.cpp | 5 ----- libraries/render-utils/src/MeshPartPayload.h | 2 -- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7017f2a083..c1d7c05f79 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -540,7 +540,7 @@ Menu::Menu() { action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::MaterialProceduralShaders, 0, false); connect(action, &QAction::triggered, [action] { - ModelMeshPartPayload::enableMaterialProceduralShaders = action->isChecked(); + Procedural::enableProceduralShaders = action->isChecked(); }); { diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 91b949e280..5a27d393bc 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -28,6 +28,8 @@ Q_LOGGING_CATEGORY(proceduralLog, "hifi.gpu.procedural") +bool Procedural::enableProceduralShaders = false; + // User-data parsing constants static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity"; static const QString VERTEX_URL_KEY = "vertexShaderURL"; @@ -377,16 +379,27 @@ void Procedural::prepare(gpu::Batch& batch, _proceduralPipelines[key] = gpu::Pipeline::create(program, key.isTransparent() ? _transparentState : _opaqueState); + // Error falllback: pink checkerboard if (_errorFallbackFragmentSource.isEmpty()) { QFile file(_errorFallbackFragmentPath); file.open(QIODevice::ReadOnly); _errorFallbackFragmentSource = QTextStream(&file).readAll(); } + vertexSource.replacements.erase(PROCEDURAL_BLOCK); fragmentSource.replacements[PROCEDURAL_BLOCK] = _errorFallbackFragmentSource.toStdString(); + gpu::ShaderPointer errorVertexShader = gpu::Shader::createVertex(vertexSource); gpu::ShaderPointer errorFragmentShader = gpu::Shader::createPixel(fragmentSource); - gpu::ShaderPointer errorProgram = gpu::Shader::createProgram(vertexShader, errorFragmentShader); + gpu::ShaderPointer errorProgram = gpu::Shader::createProgram(errorVertexShader, errorFragmentShader); _errorPipelines[key] = gpu::Pipeline::create(errorProgram, _opaqueState); + // Disabled falllback: nothing + vertexSource.replacements.erase(PROCEDURAL_BLOCK); + fragmentSource.replacements.erase(PROCEDURAL_BLOCK); + gpu::ShaderPointer disabledVertexShader = gpu::Shader::createVertex(vertexSource); + gpu::ShaderPointer disabledFragmentShader = gpu::Shader::createPixel(fragmentSource); + gpu::ShaderPointer disabledProgram = gpu::Shader::createProgram(disabledVertexShader, disabledFragmentShader); + _disabledPipelines[key] = gpu::Pipeline::create(disabledProgram, _opaqueState); + _lastCompile = usecTimestampNow(); if (_firstCompile == 0) { _firstCompile = _lastCompile; @@ -396,7 +409,9 @@ void Procedural::prepare(gpu::Batch& batch, } gpu::PipelinePointer finalPipeline = recompiledShader ? _proceduralPipelines[key] : pipeline->second; - if (!finalPipeline || finalPipeline->getProgram()->compilationHasFailed()) { + if (!enableProceduralShaders) { + finalPipeline = _disabledPipelines[key]; + } else if (!finalPipeline || finalPipeline->getProgram()->compilationHasFailed()) { finalPipeline = _errorPipelines[key]; } diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 3b78563b40..9e6f102e36 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -124,7 +124,7 @@ public: gpu::Shader::Source _opaqueFragmentSource; gpu::Shader::Source _transparentFragmentSource; - QString _errorFallbackFragmentSource; + QString _errorFallbackFragmentPath; gpu::StatePointer _opaqueState { std::make_shared() }; gpu::StatePointer _transparentState { std::make_shared() }; @@ -132,6 +132,8 @@ public: static std::function opaqueStencil; static std::function transparentStencil; + static bool enableProceduralShaders; + protected: // DO NOT TOUCH // We have to pack these in a particular way to match the ProceduralCommon.slh @@ -178,7 +180,7 @@ protected: bool _shaderDirty { true }; bool _uniformsDirty { true }; - QString _errorFallbackFragmentPath; + QString _errorFallbackFragmentSource; // Rendering objects UniformLambdas _uniforms; @@ -186,6 +188,7 @@ protected: std::unordered_map _proceduralPipelines; std::unordered_map _errorPipelines; + std::unordered_map _disabledPipelines; StandardInputs _standardInputs; gpu::BufferPointer _standardInputsBuffer; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index e095d9b15d..a77dc6b160 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -25,8 +25,6 @@ using namespace render; -bool ModelMeshPartPayload::enableMaterialProceduralShaders = false; - ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const uint64_t& created) : _meshIndex(meshIndex), @@ -345,9 +343,6 @@ void ModelMeshPartPayload::render(RenderArgs* args) { } if (_shapeKey.hasOwnPipeline()) { - if (!(enableMaterialProceduralShaders)) { - return; - } auto procedural = std::static_pointer_cast(_drawMaterials.top().material); auto& schema = _drawMaterials.getSchemaBuffer().get(); glm::vec4 outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index b502865f94..0818340981 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -68,8 +68,6 @@ public: void setBlendshapeBuffer(const std::unordered_map& blendshapeBuffers, const QVector& blendedMeshSizes); - static bool enableMaterialProceduralShaders; - private: void initCache(const ModelPointer& model, int shapeID); From 200a6e4821dda381b4f10f4446b5a34f30545618 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sat, 6 Jul 2024 16:40:36 -0700 Subject: [PATCH 3/3] typo --- libraries/procedural/src/procedural/Procedural.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 5a27d393bc..49d05d8059 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -379,7 +379,7 @@ void Procedural::prepare(gpu::Batch& batch, _proceduralPipelines[key] = gpu::Pipeline::create(program, key.isTransparent() ? _transparentState : _opaqueState); - // Error falllback: pink checkerboard + // Error fallback: pink checkerboard if (_errorFallbackFragmentSource.isEmpty()) { QFile file(_errorFallbackFragmentPath); file.open(QIODevice::ReadOnly); @@ -392,7 +392,7 @@ void Procedural::prepare(gpu::Batch& batch, gpu::ShaderPointer errorProgram = gpu::Shader::createProgram(errorVertexShader, errorFragmentShader); _errorPipelines[key] = gpu::Pipeline::create(errorProgram, _opaqueState); - // Disabled falllback: nothing + // Disabled fallback: nothing vertexSource.replacements.erase(PROCEDURAL_BLOCK); fragmentSource.replacements.erase(PROCEDURAL_BLOCK); gpu::ShaderPointer disabledVertexShader = gpu::Shader::createVertex(vertexSource);