Added opengl resources deleting at exit (textures, arrays...)

This commit is contained in:
Michaël Lemaire 2015-12-10 23:41:42 +01:00
parent bc9db69564
commit 479dcb03ac
27 changed files with 203 additions and 65 deletions

View file

@ -117,7 +117,7 @@ Vector3 Vector3::midPointTo(const Vector3 &other) const {
Vector3 Vector3::randomInSphere(double radius, bool only_surface, RandomGenerator &random) {
// TODO More uniform spatial repartition
// The current randomization clusters result near the center and at the poles
VectorSpherical vec = {only_surface ? radius : random.genDouble() * radius,
(random.genDouble() - 0.5) * M_PI, random.genDouble() * M_2PI};
VectorSpherical vec = {only_surface ? radius : random.genDouble() * radius, (random.genDouble() - 0.5) * M_PI,
random.genDouble() * M_2PI};
return Vector3(vec);
}

View file

@ -71,7 +71,8 @@ class BASICSSHARED_EXPORT Vector3 {
*
* If *only_surface* is true, produce a vector with *radius* as length.
*/
static Vector3 randomInSphere(double radius = 1.0, bool only_surface = false, RandomGenerator &random = RandomGeneratorDefault);
static Vector3 randomInSphere(double radius = 1.0, bool only_surface = false,
RandomGenerator &random = RandomGeneratorDefault);
public:
// TODO Make private

View file

@ -153,9 +153,8 @@ void AtmosphereDefinition::generateStars(int count, RandomGenerator &random) {
for (int i = 0; i < count; ++i) {
Star star;
star.location =
Vector3((random.genDouble() - 0.5) * 100000.0, (random.genDouble() * 0.5) * 100000.0,
(random.genDouble() - 0.5) * 100000.0);
star.location = Vector3((random.genDouble() - 0.5) * 100000.0, (random.genDouble() * 0.5) * 100000.0,
(random.genDouble() - 0.5) * 100000.0);
if (star.location.getNorm() < 30000.0) {
i--;
continue;

View file

@ -108,8 +108,7 @@ void Scenery::autoPreset(RandomGenerator &random) {
Logs::debug() << "[Definition] New scenery generated from seed " << random.getSeed() << std::endl;
}
void Scenery::autoPreset(unsigned int seed)
{
void Scenery::autoPreset(unsigned int seed) {
RandomGenerator random(seed);
autoPreset(random);
}

View file

@ -42,23 +42,11 @@ MainModelerWindow::MainModelerWindow() {
render_process = new RenderProcess(this, render_preview_provider);
// Bind file buttons
QObject *button_new = findQmlObject("tool_file_new");
if (button_new) {
connect(button_new, SIGNAL(clicked()), this, SLOT(newFile()));
}
QObject *button_save = findQmlObject("tool_file_save");
if (button_save) {
connect(button_save, SIGNAL(clicked()), this, SLOT(saveFile()));
}
QObject *button_load = findQmlObject("tool_file_load");
if (button_load) {
connect(button_load, SIGNAL(clicked()), this, SLOT(loadFile()));
}
QObject *button_exit = findQmlObject("tool_file_exit");
if (button_exit) {
connect(button_exit, SIGNAL(clicked()), this, SLOT(exit()));
}
connectQmlSignal("tool_file_new", SIGNAL(clicked()), this, SLOT(newFile()));
connectQmlSignal("tool_file_save", SIGNAL(clicked()), this, SLOT(saveFile()));
connectQmlSignal("tool_file_load", SIGNAL(clicked()), this, SLOT(loadFile()));
connectQmlSignal("tool_file_exit", SIGNAL(clicked()), this, SLOT(exit()));
connectQmlSignal("root", SIGNAL(stopped()), this, SLOT(effectiveExit()));
}
MainModelerWindow::~MainModelerWindow() {
@ -126,7 +114,7 @@ void MainModelerWindow::loadFile() {
}
void MainModelerWindow::exit() {
close();
renderer->stop();
}
void MainModelerWindow::keyReleaseEvent(QKeyEvent *event) {
@ -178,3 +166,7 @@ void MainModelerWindow::keyReleaseEvent(QKeyEvent *event) {
}
}
}
void MainModelerWindow::effectiveExit() {
close();
}

View file

@ -40,6 +40,9 @@ class MainModelerWindow : public QQuickView {
protected:
virtual void keyReleaseEvent(QKeyEvent *event) override;
protected slots:
void effectiveExit();
private:
Scenery *scenery;
OpenGLRenderer *renderer;

View file

@ -41,6 +41,11 @@ void OpenGLView::paint() {
return;
}
if (renderer->isStopped()) {
emit stopped();
return;
}
if (not initialized or not renderer) {
renderer->initialize();
initialized = true;

View file

@ -19,6 +19,9 @@ class OpenGLView : public QQuickItem {
void handleResize();
void handleSceneGraphReady();
signals:
void stopped();
protected:
virtual void wheelEvent(QWheelEvent *event) override;
virtual void mousePressEvent(QMouseEvent *event) override;

View file

@ -1,5 +1,6 @@
#include "OpenGLPart.h"
#include "OpenGLRenderer.h"
#include "OpenGLShaderProgram.h"
#include "OpenGLVertexArray.h"
@ -7,14 +8,25 @@ OpenGLPart::OpenGLPart(OpenGLRenderer *renderer) : renderer(renderer) {
}
OpenGLPart::~OpenGLPart() {
for (auto &pair: shaders) {
for (auto pair : shaders) {
delete pair.second;
}
for (auto &array: arrays) {
for (auto array : arrays) {
delete array;
}
}
void OpenGLPart::destroy() {
OpenGLFunctions *functions = getFunctions();
for (auto shader : shaders) {
shader.second->destroy(functions);
}
for (auto array : arrays) {
array->destroy(functions);
}
}
void OpenGLPart::interrupt() {
}
@ -29,13 +41,16 @@ OpenGLShaderProgram *OpenGLPart::createShader(const std::string &name) {
}
}
OpenGLVertexArray *OpenGLPart::createVertexArray(bool has_uv, bool strip)
{
OpenGLVertexArray *OpenGLPart::createVertexArray(bool has_uv, bool strip) {
OpenGLVertexArray *result = new OpenGLVertexArray(has_uv, strip);
arrays.push_back(result);
return result;
}
OpenGLFunctions *OpenGLPart::getFunctions() {
return renderer->getOpenGlFunctions();
}
void OpenGLPart::updateScenery(bool onlyCommon) {
// Let subclass do its own collecting
if (not onlyCommon) {

View file

@ -26,6 +26,9 @@ class OPENGLSHARED_EXPORT OpenGLPart {
// Do the rendering
virtual void render() = 0;
// Free opengl resources generated in context (like textures...)
virtual void destroy();
// Interrupt the rendering
virtual void interrupt();
@ -46,6 +49,8 @@ class OPENGLSHARED_EXPORT OpenGLPart {
*/
OpenGLVertexArray *createVertexArray(bool has_uv, bool strip);
OpenGLFunctions *getFunctions();
// Access to the main scenery renderer
OpenGLRenderer *renderer;

View file

@ -18,6 +18,8 @@ OpenGLRenderer::OpenGLRenderer(Scenery *scenery) : SoftwareRenderer(scenery) {
ready = false;
paused = false;
displayed = false;
stopping = false;
stopped = false;
vp_width = 1;
vp_height = 1;
@ -65,6 +67,16 @@ void OpenGLRenderer::checkForErrors(const std::string &domain) {
}
}
void OpenGLRenderer::destroy() {
shared_state->destroy(functions);
skybox->destroy();
terrain->destroy();
water->destroy();
checkForErrors("stopping");
}
void OpenGLRenderer::initialize() {
ready = functions->initializeOpenGLFunctions();
@ -145,7 +157,12 @@ void OpenGLRenderer::resize(int width, int height) {
}
void OpenGLRenderer::paint(bool clear) {
if (ready and not paused) {
if (stopping) {
if (not stopped) {
destroy();
stopped = true;
}
} else if (ready and not paused) {
checkForErrors("before_paint");
if (clear) {
functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -169,6 +186,11 @@ void OpenGLRenderer::paint(bool clear) {
}
}
bool OpenGLRenderer::stop() {
stopping = true;
return stopped;
}
void OpenGLRenderer::reset() {
if (ready) {
skybox->updateScenery();

View file

@ -10,8 +10,8 @@ class QMatrix4x4;
namespace paysages {
namespace opengl {
/*!
* \brief Scenery renderer in an OpenGL context.
/**
* Scenery renderer in an OpenGL context.
*/
class OPENGLSHARED_EXPORT OpenGLRenderer : public SoftwareRenderer {
public:
@ -30,6 +30,12 @@ class OPENGLSHARED_EXPORT OpenGLRenderer : public SoftwareRenderer {
inline bool isDisplayed() const {
return displayed;
}
inline bool isStopping() const {
return stopping;
}
inline bool isStopped() const {
return stopped;
}
/**
* Check for errors in OpenGL context.
@ -38,10 +44,26 @@ class OPENGLSHARED_EXPORT OpenGLRenderer : public SoftwareRenderer {
*/
void checkForErrors(const std::string &domain);
/**
* Release any allocated resource in the opengl context.
*
* Must be called in the opengl rendering thread, and before the destructor is called.
*/
void destroy();
void initialize();
void prepareOpenGLState(bool clear=true);
void prepareOpenGLState(bool clear = true);
void resize(int width, int height);
void paint(bool clear=true);
void paint(bool clear = true);
/**
* Ask for the rendering to stop gracefully.
*
* Returns true if the rendering is stopped and resources freed.
*
* This should be called in an idle loop, while it returns false.
*/
bool stop();
/**
* Reset the whole state (when the scenery has been massively updated).
@ -95,6 +117,8 @@ class OPENGLSHARED_EXPORT OpenGLRenderer : public SoftwareRenderer {
bool ready;
bool paused;
bool displayed;
bool stopping;
bool stopped;
int vp_width;
int vp_height;

View file

@ -41,6 +41,10 @@ void OpenGLShaderProgram::addFragmentSource(const std::string &path) {
}
}
void OpenGLShaderProgram::destroy(OpenGLFunctions *functions) {
program->removeAllShaders();
}
void OpenGLShaderProgram::compile() {
std::string prefix = std::string("#version ") + OPENGL_GLSL_VERSION + "\n\n";

View file

@ -16,6 +16,13 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram {
void addVertexSource(const std::string &path);
void addFragmentSource(const std::string &path);
/**
* Release any allocated resource in the opengl context.
*
* Must be called in the opengl rendering thread, and before the destructor is called.
*/
void destroy(OpenGLFunctions *functions);
/**
* Draw a VertexArray object.
*

View file

@ -15,6 +15,12 @@ void OpenGLSharedState::apply(OpenGLShaderProgram *program, int &texture_unit) {
}
}
void OpenGLSharedState::destroy(OpenGLFunctions *functions) {
for (const auto &pair : variables) {
pair.second->destroy(functions);
}
}
OpenGLVariable *OpenGLSharedState::get(const std::string &name) {
OpenGLVariable *&var = variables[name];
if (var == NULL) {

View file

@ -11,21 +11,28 @@ class QImage;
namespace paysages {
namespace opengl {
/*!
* \brief OpenGL variables that can be shared between shaders.
/**
* OpenGL variables that can be shared between shaders.
*/
class OPENGLSHARED_EXPORT OpenGLSharedState {
public:
OpenGLSharedState();
~OpenGLSharedState();
/*!
* \brief Apply the stored variables to the bound program.
/**
* Apply the stored variables to the bound program.
*/
void apply(OpenGLShaderProgram *program, int &texture_unit);
/*!
* \brief Get or create a variable in the state.
/**
* Release any allocated resource in the opengl context.
*
* Must be called in the opengl rendering thread, and before the destructor is called.
*/
void destroy(OpenGLFunctions *functions);
/**
* Get or create a variable in the state.
*/
OpenGLVariable *get(const std::string &name);

View file

@ -62,7 +62,7 @@ void OpenGLTerrain::initialize() {
for (int i = 0; i < chunks; i++) {
for (int j = 0; j < chunks; j++) {
OpenGLTerrainChunk *chunk = new OpenGLTerrainChunk(renderer, start + chunksize * (double)i,
start + chunksize * (double)j, chunksize, chunks);
start + chunksize * (double)j, chunksize, chunks);
_chunks.append(chunk);
_updateQueue.append(chunk);
}
@ -94,6 +94,13 @@ void OpenGLTerrain::interrupt() {
}
}
void OpenGLTerrain::destroy() {
OpenGLFunctions *functions = getFunctions();
for (auto &chunk : _chunks) {
chunk->destroy(functions);
}
}
void OpenGLTerrain::pause() {
paused = true;
interrupt();

View file

@ -22,6 +22,7 @@ class OPENGLSHARED_EXPORT OpenGLTerrain : public OpenGLPart, public DefinitionWa
virtual void update() override;
virtual void render() override;
virtual void interrupt() override;
virtual void destroy() override;
void pause();
void resume();

View file

@ -146,14 +146,14 @@ void OpenGLTerrainChunk::updatePriority(CameraDefinition *camera) {
_lock_data->release();
// Update wanted LOD
if (distance_to_camera < 60.0) {
if (distance_to_camera < 100.0) {
_texture_wanted_size = _texture_max_size;
} else if (distance_to_camera < 140.0) {
} else if (distance_to_camera < 200.0) {
_texture_wanted_size = _texture_max_size / 4;
} else if (distance_to_camera < 300.0) {
} else if (distance_to_camera < 400.0) {
_texture_wanted_size = _texture_max_size / 8;
} else {
_texture_wanted_size = 8;
_texture_wanted_size = _texture_max_size / 16;
}
// Update priority
@ -195,6 +195,11 @@ void OpenGLTerrainChunk::askResume() {
interrupt = false;
}
void OpenGLTerrainChunk::destroy(OpenGLFunctions *functions) {
vertices->destroy(functions);
glstate->destroy(functions);
}
void OpenGLTerrainChunk::setFirstStepVertices() {
OpenGLVertexArray next(true);
next.setVertexCount(6);
@ -210,6 +215,9 @@ void OpenGLTerrainChunk::augmentVertices() {
// TODO Re-use existing vertices from previous level when possible
double quad_size = _size / (double)next_vertices_level;
for (int iz = 0; iz < next_vertices_level; iz++) {
if (interrupt or _reset_topology) {
return;
}
for (int ix = 0; ix < next_vertices_level; ix++) {
fillVerticesFromSquare(&next, (iz * next_vertices_level + ix) * 6, _startx + quad_size * (double)ix,
_startz + quad_size * (double)iz, quad_size);

View file

@ -28,6 +28,13 @@ class OPENGLSHARED_EXPORT OpenGLTerrainChunk {
return vertices;
}
/**
* Release any allocated resource in the opengl context.
*
* Must be called in the opengl rendering thread, and before the destructor is called.
*/
void destroy(OpenGLFunctions *functions);
/**
* Fill *vertices* with a quick initial set of vertices, that can be augmented later using *augmentVertices*.
*/

View file

@ -79,6 +79,13 @@ void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit) {
}
}
void OpenGLVariable::destroy(OpenGLFunctions *functions) {
if (texture_id) {
functions->glDeleteTextures(1, &texture_id);
texture_id = 0;
}
}
void OpenGLVariable::set(const Texture2D *texture, bool repeat, bool color) {
assert(type == TYPE_NONE or type == TYPE_TEXTURE_2D);
@ -111,8 +118,7 @@ void OpenGLVariable::set(const Texture2D *texture, bool repeat, bool color) {
texture_color = color;
}
void OpenGLVariable::set(const QImage &texture, bool repeat, bool color)
{
void OpenGLVariable::set(const QImage &texture, bool repeat, bool color) {
assert(type == TYPE_NONE or type == TYPE_TEXTURE_2D);
type = TYPE_TEXTURE_2D;
@ -272,8 +278,10 @@ void OpenGLVariable::uploadTexture(OpenGLRenderer *renderer) {
int dest_format = texture_color ? GL_RGBA : GL_RED;
if (type == TYPE_TEXTURE_2D) {
functions->glTexImage2D(GL_TEXTURE_2D, 0, dest_format, texture_size_x, texture_size_y, 0, GL_RGBA, GL_FLOAT, value_texture_data);
functions->glTexImage2D(GL_TEXTURE_2D, 0, dest_format, texture_size_x, texture_size_y, 0, GL_RGBA, GL_FLOAT,
value_texture_data);
} else {
functions->glTexImage3D(GL_TEXTURE_3D, 0, dest_format, texture_size_x, texture_size_y, texture_size_z, 0, GL_RGBA, GL_FLOAT, value_texture_data);
functions->glTexImage3D(GL_TEXTURE_3D, 0, dest_format, texture_size_x, texture_size_y, texture_size_z, 0,
GL_RGBA, GL_FLOAT, value_texture_data);
}
}

View file

@ -33,6 +33,13 @@ class OpenGLVariable {
void apply(OpenGLShaderProgram *program, int &texture_unit);
/**
* Release any allocated resource in the opengl context.
*
* Must be called in the opengl rendering thread, and before the destructor is called.
*/
void destroy(OpenGLFunctions *functions);
void set(const Texture2D *texture, bool repeat = false, bool color = true);
void set(const QImage &texture, bool repeat = false, bool color = true);
void set(const Texture3D *texture, bool repeat = false, bool color = true);

View file

@ -30,8 +30,19 @@ OpenGLVertexArray::~OpenGLVertexArray() {
free(array_uv);
}
void OpenGLVertexArray::destroy() {
// TODO
void OpenGLVertexArray::destroy(OpenGLFunctions *functions) {
if (vbo_vertex) {
functions->glDeleteBuffers(1, &vbo_vertex);
vbo_vertex = 0;
}
if (vbo_uv) {
functions->glDeleteBuffers(1, &vbo_uv);
vbo_uv = 0;
}
if (vao) {
functions->glDeleteVertexArrays(1, &vao);
vao = 0;
}
}
void OpenGLVertexArray::render(OpenGLFunctions *functions) {
@ -72,8 +83,7 @@ void OpenGLVertexArray::set(int index, const Vector3 &location, double u, double
}
}
void OpenGLVertexArray::get(int index, Vector3 *location, double *u, double *v) const
{
void OpenGLVertexArray::get(int index, Vector3 *location, double *u, double *v) const {
if (index >= 0 and index < vertexcount) {
location->x = array_vertex[index * 3];
location->y = array_vertex[index * 3 + 1];
@ -85,8 +95,7 @@ void OpenGLVertexArray::get(int index, Vector3 *location, double *u, double *v)
}
}
void OpenGLVertexArray::copyTo(OpenGLVertexArray *destination) const
{
void OpenGLVertexArray::copyTo(OpenGLVertexArray *destination) const {
destination->setVertexCount(vertexcount);
if (vertexcount) {
memcpy(destination->array_vertex, array_vertex, sizeof(float) * vertexcount * 3);

View file

@ -25,7 +25,7 @@ class OpenGLVertexArray {
*
* Must be called in the opengl rendering thread, and before the destructor is called.
*/
void destroy();
void destroy(OpenGLFunctions *functions);
/**
* Render this array in current opengl context.

View file

@ -4,11 +4,11 @@
#include <random>
static RandomGenerator _RandomGeneratorDefault;
RandomGenerator& paysages::system::RandomGeneratorDefault = _RandomGeneratorDefault;
RandomGenerator &paysages::system::RandomGeneratorDefault = _RandomGeneratorDefault;
class RandomGenerator::RandomGeneratorPrivate {
public:
RandomGeneratorPrivate(unsigned int seed): generator(seed) {
RandomGeneratorPrivate(unsigned int seed) : generator(seed) {
}
std::default_random_engine generator;
@ -27,12 +27,10 @@ RandomGenerator::RandomGenerator(RandomGenerator::Seed seed) {
data = new RandomGeneratorPrivate(seed);
}
RandomGenerator::~RandomGenerator()
{
RandomGenerator::~RandomGenerator() {
delete data;
}
double RandomGenerator::genDouble()
{
double RandomGenerator::genDouble() {
return data->distribution_double(data->generator);
}

View file

@ -31,7 +31,7 @@ class PictureWriter;
class Time;
class RandomGenerator;
extern RandomGenerator& RandomGeneratorDefault;
extern RandomGenerator &RandomGeneratorDefault;
}
}
using namespace paysages::system;

View file

@ -6,7 +6,8 @@
#include "OpenGLVertexArray.h"
#include "Vector3.h"
static void checkVertex(const OpenGLVertexArray *array, int index, const Vector3 &expected_location, double expected_u, double expected_v) {
static void checkVertex(const OpenGLVertexArray *array, int index, const Vector3 &expected_location, double expected_u,
double expected_v) {
Vector3 location;
double u, v;