diff --git a/CHANGELOG.md b/CHANGELOG.md index 43f1cad..20e71c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 3.1.0 - 2021-02-21 + +### Changed + +- Improved logging and error messages in case shader compilation fails +- Population weight was changed from an integer to a decimal number for more granular control + ## 3.0.0 - 2021-02-21 ### Added diff --git a/README.md b/README.md index a012047..59bad2b 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,8 @@ Here are some general settings for the whole simulation. HaloRay allows you to simulate multiple different ice crystal populations simultaneously. You give each population a name for easier reference by typing in the **Crystal population** dropdown menu. Each population has a relative -weight, which can be changed by adjusting the **Population weight** spin box. -For example, giving weights 1 and 3 to two crystal populations respectively +weight, which can be changed by adjusting the **Population weight** slider. +For example, giving weights 1.0 and 3.0 to two crystal populations respectively would trace three times as many rays through the latter population than the former. It is also possible to enable or disable a crystal population temporarily with the **Population enabled** checkbox. diff --git a/appveyor.yml b/appveyor.yml index 5c881ce..c352268 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: "3.0.0-{build}" +version: "3.1.0-{build}" branches: only: - master @@ -24,6 +24,6 @@ deploy: description: "" skip_tags: true auth_token: - secure: pb9keaNklmNgmLaw1doReZDdP5Oh/pLZPdwjt+anpcoi34MyqAbFoJbiHJMcWkgD + secure: qxadIRLRDKo8Tji0y+kZ03BIbNPJzdmp2HkzE6+G5lp1xtRCoeSpp6c4m4KU99D4 on: branch: master diff --git a/src/haloray-core/gui/crystalSettingsWidget.cpp b/src/haloray-core/gui/crystalSettingsWidget.cpp index 8e2a30c..c86d5e0 100644 --- a/src/haloray-core/gui/crystalSettingsWidget.cpp +++ b/src/haloray-core/gui/crystalSettingsWidget.cpp @@ -53,7 +53,7 @@ CrystalSettingsWidget::CrystalSettingsWidget(CrystalModel *model, QWidget *paren m_mapper->addMapping(m_lowerApexAngleSpinBox, CrystalModel::LowerApexAngle); m_mapper->addMapping(m_lowerApexHeightAverageSlider, CrystalModel::LowerApexHeightAverage); m_mapper->addMapping(m_lowerApexHeightStdSlider, CrystalModel::LowerApexHeightStd); - m_mapper->addMapping(m_weightSpinBox, CrystalModel::PopulationWeight); + m_mapper->addMapping(m_weightSlider, CrystalModel::PopulationWeight); m_mapper->addMapping(m_populationEnabledCheckBox, CrystalModel::Enabled); m_mapper->addMapping(m_populationComboBox, CrystalModel::PopulationName, "currentText"); for (auto i = 0; i < 6; ++i) @@ -69,7 +69,7 @@ CrystalSettingsWidget::CrystalSettingsWidget(CrystalModel *model, QWidget *paren to the submit slot of the mapper. */ connect(m_populationEnabledCheckBox, &QCheckBox::toggled, m_mapper, &QDataWidgetMapper::submit, Qt::QueuedConnection); - connect(m_weightSpinBox, QOverload::of(&QSpinBox::valueChanged), m_mapper, &QDataWidgetMapper::submit, Qt::QueuedConnection); + connect(m_weightSlider, &SliderSpinBox::valueChanged, m_mapper, &QDataWidgetMapper::submit, Qt::QueuedConnection); connect(m_caRatioSlider, &SliderSpinBox::valueChanged, m_mapper, &QDataWidgetMapper::submit, Qt::QueuedConnection); connect(m_caRatioStdSlider, &SliderSpinBox::valueChanged, m_mapper, &QDataWidgetMapper::submit, Qt::QueuedConnection); connect(m_tiltDistributionComboBox, QOverload::of(&QComboBox::currentIndexChanged), m_mapper, &QDataWidgetMapper::submit, Qt::QueuedConnection); @@ -199,9 +199,7 @@ void CrystalSettingsWidget::setupUi() m_lowerApexHeightStdSlider = new SliderSpinBox(0.0, 5.0); - m_weightSpinBox = new QSpinBox(); - m_weightSpinBox->setMinimum(0); - m_weightSpinBox->setMaximum(10000); + m_weightSlider = new SliderSpinBox(0.0, 20.0); for (auto i = 0; i < 6; ++i) { @@ -221,7 +219,7 @@ void CrystalSettingsWidget::setupUi() auto populationSettingsLayout = new QFormLayout(populationSettingsWidget); populationSettingsLayout->addRow(populationManagementLayout); populationSettingsLayout->addRow(tr("Population enabled"), m_populationEnabledCheckBox); - populationSettingsLayout->addRow(tr("Population weight"), m_weightSpinBox); + populationSettingsLayout->addRow(tr("Population weight"), m_weightSlider); mainLayout->addWidget(populationSettingsWidget); mainLayout->addWidget(tabWidget); diff --git a/src/haloray-core/gui/crystalSettingsWidget.h b/src/haloray-core/gui/crystalSettingsWidget.h index c447f5f..dee442c 100644 --- a/src/haloray-core/gui/crystalSettingsWidget.h +++ b/src/haloray-core/gui/crystalSettingsWidget.h @@ -64,7 +64,7 @@ class CrystalSettingsWidget : public CollapsibleBox SliderSpinBox *m_prismFaceDistanceSliders[6]; - QSpinBox *m_weightSpinBox; + SliderSpinBox *m_weightSlider; CrystalModel *m_model; QDataWidgetMapper *m_mapper; diff --git a/src/haloray-core/gui/models/crystalModel.cpp b/src/haloray-core/gui/models/crystalModel.cpp index ed89baf..a5cc3b8 100644 --- a/src/haloray-core/gui/models/crystalModel.cpp +++ b/src/haloray-core/gui/models/crystalModel.cpp @@ -147,7 +147,7 @@ bool CrystalModel::setData(const QModelIndex &index, const QVariant &value, int crystal.lowerApexHeightStd = value.toFloat(); break; case PopulationWeight: - m_crystals->setWeight(row, value.toUInt()); + m_crystals->setWeight(row, value.toDouble()); break; case PopulationName: m_crystals->setName(row, value.toString().toStdString()); @@ -197,7 +197,7 @@ void CrystalModel::addRow(CrystalPopulationPreset preset) endInsertRows(); } -void CrystalModel::addRow(CrystalPopulation population, unsigned int weight, QString name) +void CrystalModel::addRow(CrystalPopulation population, double weight, QString name) { auto row = m_crystals->getCount(); beginInsertRows(QModelIndex(), row, row); diff --git a/src/haloray-core/gui/models/crystalModel.h b/src/haloray-core/gui/models/crystalModel.h index adf4815..15d46c5 100644 --- a/src/haloray-core/gui/models/crystalModel.h +++ b/src/haloray-core/gui/models/crystalModel.h @@ -54,7 +54,7 @@ class CrystalModel : public QAbstractTableModel Qt::ItemFlags flags(const QModelIndex &index) const override; void addRow(CrystalPopulationPreset preset = CrystalPopulationPreset::Random); - void addRow(CrystalPopulation population, unsigned int weight, QString name); + void addRow(CrystalPopulation population, double weight, QString name); bool removeRow(int row); void clear(); void setName(int row, QString name); diff --git a/src/haloray-core/gui/openGLWidget.cpp b/src/haloray-core/gui/openGLWidget.cpp index a52b343..c42a2cd 100644 --- a/src/haloray-core/gui/openGLWidget.cpp +++ b/src/haloray-core/gui/openGLWidget.cpp @@ -67,9 +67,18 @@ void OpenGLWidget::initializeGL() int maxComputeGroups; glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &maxComputeGroups); + qInfo("Maximum supported number of compute shader workgroups: %i", maxComputeGroups); const int absoluteMaxRaysPerFrame = 5000000; int maxRaysPerFrame = std::min(absoluteMaxRaysPerFrame, maxComputeGroups); m_viewModel->setRaysPerFrameUpperLimit(maxRaysPerFrame); + + int maxWorkGroupSizeX; + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &maxWorkGroupSizeX); + int maxWorkGroupSizeY; + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &maxWorkGroupSizeY); + int maxWorkGroupSizeZ; + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &maxWorkGroupSizeZ); + qInfo("Maximum supported compute shader workgroup size: %i, %i, %i", maxWorkGroupSizeX, maxWorkGroupSizeY, maxWorkGroupSizeZ); } void OpenGLWidget::mousePressEvent(QMouseEvent *event) diff --git a/src/haloray-core/gui/stateSaver.cpp b/src/haloray-core/gui/stateSaver.cpp index 441eb6c..568b2fc 100644 --- a/src/haloray-core/gui/stateSaver.cpp +++ b/src/haloray-core/gui/stateSaver.cpp @@ -96,7 +96,6 @@ void StateSaver::LoadState(QString filename, SimulationStateModel *simState, Cry { settings.setArrayIndex(i); auto pop = CrystalPopulation::createRandom(); - unsigned int weight = settings.value("Weight", 1).toUInt(); pop.enabled = settings.value("Enabled", pop.enabled).toBool(); pop.caRatioAverage = settings.value("CaRatioAverage", pop.caRatioAverage).toFloat(); @@ -119,6 +118,7 @@ void StateSaver::LoadState(QString filename, SimulationStateModel *simState, Cry pop.lowerApexHeightStd = settings.value("LowerApexHeightStd", pop.lowerApexHeightStd).toFloat(); auto name = settings.value("Name", "Default name").toString(); + double weight = settings.value("Weight", 1.0).toDouble(); crystalModel->addRow(pop, weight, name); } diff --git a/src/haloray-core/opengl/textureRenderer.cpp b/src/haloray-core/opengl/textureRenderer.cpp index 12b0f21..2367203 100644 --- a/src/haloray-core/opengl/textureRenderer.cpp +++ b/src/haloray-core/opengl/textureRenderer.cpp @@ -1,6 +1,7 @@ #include "textureRenderer.h" #include #include +#include #include namespace OpenGL @@ -9,11 +10,25 @@ namespace OpenGL std::unique_ptr TextureRenderer::initializeTexDrawShaderProgram() { auto program = std::make_unique(); - program->addCacheableShaderFromSourceFile(QOpenGLShader::ShaderTypeBit::Vertex, ":/shaders/renderer.vert"); - program->addCacheableShaderFromSourceFile(QOpenGLShader::ShaderTypeBit::Fragment, ":/shaders/renderer.frag"); + bool vertexShaderCompilationSucceeded = program->addCacheableShaderFromSourceFile(QOpenGLShader::ShaderTypeBit::Vertex, ":/shaders/renderer.vert"); + + if (vertexShaderCompilationSucceeded == false) + { + qWarning("Texture renderer vertex shader compilation failed"); + throw std::runtime_error(program->log().toUtf8()); + } + + bool fragmentShaderCompilationSucceeded = program->addCacheableShaderFromSourceFile(QOpenGLShader::ShaderTypeBit::Fragment, ":/shaders/renderer.frag"); + + if (fragmentShaderCompilationSucceeded == false) + { + qWarning("Texture renderer fragment shader compilation failed"); + throw std::runtime_error(program->log().toUtf8()); + } if (program->link() == false) { + qWarning("Texture renderer shader linking failed"); throw std::runtime_error(program->log().toUtf8()); } diff --git a/src/haloray-core/resources/shaders/raytrace.glsl b/src/haloray-core/resources/shaders/raytrace.glsl index 5eb16b3..abd38e7 100644 --- a/src/haloray-core/resources/shaders/raytrace.glsl +++ b/src/haloray-core/resources/shaders/raytrace.glsl @@ -142,14 +142,14 @@ vec3 triangleNormalCache[triangles.length()]; uint wang_hash(uint a) { - a -= (a << 6); - a ^= (a >> 17); - a -= (a << 9); - a ^= (a << 4); - a -= (a << 3); - a ^= (a << 10); - a ^= (a >> 15); - return a; + a -= (a << 6); + a ^= (a >> 17); + a -= (a << 9); + a ^= (a << 4); + a -= (a << 3); + a ^= (a << 10); + a ^= (a >> 15); + return a; } uint rngState = wang_hash(rngSeed + uint(gl_GlobalInvocationID.x)); diff --git a/src/haloray-core/simulation/crystalPopulationRepository.cpp b/src/haloray-core/simulation/crystalPopulationRepository.cpp index 662c122..742cfdd 100644 --- a/src/haloray-core/simulation/crystalPopulationRepository.cpp +++ b/src/haloray-core/simulation/crystalPopulationRepository.cpp @@ -22,10 +22,10 @@ void CrystalPopulationRepository::add(CrystalPopulationPreset preset) m_crystals.push_back(CrystalPopulation::presetPopulation(preset)); m_names.push_back(QString("%1 population %2").arg(presetNameMap[preset]).arg(m_nextId).toStdString()); m_nextId = m_nextId + 1; - m_weights.push_back(1); + m_weights.push_back(1.0); } -void CrystalPopulationRepository::add(CrystalPopulation population, unsigned int weight, std::string name) +void CrystalPopulationRepository::add(CrystalPopulation population, double weight, std::string name) { m_crystals.push_back(population); m_names.push_back(name); @@ -36,15 +36,15 @@ void CrystalPopulationRepository::addDefaults() { m_crystals.push_back(CrystalPopulation::presetPopulation(CrystalPopulationPreset::Column)); m_names.push_back("Column"); - m_weights.push_back(1); + m_weights.push_back(1.0); m_crystals.push_back(CrystalPopulation::presetPopulation(CrystalPopulationPreset::Plate)); m_names.push_back("Plate"); - m_weights.push_back(1); + m_weights.push_back(1.0); m_crystals.push_back(CrystalPopulation::presetPopulation(CrystalPopulationPreset::Random)); m_names.push_back("Random"); - m_weights.push_back(1); + m_weights.push_back(1.0); } void CrystalPopulationRepository::remove(unsigned int index) @@ -80,20 +80,20 @@ double CrystalPopulationRepository::getProbability(unsigned int index) const { if (m_crystals[index].enabled == false) return 0.0; - auto totalWeights = 0u; + auto totalWeights = 0.0; for (auto i = 0u; i < getCount(); ++i) { - totalWeights += m_crystals[i].enabled ? m_weights[i] : 0; + totalWeights += m_crystals[i].enabled ? m_weights[i] : 0.0; } - return static_cast(m_weights[index]) / totalWeights; + return m_weights[index] / totalWeights; } -unsigned int CrystalPopulationRepository::getWeight(unsigned int index) const +double CrystalPopulationRepository::getWeight(unsigned int index) const { return m_weights[index]; } -void CrystalPopulationRepository::setWeight(unsigned int index, unsigned int weight) +void CrystalPopulationRepository::setWeight(unsigned int index, double weight) { m_weights[index] = weight; } diff --git a/src/haloray-core/simulation/crystalPopulationRepository.h b/src/haloray-core/simulation/crystalPopulationRepository.h index 2505959..06a5845 100644 --- a/src/haloray-core/simulation/crystalPopulationRepository.h +++ b/src/haloray-core/simulation/crystalPopulationRepository.h @@ -11,7 +11,7 @@ class CrystalPopulationRepository public: CrystalPopulationRepository(); void add(CrystalPopulationPreset preset = Random); - void add(CrystalPopulation population, unsigned int weight, std::string name); + void add(CrystalPopulation population, double weight, std::string name); void remove(unsigned int index); void clear(); @@ -20,8 +20,8 @@ class CrystalPopulationRepository void setName(unsigned int index, std::string name); std::string getName(unsigned int index) const; - unsigned int getWeight(unsigned int index) const; - void setWeight(unsigned int index, unsigned int weight); + double getWeight(unsigned int index) const; + void setWeight(unsigned int index, double weight); double getProbability(unsigned int index) const; unsigned int getCount() const; @@ -29,7 +29,7 @@ class CrystalPopulationRepository private: void addDefaults(); std::vector m_crystals; - std::vector m_weights; + std::vector m_weights; std::vector m_names; unsigned int m_nextId; }; diff --git a/src/haloray-core/simulation/simulationEngine.cpp b/src/haloray-core/simulation/simulationEngine.cpp index 1ab2daf..31a8af2 100644 --- a/src/haloray-core/simulation/simulationEngine.cpp +++ b/src/haloray-core/simulation/simulationEngine.cpp @@ -262,16 +262,29 @@ void SimulationEngine::initialize() void SimulationEngine::initializeShaders() { m_simulationShader = std::make_unique(); - m_simulationShader->addCacheableShaderFromSourceFile(QOpenGLShader::ShaderTypeBit::Compute, ":/shaders/raytrace.glsl"); + bool raytraceShaderCompilationSucceeded = m_simulationShader->addCacheableShaderFromSourceFile(QOpenGLShader::ShaderTypeBit::Compute, ":/shaders/raytrace.glsl"); + if (raytraceShaderCompilationSucceeded == false) + { + qWarning("Compiling raytracing shader failed"); + throw std::runtime_error(m_simulationShader->log().toUtf8()); + } + if (m_simulationShader->link() == false) { + qWarning("Linking raytracing shader failed"); throw std::runtime_error(m_simulationShader->log().toUtf8()); } m_skyShader = new QOpenGLShaderProgram(this); - m_skyShader->addCacheableShaderFromSourceFile(QOpenGLShader::ShaderTypeBit::Compute, ":/shaders/sky.glsl"); + bool skyShaderCompilationSucceeded = m_skyShader->addCacheableShaderFromSourceFile(QOpenGLShader::ShaderTypeBit::Compute, ":/shaders/sky.glsl"); + if (skyShaderCompilationSucceeded == false) + { + qWarning("Compiling sky shader failed"); + throw std::runtime_error(m_skyShader->log().toUtf8()); + } if (m_skyShader->link() == false) { + qWarning("Linking sky shader failed"); throw std::runtime_error(m_skyShader->log().toUtf8()); } } diff --git a/src/tests/crystalPopulationRepositoryTests/crystalPopulationRepositoryTests.cpp b/src/tests/crystalPopulationRepositoryTests/crystalPopulationRepositoryTests.cpp index 29319d1..af2aa01 100644 --- a/src/tests/crystalPopulationRepositoryTests/crystalPopulationRepositoryTests.cpp +++ b/src/tests/crystalPopulationRepositoryTests/crystalPopulationRepositoryTests.cpp @@ -39,9 +39,9 @@ private slots: void evenWeightsByDefault() { auto repository = HaloRay::CrystalPopulationRepository(); - QCOMPARE(repository.getWeight(0), 1); - QCOMPARE(repository.getWeight(1), 1); - QCOMPARE(repository.getWeight(2), 1); + QCOMPARE(repository.getWeight(0), 1.0); + QCOMPARE(repository.getWeight(1), 1.0); + QCOMPARE(repository.getWeight(2), 1.0); } void disabledPopulationsDoNotCountTowardsProbability()